WIP: Replace ropey with our own Rope

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2021-05-14 18:30:47 +02:00
parent 2f5754db63
commit 2cdf315d95
6 changed files with 220 additions and 243 deletions

10
Cargo.lock generated
View file

@ -2188,15 +2188,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
[[package]]
name = "ropey"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f3ef16589fdbb3e8fbce3dca944c08e61f39c7f16064b21a257d68ea911a83"
dependencies = [
"smallvec",
]
[[package]]
name = "roxmltree"
version = "0.14.1"
@ -2987,7 +2978,6 @@ dependencies = [
"parking_lot",
"postage",
"rand 0.8.3",
"ropey",
"rust-embed",
"seahash",
"serde 1.0.125",

View file

@ -31,7 +31,6 @@ num_cpus = "1.13.0"
parking_lot = "0.11.1"
postage = {version = "0.4.1", features = ["futures-traits"]}
rand = "0.8.3"
ropey = "1.2"
rust-embed = "5.9.0"
seahash = "4.1"
serde = {version = "1", features = ["derive"]}

View file

@ -1,11 +1,11 @@
mod anchor;
mod point;
mod rope;
pub mod rope;
mod selection;
pub use anchor::*;
pub use point::*;
use ropey::{Rope, RopeSlice};
pub use rope::{Rope, TextSummary};
use seahash::SeaHasher;
pub use selection::*;
use similar::{ChangeTag, TextDiff};
@ -57,9 +57,9 @@ type HashMap<K, V> = std::collections::HashMap<K, V>;
type HashSet<T> = std::collections::HashSet<T>;
pub struct Buffer {
fragments: SumTree<Fragment>,
visible_text: Rope,
deleted_text: Rope,
fragments: SumTree<Fragment>,
insertion_splits: HashMap<time::Local, SumTree<InsertionSplit>>,
pub version: time::Global,
saved_version: time::Global,
@ -305,74 +305,6 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary {
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TextSummary {
pub chars: usize,
pub bytes: usize,
pub lines: Point,
pub first_line_len: u32,
pub rightmost_point: Point,
}
impl<'a> From<RopeSlice<'a>> for TextSummary {
fn from(slice: RopeSlice<'a>) -> Self {
let last_row = slice.len_lines() - 1;
let last_column = slice.line(last_row).len_chars();
let mut point = Point::default();
let mut rightmost_point = point;
let mut first_line_len = None;
for (i, c) in slice.chars().enumerate() {
if c == '\n' {
if first_line_len.is_none() {
first_line_len = Some(i as u32);
}
point.row += 1;
point.column = 0;
} else {
point.column += 1;
if point.column > rightmost_point.column {
rightmost_point = point;
}
}
}
Self {
chars: slice.len_chars(),
bytes: slice.len_bytes(),
lines: Point::new(last_row as u32, last_column as u32),
first_line_len: first_line_len.unwrap_or(slice.len_chars() as u32),
rightmost_point,
}
}
}
impl<'a> std::ops::AddAssign<&'a Self> for TextSummary {
fn add_assign(&mut self, other: &'a Self) {
let joined_line_len = self.lines.column + other.first_line_len;
if joined_line_len > self.rightmost_point.column {
self.rightmost_point = Point::new(self.lines.row, joined_line_len);
}
if other.rightmost_point.column > self.rightmost_point.column {
self.rightmost_point = self.lines + &other.rightmost_point;
}
if self.lines.row == 0 {
self.first_line_len += other.first_line_len;
}
self.chars += other.chars;
self.bytes += other.bytes;
self.lines += &other.lines;
}
}
impl std::ops::AddAssign<Self> for TextSummary {
fn add_assign(&mut self, other: Self) {
*self += &other;
}
}
#[derive(Eq, PartialEq, Clone, Debug)]
struct InsertionSplit {
extent: usize,
@ -510,10 +442,10 @@ impl Buffer {
&(),
);
if base_text.len_chars() > 0 {
if base_text.len() > 0 {
let base_fragment_id =
FragmentId::between(&FragmentId::min_value(), &FragmentId::max_value());
let range_in_insertion = 0..base_text.len_chars();
let range_in_insertion = 0..base_text.len();
visible_text = base_text.clone();
insertion_splits.get_mut(&base_insertion.id).unwrap().push(
@ -663,11 +595,12 @@ impl Buffer {
}
pub fn text_summary(&self) -> TextSummary {
TextSummary::from(self.visible_text.slice(..))
self.visible_text.summary()
}
pub fn text_summary_for_range(&self, range: Range<usize>) -> TextSummary {
TextSummary::from(self.visible_text.slice(range))
// TODO: Use a dedicated ::summarize method in Rope.
self.visible_text.slice(range).summary()
}
pub fn len(&self) -> usize {
@ -686,7 +619,7 @@ impl Buffer {
}
pub fn rightmost_point(&self) -> Point {
self.rightmost_point_in_range(0..self.len())
self.visible_text.summary().rightmost_point
}
pub fn rightmost_point_in_range(&self, range: Range<usize>) -> Point {
@ -694,7 +627,7 @@ impl Buffer {
}
pub fn max_point(&self) -> Point {
self.text_summary().lines
self.visible_text.max_point()
}
pub fn line(&self, row: u32) -> Result<String> {
@ -717,11 +650,11 @@ impl Buffer {
Ok(self.chars_at(start)?.take(end - start))
}
pub fn chars(&self) -> ropey::iter::Chars {
pub fn chars(&self) -> rope::Chars {
self.chars_at(0).unwrap()
}
pub fn chars_at<T: ToOffset>(&self, position: T) -> Result<ropey::iter::Chars> {
pub fn chars_at<T: ToOffset>(&self, position: T) -> Result<rope::Chars> {
let offset = position.to_offset(self)?;
Ok(self.visible_text.chars_at(offset))
}
@ -1084,22 +1017,25 @@ impl Buffer {
let end_fragment_id = self.resolve_fragment_id(end_id, end_offset)?;
let old_fragments = self.fragments.clone();
let last_id = old_fragments.extent::<FragmentIdRef>().0.unwrap();
let last_id_ref = FragmentIdRef::new(&last_id);
let old_visible_text = self.visible_text.clone();
let old_deleted_text = self.deleted_text.clone();
let mut fragments_cursor = old_fragments.cursor::<FragmentIdRef, FragmentTextSummary>();
let mut visible_text_cursor = old_visible_text.cursor(0);
let mut deleted_text_cursor = old_deleted_text.cursor(0);
let mut cursor = old_fragments.cursor::<FragmentIdRef, FragmentTextSummary>();
let mut new_fragments =
cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &());
let mut new_visible_text = self.visible_text.clone();
let mut new_deleted_text = self.deleted_text.clone();
fragments_cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &());
let mut new_visible_text = visible_text_cursor.slice(fragments_cursor.start().visible);
let mut new_deleted_text = deleted_text_cursor.slice(fragments_cursor.start().deleted);
let start_fragment = cursor.item().unwrap();
let start_fragment = fragments_cursor.item().unwrap();
if start_offset == start_fragment.range_in_insertion.end {
new_fragments.push(cursor.item().unwrap().clone(), &());
cursor.next();
new_fragments.push(fragments_cursor.item().unwrap().clone(), &());
fragments_cursor.next();
}
while let Some(fragment) = cursor.item() {
while let Some(fragment) = fragments_cursor.item() {
if new_text.is_none() && fragment.id > end_fragment_id {
break;
}
@ -1118,13 +1054,14 @@ impl Buffer {
fragment.range_in_insertion.end
};
let (before_range, within_range, after_range) = self.split_fragment(
cursor.prev_item().as_ref().unwrap(),
fragments_cursor.prev_item().as_ref().unwrap(),
&fragment,
split_start..split_end,
);
let insertion = if let Some(new_text) = new_text {
let prev_fragment = fragments_cursor.prev_item();
Some(self.build_fragment_to_insert(
before_range.as_ref().or(cursor.prev_item()).unwrap(),
before_range.as_ref().or(prev_fragment).unwrap(),
within_range.as_ref().or(after_range.as_ref()),
new_text,
local_timestamp,
@ -1137,25 +1074,26 @@ impl Buffer {
new_fragments.push(fragment, &());
}
if let Some(fragment) = insertion {
new_visible_text.insert(
new_fragments.summary().text.visible,
new_text.take().unwrap(),
);
new_visible_text
.append(visible_text_cursor.slice(new_fragments.summary().text.visible));
new_fragments.push(fragment, &());
new_visible_text.push(new_text.take().unwrap());
}
if let Some(mut fragment) = within_range {
if fragment.was_visible(&version_in_range, &self.undo_map) {
fragment.deletions.insert(local_timestamp);
if fragment.visible {
fragment.visible = false;
// TODO: avoid calling to_string on rope slice.
let deleted_start = new_fragments.summary().text.visible;
let deleted_range = deleted_start..deleted_start + fragment.len();
new_deleted_text.insert(
new_fragments.summary().text.deleted,
&new_visible_text.slice(deleted_range.clone()).to_string(),
new_visible_text.append(
visible_text_cursor.slice(new_fragments.summary().text.visible),
);
new_deleted_text.append(
deleted_text_cursor.slice(new_fragments.summary().text.deleted),
);
new_deleted_text.append(
visible_text_cursor
.slice(new_fragments.summary().text.visible + fragment.len()),
);
new_visible_text.remove(deleted_range);
}
}
@ -1168,14 +1106,16 @@ impl Buffer {
if new_text.is_some() && lamport_timestamp > fragment.insertion.lamport_timestamp {
let new_text = new_text.take().unwrap();
let fragment = self.build_fragment_to_insert(
cursor.prev_item().as_ref().unwrap(),
fragments_cursor.prev_item().as_ref().unwrap(),
Some(&fragment),
new_text,
local_timestamp,
lamport_timestamp,
);
new_visible_text.insert(new_fragments.summary().text.visible, new_text);
new_visible_text
.append(visible_text_cursor.slice(new_fragments.summary().text.visible));
new_fragments.push(fragment, &());
new_visible_text.push(new_text);
}
if fragment.id < end_fragment_id
@ -1184,39 +1124,46 @@ impl Buffer {
fragment.deletions.insert(local_timestamp);
if fragment.visible {
fragment.visible = false;
// TODO: avoid calling to_string on rope slice.
let deleted_start = new_fragments.summary().text.visible;
let deleted_range = deleted_start..deleted_start + fragment.len();
new_deleted_text.insert(
new_fragments.summary().text.deleted,
&new_visible_text.slice(deleted_range.clone()).to_string(),
new_visible_text.append(
visible_text_cursor.slice(new_fragments.summary().text.visible),
);
new_deleted_text.append(
deleted_text_cursor.slice(new_fragments.summary().text.deleted),
);
new_deleted_text.append(
visible_text_cursor
.slice(new_fragments.summary().text.visible + fragment.len()),
);
new_visible_text.remove(deleted_range);
}
}
new_fragments.push(fragment, &());
}
cursor.next();
fragments_cursor.next();
}
if let Some(new_text) = new_text {
let fragment = self.build_fragment_to_insert(
cursor.prev_item().as_ref().unwrap(),
fragments_cursor.prev_item().as_ref().unwrap(),
None,
new_text,
local_timestamp,
lamport_timestamp,
);
new_visible_text.insert(new_fragments.summary().text.visible, new_text);
new_visible_text
.append(visible_text_cursor.slice(new_fragments.summary().text.visible));
new_fragments.push(fragment, &());
new_visible_text.push(new_text);
}
new_fragments.push_tree(cursor.slice(&last_id_ref, SeekBias::Right, &()), &());
new_fragments.push_tree(fragments_cursor.suffix(&()), &());
new_visible_text.append(visible_text_cursor.suffix());
new_deleted_text.append(deleted_text_cursor.suffix());
self.fragments = new_fragments;
self.visible_text = new_visible_text;
self.deleted_text = new_deleted_text;
self.fragments = new_fragments;
self.local_clock.observe(local_timestamp);
self.lamport_clock.observe(lamport_timestamp);
Ok(())
@ -1291,52 +1238,60 @@ impl Buffer {
fn apply_undo(&mut self, undo: UndoOperation) -> Result<()> {
let mut new_fragments;
let mut new_visible_text = self.visible_text.clone();
let mut new_deleted_text = self.deleted_text.clone();
let mut new_visible_text = Rope::new();
let mut new_deleted_text = Rope::new();
self.undo_map.insert(undo);
let edit = &self.history.ops[&undo.edit_id];
let start_fragment_id = self.resolve_fragment_id(edit.start_id, edit.start_offset)?;
let end_fragment_id = self.resolve_fragment_id(edit.end_id, edit.end_offset)?;
let mut cursor = self.fragments.cursor::<FragmentIdRef, ()>();
let mut fragments_cursor = self.fragments.cursor::<FragmentIdRef, ()>();
let mut visible_text_cursor = self.visible_text.cursor(0);
let mut deleted_text_cursor = self.deleted_text.cursor(0);
if edit.start_id == edit.end_id && edit.start_offset == edit.end_offset {
let splits = &self.insertion_splits[&undo.edit_id];
let mut insertion_splits = splits.cursor::<(), ()>().map(|s| &s.fragment_id).peekable();
let first_split_id = insertion_splits.next().unwrap();
new_fragments = cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &());
new_fragments =
fragments_cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &());
new_visible_text
.append(visible_text_cursor.slice(new_fragments.summary().text.visible));
new_deleted_text
.append(deleted_text_cursor.slice(new_fragments.summary().text.deleted));
loop {
let mut fragment = cursor.item().unwrap().clone();
let mut fragment = fragments_cursor.item().unwrap().clone();
let was_visible = fragment.visible;
fragment.visible = fragment.is_visible(&self.undo_map);
fragment.max_undos.observe(undo.id);
// TODO: avoid calling to_string on rope slice.
if fragment.visible != was_visible {
new_visible_text
.append(visible_text_cursor.slice(new_fragments.summary().text.visible));
new_deleted_text
.append(deleted_text_cursor.slice(new_fragments.summary().text.deleted));
}
if fragment.visible && !was_visible {
let visible_start = new_fragments.summary().text.deleted;
let visible_range = visible_start..visible_start + fragment.len();
new_visible_text.insert(
new_fragments.summary().text.visible,
&new_deleted_text.slice(visible_range.clone()).to_string(),
new_visible_text.append(
deleted_text_cursor
.slice(new_fragments.summary().text.deleted + fragment.len()),
);
new_deleted_text.remove(visible_range);
} else if !fragment.visible && was_visible {
let deleted_start = new_fragments.summary().text.visible;
let deleted_range = deleted_start..deleted_start + fragment.len();
new_deleted_text.insert(
new_fragments.summary().text.deleted,
&new_visible_text.slice(deleted_range.clone()).to_string(),
new_deleted_text.append(
visible_text_cursor
.slice(new_fragments.summary().text.visible + fragment.len()),
);
new_visible_text.remove(deleted_range);
}
new_fragments.push(fragment, &());
cursor.next();
fragments_cursor.next();
if let Some(split_id) = insertion_splits.next() {
new_fragments.push_tree(
cursor.slice(&FragmentIdRef::new(split_id), SeekBias::Left, &()),
fragments_cursor.slice(&FragmentIdRef::new(split_id), SeekBias::Left, &()),
&(),
);
} else {
@ -1344,9 +1299,12 @@ impl Buffer {
}
}
} else {
new_fragments =
cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &());
while let Some(fragment) = cursor.item() {
new_fragments = fragments_cursor.slice(
&FragmentIdRef::new(&start_fragment_id),
SeekBias::Left,
&(),
);
while let Some(fragment) = fragments_cursor.item() {
if fragment.id > end_fragment_id {
break;
} else {
@ -1358,37 +1316,42 @@ impl Buffer {
fragment.visible = fragment.is_visible(&self.undo_map);
fragment.max_undos.observe(undo.id);
// TODO: avoid calling to_string on rope slice.
if fragment.visible != was_visible {
new_visible_text.append(
visible_text_cursor.slice(new_fragments.summary().text.visible),
);
new_deleted_text.append(
deleted_text_cursor.slice(new_fragments.summary().text.deleted),
);
}
if fragment.visible && !was_visible {
let visible_start = new_fragments.summary().text.deleted;
let visible_range = visible_start..visible_start + fragment.len();
new_visible_text.insert(
new_fragments.summary().text.visible,
&new_deleted_text.slice(visible_range.clone()).to_string(),
new_visible_text.append(
deleted_text_cursor
.slice(new_fragments.summary().text.deleted + fragment.len()),
);
new_deleted_text.remove(visible_range);
} else if !fragment.visible && was_visible {
let deleted_start = new_fragments.summary().text.visible;
let deleted_range = deleted_start..deleted_start + fragment.len();
new_deleted_text.insert(
new_fragments.summary().text.deleted,
&new_visible_text.slice(deleted_range.clone()).to_string(),
new_deleted_text.append(
visible_text_cursor
.slice(new_fragments.summary().text.visible + fragment.len()),
);
new_visible_text.remove(deleted_range);
}
}
new_fragments.push(fragment, &());
cursor.next();
fragments_cursor.next();
}
}
}
new_fragments.push_tree(cursor.suffix(&()), &());
drop(cursor);
new_fragments.push_tree(fragments_cursor.suffix(&()), &());
new_visible_text.append(visible_text_cursor.suffix());
new_deleted_text.append(deleted_text_cursor.suffix());
drop(fragments_cursor);
self.fragments = new_fragments;
self.visible_text = new_visible_text;
self.deleted_text = new_deleted_text;
self.fragments = new_fragments;
Ok(())
}
@ -1470,15 +1433,23 @@ impl Buffer {
let mut ops = Vec::with_capacity(old_ranges.size_hint().0);
let old_fragments = self.fragments.clone();
let mut cursor = old_fragments.cursor::<usize, usize>();
let old_visible_text = self.visible_text.clone();
let old_deleted_text = self.deleted_text.clone();
let mut fragments_cursor = old_fragments.cursor::<usize, usize>();
let mut visible_text_cursor = old_visible_text.cursor(0);
let mut deleted_text_cursor = old_deleted_text.cursor(0);
let mut new_fragments = SumTree::new();
let mut new_visible_text = self.visible_text.clone();
let mut new_deleted_text = self.deleted_text.clone();
let mut new_visible_text = Rope::new();
let mut new_deleted_text = Rope::new();
new_fragments.push_tree(
cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()),
fragments_cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()),
&(),
);
new_visible_text.append(visible_text_cursor.slice(new_fragments.summary().text.visible));
new_deleted_text.append(deleted_text_cursor.slice(new_fragments.summary().text.deleted));
let mut start_id = None;
let mut start_offset = None;
@ -1489,10 +1460,10 @@ impl Buffer {
let mut local_timestamp = self.local_clock.tick();
let mut lamport_timestamp = self.lamport_clock.tick();
while cur_range.is_some() && cursor.item().is_some() {
let mut fragment = cursor.item().unwrap().clone();
let fragment_summary = cursor.item_summary().unwrap();
let mut fragment_start = *cursor.start();
while cur_range.is_some() && fragments_cursor.item().is_some() {
let mut fragment = fragments_cursor.item().unwrap().clone();
let fragment_summary = fragments_cursor.item_summary().unwrap();
let mut fragment_start = *fragments_cursor.start();
let mut fragment_end = fragment_start + fragment.visible_len();
let old_split_tree = self
@ -1546,8 +1517,12 @@ impl Buffer {
local_timestamp,
lamport_timestamp,
);
new_visible_text.insert(new_fragments.summary().text.visible, &new_text);
new_visible_text.append(
visible_text_cursor.slice(new_fragments.summary().text.visible),
);
new_fragments.push(new_fragment, &());
new_visible_text.push(&new_text);
}
}
@ -1559,18 +1534,20 @@ impl Buffer {
prefix.id =
FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id);
version_in_range.observe_all(&fragment_summary.max_version);
if fragment.visible {
if prefix.visible {
prefix.deletions.insert(local_timestamp);
prefix.visible = false;
// TODO: avoid calling to_string on rope slice.
let deleted_start = new_fragments.summary().text.visible;
let deleted_range = deleted_start..deleted_start + prefix.len();
new_deleted_text.insert(
new_fragments.summary().text.deleted,
&new_visible_text.slice(deleted_range.clone()).to_string(),
new_visible_text.append(
visible_text_cursor.slice(new_fragments.summary().text.visible),
);
new_deleted_text.append(
deleted_text_cursor.slice(new_fragments.summary().text.deleted),
);
new_deleted_text.append(
visible_text_cursor
.slice(new_fragments.summary().text.visible + prefix.len()),
);
new_visible_text.remove(deleted_range);
}
fragment.range_in_insertion.start = prefix.range_in_insertion.end;
new_fragments.push(prefix.clone(), &());
@ -1592,14 +1569,16 @@ impl Buffer {
fragment.deletions.insert(local_timestamp);
fragment.visible = false;
// TODO: avoid calling to_string on rope slice.
let deleted_start = new_fragments.summary().text.visible;
let deleted_range = deleted_start..deleted_start + fragment.len();
new_deleted_text.insert(
new_fragments.summary().text.deleted,
&new_visible_text.slice(deleted_range.clone()).to_string(),
new_visible_text.append(
visible_text_cursor.slice(new_fragments.summary().text.visible),
);
new_deleted_text.append(
deleted_text_cursor.slice(new_fragments.summary().text.deleted),
);
new_deleted_text.append(
visible_text_cursor
.slice(new_fragments.summary().text.visible + fragment.len()),
);
new_visible_text.remove(deleted_range);
}
}
@ -1651,11 +1630,11 @@ impl Buffer {
new_fragments.push(fragment, &());
// Scan forward until we find a fragment that is not fully contained by the current splice.
cursor.next();
fragments_cursor.next();
if let Some(range) = cur_range.clone() {
while let Some(fragment) = cursor.item() {
let fragment_summary = cursor.item_summary().unwrap();
fragment_start = *cursor.start();
while let Some(fragment) = fragments_cursor.item() {
let fragment_summary = fragments_cursor.item_summary().unwrap();
fragment_start = *fragments_cursor.start();
fragment_end = fragment_start + fragment.visible_len();
if range.start < fragment_start && range.end >= fragment_end {
let mut new_fragment = fragment.clone();
@ -1664,17 +1643,20 @@ impl Buffer {
new_fragment.deletions.insert(local_timestamp);
new_fragment.visible = false;
// TODO: avoid calling to_string on rope slice.
let deleted_start = new_fragments.summary().text.visible;
let deleted_range = deleted_start..deleted_start + new_fragment.len();
new_deleted_text.insert(
new_fragments.summary().text.deleted,
&new_visible_text.slice(deleted_range.clone()).to_string(),
new_visible_text.append(
visible_text_cursor.slice(new_fragments.summary().text.visible),
);
new_deleted_text.append(
deleted_text_cursor.slice(new_fragments.summary().text.deleted),
);
new_deleted_text.append(
visible_text_cursor.slice(
new_fragments.summary().text.visible + new_fragment.len(),
),
);
new_visible_text.remove(deleted_range);
}
new_fragments.push(new_fragment, &());
cursor.next();
fragments_cursor.next();
if range.end == fragment_end {
end_id = Some(fragment.insertion.id);
@ -1715,7 +1697,11 @@ impl Buffer {
// and push all the fragments in between into the new tree.
if cur_range.as_ref().map_or(false, |r| r.start > fragment_end) {
new_fragments.push_tree(
cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()),
fragments_cursor.slice(
&cur_range.as_ref().unwrap().start,
SeekBias::Right,
&(),
),
&(),
);
}
@ -1749,19 +1735,21 @@ impl Buffer {
local_timestamp,
lamport_timestamp,
);
new_visible_text.insert(new_fragments.summary().text.visible, &new_text);
new_visible_text
.append(visible_text_cursor.slice(new_fragments.summary().text.visible));
new_fragments.push(new_fragment, &());
new_visible_text.push(&new_text);
}
} else {
new_fragments.push_tree(
cursor.slice(&old_fragments.extent::<usize>(), SeekBias::Right, &()),
&(),
);
}
new_fragments.push_tree(fragments_cursor.suffix(&()), &());
new_visible_text.append(visible_text_cursor.suffix());
new_deleted_text.append(deleted_text_cursor.suffix());
self.fragments = new_fragments;
self.visible_text = new_visible_text;
self.deleted_text = new_deleted_text;
self.fragments = new_fragments;
ops
}
@ -2031,9 +2019,9 @@ impl Buffer {
impl Clone for Buffer {
fn clone(&self) -> Self {
Self {
fragments: self.fragments.clone(),
visible_text: self.visible_text.clone(),
deleted_text: self.deleted_text.clone(),
fragments: self.fragments.clone(),
insertion_splits: self.insertion_splits.clone(),
version: self.version.clone(),
saved_version: self.saved_version.clone(),
@ -2409,12 +2397,7 @@ pub trait ToOffset {
impl ToOffset for Point {
fn to_offset(&self, buffer: &Buffer) -> Result<usize> {
if *self <= buffer.max_point() {
// TODO: return an error if line is shorter than column.
Ok(buffer.visible_text.line_to_char(self.row as usize) + self.column as usize)
} else {
Err(anyhow!("point is out of bounds"))
}
buffer.visible_text.to_offset(*self)
}
}
@ -2448,13 +2431,7 @@ impl ToPoint for Anchor {
impl ToPoint for usize {
fn to_point(&self, buffer: &Buffer) -> Result<Point> {
if *self <= buffer.len() {
let row = buffer.visible_text.char_to_line(*self);
let column = *self - buffer.visible_text.line_to_char(row);
Ok(Point::new(row as u32, column as u32))
} else {
Err(anyhow!("offset is out of bounds"))
}
buffer.visible_text.to_point(*self)
}
}

View file

@ -100,6 +100,14 @@ impl Rope {
self.chunks.summary()
}
pub fn len(&self) -> usize {
self.chunks.extent()
}
pub fn max_point(&self) -> Point {
self.chunks.extent()
}
pub fn cursor(&self, offset: usize) -> Cursor {
Cursor::new(self, offset)
}
@ -116,15 +124,7 @@ impl Rope {
self.chunks.cursor::<(), ()>().map(|c| c.0.as_str())
}
fn text(&self) -> String {
let mut text = String::new();
for chunk in self.chunks.cursor::<(), ()>() {
text.push_str(&chunk.0);
}
text
}
fn to_point(&self, offset: usize) -> Result<Point> {
pub fn to_point(&self, offset: usize) -> Result<Point> {
if offset <= self.summary().chars {
let mut cursor = self.chunks.cursor::<usize, TextSummary>();
cursor.seek(&offset, SeekBias::Left, &());
@ -135,7 +135,8 @@ impl Rope {
}
}
fn to_offset(&self, point: Point) -> Result<usize> {
pub fn to_offset(&self, point: Point) -> Result<usize> {
// TODO: Verify the point actually exists.
if point <= self.summary().lines {
let mut cursor = self.chunks.cursor::<Point, TextSummary>();
cursor.seek(&point, SeekBias::Left, &());
@ -162,7 +163,7 @@ pub struct Cursor<'a> {
}
impl<'a> Cursor<'a> {
fn new(rope: &'a Rope, offset: usize) -> Self {
pub fn new(rope: &'a Rope, offset: usize) -> Self {
let mut chunks = rope.chunks.cursor();
chunks.seek(&offset, SeekBias::Right, &());
Self {
@ -172,14 +173,14 @@ impl<'a> Cursor<'a> {
}
}
fn seek_forward(&mut self, end_offset: usize) {
pub fn seek_forward(&mut self, end_offset: usize) {
debug_assert!(end_offset >= self.offset);
self.chunks.seek_forward(&end_offset, SeekBias::Right, &());
self.offset = end_offset;
}
fn slice(&mut self, end_offset: usize) -> Rope {
pub fn slice(&mut self, end_offset: usize) -> Rope {
debug_assert!(end_offset >= self.offset);
let mut slice = Rope::new();
@ -203,7 +204,7 @@ impl<'a> Cursor<'a> {
slice
}
fn suffix(mut self) -> Rope {
pub fn suffix(mut self) -> Rope {
self.slice(self.rope.chunks.extent())
}
}
@ -456,4 +457,14 @@ mod tests {
}
}
}
impl Rope {
fn text(&self) -> String {
let mut text = String::new();
for chunk in self.chunks.cursor::<(), ()>() {
text.push_str(&chunk.0);
}
text
}
}
}

View file

@ -3,6 +3,7 @@ use super::{
Anchor, Buffer, DisplayPoint, Edit, Point, ToOffset,
};
use crate::{
editor::rope,
sum_tree::{self, Cursor, FilterCursor, SeekBias, SumTree},
time,
};
@ -607,7 +608,7 @@ pub struct Chars<'a> {
cursor: Cursor<'a, Transform, DisplayOffset, TransformSummary>,
offset: usize,
buffer: &'a Buffer,
buffer_chars: Option<Take<ropey::iter::Chars<'a>>>,
buffer_chars: Option<Take<rope::Chars<'a>>>,
}
impl<'a> Iterator for Chars<'a> {

View file

@ -3,7 +3,7 @@ mod fuzzy;
mod ignore;
use crate::{
editor::History,
editor::{History, Rope},
sum_tree::{self, Cursor, Edit, SeekBias, SumTree},
};
use ::ignore::gitignore::Gitignore;
@ -16,7 +16,6 @@ use postage::{
prelude::{Sink, Stream},
watch,
};
use ropey::Rope;
use smol::channel::Sender;
use std::{
cmp,
@ -204,7 +203,7 @@ impl Worktree {
let path = path.to_path_buf();
let abs_path = self.absolutize(&path);
ctx.background_executor().spawn(async move {
let buffer_size = content.len_bytes().min(10 * 1024);
let buffer_size = content.summary().bytes.min(10 * 1024);
let file = fs::File::create(&abs_path)?;
let mut writer = io::BufWriter::with_capacity(buffer_size, &file);
for chunk in content.chunks() {