Save changes in the rope.

Also changes to using the new rustc interface
This commit is contained in:
Nick Cameron 2015-02-02 21:59:03 +13:00
parent 5caf49ff63
commit f1e698c838
2 changed files with 545 additions and 214 deletions

View File

@ -15,9 +15,8 @@
// docs
use rope::{Rope, RopeSlice};
use std::collections::{HashMap, BTreeMap};
use std::collections::Bound::{Included, Unbounded};
use syntax::codemap::{CodeMap, Span, Pos};
use std::collections::HashMap;
use syntax::codemap::{CodeMap, Span, Pos, BytePos};
use std::fmt;
pub struct ChangeSet<'a> {
@ -27,34 +26,6 @@ pub struct ChangeSet<'a> {
// out into an adaptor.
codemap: &'a CodeMap,
pub count: u64,
// TODO we need to map the start and end of spans differently
// TODO needs to be per file
adjusts: BTreeMap<usize, Adjustment>,
}
// An extent over which we must adjust the position values.
#[derive(Show, Clone, Eq, PartialEq)]
struct Adjustment {
// Start is implicit, given by its position in the map.
end: usize,
delta: isize,
}
impl Adjustment {
fn chop_left(&self, new_end: usize) -> Adjustment {
Adjustment {
end: new_end,
delta: self.delta,
}
}
fn move_left(&self, mov: usize) -> Adjustment {
assert!(self.delta > mov);
Adjustment {
end: self.end,
delta: self.delta - mov,
}
}
}
pub struct FileIterator<'c, 'a: 'c> {
@ -69,7 +40,6 @@ impl<'a> ChangeSet<'a> {
file_map: HashMap::new(),
codemap: codemap,
count: 0,
adjusts: BTreeMap::new(),
};
for f in codemap.files.borrow().iter() {
@ -84,100 +54,21 @@ impl<'a> ChangeSet<'a> {
pub fn change(&mut self, file_name: &str, start: usize, end: usize, text: String) {
println!("change: {}:{}-{} \"{}\"", file_name, start, end, text);
let new_len = text.len();
self.count += 1;
let (key_start, adj_start, abs_start): (Option<usize>, Option<Adjustment>, usize) = {
let before_start = self.adjusts.range(Unbounded, Included(&start)).next_back();
match before_start {
Some((k, a)) if a.end > start => (Some(*k), Some(a.clone()), (start as isize + a.delta) as usize),
_ => (None, None, start)
}
};
let (key_end, adj_end, abs_end) = {
let before_end = self.adjusts.range(Unbounded, Included(&end)).next_back();
match before_end {
Some((k, a)) if a.end > end => (Some(*k), Some(a.clone()), (end as isize + a.delta) as usize),
_ => (None, None, end)
}
};
let file = &mut self.file_map[*file_name];
{
let file = &mut self.file_map[*file_name];
println!("change: absolute values {}-{}, replaces \"{}\"",
abs_start, abs_end, file.slice(abs_start..abs_end));
file.remove(abs_start, abs_end);
file.insert(abs_start, text);
// Record the changed locations.
// TODO what if there is a change to the right of end? - need to iterate over all changes to the right :-(
match (key_start, key_end) {
(None, None) => {
// Factor this out?
let old_len = end as isize - start as isize;
let delta = new_len as isize - old_len;
self.adjusts.insert(end, Adjustment { end: file.len(), delta: delta });
}
(Some(k), None) => {
// Adjust the old change.
self.adjusts[k] = adj_start.unwrap().chop_left(end);
// Add the new one.
let old_len = end as isize - start as isize;
let delta = new_len as isize - old_len;
self.adjusts.insert(end, Adjustment { end: file.len(), delta: delta });
}
(None, Some(k)) => {
let old_len = end as isize - start as isize;
let delta = new_len as isize - old_len;
// Adjust the old change.
// TODO only if we move left, but what if moving right?
self.adjusts[abs_end] = adj_end.unwrap().move_left(TODO);
self.adjusts.remove(&k);
// Add the new one.
self.adjusts.insert(end, Adjustment { end: file.len(), delta: delta });
}
_ => {
println!("{}", file);
panic!();
}
}
if end - start == text.len() {
// TODO
panic!();
file.replace_str(start, &text[]);
} else {
// TODO if we do this in one op, could we get better change info?
file.src_remove(start, end);
file.src_insert(start, text);
}
debug_assert!(self.verify_adjustments(), "Bad change, created an overlapping adjustment");
}
// Intended for debugging.
fn verify_adjustments(&self) -> bool {
let mut prev_end = 0;
let mut prev_delta = 0;
for (&k, a) in self.adjusts.iter() {
if k < prev_end {
debug!("Found bad adjustment at start {}, overlaps with previous adjustment", k);
return false;
}
if k as isize + a.delta < 0 {
debug!("Found bad adjustment at start {}, absolute start < 0", k);
return false;
}
if k as isize + a.delta < prev_end as isize + prev_delta {
debug!("Found bad adjustment at start {}, \
projection overlaps with previous projection", k);
return false;
}
// TODO Check end + delta <= file.len - needs per file
prev_end = a.end;
prev_delta = a.delta;
}
true
}
// span is unadjusted.
pub fn change_span(&mut self, span: Span, text: String) {
let l_loc = self.codemap.lookup_char_pos(span.lo);
let file_offset = l_loc.file.start_pos.0;
@ -187,29 +78,11 @@ impl<'a> ChangeSet<'a> {
text)
}
// start and end are unadjusted.
pub fn slice(&self, file_name: &str, start: usize, end: usize) -> RopeSlice {
// TODO refactor with change?
let abs_start = {
let before_start = self.adjusts.range(Unbounded, Included(&start)).next_back();
match before_start {
Some((k, ref a)) if a.end > start => (start as isize + a.delta) as usize,
_ => start
}
};
let abs_end = {
let before_end = self.adjusts.range(Unbounded, Included(&end)).next_back();
match before_end {
Some((k, ref a)) if a.end > end => (end as isize + a.delta) as usize,
_ => end
}
};
let file = &self.file_map[*file_name];
file.slice(abs_start..abs_end)
file.src_slice(start..end)
}
// span is unadjusted.
pub fn slice_span(&self, span:Span) -> RopeSlice {
let l_loc = self.codemap.lookup_char_pos(span.lo);
let file_offset = l_loc.file.start_pos.0;
@ -225,6 +98,13 @@ impl<'a> ChangeSet<'a> {
cur_key: 0,
}
}
pub fn col(&self, loc: BytePos) -> usize {
let l_loc = self.codemap.lookup_char_pos(loc);
let file_offset = l_loc.file.start_pos.0;
let file = &self.file_map[l_loc.file.name[]];
file.col_for_src_loc(loc.0 as usize - file_offset as usize)
}
}
impl<'c, 'a> Iterator for FileIterator<'c, 'a> {

View File

@ -28,6 +28,7 @@ use std::ops::Range;
pub struct Rope {
root: Node,
len: usize,
src_len: usize,
// FIXME: Allocation is very dumb at the moment, we always add another buffer for every inserted string and we never resuse or collect old memory
storage: Vec<Vec<u8>>
}
@ -54,6 +55,7 @@ impl Rope {
Rope {
root: Node::empty_inner(),
len: 0,
src_len: 0,
storage: vec![],
}
}
@ -64,9 +66,15 @@ impl Rope {
let mut result = Rope::new();
result.insert(0, text);
result.fix_src();
result
}
fn fix_src(&mut self) {
self.root.fix_src();
self.src_len = self.len;
}
pub fn len(&self) -> usize {
self.len
}
@ -80,10 +88,10 @@ impl Rope {
let len = text.len();
let storage = text.into_bytes();
let new_node = box Node::new_leaf(&storage[][0] as *const u8, len);
let new_node = box Node::new_leaf(&storage[][0] as *const u8, len, 0);
self.storage.push(storage);
match self.root.insert(new_node, start) {
match self.root.insert(new_node, start, start) {
NodeAction::Change(n, adj) => {
assert!(adj as usize == len);
self.root = *n;
@ -101,6 +109,32 @@ impl Rope {
self.insert(start, text.to_string());
}
pub fn src_insert(&mut self, start: usize, text: String) {
// TODO refactor with insert
if text.len() == 0 {
return;
}
debug_assert!(start <= self.src_len, "insertion out of bounds of rope");
let len = text.len();
let storage = text.into_bytes();
let new_node = box Node::new_leaf(&storage[][0] as *const u8, len, 0);
self.storage.push(storage);
match self.root.src_insert(new_node, start, start) {
NodeAction::Change(n, adj) => {
assert!(adj as usize == len);
self.root = *n;
}
NodeAction::Adjust(adj) => {
assert!(adj as usize == len);
}
_ => panic!("Unexpected action")
}
self.len += len;
}
pub fn push(&mut self, text: String) {
let len = self.len();
self.insert(len, text);
@ -118,7 +152,7 @@ impl Rope {
return;
}
let action = self.root.remove(start, end, 0);
let action = self.root.remove(start, end, start);
match action {
NodeAction::None => {}
NodeAction::Remove => {
@ -133,6 +167,30 @@ impl Rope {
}
}
pub fn src_remove(&mut self, start: usize, end: usize) {
// TODO refactor with remove
assert!(end >= start);
if start == end {
return;
}
let action = self.root.src_remove(start, end, start);
match action {
NodeAction::None => {}
NodeAction::Remove => {
self.root = Node::empty_inner();
self.len = 0;
}
NodeAction::Adjust(adj) => self.len = (self.len as isize + adj) as usize,
NodeAction::Change(node, adj) => {
self.root = *node;
self.len = (self.len as isize + adj) as usize;
}
}
}
// TODO src_replace
// This can go horribly wrong if you overwrite a grapheme of different size.
// It is the callers responsibility to ensure that the grapheme at point start
// has the same size as new_char.
@ -150,6 +208,14 @@ impl Rope {
self.root.replace(start, new_str);
}
// Note, this is not necessarily cheap.
pub fn col_for_src_loc(&self, src_loc: usize) -> usize {
assert!(src_loc <= self.src_len);
match self.root.col_for_src_loc(src_loc) {
Search::Done(c) | Search::Continue(c) => c
}
}
pub fn slice(&self, Range { start, end }: Range<usize>) -> RopeSlice {
debug_assert!(end > start && start <= self.len && end <= self.len);
if start == end {
@ -165,6 +231,17 @@ impl Rope {
self.slice(0..self.len)
}
pub fn src_slice(&self, Range { start, end }: Range<usize>) -> RopeSlice {
debug_assert!(end > start && start <= self.src_len && end <= self.src_len);
if start == end {
return RopeSlice::empty();
}
let mut result = RopeSlice::empty();
self.root.find_src_slice(start, end, &mut result);
result
}
pub fn chars(&self) -> RopeChars {
RopeChars {
data: self.full_slice(),
@ -242,12 +319,14 @@ impl<'rope> RopeChars<'rope> {
}
impl ::std::str::FromStr for Rope {
fn from_str(text: &str) -> Option<Rope> {
type Err = ();
fn from_str(text: &str) -> Result<Rope, ()> {
// TODO should split large texts into segments as we insert
let mut result = Rope::new();
result.insert_copy(0, text);
Some(result)
result.fix_src();
Ok(result)
}
}
@ -325,7 +404,7 @@ impl fmt::Display for Node {
Ok(())
})
}
Node::LeafNode(Lnode{ ref text, len }) => {
Node::LeafNode(Lnode{ ref text, len, .. }) => {
unsafe {
write!(fmt,
"{}",
@ -339,7 +418,7 @@ impl fmt::Display for Node {
impl fmt::Debug for Node {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Node::InnerNode(Inode { ref left, ref right, weight }) => {
Node::InnerNode(Inode { ref left, ref right, weight, .. }) => {
try!(write!(fmt, "("));
if let Some(ref left) = *left {
try!(write!(fmt, "left: {:?}", &**left));
@ -354,10 +433,10 @@ impl fmt::Debug for Node {
}
write!(fmt, "; {})", weight)
}
Node::LeafNode(Lnode{ ref text, len }) => {
Node::LeafNode(Lnode{ ref text, len, .. }) => {
unsafe {
write!(fmt,
"\"{}\"; {}",
"(\"{}\"; {})",
::std::str::from_utf8(::std::slice::from_raw_buf(text, len)).unwrap(),
len)
}
@ -375,6 +454,7 @@ enum Node {
#[derive(Clone, Eq, PartialEq)]
struct Inode {
weight: usize,
src_weight: usize,
left: Option<Box<Node>>,
right: Option<Box<Node>>,
}
@ -383,6 +463,8 @@ struct Inode {
struct Lnode {
text: *const u8,
len: usize,
// text + src_offset = src text (src_offset should always be <= 0)
src_offset: isize,
}
impl Node {
@ -390,25 +472,29 @@ impl Node {
Node::InnerNode(Inode {
left: None,
right: None,
weight: 0
weight: 0,
src_weight: 0,
})
}
fn new_inner(left: Option<Box<Node>>,
right: Option<Box<Node>>,
weight: usize)
weight: usize,
src_weight: usize)
-> Node {
Node::InnerNode(Inode {
left: left,
right: right,
weight: weight
weight: weight,
src_weight: src_weight,
})
}
fn new_leaf(text: *const u8, len: usize) -> Node {
fn new_leaf(text: *const u8, len: usize, src_offset: isize) -> Node {
Node::LeafNode(Lnode {
text: text,
len: len
len: len,
src_offset: src_offset,
})
}
@ -424,23 +510,77 @@ impl Node {
}
}
// precond: start < end
fn remove(&mut self, start: usize, end: usize, offset: usize) -> NodeAction {
if end < offset {
// The span to remove is to the left of this node.
return NodeAction::None;
}
fn fix_src(&mut self) {
match *self {
Node::InnerNode(ref mut i) => i.remove(start, end, offset),
Node::LeafNode(ref mut l) => l.remove(start, end, offset),
Node::InnerNode(ref mut i) => i.fix_src(),
Node::LeafNode(ref mut l) => {
l.src_offset = 0;
},
}
}
fn insert(&mut self, node: Box<Node>, start: usize) -> NodeAction {
// All these methods are just doing dynamic dispatch, TODO use a macro
// precond: start < end
fn remove(&mut self, start: usize, end: usize, src_start: usize) -> NodeAction {
match *self {
Node::InnerNode(ref mut i) => i.insert(node, start),
Node::LeafNode(ref mut l) => l.insert(node, start),
Node::InnerNode(ref mut i) => i.remove(start, end, src_start),
Node::LeafNode(ref mut l) => l.remove(start, end, src_start),
}
}
fn src_remove(&mut self, start: usize, end: usize, src_start: usize) -> NodeAction {
match *self {
Node::InnerNode(ref mut i) => i.src_remove(start, end, src_start),
Node::LeafNode(ref mut l) => {
debug!("src_remove: pre-adjust {}-{}; {}", start, end, l.src_offset);
let mut start = start as isize + l.src_offset;
if start < 0 {
start = 0;
}
let mut end = end as isize + l.src_offset;
if end < 0 {
end = 0;
}
// TODO src_start?
let mut src_start = src_start as isize + l.src_offset;
if src_start < 0 {
src_start = 0;
}
debug!("src_remove: post-adjust {}-{}, {}", start, end, src_start);
if end > start {
l.remove(start as usize, end as usize, src_start as usize)
} else {
NodeAction::None
}
}
}
}
fn insert(&mut self, node: Box<Node>, start: usize, src_start: usize) -> NodeAction {
match *self {
Node::InnerNode(ref mut i) => i.insert(node, start, src_start),
Node::LeafNode(ref mut l) => l.insert(node, start, src_start),
}
}
fn src_insert(&mut self, node: Box<Node>, start: usize, src_start: usize) -> NodeAction {
match *self {
Node::InnerNode(ref mut i) => i.src_insert(node, start, src_start),
Node::LeafNode(ref mut l) => {
debug!("src_insert: pre-adjust {}, {}; {}", start, src_start, l.src_offset);
let mut start = start as isize + l.src_offset;
if start < 0 {
start = 0;
}
// TODO src_start?
let mut src_start = src_start as isize + l.src_offset;
if src_start < 0 {
src_start = 0;
}
debug!("src_insert: post-adjust {}, {}", start, src_start);
l.insert(node, start as usize, src_start as usize)
}
}
}
@ -451,15 +591,50 @@ impl Node {
}
}
fn find_src_slice<'a>(&'a self, start: usize, end: usize, slice: &mut RopeSlice<'a>) {
match *self {
Node::InnerNode(ref i) => i.find_src_slice(start, end, slice),
Node::LeafNode(ref l) => {
debug!("find_src_slice: pre-adjust {}-{}; {}", start, end, l.src_offset);
let mut start = start as isize + l.src_offset;
if start < 0 {
start = 0;
}
let mut end = end as isize + l.src_offset;
if end < 0 {
end = 0;
}
debug!("find_src_slice: post-adjust {}-{}", start, end);
if end > start {
l.find_slice(start as usize, end as usize, slice);
}
}
}
}
fn replace(&mut self, start: usize, new_str: &str) {
match *self {
Node::InnerNode(ref mut i) => i.replace(start, new_str),
Node::LeafNode(ref mut l) => l.replace(start, new_str),
}
}
fn col_for_src_loc(&self, src_loc: usize) -> Search {
match *self {
Node::InnerNode(ref i) => i.col_for_src_loc(src_loc),
Node::LeafNode(ref l) => l.col_for_src_loc(src_loc),
}
}
fn find_last_char(&self, c: char) -> Option<usize> {
match *self {
Node::InnerNode(ref i) => i.find_last_char(c),
Node::LeafNode(ref l) => l.find_last_char(c),
}
}
}
#[derive(Show, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq)]
enum NodeAction {
None,
Remove,
@ -468,28 +643,40 @@ enum NodeAction {
}
impl Inode {
// precond: start < end && end >= offset
fn remove(&mut self, start: usize, end: usize, offset: usize) -> NodeAction {
debug!("Inode::remove: {}, {}, {}, {}", start, end, offset, self.weight);
if start >= offset + self.weight {
// The removal cannot affect our left side.
match self.right {
Some(_) => {}
None => {}
}
}
fn remove(&mut self, start: usize, end: usize, src_start: usize) -> NodeAction {
debug!("Inode::remove: {}, {}, {}", start, end, self.weight);
let left_action = if let Some(ref mut left) = self.left {
left.remove(start, end, offset)
let left_action = if start <= self.weight {
if let Some(ref mut left) = self.left {
left.remove(start, end, src_start)
} else {
panic!();
}
} else {
NodeAction::None
};
let right_action = if let Some(ref mut right) = self.right {
right.remove(start, end, offset + self.weight)
let right_action = if end > self.weight {
if let Some(ref mut right) = self.right {
let start = if start < self.weight {
0
} else {
start - self.weight
};
let src_start = if src_start < self.src_weight {
0
} else {
src_start - self.src_weight
};
right.remove(start, end - self.weight, src_start)
} else {
panic!();
}
} else {
NodeAction::None
};
if left_action == NodeAction::Remove && right_action == NodeAction::Remove ||
left_action == NodeAction::Remove && self.right.is_none() ||
right_action == NodeAction::Remove && self.left.is_none() {
@ -527,11 +714,84 @@ impl Inode {
return NodeAction::Adjust(total_adj);
}
fn insert(&mut self, node: Box<Node>, start: usize) -> NodeAction {
fn src_remove(&mut self, start: usize, end: usize, src_start: usize) -> NodeAction {
// TODO refactor with remove
debug!("Inode::src_remove: {}, {}, {}/{}", start, end, self.src_weight, self.weight);
let left_action = if start <= self.src_weight {
if let Some(ref mut left) = self.left {
left.src_remove(start, end, src_start)
} else {
panic!();
}
} else {
NodeAction::None
};
let right_action = if end > self.src_weight {
if let Some(ref mut right) = self.right {
let start = if start < self.src_weight {
0
} else {
start - self.src_weight
};
let src_start = if src_start < self.src_weight {
0
} else {
src_start - self.src_weight
};
right.src_remove(start, end - self.src_weight, src_start)
} else {
panic!();
}
} else {
NodeAction::None
};
if left_action == NodeAction::Remove && right_action == NodeAction::Remove ||
left_action == NodeAction::Remove && self.right.is_none() ||
right_action == NodeAction::Remove && self.left.is_none() {
return NodeAction::Remove;
}
if left_action == NodeAction::Remove {
return NodeAction::Change(self.right.clone().unwrap(),
-(self.weight as isize));
}
if right_action == NodeAction::Remove {
return NodeAction::Change(self.left.clone().unwrap(),
-(self.right.as_ref().map(|n| n.len()).unwrap() as isize));
}
let mut total_adj = 0;
if start < self.weight {
if let NodeAction::Change(ref n, adj) = left_action {
self.left = Some(n.clone());
self.weight = (self.weight as isize + adj) as usize;
total_adj += adj;
}
if let NodeAction::Change(ref n, adj) = right_action {
self.right = Some(n.clone());
total_adj += adj;
}
if let NodeAction::Adjust(adj) = left_action {
self.weight = (self.weight as isize + adj) as usize;
total_adj += adj;
}
if let NodeAction::Adjust(adj) = right_action {
total_adj += adj;
}
return NodeAction::Adjust(total_adj);
}
fn insert(&mut self, node: Box<Node>, start: usize, src_start: usize) -> NodeAction {
let mut total_adj = 0;
if start <= self.weight {
let action = if let Some(ref mut left) = self.left {
left.insert(node, start)
left.insert(node, start, src_start)
} else {
assert!(self.weight == 0);
let len = node.len() as isize;
@ -553,7 +813,53 @@ impl Inode {
} else {
let action = if let Some(ref mut right) = self.right {
assert!(start >= self.weight);
right.insert(node, start - self.weight)
assert!(src_start >= self.src_weight);
right.insert(node, start - self.weight, src_start - self.src_weight)
} else {
let len = node.len() as isize;
NodeAction::Change(node, len)
};
match action {
NodeAction::Change(n, adj) => {
self.right = Some(n);
total_adj += adj;
}
NodeAction::Adjust(adj) => total_adj += adj,
_ => panic!("Unexpected action"),
}
}
NodeAction::Adjust(total_adj)
}
fn src_insert(&mut self, node: Box<Node>, start: usize, src_start: usize) -> NodeAction {
let mut total_adj = 0;
if start <= self.src_weight {
let action = if let Some(ref mut left) = self.left {
left.src_insert(node, start, src_start)
} else {
let len = node.len() as isize;
NodeAction::Change(node, len)
};
match action {
NodeAction::Change(n, adj) => {
self.left = Some(n);
self.weight += adj as usize;
total_adj += adj;
}
NodeAction::Adjust(adj) => {
self.weight += adj as usize;
total_adj += adj;
}
_ => panic!("Unexpected action"),
}
} else {
let action = if let Some(ref mut right) = self.right {
assert!(start >= self.src_weight);
assert!(src_start >= self.src_weight);
right.src_insert(node, start - self.src_weight, src_start - self.src_weight)
} else {
let len = node.len() as isize;
NodeAction::Change(node, len)
@ -587,6 +893,21 @@ impl Inode {
}
}
fn find_src_slice<'a>(&'a self, start: usize, end: usize, slice: &mut RopeSlice<'a>) {
debug!("Inode::find_src_slice: {}, {}, {}", start, end, self.src_weight);
if start < self.src_weight && self.left.is_some() {
self.left.as_ref().unwrap().find_src_slice(start, end, slice);
}
if end > self.src_weight && self.right.is_some() {
let start = if start < self.src_weight {
0
} else {
start - self.src_weight
};
self.right.as_ref().unwrap().find_src_slice(start, end - self.src_weight, slice)
}
}
fn replace(&mut self, start: usize, new_str: &str) {
debug!("Inode::replace: {}, {}, {}", start, new_str, self.weight);
let end = start + new_str.len();
@ -610,52 +931,124 @@ impl Inode {
}
}
}
fn fix_src(&mut self) {
self.src_weight = self.weight;
if let Some(ref mut left) = self.left {
left.fix_src();
}
if let Some(ref mut right) = self.right {
right.fix_src();
}
}
fn col_for_src_loc(&self, src_loc: usize) -> Search {
debug!("Inode::col_for_src_loc: {}, {}", src_loc, self.src_weight);
let result = if src_loc < self.src_weight {
if self.left.is_some() {
Some(self.left.as_ref().unwrap().col_for_src_loc(src_loc))
} else {
None
}
} else {
None
};
if result.is_none() {
if self.right.is_some() {
match self.right.as_ref().unwrap().col_for_src_loc(src_loc - self.src_weight) {
Search::Continue(c) if self.left.is_some() => {
// TODO broken - need number of chars, not bytes
match self.left.as_ref().unwrap().find_last_char('\n') {
Some(l) => {
Search::Done((self.weight - l - 1) + c)
}
None => {
Search::Continue(c + self.weight)
}
}
}
result => result,
}
} else {
panic!("Can't look up source location");
}
} else {
// TODO don't do it this way
result.unwrap()
}
}
fn find_last_char(&self, c: char) -> Option<usize> {
// TODO use map or something
match self.right {
Some(ref right) => match right.find_last_char(c) {
Some(x) => return Some(x),
None => {},
},
None => {}
}
match self.left {
Some(ref left) => match left.find_last_char(c) {
Some(x) => return Some(x),
None => {},
},
None => {}
}
None
}
}
impl Lnode {
// precond: start < end && end >= offset
fn remove(&mut self, start: usize, end: usize, offset: usize) -> NodeAction {
debug!("Lnode::remove: {}, {}, {}, {}", start, end, offset, self.len);
if start > offset + self.len {
// The span to remove is to the right of this node.
return NodeAction::None;
}
fn remove(&mut self, start: usize, end: usize, src_start: usize) -> NodeAction {
debug!("Lnode::remove: {}, {}, {}", start, end, self.len);
assert!(start <= self.len);
if start <= offset && end >= offset + self.len {
if start == 0 && end >= self.len {
// The removal span includes us, remove ourselves.
return NodeAction::Remove;
}
let old_len = self.len;
if start <= offset {
if start == 0 {
// Truncate the left of the node.
self.text = (self.text as usize + (end - offset)) as *const u8;
self.len = old_len - (end - offset);
return NodeAction::Adjust(self.len as isize - old_len as isize);
self.text = (self.text as usize + end) as *const u8;
self.len = old_len - end;
let delta = self.len as isize - old_len as isize;
self.src_offset += delta;
return NodeAction::Adjust(delta);
}
if end >= offset + self.len {
if end >= self.len {
// Truncate the right of the node.
self.len = start - offset;
self.len = start;
return NodeAction::Adjust(self.len as isize - old_len as isize);
}
let delta = -((end - start) as isize);
// Split the node (span to remove is in the middle of the node).
let new_node = Node::new_inner(
Some(box Node::new_leaf(self.text, start - offset)),
Some(box Node::new_leaf((self.text as usize + (end - offset)) as *const u8,
old_len - (end - offset))),
start - offset);
return NodeAction::Change(box new_node, -((end - start) as isize));
Some(box Node::new_leaf(self.text, start, self.src_offset)),
Some(box Node::new_leaf((self.text as usize + end) as *const u8,
old_len - end,
self.src_offset + delta)),
start,
src_start);
return NodeAction::Change(box new_node, delta);
}
fn insert(&mut self, node: Box<Node>, start: usize) -> NodeAction {
fn insert(&mut self, mut node: Box<Node>, start: usize, src_start: usize) -> NodeAction {
match node {
box Node::LeafNode(ref mut node) => node.src_offset = self.src_offset,
_ => panic!()
}
let len = node.len();
if start == 0 {
// Insert at the start of the node
let new_node = box Node::new_inner(Some(node),
Some(box Node::LeafNode(self.clone())),
len);
len,
0);
return NodeAction::Change(new_node, len as isize)
}
@ -663,33 +1056,33 @@ impl Lnode {
// Insert at the end of the node
let new_node = box Node::new_inner(Some(box Node::LeafNode(self.clone())),
Some(node),
self.len,
self.len);
return NodeAction::Change(new_node, len as isize)
}
// Insert into the middle of the node
let left = Some(box Node::new_leaf(self.text, start));
let new_left = box Node::new_inner(left, Some(node), start);
let left = Some(box Node::new_leaf(self.text, start, self.src_offset));
let new_left = box Node::new_inner(left, Some(node), start, src_start);
let right = Some(box Node::new_leaf((self.text as usize + (start)) as *const u8,
self.len - (start)));
let new_node = box Node::new_inner(Some(new_left), right, start + len);
self.len - start,
self.src_offset));
let new_node = box Node::new_inner(Some(new_left), right, start + len, src_start);
return NodeAction::Change(new_node, len as isize)
}
fn find_slice<'a>(&'a self, start: usize, end: usize, slice: &mut RopeSlice<'a>) {
debug!("Lnode::find_slice: {}, {}, {}", start, end, self.len);
debug!("Lnode::find_slice: {}, {}, {}, {}", start, end, self.len, self.src_offset);
debug_assert!(start < self.len, "Shouldn't have called this fn, we're out of bounds");
slice.nodes.push(self);
let mut len = end;
let mut len = ::std::cmp::min(end, self.len);
if start > 0 {
slice.start = start;
len -= start;
}
if end <= self.len {
slice.len = len;
}
slice.len = len;
}
fn replace(&mut self, start: usize, new_str: &str) {
@ -700,4 +1093,62 @@ impl Lnode {
::std::intrinsics::copy_nonoverlapping_memory(addr, &new_str.as_bytes()[0], new_str.len());
}
}
fn col_for_src_loc(&self, src_loc: usize) -> Search {
debug!("Lnode::col_for_src_loc {}; {}; {}", src_loc, self.len, self.src_offset);
let loc = if (src_loc as isize) > (self.len as isize - self.src_offset) {
// The source location we are looking up has been removed
self.len as isize
} else {
(src_loc as isize + self.src_offset)
};
// FIXME if '/n' as u8 is part of a multi-byte grapheme, then this will
// cause false positives.
let mut i = loc - 1;
while i >= 0 {
unsafe {
let c = *((self.text as usize + i as usize) as *const u8);
if c as char == '\n' {
debug!("Lnode::col_for_src_loc, return Done({})", loc - i - 1);
return Search::Done((loc - i - 1) as usize)
}
}
i -= 1;
}
let loc = if loc < 0 {
0
} else {
loc as usize
};
debug!("Lnode::col_for_src_loc, return Continue({})", loc);
Search::Continue(loc)
}
fn find_last_char(&self, needle: char) -> Option<usize> {
// FIXME due to multi-byte chars, this will give false positives
// I think we must search forwards from the start :-( Perhaps we could
// track unicode vs ascii or something (I don't think there is an efficient
// way to read unicode backwards, I might be wrong).
// std::str::GraphemeIndices can do this!
let mut loc = self.len as isize - 1;
while loc >= 0 {
unsafe {
let c = *((self.text as usize + loc as usize) as *const u8);
if c as char == needle {
return Some(loc as usize)
}
}
loc -= 1;
}
return None
}
}
//TODO comment etc.
enum Search {
Continue(usize),
Done(usize)
}