mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-05 10:20:51 +00:00
Start rendering highlighted text and line numbers via the wrap map
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
b513df3844
commit
72fdd3fb9a
6 changed files with 161 additions and 26 deletions
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue