@@ -15,61 +15,26 @@ use std::{
cmp::{self, Ordering},
iter,
ops::Range,
+ sync::atomic::{AtomicUsize, Ordering::SeqCst},
};
-pub struct FoldMap {
- buffer: ModelHandle<Buffer>,
- transforms: Mutex<SumTree<Transform>>,
- folds: SumTree<Fold>,
- last_sync: Mutex<time::Global>,
-}
-
-impl FoldMap {
- pub fn new(buffer_handle: ModelHandle<Buffer>, cx: &AppContext) -> Self {
- let buffer = buffer_handle.read(cx);
- Self {
- buffer: buffer_handle,
- folds: Default::default(),
- transforms: Mutex::new(SumTree::from_item(
- Transform {
- summary: TransformSummary {
- buffer: buffer.text_summary(),
- display: buffer.text_summary(),
- },
- display_text: None,
- },
- &(),
- )),
- last_sync: Mutex::new(buffer.version()),
- }
- }
-
- pub fn snapshot(&self, cx: &AppContext) -> (FoldMapSnapshot, Vec<Edit>) {
- let edits = self.sync(cx);
- let snapshot = FoldMapSnapshot {
- transforms: self.transforms.lock().clone(),
- folds: self.folds.clone(),
- buffer: self.buffer.read(cx).snapshot(),
- };
- (snapshot, edits)
- }
+pub struct FoldMapWriter<'a>(&'a mut FoldMap);
+impl<'a> FoldMapWriter<'a> {
pub fn fold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
cx: &AppContext,
- ) {
- let edits = self.sync(cx);
-
- let mut fold_edits = Vec::new();
+ ) -> Vec<Edit> {
+ let mut edits = Vec::new();
let mut folds = Vec::new();
- let buffer = self.buffer.read(cx).snapshot();
+ let buffer = self.0.buffer.read(cx).snapshot();
for range in ranges.into_iter() {
let range = range.start.to_offset(&buffer)..range.end.to_offset(&buffer);
if range.start != range.end {
let fold = Fold(buffer.anchor_after(range.start)..buffer.anchor_before(range.end));
folds.push(fold);
- fold_edits.push(Edit {
+ edits.push(Edit {
old_bytes: range.clone(),
new_bytes: range.clone(),
});
@@ -78,9 +43,9 @@ impl FoldMap {
folds.sort_unstable_by(|a, b| sum_tree::SeekDimension::cmp(a, b, &buffer));
- self.folds = {
+ self.0.folds = {
let mut new_tree = SumTree::new();
- let mut cursor = self.folds.cursor::<_, ()>();
+ let mut cursor = self.0.folds.cursor::<_, ()>();
for fold in folds {
new_tree.push_tree(cursor.slice(&fold, Bias::Right, &buffer), &buffer);
new_tree.push(fold, &buffer);
@@ -89,26 +54,24 @@ impl FoldMap {
new_tree
};
- self.consolidate_edits(&mut fold_edits);
- self.apply_edits(fold_edits, cx);
+ self.consolidate_edits(&mut edits);
+ self.0.apply_edits(edits, cx)
}
pub fn unfold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
cx: &AppContext,
- ) {
- let edits = self.sync(cx);
-
- let mut fold_edits = Vec::new();
+ ) -> Vec<Edit> {
+ let mut edits = Vec::new();
let mut fold_ixs_to_delete = Vec::new();
- let buffer = self.buffer.read(cx).snapshot();
+ let buffer = self.0.buffer.read(cx).snapshot();
for range in ranges.into_iter() {
// Remove intersecting folds and add their ranges to edits that are passed to apply_edits.
- let mut folds_cursor = intersecting_folds(&buffer, &self.folds, range);
+ let mut folds_cursor = intersecting_folds(&buffer, &self.0.folds, range);
while let Some(fold) = folds_cursor.item() {
let offset_range = fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer);
- fold_edits.push(Edit {
+ edits.push(Edit {
old_bytes: offset_range.clone(),
new_bytes: offset_range,
});
@@ -120,8 +83,8 @@ impl FoldMap {
fold_ixs_to_delete.sort_unstable();
fold_ixs_to_delete.dedup();
- self.folds = {
- let mut cursor = self.folds.cursor::<_, ()>();
+ self.0.folds = {
+ let mut cursor = self.0.folds.cursor::<_, ()>();
let mut folds = SumTree::new();
for fold_ix in fold_ixs_to_delete {
folds.push_tree(cursor.slice(&fold_ix, Bias::Right, &buffer), &buffer);
@@ -131,11 +94,79 @@ impl FoldMap {
folds
};
- self.consolidate_edits(&mut fold_edits);
- self.apply_edits(fold_edits, cx);
+ self.consolidate_edits(&mut edits);
+ self.0.apply_edits(edits, cx)
+ }
+
+ fn consolidate_edits(&self, edits: &mut Vec<Edit>) {
+ edits.sort_unstable_by(|a, b| {
+ a.old_bytes
+ .start
+ .cmp(&b.old_bytes.start)
+ .then_with(|| b.old_bytes.end.cmp(&a.old_bytes.end))
+ });
+
+ let mut i = 0;
+ while i < edits.len() {
+ let range = edits[i].old_bytes.clone();
+ if i > 0 {
+ if edits[i - 1].old_bytes.end >= range.start {
+ edits[i - 1].old_bytes.end = edits[i - 1].old_bytes.end.max(range.end);
+ edits[i - 1].new_bytes.end = edits[i - 1].new_bytes.end.max(range.end);
+ edits.remove(i);
+ continue;
+ }
+ }
+ i += 1;
+ }
+ }
+}
+
+pub struct FoldMap {
+ buffer: ModelHandle<Buffer>,
+ transforms: Mutex<SumTree<Transform>>,
+ folds: SumTree<Fold>,
+ last_sync: Mutex<time::Global>,
+ version: AtomicUsize,
+}
+
+impl FoldMap {
+ pub fn new(buffer_handle: ModelHandle<Buffer>, cx: &AppContext) -> Self {
+ let buffer = buffer_handle.read(cx);
+ Self {
+ buffer: buffer_handle,
+ folds: Default::default(),
+ transforms: Mutex::new(SumTree::from_item(
+ Transform {
+ summary: TransformSummary {
+ buffer: buffer.text_summary(),
+ display: buffer.text_summary(),
+ },
+ display_text: None,
+ },
+ &(),
+ )),
+ last_sync: Mutex::new(buffer.version()),
+ version: AtomicUsize::new(0),
+ }
+ }
+
+ pub fn read(&self, cx: &AppContext) -> (Snapshot, Vec<Edit>) {
+ let edits = self.sync(cx);
+ let snapshot = Snapshot {
+ transforms: self.transforms.lock().clone(),
+ folds: self.folds.clone(),
+ buffer: self.buffer.read(cx).snapshot(),
+ version: self.version.load(SeqCst),
+ };
+ (snapshot, edits)
+ }
+
+ pub fn write(&mut self, cx: &AppContext) -> (FoldMapWriter, Snapshot, Vec<Edit>) {
+ let (snapshot, edits) = self.read(cx);
+ (FoldMapWriter(self), snapshot, edits)
}
- #[must_use]
fn sync(&self, cx: &AppContext) -> Vec<Edit> {
let buffer = self.buffer.read(cx);
let edits = buffer
@@ -325,45 +356,29 @@ impl FoldMap {
}
*transforms = new_transforms;
+ self.version.fetch_add(1, SeqCst);
edits
}
-
- fn consolidate_edits(&self, edits: &mut Vec<Edit>) {
- edits.sort_unstable_by(|a, b| {
- a.old_bytes
- .start
- .cmp(&b.old_bytes.start)
- .then_with(|| b.old_bytes.end.cmp(&a.old_bytes.end))
- });
-
- let mut i = 0;
- while i < edits.len() {
- let range = edits[i].old_bytes.clone();
- if i > 0 {
- if edits[i - 1].old_bytes.end >= range.start {
- edits[i - 1].old_bytes.end = edits[i - 1].old_bytes.end.max(range.end);
- edits[i - 1].new_bytes.end = edits[i - 1].new_bytes.end.max(range.end);
- edits.remove(i);
- continue;
- }
- }
- i += 1;
- }
- }
}
-pub struct FoldMapSnapshot {
+#[derive(Clone)]
+pub struct Snapshot {
transforms: SumTree<Transform>,
folds: SumTree<Fold>,
buffer: buffer::Snapshot,
+ pub version: usize,
}
-impl FoldMapSnapshot {
+impl Snapshot {
#[cfg(test)]
pub fn text(&self) -> String {
self.chunks_at(DisplayOffset(0)).collect()
}
+ pub fn text_summary(&self) -> TextSummary {
+ self.transforms.summary().display
+ }
+
pub fn len(&self) -> usize {
self.transforms.summary().display.bytes
}
@@ -928,14 +943,15 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
- map.fold(
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(2, 4)..Point::new(4, 1),
],
cx.as_ref(),
);
- let (snapshot2, edits) = map.snapshot(cx.as_ref());
+ let (snapshot2, edits) = map.read(cx.as_ref());
assert_eq!(snapshot2.text(), "aa…cc…eeeee");
assert_eq!(
edits,
@@ -961,7 +977,7 @@ mod tests {
cx,
);
});
- let (snapshot3, edits) = map.snapshot(cx.as_ref());
+ let (snapshot3, edits) = map.read(cx.as_ref());
assert_eq!(snapshot3.text(), "123a…c123c…eeeee");
assert_eq!(
edits,
@@ -980,11 +996,12 @@ mod tests {
buffer.update(cx, |buffer, cx| {
buffer.edit(vec![Point::new(2, 6)..Point::new(4, 3)], "456", cx)
});
- let (snapshot4, _) = map.snapshot(cx.as_ref());
+ let (snapshot4, _) = map.read(cx.as_ref());
assert_eq!(snapshot4.text(), "123a…c123456eee");
- map.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), cx.as_ref());
- let (snapshot5, _) = map.snapshot(cx.as_ref());
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), cx.as_ref());
+ let (snapshot5, _) = map.read(cx.as_ref());
assert_eq!(snapshot5.text(), "123aaaaa\nbbbbbb\nccc123456eee");
}
@@ -995,21 +1012,24 @@ mod tests {
{
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
- map.fold(vec![5..8], cx.as_ref());
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(vec![5..8], cx.as_ref());
map.check_invariants(cx.as_ref());
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "abcde…ijkl");
// Create an fold adjacent to the start of the first fold.
- map.fold(vec![0..1, 2..5], cx.as_ref());
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(vec![0..1, 2..5], cx.as_ref());
map.check_invariants(cx.as_ref());
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "…b…ijkl");
// Create an fold adjacent to the end of the first fold.
- map.fold(vec![11..11, 8..10], cx.as_ref());
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(vec![11..11, 8..10], cx.as_ref());
map.check_invariants(cx.as_ref());
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "…b…kl");
}
@@ -1017,9 +1037,10 @@ mod tests {
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
// Create two adjacent folds.
- map.fold(vec![0..2, 2..5], cx.as_ref());
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(vec![0..2, 2..5], cx.as_ref());
map.check_invariants(cx.as_ref());
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "…fghijkl");
// Edit within one of the folds.
@@ -1029,7 +1050,7 @@ mod tests {
buffer.edits_since(version).collect::<Vec<_>>()
});
map.check_invariants(cx.as_ref());
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "12345…fghijkl");
}
}
@@ -1038,7 +1059,8 @@ mod tests {
fn test_overlapping_folds(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
- map.fold(
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(0, 4)..Point::new(1, 0),
@@ -1047,7 +1069,7 @@ mod tests {
],
cx.as_ref(),
);
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "aa…eeeee");
}
@@ -1056,20 +1078,21 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
- map.fold(
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(3, 1)..Point::new(4, 1),
],
cx.as_ref(),
);
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee");
buffer.update(cx, |buffer, cx| {
buffer.edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", cx)
});
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "aa…eeeee");
}
@@ -1079,7 +1102,8 @@ mod tests {
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
let buffer = buffer.read(cx);
- map.fold(
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(0, 4)..Point::new(1, 0),
@@ -1088,7 +1112,7 @@ mod tests {
],
cx.as_ref(),
);
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
let fold_ranges = snapshot
.folds_in_range(Point::new(1, 0)..Point::new(1, 3))
.map(|fold| fold.start.to_point(buffer)..fold.end.to_point(buffer))
@@ -1146,7 +1170,8 @@ mod tests {
to_fold.push(start..end);
}
log::info!("folding {:?}", to_fold);
- map.fold(to_fold, cx.as_ref());
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(to_fold, cx.as_ref());
}
35..=59 if !map.folds.is_empty() => {
let buffer = buffer.read(cx);
@@ -1157,7 +1182,8 @@ mod tests {
to_unfold.push(start..end);
}
log::info!("unfolding {:?}", to_unfold);
- map.unfold(to_unfold, cx.as_ref());
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.unfold(to_unfold, cx.as_ref());
}
_ => {
let edits = buffer.update(cx, |buffer, cx| {
@@ -1186,7 +1212,7 @@ mod tests {
expected_buffer_rows.extend((0..=next_row).rev());
expected_buffer_rows.reverse();
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), expected_text);
for (display_row, line) in expected_text.lines().enumerate() {
@@ -1306,7 +1332,8 @@ mod tests {
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
- map.fold(
+ let (mut writer, _, _) = map.write(cx.as_ref());
+ writer.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(3, 1)..Point::new(4, 1),
@@ -1314,7 +1341,7 @@ mod tests {
cx.as_ref(),
);
- let (snapshot, _) = map.snapshot(cx.as_ref());
+ let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee\nffffff\n");
assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), [0, 3, 5, 6]);
assert_eq!(snapshot.buffer_rows(3).collect::<Vec<_>>(), [6]);
@@ -1,97 +1,85 @@
use crate::{
- editor::{display_map::FoldMap, Buffer, Point, TextSummary},
+ editor::{display_map::fold_map, Point, TextSummary},
sum_tree::{self, SumTree},
- time,
util::Bias,
};
-use gpui::{Entity, ModelContext, ModelHandle, Task};
+use gpui::{AppContext, Task};
use parking_lot::Mutex;
-use postage::{
- mpsc,
- prelude::{Sink, Stream},
- watch,
-};
+use postage::{prelude::Sink, watch};
+use smol::channel;
#[derive(Clone)]
-struct Snapshot {
+pub struct Snapshot {
transforms: SumTree<Transform>,
- version: time::Global,
+ version: usize,
}
struct State {
snapshot: Snapshot,
- interpolated_version: time::Global,
+ interpolated_version: usize,
}
-struct WrapMap {
- buffer: ModelHandle<Buffer>,
- fold_map: FoldMap,
+pub struct WrapMap {
state: Mutex<State>,
+ edits_tx: channel::Sender<(fold_map::Snapshot, Vec<fold_map::Edit>)>,
background_snapshots: watch::Receiver<Snapshot>,
_background_task: Task<()>,
}
-impl Entity for WrapMap {
- type Event = ();
-}
-
impl WrapMap {
- fn new(buffer_handle: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
- let buffer = buffer_handle.read(cx).clone();
- let version = buffer.version();
+ pub fn new(folds_snapshot: fold_map::Snapshot, cx: &AppContext) -> Self {
let snapshot = Snapshot {
transforms: SumTree::from_item(
Transform {
summary: TransformSummary {
- buffer: buffer.text_summary(),
- display: buffer.text_summary(),
+ folded: folds_snapshot.text_summary(),
+ wrapped: folds_snapshot.text_summary(),
},
display_text: None,
},
&(),
),
- version: version.clone(),
+ version: folds_snapshot.version,
};
let (background_snapshots_tx, background_snapshots_rx) =
watch::channel_with(snapshot.clone());
- let (buffers_tx, buffers_rx) = mpsc::channel(32);
- cx.observe(&buffer_handle, move |_, buffer, cx| {
- let mut buffers_tx = buffers_tx.clone();
- // TODO: replace cloning buffers with sending `Buffer::snapshot`.
- let buffer = buffer.read(cx).clone();
- cx.spawn_weak(|_, _| async move {
- let _ = buffers_tx.send(buffer).await;
- })
- .detach();
- });
+ let (edits_tx, edits_rx) = channel::unbounded();
let background_task = cx.background().spawn(async move {
- let mut wrapper = BackgroundWrapper::new(buffers_rx, background_snapshots_tx);
- wrapper.run(buffer).await;
+ let mut wrapper = BackgroundWrapper::new(edits_rx, background_snapshots_tx);
+ wrapper.run(folds_snapshot).await;
});
Self {
- buffer: buffer_handle.clone(),
- fold_map: FoldMap::new(buffer_handle, cx.as_ref()),
state: Mutex::new(State {
+ interpolated_version: snapshot.version,
snapshot,
- interpolated_version: version,
}),
+ edits_tx,
background_snapshots: background_snapshots_rx,
_background_task: background_task,
}
}
+
+ pub fn read(&self, folds_snapshot: fold_map::Snapshot, edits: Vec<fold_map::Edit>) -> Snapshot {
+ // TODO: interpolate
+ self.edits_tx.try_send((folds_snapshot, edits)).unwrap();
+ self.state.lock().snapshot.clone()
+ }
}
struct BackgroundWrapper {
- buffers_rx: mpsc::Receiver<Buffer>,
+ edits_rx: channel::Receiver<(fold_map::Snapshot, Vec<fold_map::Edit>)>,
snapshots_tx: watch::Sender<Snapshot>,
snapshot: Snapshot,
}
impl BackgroundWrapper {
- fn new(buffers_rx: mpsc::Receiver<Buffer>, snapshots_tx: watch::Sender<Snapshot>) -> Self {
+ fn new(
+ edits_rx: channel::Receiver<(fold_map::Snapshot, Vec<fold_map::Edit>)>,
+ snapshots_tx: watch::Sender<Snapshot>,
+ ) -> Self {
Self {
- buffers_rx,
+ edits_rx,
snapshots_tx,
snapshot: Snapshot {
transforms: Default::default(),
@@ -100,32 +88,36 @@ impl BackgroundWrapper {
}
}
- async fn run(&mut self, buffer: Buffer) {
- if !self.sync(buffer).await {
+ async fn run(&mut self, snapshot: fold_map::Snapshot) {
+ let edit = fold_map::Edit {
+ old_bytes: 0..0,
+ new_bytes: 0..snapshot.len(),
+ };
+ if !self.sync(snapshot, vec![edit]).await {
return;
}
- while let Some(buffer) = self.buffers_rx.recv().await {
- if !self.sync(buffer).await {
+ while let Ok((snapshot, edits)) = self.edits_rx.recv().await {
+ if !self.sync(snapshot, edits).await {
break;
}
}
}
- async fn sync(&mut self, buffer: Buffer) -> bool {
+ async fn sync(&mut self, snapshot: fold_map::Snapshot, edits: Vec<fold_map::Edit>) -> bool {
let mut new_transforms = SumTree::new();
{
- let mut old_cursor = self.snapshot.transforms.cursor::<Point, ()>();
- for edit in buffer.edits_since(self.snapshot.version.clone()) {
- new_transforms.push_tree(
- old_cursor.slice(&Point::new(edit.old_lines.start.row, 0), Bias::Left, &()),
- &(),
- );
- }
+ // let mut old_cursor = self.snapshot.transforms.cursor::<Point, ()>();
+ // for edit in buffer.edits_since(self.snapshot.version.clone()) {
+ // new_transforms.push_tree(
+ // old_cursor.slice(&Point::new(edit.old_lines.start.row, 0), Bias::Left, &()),
+ // &(),
+ // );
+ // }
}
self.snapshot.transforms = new_transforms;
- self.snapshot.version = buffer.version();
+ self.snapshot.version = snapshot.version;
self.snapshots_tx.send(self.snapshot.clone()).await.is_ok()
}
}
@@ -146,21 +138,21 @@ impl sum_tree::Item for Transform {
#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct TransformSummary {
- display: TextSummary,
- buffer: TextSummary,
+ folded: TextSummary,
+ wrapped: TextSummary,
}
impl sum_tree::Summary for TransformSummary {
type Context = ();
fn add_summary(&mut self, other: &Self, _: &()) {
- self.buffer += &other.buffer;
- self.display += &other.display;
+ self.folded += &other.folded;
+ self.wrapped += &other.wrapped;
}
}
impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
- *self += &summary.buffer.lines;
+ *self += &summary.folded.lines;
}
}