Detailed changes
@@ -21,7 +21,7 @@ use gpui::{
WeakViewHandle,
};
use parking_lot::Mutex;
-use postage::watch;
+use postage::{prelude::Stream, watch};
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use smol::Timer;
@@ -413,6 +413,14 @@ impl Editor {
let display_map =
DisplayMap::new(buffer.clone(), settings.borrow().clone(), None, cx.as_ref());
+ let mut notifications = display_map.notifications();
+ cx.spawn(|this, mut cx| async move {
+ while notifications.recv().await.is_some() {
+ this.update(&mut cx, |_, cx| cx.notify());
+ }
+ })
+ .detach();
+
let mut next_selection_id = 0;
let selection_set_id = buffer.update(cx, |buffer, cx| {
buffer.add_selection_set(
@@ -4,10 +4,11 @@ mod wrap_map;
use super::{buffer, Anchor, Bias, Buffer, Point, Settings, ToOffset, ToPoint};
use fold_map::FoldMap;
-pub use fold_map::InputRows;
use gpui::{AppContext, ModelHandle};
+use postage::prelude::Stream;
use std::ops::Range;
use tab_map::TabMap;
+pub use wrap_map::BufferRows;
use wrap_map::WrapMap;
pub struct DisplayMap {
@@ -76,6 +77,10 @@ impl DisplayMap {
pub fn set_wrap_width(&self, width: Option<f32>) {
self.wrap_map.set_wrap_width(width);
}
+
+ pub fn notifications(&self) -> impl Stream<Item = ()> {
+ self.wrap_map.notifications()
+ }
}
pub struct DisplayMapSnapshot {
@@ -86,8 +91,8 @@ pub struct DisplayMapSnapshot {
}
impl DisplayMapSnapshot {
- pub fn buffer_rows(&self, start_row: u32) -> InputRows {
- self.folds_snapshot.input_rows(start_row)
+ pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
+ self.wraps_snapshot.buffer_rows(start_row)
}
pub fn max_point(&self) -> DisplayPoint {
@@ -98,8 +103,8 @@ impl DisplayMapSnapshot {
self.wraps_snapshot.chunks_at(point.0)
}
- pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> tab_map::HighlightedChunks {
- self.tabs_snapshot.highlighted_chunks_for_rows(rows)
+ pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> wrap_map::HighlightedChunks {
+ self.wraps_snapshot.highlighted_chunks_for_rows(rows)
}
pub fn chars_at<'a>(&'a self, point: DisplayPoint) -> impl Iterator<Item = char> + 'a {
@@ -491,7 +491,7 @@ impl Snapshot {
(line_end - line_start) as u32
}
- pub fn input_rows(&self, start_row: u32) -> InputRows {
+ pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
if start_row > self.transforms.summary().output.lines.row {
panic!("invalid display row {}", start_row);
}
@@ -499,7 +499,7 @@ impl Snapshot {
let output_point = OutputPoint::new(start_row, 0);
let mut cursor = self.transforms.cursor();
cursor.seek(&output_point, Bias::Left, &());
- InputRows {
+ BufferRows {
output_point,
cursor,
}
@@ -880,12 +880,12 @@ impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize {
}
}
-pub struct InputRows<'a> {
+pub struct BufferRows<'a> {
cursor: Cursor<'a, Transform, OutputPoint, InputPoint>,
output_point: OutputPoint,
}
-impl<'a> Iterator for InputRows<'a> {
+impl<'a> Iterator for BufferRows<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
@@ -1450,7 +1450,7 @@ mod tests {
.to_output_point(InputPoint::new(*input_row, 0))
.row();
assert_eq!(
- snapshot.input_rows(output_row).collect::<Vec<_>>(),
+ snapshot.buffer_rows(output_row).collect::<Vec<_>>(),
expected_input_rows[idx..],
);
}
@@ -1544,8 +1544,8 @@ mod tests {
let (snapshot, _) = map.read(cx.as_ref());
assert_eq!(snapshot.text(), "aaβ¦cccc\ndβ¦eeeee\nffffff\n");
- assert_eq!(snapshot.input_rows(0).collect::<Vec<_>>(), [0, 3, 5, 6]);
- assert_eq!(snapshot.input_rows(3).collect::<Vec<_>>(), [6]);
+ assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), [0, 3, 5, 6]);
+ assert_eq!(snapshot.buffer_rows(3).collect::<Vec<_>>(), [6]);
}
impl FoldMap {
@@ -1,7 +1,7 @@
use parking_lot::Mutex;
use super::fold_map::{
- Chunks as InputChunks, Edit as InputEdit, HighlightedChunks as InputHighlightedChunks,
+ self, Chunks as InputChunks, Edit as InputEdit, HighlightedChunks as InputHighlightedChunks,
OutputOffset as InputOffset, OutputPoint as InputPoint, Snapshot as InputSnapshot,
};
use crate::{editor::rope, settings::StyleId, util::Bias};
@@ -94,13 +94,15 @@ impl Snapshot {
}
}
- pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> HighlightedChunks {
- let start = self.input.to_output_offset(InputPoint::new(rows.start, 0));
- let end = self
+ pub fn highlighted_chunks(&mut self, range: Range<OutputPoint>) -> HighlightedChunks {
+ let input_start = self
.input
- .to_output_offset(InputPoint::new(rows.end, 0).min(self.input.max_point()));
+ .to_output_offset(self.to_input_point(range.start, Bias::Left).0);
+ let input_end = self
+ .input
+ .to_output_offset(self.to_input_point(range.end, Bias::Left).0);
HighlightedChunks {
- input_chunks: self.input.highlighted_chunks(start..end),
+ input_chunks: self.input.highlighted_chunks(input_start..input_end),
column: 0,
tab_size: self.tab_size,
chunk: "",
@@ -108,6 +110,10 @@ impl Snapshot {
}
}
+ pub fn buffer_rows(&self, row: u32) -> fold_map::BufferRows {
+ self.input.buffer_rows(row)
+ }
+
#[cfg(test)]
pub fn text(&self) -> String {
self.chunks_at(Default::default()).collect()
@@ -1,13 +1,17 @@
-use super::tab_map::{
- self, Edit as InputEdit, OutputPoint as InputPoint, Snapshot as InputSnapshot, TextSummary,
+use super::{
+ fold_map,
+ tab_map::{
+ self, Edit as InputEdit, OutputPoint as InputPoint, Snapshot as InputSnapshot, TextSummary,
+ },
};
use crate::{
- editor::{Editor, Point},
+ editor::Point,
+ settings::StyleId,
sum_tree::{self, Cursor, SumTree},
util::Bias,
Settings,
};
-use gpui::{AppContext, FontCache, FontSystem, Task, ViewContext};
+use gpui::{AppContext, FontCache, FontSystem, Task};
use parking_lot::Mutex;
use postage::{
prelude::{Sink, Stream},
@@ -139,10 +143,41 @@ impl Snapshot {
}
}
+ pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> HighlightedChunks {
+ let output_start = OutputPoint::new(rows.start, 0);
+ let output_end = OutputPoint::new(rows.end, 0);
+ let mut transforms = self.transforms.cursor::<OutputPoint, InputPoint>();
+ transforms.seek(&output_start, Bias::Right, &());
+ let input_start =
+ InputPoint(transforms.sum_start().0 + (output_start.0 - transforms.seek_start().0));
+ let input_end = self.to_input_point(output_end).min(self.input.max_point());
+ HighlightedChunks {
+ input_chunks: self.input.highlighted_chunks(input_start..input_end),
+ input_position: input_start,
+ style_id: StyleId::default(),
+ input_chunk: "",
+ transforms,
+ }
+ }
+
pub fn max_point(&self) -> OutputPoint {
self.to_output_point(self.input.max_point())
}
+ pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
+ let mut transforms = self.transforms.cursor::<OutputPoint, InputPoint>();
+ transforms.seek(&OutputPoint::new(start_row, 0), Bias::Right, &());
+ let input_row = transforms.sum_start().row();
+ let mut input_buffer_rows = self.input.buffer_rows(start_row);
+ let input_buffer_row = input_buffer_rows.next().unwrap();
+ BufferRows {
+ transforms,
+ input_row,
+ input_buffer_row,
+ input_buffer_rows,
+ }
+ }
+
pub fn to_input_point(&self, point: OutputPoint) -> InputPoint {
let mut cursor = self.transforms.cursor::<OutputPoint, InputPoint>();
cursor.seek(&point, Bias::Right, &());
@@ -167,6 +202,21 @@ pub struct Chunks<'a> {
transforms: Cursor<'a, Transform, OutputPoint, InputPoint>,
}
+pub struct HighlightedChunks<'a> {
+ input_chunks: tab_map::HighlightedChunks<'a>,
+ input_chunk: &'a str,
+ style_id: StyleId,
+ input_position: InputPoint,
+ transforms: Cursor<'a, Transform, OutputPoint, InputPoint>,
+}
+
+pub struct BufferRows<'a> {
+ input_buffer_rows: fold_map::BufferRows<'a>,
+ input_row: u32,
+ input_buffer_row: u32,
+ transforms: Cursor<'a, Transform, OutputPoint, InputPoint>,
+}
+
impl<'a> Iterator for Chunks<'a> {
type Item = &'a str;
@@ -205,6 +255,65 @@ impl<'a> Iterator for Chunks<'a> {
}
}
+impl<'a> Iterator for HighlightedChunks<'a> {
+ type Item = (&'a str, StyleId);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let transform = self.transforms.item()?;
+ if let Some(display_text) = transform.display_text {
+ self.transforms.next(&());
+ return Some((display_text, self.style_id));
+ }
+
+ if self.input_chunk.is_empty() {
+ let (chunk, style_id) = self.input_chunks.next().unwrap();
+ self.input_chunk = chunk;
+ self.style_id = style_id;
+ }
+
+ let mut input_len = 0;
+ let transform_end = self.transforms.sum_end(&());
+ for c in self.input_chunk.chars() {
+ let char_len = c.len_utf8();
+ input_len += char_len;
+ if c == '\n' {
+ *self.input_position.row_mut() += 1;
+ *self.input_position.column_mut() = 0;
+ } else {
+ *self.input_position.column_mut() += char_len as u32;
+ }
+
+ if self.input_position >= transform_end {
+ self.transforms.next(&());
+ break;
+ }
+ }
+
+ let (prefix, suffix) = self.input_chunk.split_at(input_len);
+ self.input_chunk = suffix;
+ Some((prefix, self.style_id))
+ }
+}
+
+impl<'a> Iterator for BufferRows<'a> {
+ type Item = u32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let result = self.input_buffer_row;
+ if self.input_row + 1 < self.transforms.sum_end(&()).row() {
+ self.input_row += 1;
+ self.input_buffer_row = self.input_buffer_rows.next().unwrap();
+ } else {
+ self.transforms.seek_forward(
+ &OutputPoint::new(self.transforms.seek_start().row() + 1, 0),
+ Bias::Right,
+ &(),
+ );
+ }
+ Some(result)
+ }
+}
+
struct State {
snapshot: Snapshot,
pending_edits: VecDeque<(InputSnapshot, Vec<InputEdit>)>,
@@ -222,7 +331,7 @@ impl WrapMap {
input: InputSnapshot,
settings: Settings,
wrap_width: Option<f32>,
- cx: &mut ViewContext<Editor>,
+ cx: &AppContext,
) -> Self {
let font_cache = cx.font_cache().clone();
let font_system = cx.platform().fonts();
@@ -252,7 +361,9 @@ impl WrapMap {
pub fn sync(&self, input: InputSnapshot, edits: Vec<InputEdit>, cx: &AppContext) -> Snapshot {
let mut background_snapshot = self.background_snapshot.clone();
- let mut snapshot = self.background_snapshot.borrow().clone();
+ let mut snapshot = background_snapshot.borrow().clone();
+
+ log::info!("sync version: {:?}", snapshot.input.version());
if !edits.is_empty() {
self.background_changes_tx
@@ -295,6 +406,10 @@ impl WrapMap {
.try_send(Change::Width(width))
.unwrap();
}
+
+ pub fn notifications(&self) -> impl Stream<Item = ()> {
+ self.background_snapshot.clone().map(|_| ())
+ }
}
struct BackgroundWrapper {
@@ -362,6 +477,7 @@ impl BackgroundWrapper {
}
}
};
+
if snapshot_tx.send(self.snapshot.clone()).await.is_err() {
break;
}
@@ -338,7 +338,6 @@ impl Element for EditorElement {
}
let view = self.view(app);
- view.set_width(size.x());
let font_cache = &cx.font_cache;
let layout_cache = &cx.text_layout_cache;
@@ -362,6 +361,7 @@ impl Element for EditorElement {
let gutter_size = vec2f(gutter_width, size.y());
let text_size = size - vec2f(gutter_width, 0.0);
+ view.set_width(text_size.x());
let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, app);