From 85bdd9329b550475aae34340e50abd4e79f2dd82 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 25 Oct 2024 11:59:22 -0600 Subject: [PATCH] Revert "Show invisibles in editor (#19298)" (#19752) Closes: #19714 This reverts commit 6dcec47235fa85f0e416b9230e2fedc61de510ee. Release Notes: - (preview only) Fixes a crash when rendering invisibles --- Cargo.lock | 1 - Cargo.toml | 2 +- crates/editor/Cargo.toml | 1 - crates/editor/src/display_map.rs | 118 ++++------ crates/editor/src/display_map/block_map.rs | 55 ++--- crates/editor/src/display_map/invisibles.rs | 157 ------------- .../display_map/{char_map.rs => tab_map.rs} | 162 +++++--------- crates/editor/src/display_map/wrap_map.rs | 211 +++++++++--------- crates/editor/src/element.rs | 17 +- crates/editor/src/hover_popover.rs | 45 +--- crates/gpui/src/text_system/line.rs | 51 +---- crates/language/src/buffer.rs | 3 +- 12 files changed, 260 insertions(+), 563 deletions(-) delete mode 100644 crates/editor/src/display_map/invisibles.rs rename crates/editor/src/display_map/{char_map.rs => tab_map.rs} (82%) diff --git a/Cargo.lock b/Cargo.lock index f4e84f7a03..75d058db38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3711,7 +3711,6 @@ dependencies = [ "tree-sitter-rust", "tree-sitter-typescript", "ui", - "unicode-segmentation", "unindent", "url", "util", diff --git a/Cargo.toml b/Cargo.toml index 732306a9af..64a2546020 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -464,7 +464,7 @@ tree-sitter-typescript = "0.23" tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "baff0b51c64ef6a1fb1f8390f3ad6015b83ec13a" } unicase = "2.6" unindent = "0.1.7" -unicode-segmentation = "1.11" +unicode-segmentation = "1.10" url = "2.2" uuid = { version = "1.1.2", features = ["v4", "v5", "serde"] } wasmparser = "0.215" diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index f6a0058c7b..cfd9284f80 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -81,7 +81,6 @@ ui.workspace = true url.workspace = true util.workspace = true workspace.workspace = true -unicode-segmentation.workspace = true [dev-dependencies] ctor.workspace = true diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index e24336d1e9..67b7e5b60f 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -8,7 +8,7 @@ //! of several smaller structures that form a hierarchy (starting at the bottom): //! - [`InlayMap`] that decides where the [`Inlay`]s should be displayed. //! - [`FoldMap`] that decides where the fold indicators should be; it also tracks parts of a source file that are currently folded. -//! - [`CharMap`] that replaces tabs and non-printable characters +//! - [`TabMap`] that keeps track of hard tabs in a buffer. //! - [`WrapMap`] that handles soft wrapping. //! - [`BlockMap`] that tracks custom blocks such as diagnostics that should be displayed within buffer. //! - [`DisplayMap`] that adds background highlights to the regions of text. @@ -18,11 +18,10 @@ //! [EditorElement]: crate::element::EditorElement mod block_map; -mod char_map; mod crease_map; mod fold_map; mod inlay_map; -mod invisibles; +mod tab_map; mod wrap_map; use crate::{ @@ -33,7 +32,6 @@ pub use block_map::{ BlockPlacement, BlockPoint, BlockProperties, BlockStyle, CustomBlockId, RenderBlock, }; use block_map::{BlockRow, BlockSnapshot}; -use char_map::{CharMap, CharSnapshot}; use collections::{HashMap, HashSet}; pub use crease_map::*; pub use fold_map::{Fold, FoldId, FoldPlaceholder, FoldPoint}; @@ -44,7 +42,6 @@ use gpui::{ pub(crate) use inlay_map::Inlay; use inlay_map::{InlayMap, InlaySnapshot}; pub use inlay_map::{InlayOffset, InlayPoint}; -pub use invisibles::is_invisible; use language::{ language_settings::language_settings, ChunkRenderer, OffsetUtf16, Point, Subscription as BufferSubscription, @@ -64,9 +61,9 @@ use std::{ sync::Arc, }; use sum_tree::{Bias, TreeMap}; +use tab_map::{TabMap, TabSnapshot}; use text::LineIndent; -use ui::{px, WindowContext}; -use unicode_segmentation::UnicodeSegmentation; +use ui::WindowContext; use wrap_map::{WrapMap, WrapSnapshot}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -97,7 +94,7 @@ pub struct DisplayMap { /// Decides where the fold indicators should be and tracks parts of a source file that are currently folded. fold_map: FoldMap, /// Keeps track of hard tabs in a buffer. - char_map: CharMap, + tab_map: TabMap, /// Handles soft wrapping. wrap_map: Model, /// Tracks custom blocks such as diagnostics that should be displayed within buffer. @@ -134,7 +131,7 @@ impl DisplayMap { let crease_map = CreaseMap::new(&buffer_snapshot); let (inlay_map, snapshot) = InlayMap::new(buffer_snapshot); let (fold_map, snapshot) = FoldMap::new(snapshot); - let (char_map, snapshot) = CharMap::new(snapshot, tab_size); + let (tab_map, snapshot) = TabMap::new(snapshot, tab_size); let (wrap_map, snapshot) = WrapMap::new(snapshot, font, font_size, wrap_width, cx); let block_map = BlockMap::new( snapshot, @@ -151,7 +148,7 @@ impl DisplayMap { buffer_subscription, fold_map, inlay_map, - char_map, + tab_map, wrap_map, block_map, crease_map, @@ -169,17 +166,17 @@ impl DisplayMap { let (inlay_snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits); let (fold_snapshot, edits) = self.fold_map.read(inlay_snapshot.clone(), edits); let tab_size = Self::tab_size(&self.buffer, cx); - let (char_snapshot, edits) = self.char_map.sync(fold_snapshot.clone(), edits, tab_size); + let (tab_snapshot, edits) = self.tab_map.sync(fold_snapshot.clone(), edits, tab_size); let (wrap_snapshot, edits) = self .wrap_map - .update(cx, |map, cx| map.sync(char_snapshot.clone(), edits, cx)); + .update(cx, |map, cx| map.sync(tab_snapshot.clone(), edits, cx)); let block_snapshot = self.block_map.read(wrap_snapshot.clone(), edits).snapshot; DisplaySnapshot { buffer_snapshot: self.buffer.read(cx).snapshot(cx), fold_snapshot, inlay_snapshot, - char_snapshot, + tab_snapshot, wrap_snapshot, block_snapshot, crease_snapshot: self.crease_map.snapshot(), @@ -215,13 +212,13 @@ impl DisplayMap { let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.inlay_map.sync(snapshot, edits); let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); self.block_map.read(snapshot, edits); let (snapshot, edits) = fold_map.fold(ranges); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -239,13 +236,13 @@ impl DisplayMap { let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.inlay_map.sync(snapshot, edits); let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); self.block_map.read(snapshot, edits); let (snapshot, edits) = fold_map.unfold(ranges, inclusive); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -280,7 +277,7 @@ impl DisplayMap { let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.inlay_map.sync(snapshot, edits); let (snapshot, edits) = self.fold_map.read(snapshot, edits); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -298,7 +295,7 @@ impl DisplayMap { let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.inlay_map.sync(snapshot, edits); let (snapshot, edits) = self.fold_map.read(snapshot, edits); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -316,7 +313,7 @@ impl DisplayMap { let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.inlay_map.sync(snapshot, edits); let (snapshot, edits) = self.fold_map.read(snapshot, edits); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -334,7 +331,7 @@ impl DisplayMap { let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.inlay_map.sync(snapshot, edits); let (snapshot, edits) = self.fold_map.read(snapshot, edits); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -410,7 +407,7 @@ impl DisplayMap { let (snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits); let (snapshot, edits) = self.fold_map.read(snapshot, edits); let tab_size = Self::tab_size(&self.buffer, cx); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -418,7 +415,7 @@ impl DisplayMap { let (snapshot, edits) = self.inlay_map.splice(to_remove, to_insert); let (snapshot, edits) = self.fold_map.read(snapshot, edits); - let (snapshot, edits) = self.char_map.sync(snapshot, edits, tab_size); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -470,7 +467,7 @@ pub struct DisplaySnapshot { pub fold_snapshot: FoldSnapshot, pub crease_snapshot: CreaseSnapshot, inlay_snapshot: InlaySnapshot, - char_snapshot: CharSnapshot, + tab_snapshot: TabSnapshot, wrap_snapshot: WrapSnapshot, block_snapshot: BlockSnapshot, text_highlights: TextHighlights, @@ -570,8 +567,8 @@ impl DisplaySnapshot { fn point_to_display_point(&self, point: MultiBufferPoint, bias: Bias) -> DisplayPoint { let inlay_point = self.inlay_snapshot.to_inlay_point(point); let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias); - let char_point = self.char_snapshot.to_char_point(fold_point); - let wrap_point = self.wrap_snapshot.char_point_to_wrap_point(char_point); + let tab_point = self.tab_snapshot.to_tab_point(fold_point); + let wrap_point = self.wrap_snapshot.tab_point_to_wrap_point(tab_point); let block_point = self.block_snapshot.to_block_point(wrap_point); DisplayPoint(block_point) } @@ -599,21 +596,21 @@ impl DisplaySnapshot { fn display_point_to_inlay_point(&self, point: DisplayPoint, bias: Bias) -> InlayPoint { let block_point = point.0; let wrap_point = self.block_snapshot.to_wrap_point(block_point); - let char_point = self.wrap_snapshot.to_char_point(wrap_point); - let fold_point = self.char_snapshot.to_fold_point(char_point, bias).0; + let tab_point = self.wrap_snapshot.to_tab_point(wrap_point); + let fold_point = self.tab_snapshot.to_fold_point(tab_point, bias).0; fold_point.to_inlay_point(&self.fold_snapshot) } pub fn display_point_to_fold_point(&self, point: DisplayPoint, bias: Bias) -> FoldPoint { let block_point = point.0; let wrap_point = self.block_snapshot.to_wrap_point(block_point); - let char_point = self.wrap_snapshot.to_char_point(wrap_point); - self.char_snapshot.to_fold_point(char_point, bias).0 + let tab_point = self.wrap_snapshot.to_tab_point(wrap_point); + self.tab_snapshot.to_fold_point(tab_point, bias).0 } pub fn fold_point_to_display_point(&self, fold_point: FoldPoint) -> DisplayPoint { - let char_point = self.char_snapshot.to_char_point(fold_point); - let wrap_point = self.wrap_snapshot.char_point_to_wrap_point(char_point); + let tab_point = self.tab_snapshot.to_tab_point(fold_point); + let wrap_point = self.wrap_snapshot.tab_point_to_wrap_point(tab_point); let block_point = self.block_snapshot.to_block_point(wrap_point); DisplayPoint(block_point) } @@ -691,23 +688,6 @@ impl DisplaySnapshot { } } - if chunk.is_invisible { - let invisible_highlight = HighlightStyle { - background_color: Some(editor_style.status.hint_background), - underline: Some(UnderlineStyle { - color: Some(editor_style.status.hint), - thickness: px(1.), - wavy: false, - }), - ..Default::default() - }; - if let Some(highlight_style) = highlight_style.as_mut() { - highlight_style.highlight(invisible_highlight); - } else { - highlight_style = Some(invisible_highlight); - } - } - let mut diagnostic_highlight = HighlightStyle::default(); if chunk.is_unnecessary { @@ -804,11 +784,12 @@ impl DisplaySnapshot { layout_line.closest_index_for_x(x) as u32 } - pub fn grapheme_at(&self, mut point: DisplayPoint) -> Option { + pub fn display_chars_at( + &self, + mut point: DisplayPoint, + ) -> impl Iterator + '_ { point = DisplayPoint(self.block_snapshot.clip_point(point.0, Bias::Left)); - - let chars = self - .text_chunks(point.row()) + self.text_chunks(point.row()) .flat_map(str::chars) .skip_while({ let mut column = 0; @@ -818,21 +799,16 @@ impl DisplaySnapshot { !at_point } }) - .take_while({ - let mut prev = false; - move |char| { - let now = char.is_ascii(); - let end = char.is_ascii() && (char.is_ascii_whitespace() || prev); - prev = now; - !end + .map(move |ch| { + let result = (ch, point); + if ch == '\n' { + *point.row_mut() += 1; + *point.column_mut() = 0; + } else { + *point.column_mut() += ch.len_utf8() as u32; } - }); - - chars - .collect::() - .graphemes(true) - .next() - .map(|s| s.to_owned()) + result + }) } pub fn buffer_chars_at(&self, mut offset: usize) -> impl Iterator + '_ { @@ -1144,8 +1120,8 @@ impl DisplayPoint { pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize { let wrap_point = map.block_snapshot.to_wrap_point(self.0); - let char_point = map.wrap_snapshot.to_char_point(wrap_point); - let fold_point = map.char_snapshot.to_fold_point(char_point, bias).0; + let tab_point = map.wrap_snapshot.to_tab_point(wrap_point); + let fold_point = map.tab_snapshot.to_fold_point(tab_point, bias).0; let inlay_point = fold_point.to_inlay_point(&map.fold_snapshot); map.inlay_snapshot .to_buffer_offset(map.inlay_snapshot.to_offset(inlay_point)) @@ -1253,7 +1229,7 @@ pub mod tests { let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); log::info!("buffer text: {:?}", snapshot.buffer_snapshot.text()); log::info!("fold text: {:?}", snapshot.fold_snapshot.text()); - log::info!("char text: {:?}", snapshot.char_snapshot.text()); + log::info!("tab text: {:?}", snapshot.tab_snapshot.text()); log::info!("wrap text: {:?}", snapshot.wrap_snapshot.text()); log::info!("block text: {:?}", snapshot.block_snapshot.text()); log::info!("display text: {:?}", snapshot.text()); @@ -1368,7 +1344,7 @@ pub mod tests { fold_count = snapshot.fold_count(); log::info!("buffer text: {:?}", snapshot.buffer_snapshot.text()); log::info!("fold text: {:?}", snapshot.fold_snapshot.text()); - log::info!("char text: {:?}", snapshot.char_snapshot.text()); + log::info!("tab text: {:?}", snapshot.tab_snapshot.text()); log::info!("wrap text: {:?}", snapshot.wrap_snapshot.text()); log::info!("block text: {:?}", snapshot.block_snapshot.text()); log::info!("display text: {:?}", snapshot.text()); diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 44a540bc95..a7d0ca9c63 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -1666,7 +1666,7 @@ fn offset_for_row(s: &str, target: u32) -> (u32, usize) { mod tests { use super::*; use crate::display_map::{ - char_map::CharMap, fold_map::FoldMap, inlay_map::InlayMap, wrap_map::WrapMap, + fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap, wrap_map::WrapMap, }; use gpui::{div, font, px, AppContext, Context as _, Element}; use language::{Buffer, Capability}; @@ -1701,9 +1701,9 @@ mod tests { let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (mut char_map, char_snapshot) = CharMap::new(fold_snapshot, 1.try_into().unwrap()); + let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap()); let (wrap_map, wraps_snapshot) = - cx.update(|cx| WrapMap::new(char_snapshot, font("Helvetica"), px(14.0), None, cx)); + cx.update(|cx| WrapMap::new(tab_snapshot, font("Helvetica"), px(14.0), None, cx)); let mut block_map = BlockMap::new(wraps_snapshot.clone(), true, 1, 1, 1); let mut writer = block_map.write(wraps_snapshot.clone(), Default::default()); @@ -1851,10 +1851,10 @@ mod tests { let (inlay_snapshot, inlay_edits) = inlay_map.sync(buffer_snapshot, subscription.consume().into_inner()); let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits); - let (char_snapshot, tab_edits) = - char_map.sync(fold_snapshot, fold_edits, 4.try_into().unwrap()); + let (tab_snapshot, tab_edits) = + tab_map.sync(fold_snapshot, fold_edits, 4.try_into().unwrap()); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { - wrap_map.sync(char_snapshot, tab_edits, cx) + wrap_map.sync(tab_snapshot, tab_edits, cx) }); let snapshot = block_map.read(wraps_snapshot, wrap_edits); assert_eq!(snapshot.text(), "aaa\n\nb!!!\n\n\nbb\nccc\nddd\n\n\n"); @@ -1914,9 +1914,8 @@ mod tests { let multi_buffer_snapshot = multi_buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(multi_buffer_snapshot.clone()); let (_, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (_, char_snapshot) = CharMap::new(fold_snapshot, 4.try_into().unwrap()); - let (_, wraps_snapshot) = - WrapMap::new(char_snapshot, font, font_size, Some(wrap_width), cx); + let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap()); + let (_, wraps_snapshot) = WrapMap::new(tab_snapshot, font, font_size, Some(wrap_width), cx); let block_map = BlockMap::new(wraps_snapshot.clone(), true, 1, 1, 1); let snapshot = block_map.read(wraps_snapshot, Default::default()); @@ -1953,9 +1952,9 @@ mod tests { let _subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); let (_inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (_fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (_char_map, char_snapshot) = CharMap::new(fold_snapshot, 1.try_into().unwrap()); + let (_tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap()); let (_wrap_map, wraps_snapshot) = - cx.update(|cx| WrapMap::new(char_snapshot, font("Helvetica"), px(14.0), None, cx)); + cx.update(|cx| WrapMap::new(tab_snapshot, font("Helvetica"), px(14.0), None, cx)); let mut block_map = BlockMap::new(wraps_snapshot.clone(), false, 1, 1, 0); let mut writer = block_map.write(wraps_snapshot.clone(), Default::default()); @@ -2055,15 +2054,9 @@ mod tests { let buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx)); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (_, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (_, char_snapshot) = CharMap::new(fold_snapshot, 4.try_into().unwrap()); + let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap()); let (_, wraps_snapshot) = cx.update(|cx| { - WrapMap::new( - char_snapshot, - font("Helvetica"), - px(14.0), - Some(px(60.)), - cx, - ) + WrapMap::new(tab_snapshot, font("Helvetica"), px(14.0), Some(px(60.)), cx) }); let mut block_map = BlockMap::new(wraps_snapshot.clone(), true, 1, 1, 0); @@ -2106,7 +2099,7 @@ mod tests { let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot); let tab_size = 1.try_into().unwrap(); - let (mut tab_map, tab_snapshot) = CharMap::new(fold_snapshot, tab_size); + let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, tab_size); let (wrap_map, wraps_snapshot) = cx.update(|cx| WrapMap::new(tab_snapshot, font("Helvetica"), px(14.0), None, cx)); let mut block_map = BlockMap::new(wraps_snapshot.clone(), false, 1, 1, 0); @@ -2257,9 +2250,9 @@ mod tests { let mut buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx)); let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (mut char_map, char_snapshot) = CharMap::new(fold_snapshot, 4.try_into().unwrap()); + let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap()); let (wrap_map, wraps_snapshot) = cx - .update(|cx| WrapMap::new(char_snapshot, font("Helvetica"), font_size, wrap_width, cx)); + .update(|cx| WrapMap::new(tab_snapshot, font("Helvetica"), font_size, wrap_width, cx)); let mut block_map = BlockMap::new( wraps_snapshot, true, @@ -2321,10 +2314,10 @@ mod tests { let (inlay_snapshot, inlay_edits) = inlay_map.sync(buffer_snapshot.clone(), vec![]); let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits); - let (char_snapshot, tab_edits) = - char_map.sync(fold_snapshot, fold_edits, tab_size); + let (tab_snapshot, tab_edits) = + tab_map.sync(fold_snapshot, fold_edits, tab_size); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { - wrap_map.sync(char_snapshot, tab_edits, cx) + wrap_map.sync(tab_snapshot, tab_edits, cx) }); let mut block_map = block_map.write(wraps_snapshot, wrap_edits); block_map.insert(block_properties.iter().map(|props| BlockProperties { @@ -2346,10 +2339,10 @@ mod tests { let (inlay_snapshot, inlay_edits) = inlay_map.sync(buffer_snapshot.clone(), vec![]); let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits); - let (char_snapshot, tab_edits) = - char_map.sync(fold_snapshot, fold_edits, tab_size); + let (tab_snapshot, tab_edits) = + tab_map.sync(fold_snapshot, fold_edits, tab_size); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { - wrap_map.sync(char_snapshot, tab_edits, cx) + wrap_map.sync(tab_snapshot, tab_edits, cx) }); let mut block_map = block_map.write(wraps_snapshot, wrap_edits); block_map.remove(block_ids_to_remove); @@ -2369,9 +2362,9 @@ mod tests { let (inlay_snapshot, inlay_edits) = inlay_map.sync(buffer_snapshot.clone(), buffer_edits); let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits); - let (char_snapshot, tab_edits) = char_map.sync(fold_snapshot, fold_edits, tab_size); + let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { - wrap_map.sync(char_snapshot, tab_edits, cx) + wrap_map.sync(tab_snapshot, tab_edits, cx) }); let blocks_snapshot = block_map.read(wraps_snapshot.clone(), wrap_edits); assert_eq!( @@ -2486,7 +2479,7 @@ mod tests { .row as usize]; let soft_wrapped = wraps_snapshot - .to_char_point(WrapPoint::new(wrap_row, 0)) + .to_tab_point(WrapPoint::new(wrap_row, 0)) .column() > 0; expected_buffer_rows.push(if soft_wrapped { None } else { buffer_row }); diff --git a/crates/editor/src/display_map/invisibles.rs b/crates/editor/src/display_map/invisibles.rs deleted file mode 100644 index 19a5bebbeb..0000000000 --- a/crates/editor/src/display_map/invisibles.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::sync::LazyLock; - -use collections::HashMap; - -// Invisibility in a Unicode context is not well defined, so we have to guess. -// -// We highlight all ASCII control codes, and unicode whitespace because they are likely -// confused with a normal space (U+0020). -// -// We also highlight the handful of blank non-space characters: -// U+2800 BRAILLE PATTERN BLANK - Category: So -// U+115F HANGUL CHOSEONG FILLER - Category: Lo -// U+1160 HANGUL CHOSEONG FILLER - Category: Lo -// U+3164 HANGUL FILLER - Category: Lo -// U+FFA0 HALFWIDTH HANGUL FILLER - Category: Lo -// U+FFFC OBJECT REPLACEMENT CHARACTER - Category: So -// -// For the rest of Unicode, invisibility happens for two reasons: -// * A Format character (like a byte order mark or right-to-left override) -// * An invisible Nonspacing Mark character (like U+034F, or variation selectors) -// -// We don't consider unassigned codepoints invisible as the font renderer already shows -// a replacement character in that case (and there are a *lot* of them) -// -// Control characters are mostly fine to highlight; except: -// * U+E0020..=U+E007F are used in emoji flags. We don't highlight them right now, but we could if we tightened our heuristics. -// * U+200D is used to join characters. We highlight this but don't replace it. As our font system ignores mid-glyph highlights this mostly works to highlight unexpected uses. -// -// Nonspacing marks are handled like U+200D. This means that mid-glyph we ignore them, but -// probably causes issues with end-of-glyph usage. -// -// ref: https://invisible-characters.com -// ref: https://www.compart.com/en/unicode/category/Cf -// ref: https://gist.github.com/ConradIrwin/f759e1fc29267143c4c7895aa495dca5?h=1 -// ref: https://unicode.org/Public/emoji/13.0/emoji-test.txt -// https://github.com/bits/UTF-8-Unicode-Test-Documents/blob/master/UTF-8_sequence_separated/utf8_sequence_0-0x10ffff_assigned_including-unprintable-asis.txt -pub fn is_invisible(c: char) -> bool { - if c <= '\u{1f}' { - c != '\t' && c != '\n' && c != '\r' - } else if c >= '\u{7f}' { - c <= '\u{9f}' || c.is_whitespace() || contains(c, &FORMAT) || contains(c, &OTHER) - } else { - false - } -} - -pub(crate) fn replacement(c: char) -> Option<&'static str> { - if !is_invisible(c) { - return None; - } - if c <= '\x7f' { - REPLACEMENTS.get(&c).copied() - } else if contains(c, &PRESERVE) { - None - } else { - Some(" ") - } -} - -const REPLACEMENTS: LazyLock> = LazyLock::new(|| { - [ - ('\x00', "␀"), - ('\x01', "␁"), - ('\x02', "␂"), - ('\x03', "␃"), - ('\x04', "␄"), - ('\x05', "␅"), - ('\x06', "␆"), - ('\x07', "␇"), - ('\x08', "␈"), - ('\x0B', "␋"), - ('\x0C', "␌"), - ('\x0D', "␍"), - ('\x0E', "␎"), - ('\x0F', "␏"), - ('\x10', "␐"), - ('\x11', "␑"), - ('\x12', "␒"), - ('\x13', "␓"), - ('\x14', "␔"), - ('\x15', "␕"), - ('\x16', "␖"), - ('\x17', "␗"), - ('\x18', "␘"), - ('\x19', "␙"), - ('\x1A', "␚"), - ('\x1B', "␛"), - ('\x1C', "␜"), - ('\x1D', "␝"), - ('\x1E', "␞"), - ('\x1F', "␟"), - ('\u{007F}', "␡"), - ] - .into_iter() - .collect() -}); - -// generated using ucd-generate: ucd-generate general-category --include Format --chars ucd-16.0.0 -pub const FORMAT: &'static [(char, char)] = &[ - ('\u{ad}', '\u{ad}'), - ('\u{600}', '\u{605}'), - ('\u{61c}', '\u{61c}'), - ('\u{6dd}', '\u{6dd}'), - ('\u{70f}', '\u{70f}'), - ('\u{890}', '\u{891}'), - ('\u{8e2}', '\u{8e2}'), - ('\u{180e}', '\u{180e}'), - ('\u{200b}', '\u{200f}'), - ('\u{202a}', '\u{202e}'), - ('\u{2060}', '\u{2064}'), - ('\u{2066}', '\u{206f}'), - ('\u{feff}', '\u{feff}'), - ('\u{fff9}', '\u{fffb}'), - ('\u{110bd}', '\u{110bd}'), - ('\u{110cd}', '\u{110cd}'), - ('\u{13430}', '\u{1343f}'), - ('\u{1bca0}', '\u{1bca3}'), - ('\u{1d173}', '\u{1d17a}'), - ('\u{e0001}', '\u{e0001}'), - ('\u{e0020}', '\u{e007f}'), -]; - -// hand-made base on https://invisible-characters.com (Excluding Cf) -pub const OTHER: &'static [(char, char)] = &[ - ('\u{034f}', '\u{034f}'), - ('\u{115F}', '\u{1160}'), - ('\u{17b4}', '\u{17b5}'), - ('\u{180b}', '\u{180d}'), - ('\u{2800}', '\u{2800}'), - ('\u{3164}', '\u{3164}'), - ('\u{fe00}', '\u{fe0d}'), - ('\u{ffa0}', '\u{ffa0}'), - ('\u{fffc}', '\u{fffc}'), - ('\u{e0100}', '\u{e01ef}'), -]; - -// a subset of FORMAT/OTHER that may appear within glyphs -const PRESERVE: &'static [(char, char)] = &[ - ('\u{034f}', '\u{034f}'), - ('\u{200d}', '\u{200d}'), - ('\u{17b4}', '\u{17b5}'), - ('\u{180b}', '\u{180d}'), - ('\u{e0061}', '\u{e007a}'), - ('\u{e007f}', '\u{e007f}'), -]; - -fn contains(c: char, list: &[(char, char)]) -> bool { - for (start, end) in list { - if c < *start { - return false; - } - if c <= *end { - return true; - } - } - false -} diff --git a/crates/editor/src/display_map/char_map.rs b/crates/editor/src/display_map/tab_map.rs similarity index 82% rename from crates/editor/src/display_map/char_map.rs rename to crates/editor/src/display_map/tab_map.rs index 8c467b1803..86fa492712 100644 --- a/crates/editor/src/display_map/char_map.rs +++ b/crates/editor/src/display_map/tab_map.rs @@ -1,6 +1,5 @@ use super::{ fold_map::{self, FoldChunks, FoldEdit, FoldPoint, FoldSnapshot}, - invisibles::{is_invisible, replacement}, Highlights, }; use language::{Chunk, Point}; @@ -10,14 +9,14 @@ use sum_tree::Bias; const MAX_EXPANSION_COLUMN: u32 = 256; -/// Keeps track of hard tabs and non-printable characters in a text buffer. +/// Keeps track of hard tabs in a text buffer. /// /// See the [`display_map` module documentation](crate::display_map) for more information. -pub struct CharMap(CharSnapshot); +pub struct TabMap(TabSnapshot); -impl CharMap { - pub fn new(fold_snapshot: FoldSnapshot, tab_size: NonZeroU32) -> (Self, CharSnapshot) { - let snapshot = CharSnapshot { +impl TabMap { + pub fn new(fold_snapshot: FoldSnapshot, tab_size: NonZeroU32) -> (Self, TabSnapshot) { + let snapshot = TabSnapshot { fold_snapshot, tab_size, max_expansion_column: MAX_EXPANSION_COLUMN, @@ -27,7 +26,7 @@ impl CharMap { } #[cfg(test)] - pub fn set_max_expansion_column(&mut self, column: u32) -> CharSnapshot { + pub fn set_max_expansion_column(&mut self, column: u32) -> TabSnapshot { self.0.max_expansion_column = column; self.0.clone() } @@ -37,9 +36,9 @@ impl CharMap { fold_snapshot: FoldSnapshot, mut fold_edits: Vec, tab_size: NonZeroU32, - ) -> (CharSnapshot, Vec) { + ) -> (TabSnapshot, Vec) { let old_snapshot = &mut self.0; - let mut new_snapshot = CharSnapshot { + let mut new_snapshot = TabSnapshot { fold_snapshot, tab_size, max_expansion_column: old_snapshot.max_expansion_column, @@ -138,15 +137,15 @@ impl CharMap { let new_start = fold_edit.new.start.to_point(&new_snapshot.fold_snapshot); let new_end = fold_edit.new.end.to_point(&new_snapshot.fold_snapshot); tab_edits.push(TabEdit { - old: old_snapshot.to_char_point(old_start)..old_snapshot.to_char_point(old_end), - new: new_snapshot.to_char_point(new_start)..new_snapshot.to_char_point(new_end), + old: old_snapshot.to_tab_point(old_start)..old_snapshot.to_tab_point(old_end), + new: new_snapshot.to_tab_point(new_start)..new_snapshot.to_tab_point(new_end), }); } } else { new_snapshot.version += 1; tab_edits.push(TabEdit { - old: CharPoint::zero()..old_snapshot.max_point(), - new: CharPoint::zero()..new_snapshot.max_point(), + old: TabPoint::zero()..old_snapshot.max_point(), + new: TabPoint::zero()..new_snapshot.max_point(), }); } @@ -156,14 +155,14 @@ impl CharMap { } #[derive(Clone)] -pub struct CharSnapshot { +pub struct TabSnapshot { pub fold_snapshot: FoldSnapshot, pub tab_size: NonZeroU32, pub max_expansion_column: u32, pub version: usize, } -impl CharSnapshot { +impl TabSnapshot { pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot { &self.fold_snapshot.inlay_snapshot.buffer } @@ -171,7 +170,7 @@ impl CharSnapshot { pub fn line_len(&self, row: u32) -> u32 { let max_point = self.max_point(); if row < max_point.row() { - self.to_char_point(FoldPoint::new(row, self.fold_snapshot.line_len(row))) + self.to_tab_point(FoldPoint::new(row, self.fold_snapshot.line_len(row))) .0 .column } else { @@ -180,10 +179,10 @@ impl CharSnapshot { } pub fn text_summary(&self) -> TextSummary { - self.text_summary_for_range(CharPoint::zero()..self.max_point()) + self.text_summary_for_range(TabPoint::zero()..self.max_point()) } - pub fn text_summary_for_range(&self, range: Range) -> TextSummary { + pub fn text_summary_for_range(&self, range: Range) -> TextSummary { let input_start = self.to_fold_point(range.start, Bias::Left).0; let input_end = self.to_fold_point(range.end, Bias::Right).0; let input_summary = self @@ -212,7 +211,7 @@ impl CharSnapshot { } else { for _ in self .chunks( - CharPoint::new(range.end.row(), 0)..range.end, + TabPoint::new(range.end.row(), 0)..range.end, false, Highlights::default(), ) @@ -233,7 +232,7 @@ impl CharSnapshot { pub fn chunks<'a>( &'a self, - range: Range, + range: Range, language_aware: bool, highlights: Highlights<'a>, ) -> TabChunks<'a> { @@ -280,7 +279,7 @@ impl CharSnapshot { #[cfg(test)] pub fn text(&self) -> String { self.chunks( - CharPoint::zero()..self.max_point(), + TabPoint::zero()..self.max_point(), false, Highlights::default(), ) @@ -288,24 +287,24 @@ impl CharSnapshot { .collect() } - pub fn max_point(&self) -> CharPoint { - self.to_char_point(self.fold_snapshot.max_point()) + pub fn max_point(&self) -> TabPoint { + self.to_tab_point(self.fold_snapshot.max_point()) } - pub fn clip_point(&self, point: CharPoint, bias: Bias) -> CharPoint { - self.to_char_point( + pub fn clip_point(&self, point: TabPoint, bias: Bias) -> TabPoint { + self.to_tab_point( self.fold_snapshot .clip_point(self.to_fold_point(point, bias).0, bias), ) } - pub fn to_char_point(&self, input: FoldPoint) -> CharPoint { + pub fn to_tab_point(&self, input: FoldPoint) -> TabPoint { let chars = self.fold_snapshot.chars_at(FoldPoint::new(input.row(), 0)); let expanded = self.expand_tabs(chars, input.column()); - CharPoint::new(input.row(), expanded) + TabPoint::new(input.row(), expanded) } - pub fn to_fold_point(&self, output: CharPoint, bias: Bias) -> (FoldPoint, u32, u32) { + pub fn to_fold_point(&self, output: TabPoint, bias: Bias) -> (FoldPoint, u32, u32) { let chars = self.fold_snapshot.chars_at(FoldPoint::new(output.row(), 0)); let expanded = output.column(); let (collapsed, expanded_char_column, to_next_stop) = @@ -317,13 +316,13 @@ impl CharSnapshot { ) } - pub fn make_char_point(&self, point: Point, bias: Bias) -> CharPoint { + pub fn make_tab_point(&self, point: Point, bias: Bias) -> TabPoint { let inlay_point = self.fold_snapshot.inlay_snapshot.to_inlay_point(point); let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias); - self.to_char_point(fold_point) + self.to_tab_point(fold_point) } - pub fn to_point(&self, point: CharPoint, bias: Bias) -> Point { + pub fn to_point(&self, point: TabPoint, bias: Bias) -> Point { let fold_point = self.to_fold_point(point, bias).0; let inlay_point = fold_point.to_inlay_point(&self.fold_snapshot); self.fold_snapshot @@ -346,9 +345,6 @@ impl CharSnapshot { let tab_len = tab_size - expanded_chars % tab_size; expanded_bytes += tab_len; expanded_chars += tab_len; - } else if let Some(replacement) = replacement(c) { - expanded_chars += replacement.chars().count() as u32; - expanded_bytes += replacement.len() as u32; } else { expanded_bytes += c.len_utf8() as u32; expanded_chars += 1; @@ -388,9 +384,6 @@ impl CharSnapshot { Bias::Right => (collapsed_bytes + 1, expanded_chars, 0), }; } - } else if let Some(replacement) = replacement(c) { - expanded_chars += replacement.chars().count() as u32; - expanded_bytes += replacement.len() as u32; } else { expanded_chars += 1; expanded_bytes += c.len_utf8() as u32; @@ -412,9 +405,9 @@ impl CharSnapshot { } #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] -pub struct CharPoint(pub Point); +pub struct TabPoint(pub Point); -impl CharPoint { +impl TabPoint { pub fn new(row: u32, column: u32) -> Self { Self(Point::new(row, column)) } @@ -432,13 +425,13 @@ impl CharPoint { } } -impl From for CharPoint { +impl From for TabPoint { fn from(point: Point) -> Self { Self(point) } } -pub type TabEdit = text::Edit; +pub type TabEdit = text::Edit; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct TextSummary { @@ -493,7 +486,7 @@ impl<'a> std::ops::AddAssign<&'a Self> for TextSummary { const SPACES: &str = " "; pub struct TabChunks<'a> { - snapshot: &'a CharSnapshot, + snapshot: &'a TabSnapshot, fold_chunks: FoldChunks<'a>, chunk: Chunk<'a>, column: u32, @@ -506,7 +499,7 @@ pub struct TabChunks<'a> { } impl<'a> TabChunks<'a> { - pub(crate) fn seek(&mut self, range: Range) { + pub(crate) fn seek(&mut self, range: Range) { let (input_start, expanded_char_column, to_next_stop) = self.snapshot.to_fold_point(range.start, Bias::Left); let input_column = input_start.column(); @@ -591,37 +584,6 @@ impl<'a> Iterator for TabChunks<'a> { self.input_column = 0; self.output_position += Point::new(1, 0); } - _ if is_invisible(c) => { - if ix > 0 { - let (prefix, suffix) = self.chunk.text.split_at(ix); - self.chunk.text = suffix; - return Some(Chunk { - text: prefix, - is_invisible: false, - ..self.chunk.clone() - }); - } - let c_len = c.len_utf8(); - let replacement = replacement(c).unwrap_or(&self.chunk.text[..c_len]); - if self.chunk.text.len() >= c_len { - self.chunk.text = &self.chunk.text[c_len..]; - } else { - self.chunk.text = ""; - } - let len = replacement.chars().count() as u32; - let next_output_position = cmp::min( - self.output_position + Point::new(0, len), - self.max_output_position, - ); - self.column += len; - self.input_column += 1; - self.output_position = next_output_position; - return Some(Chunk { - text: replacement, - is_invisible: true, - ..self.chunk.clone() - }); - } _ => { self.column += 1; if !self.inside_leading_tab { @@ -651,11 +613,11 @@ mod tests { let buffer_snapshot = buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (_, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (_, char_snapshot) = CharMap::new(fold_snapshot, 4.try_into().unwrap()); + let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap()); - assert_eq!(char_snapshot.expand_tabs("\t".chars(), 0), 0); - assert_eq!(char_snapshot.expand_tabs("\t".chars(), 1), 4); - assert_eq!(char_snapshot.expand_tabs("\ta".chars(), 2), 5); + assert_eq!(tab_snapshot.expand_tabs("\t".chars(), 0), 0); + assert_eq!(tab_snapshot.expand_tabs("\t".chars(), 1), 4); + assert_eq!(tab_snapshot.expand_tabs("\ta".chars(), 2), 5); } #[gpui::test] @@ -668,16 +630,16 @@ mod tests { let buffer_snapshot = buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (_, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (_, mut char_snapshot) = CharMap::new(fold_snapshot, 4.try_into().unwrap()); + let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap()); - char_snapshot.max_expansion_column = max_expansion_column; - assert_eq!(char_snapshot.text(), output); + tab_snapshot.max_expansion_column = max_expansion_column; + assert_eq!(tab_snapshot.text(), output); for (ix, c) in input.char_indices() { assert_eq!( - char_snapshot + tab_snapshot .chunks( - CharPoint::new(0, ix as u32)..char_snapshot.max_point(), + TabPoint::new(0, ix as u32)..tab_snapshot.max_point(), false, Highlights::default(), ) @@ -691,13 +653,13 @@ mod tests { let input_point = Point::new(0, ix as u32); let output_point = Point::new(0, output.find(c).unwrap() as u32); assert_eq!( - char_snapshot.to_char_point(FoldPoint(input_point)), - CharPoint(output_point), - "to_char_point({input_point:?})" + tab_snapshot.to_tab_point(FoldPoint(input_point)), + TabPoint(output_point), + "to_tab_point({input_point:?})" ); assert_eq!( - char_snapshot - .to_fold_point(CharPoint(output_point), Bias::Left) + tab_snapshot + .to_fold_point(TabPoint(output_point), Bias::Left) .0, FoldPoint(input_point), "to_fold_point({output_point:?})" @@ -715,10 +677,10 @@ mod tests { let buffer_snapshot = buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (_, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (_, mut char_snapshot) = CharMap::new(fold_snapshot, 4.try_into().unwrap()); + let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap()); - char_snapshot.max_expansion_column = max_expansion_column; - assert_eq!(char_snapshot.text(), input); + tab_snapshot.max_expansion_column = max_expansion_column; + assert_eq!(tab_snapshot.text(), input); } #[gpui::test] @@ -729,10 +691,10 @@ mod tests { let buffer_snapshot = buffer.read(cx).snapshot(cx); let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (_, fold_snapshot) = FoldMap::new(inlay_snapshot); - let (_, char_snapshot) = CharMap::new(fold_snapshot, 4.try_into().unwrap()); + let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap()); assert_eq!( - chunks(&char_snapshot, CharPoint::zero()), + chunks(&tab_snapshot, TabPoint::zero()), vec![ (" ".to_string(), true), (" ".to_string(), false), @@ -741,7 +703,7 @@ mod tests { ] ); assert_eq!( - chunks(&char_snapshot, CharPoint::new(0, 2)), + chunks(&tab_snapshot, TabPoint::new(0, 2)), vec![ (" ".to_string(), true), (" ".to_string(), false), @@ -750,7 +712,7 @@ mod tests { ] ); - fn chunks(snapshot: &CharSnapshot, start: CharPoint) -> Vec<(String, bool)> { + fn chunks(snapshot: &TabSnapshot, start: TabPoint) -> Vec<(String, bool)> { let mut chunks = Vec::new(); let mut was_tab = false; let mut text = String::new(); @@ -796,12 +758,12 @@ mod tests { let (inlay_snapshot, _) = inlay_map.randomly_mutate(&mut 0, &mut rng); log::info!("InlayMap text: {:?}", inlay_snapshot.text()); - let (mut char_map, _) = CharMap::new(fold_snapshot.clone(), tab_size); - let tabs_snapshot = char_map.set_max_expansion_column(32); + let (mut tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size); + let tabs_snapshot = tab_map.set_max_expansion_column(32); let text = text::Rope::from(tabs_snapshot.text().as_str()); log::info!( - "CharMap text (tab size: {}): {:?}", + "TabMap text (tab size: {}): {:?}", tab_size, tabs_snapshot.text(), ); @@ -809,11 +771,11 @@ mod tests { for _ in 0..5 { let end_row = rng.gen_range(0..=text.max_point().row); let end_column = rng.gen_range(0..=text.line_len(end_row)); - let mut end = CharPoint(text.clip_point(Point::new(end_row, end_column), Bias::Right)); + let mut end = TabPoint(text.clip_point(Point::new(end_row, end_column), Bias::Right)); let start_row = rng.gen_range(0..=text.max_point().row); let start_column = rng.gen_range(0..=text.line_len(start_row)); let mut start = - CharPoint(text.clip_point(Point::new(start_row, start_column), Bias::Left)); + TabPoint(text.clip_point(Point::new(start_row, start_column), Bias::Left)); if start > end { mem::swap(&mut start, &mut end); } diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 15f6595f19..ceb91ce0ab 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -1,6 +1,6 @@ use super::{ - char_map::{self, CharPoint, CharSnapshot, TabEdit}, fold_map::FoldBufferRows, + tab_map::{self, TabEdit, TabPoint, TabSnapshot}, Highlights, }; use gpui::{AppContext, Context, Font, LineWrapper, Model, ModelContext, Pixels, Task}; @@ -12,7 +12,7 @@ use std::{cmp, collections::VecDeque, mem, ops::Range, time::Duration}; use sum_tree::{Bias, Cursor, SumTree}; use text::Patch; -pub use super::char_map::TextSummary; +pub use super::tab_map::TextSummary; pub type WrapEdit = text::Edit; /// Handles soft wrapping of text. @@ -20,7 +20,7 @@ pub type WrapEdit = text::Edit; /// See the [`display_map` module documentation](crate::display_map) for more information. pub struct WrapMap { snapshot: WrapSnapshot, - pending_edits: VecDeque<(CharSnapshot, Vec)>, + pending_edits: VecDeque<(TabSnapshot, Vec)>, interpolated_edits: Patch, edits_since_sync: Patch, wrap_width: Option, @@ -30,7 +30,7 @@ pub struct WrapMap { #[derive(Clone)] pub struct WrapSnapshot { - char_snapshot: CharSnapshot, + tab_snapshot: TabSnapshot, transforms: SumTree, interpolated: bool, } @@ -51,11 +51,11 @@ struct TransformSummary { pub struct WrapPoint(pub Point); pub struct WrapChunks<'a> { - input_chunks: char_map::TabChunks<'a>, + input_chunks: tab_map::TabChunks<'a>, input_chunk: Chunk<'a>, output_position: WrapPoint, max_output_row: u32, - transforms: Cursor<'a, Transform, (WrapPoint, CharPoint)>, + transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>, snapshot: &'a WrapSnapshot, } @@ -66,7 +66,7 @@ pub struct WrapBufferRows<'a> { output_row: u32, soft_wrapped: bool, max_output_row: u32, - transforms: Cursor<'a, Transform, (WrapPoint, CharPoint)>, + transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>, } impl<'a> WrapBufferRows<'a> { @@ -86,7 +86,7 @@ impl<'a> WrapBufferRows<'a> { impl WrapMap { pub fn new( - char_snapshot: CharSnapshot, + tab_snapshot: TabSnapshot, font: Font, font_size: Pixels, wrap_width: Option, @@ -99,7 +99,7 @@ impl WrapMap { pending_edits: Default::default(), interpolated_edits: Default::default(), edits_since_sync: Default::default(), - snapshot: WrapSnapshot::new(char_snapshot), + snapshot: WrapSnapshot::new(tab_snapshot), background_task: None, }; this.set_wrap_width(wrap_width, cx); @@ -117,17 +117,17 @@ impl WrapMap { pub fn sync( &mut self, - char_snapshot: CharSnapshot, + tab_snapshot: TabSnapshot, edits: Vec, cx: &mut ModelContext, ) -> (WrapSnapshot, Patch) { if self.wrap_width.is_some() { - self.pending_edits.push_back((char_snapshot, edits)); + self.pending_edits.push_back((tab_snapshot, edits)); self.flush_edits(cx); } else { self.edits_since_sync = self .edits_since_sync - .compose(self.snapshot.interpolate(char_snapshot, &edits)); + .compose(self.snapshot.interpolate(tab_snapshot, &edits)); self.snapshot.interpolated = false; } @@ -177,11 +177,11 @@ impl WrapMap { let (font, font_size) = self.font_with_size.clone(); let task = cx.background_executor().spawn(async move { let mut line_wrapper = text_system.line_wrapper(font, font_size); - let char_snapshot = new_snapshot.char_snapshot.clone(); - let range = CharPoint::zero()..char_snapshot.max_point(); + let tab_snapshot = new_snapshot.tab_snapshot.clone(); + let range = TabPoint::zero()..tab_snapshot.max_point(); let edits = new_snapshot .update( - char_snapshot, + tab_snapshot, &[TabEdit { old: range.clone(), new: range.clone(), @@ -221,7 +221,7 @@ impl WrapMap { } else { let old_rows = self.snapshot.transforms.summary().output.lines.row + 1; self.snapshot.transforms = SumTree::default(); - let summary = self.snapshot.char_snapshot.text_summary(); + let summary = self.snapshot.tab_snapshot.text_summary(); if !summary.lines.is_zero() { self.snapshot .transforms @@ -239,8 +239,8 @@ impl WrapMap { fn flush_edits(&mut self, cx: &mut ModelContext) { if !self.snapshot.interpolated { let mut to_remove_len = 0; - for (char_snapshot, _) in &self.pending_edits { - if char_snapshot.version <= self.snapshot.char_snapshot.version { + for (tab_snapshot, _) in &self.pending_edits { + if tab_snapshot.version <= self.snapshot.tab_snapshot.version { to_remove_len += 1; } else { break; @@ -262,9 +262,9 @@ impl WrapMap { let update_task = cx.background_executor().spawn(async move { let mut edits = Patch::default(); let mut line_wrapper = text_system.line_wrapper(font, font_size); - for (char_snapshot, tab_edits) in pending_edits { + for (tab_snapshot, tab_edits) in pending_edits { let wrap_edits = snapshot - .update(char_snapshot, &tab_edits, wrap_width, &mut line_wrapper) + .update(tab_snapshot, &tab_edits, wrap_width, &mut line_wrapper) .await; edits = edits.compose(&wrap_edits); } @@ -301,11 +301,11 @@ impl WrapMap { let was_interpolated = self.snapshot.interpolated; let mut to_remove_len = 0; - for (char_snapshot, edits) in &self.pending_edits { - if char_snapshot.version <= self.snapshot.char_snapshot.version { + for (tab_snapshot, edits) in &self.pending_edits { + if tab_snapshot.version <= self.snapshot.tab_snapshot.version { to_remove_len += 1; } else { - let interpolated_edits = self.snapshot.interpolate(char_snapshot.clone(), edits); + let interpolated_edits = self.snapshot.interpolate(tab_snapshot.clone(), edits); self.edits_since_sync = self.edits_since_sync.compose(&interpolated_edits); self.interpolated_edits = self.interpolated_edits.compose(&interpolated_edits); } @@ -318,49 +318,45 @@ impl WrapMap { } impl WrapSnapshot { - fn new(char_snapshot: CharSnapshot) -> Self { + fn new(tab_snapshot: TabSnapshot) -> Self { let mut transforms = SumTree::default(); - let extent = char_snapshot.text_summary(); + let extent = tab_snapshot.text_summary(); if !extent.lines.is_zero() { transforms.push(Transform::isomorphic(extent), &()); } Self { transforms, - char_snapshot, + tab_snapshot, interpolated: true, } } pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot { - self.char_snapshot.buffer_snapshot() + self.tab_snapshot.buffer_snapshot() } - fn interpolate( - &mut self, - new_char_snapshot: CharSnapshot, - tab_edits: &[TabEdit], - ) -> Patch { + fn interpolate(&mut self, new_tab_snapshot: TabSnapshot, tab_edits: &[TabEdit]) -> Patch { let mut new_transforms; if tab_edits.is_empty() { new_transforms = self.transforms.clone(); } else { - let mut old_cursor = self.transforms.cursor::(&()); + let mut old_cursor = self.transforms.cursor::(&()); let mut tab_edits_iter = tab_edits.iter().peekable(); new_transforms = old_cursor.slice(&tab_edits_iter.peek().unwrap().old.start, Bias::Right, &()); while let Some(edit) = tab_edits_iter.next() { - if edit.new.start > CharPoint::from(new_transforms.summary().input.lines) { - let summary = new_char_snapshot.text_summary_for_range( - CharPoint::from(new_transforms.summary().input.lines)..edit.new.start, + if edit.new.start > TabPoint::from(new_transforms.summary().input.lines) { + let summary = new_tab_snapshot.text_summary_for_range( + TabPoint::from(new_transforms.summary().input.lines)..edit.new.start, ); new_transforms.push_or_extend(Transform::isomorphic(summary)); } if !edit.new.is_empty() { new_transforms.push_or_extend(Transform::isomorphic( - new_char_snapshot.text_summary_for_range(edit.new.clone()), + new_tab_snapshot.text_summary_for_range(edit.new.clone()), )); } @@ -369,7 +365,7 @@ impl WrapSnapshot { if next_edit.old.start > old_cursor.end(&()) { if old_cursor.end(&()) > edit.old.end { let summary = self - .char_snapshot + .tab_snapshot .text_summary_for_range(edit.old.end..old_cursor.end(&())); new_transforms.push_or_extend(Transform::isomorphic(summary)); } @@ -383,7 +379,7 @@ impl WrapSnapshot { } else { if old_cursor.end(&()) > edit.old.end { let summary = self - .char_snapshot + .tab_snapshot .text_summary_for_range(edit.old.end..old_cursor.end(&())); new_transforms.push_or_extend(Transform::isomorphic(summary)); } @@ -396,7 +392,7 @@ impl WrapSnapshot { let old_snapshot = mem::replace( self, WrapSnapshot { - char_snapshot: new_char_snapshot, + tab_snapshot: new_tab_snapshot, transforms: new_transforms, interpolated: true, }, @@ -407,7 +403,7 @@ impl WrapSnapshot { async fn update( &mut self, - new_char_snapshot: CharSnapshot, + new_tab_snapshot: TabSnapshot, tab_edits: &[TabEdit], wrap_width: Pixels, line_wrapper: &mut LineWrapper, @@ -444,27 +440,27 @@ impl WrapSnapshot { new_transforms = self.transforms.clone(); } else { let mut row_edits = row_edits.into_iter().peekable(); - let mut old_cursor = self.transforms.cursor::(&()); + let mut old_cursor = self.transforms.cursor::(&()); new_transforms = old_cursor.slice( - &CharPoint::new(row_edits.peek().unwrap().old_rows.start, 0), + &TabPoint::new(row_edits.peek().unwrap().old_rows.start, 0), Bias::Right, &(), ); while let Some(edit) = row_edits.next() { if edit.new_rows.start > new_transforms.summary().input.lines.row { - let summary = new_char_snapshot.text_summary_for_range( - CharPoint(new_transforms.summary().input.lines) - ..CharPoint::new(edit.new_rows.start, 0), + let summary = new_tab_snapshot.text_summary_for_range( + TabPoint(new_transforms.summary().input.lines) + ..TabPoint::new(edit.new_rows.start, 0), ); new_transforms.push_or_extend(Transform::isomorphic(summary)); } let mut line = String::new(); let mut remaining = None; - let mut chunks = new_char_snapshot.chunks( - CharPoint::new(edit.new_rows.start, 0)..new_char_snapshot.max_point(), + let mut chunks = new_tab_snapshot.chunks( + TabPoint::new(edit.new_rows.start, 0)..new_tab_snapshot.max_point(), false, Highlights::default(), ); @@ -511,19 +507,19 @@ impl WrapSnapshot { } new_transforms.extend(edit_transforms, &()); - old_cursor.seek_forward(&CharPoint::new(edit.old_rows.end, 0), Bias::Right, &()); + old_cursor.seek_forward(&TabPoint::new(edit.old_rows.end, 0), Bias::Right, &()); if let Some(next_edit) = row_edits.peek() { if next_edit.old_rows.start > old_cursor.end(&()).row() { - if old_cursor.end(&()) > CharPoint::new(edit.old_rows.end, 0) { - let summary = self.char_snapshot.text_summary_for_range( - CharPoint::new(edit.old_rows.end, 0)..old_cursor.end(&()), + if old_cursor.end(&()) > TabPoint::new(edit.old_rows.end, 0) { + let summary = self.tab_snapshot.text_summary_for_range( + TabPoint::new(edit.old_rows.end, 0)..old_cursor.end(&()), ); new_transforms.push_or_extend(Transform::isomorphic(summary)); } old_cursor.next(&()); new_transforms.append( old_cursor.slice( - &CharPoint::new(next_edit.old_rows.start, 0), + &TabPoint::new(next_edit.old_rows.start, 0), Bias::Right, &(), ), @@ -531,9 +527,9 @@ impl WrapSnapshot { ); } } else { - if old_cursor.end(&()) > CharPoint::new(edit.old_rows.end, 0) { - let summary = self.char_snapshot.text_summary_for_range( - CharPoint::new(edit.old_rows.end, 0)..old_cursor.end(&()), + if old_cursor.end(&()) > TabPoint::new(edit.old_rows.end, 0) { + let summary = self.tab_snapshot.text_summary_for_range( + TabPoint::new(edit.old_rows.end, 0)..old_cursor.end(&()), ); new_transforms.push_or_extend(Transform::isomorphic(summary)); } @@ -546,7 +542,7 @@ impl WrapSnapshot { let old_snapshot = mem::replace( self, WrapSnapshot { - char_snapshot: new_char_snapshot, + tab_snapshot: new_tab_snapshot, transforms: new_transforms, interpolated: false, }, @@ -599,17 +595,17 @@ impl WrapSnapshot { ) -> WrapChunks<'a> { let output_start = WrapPoint::new(rows.start, 0); let output_end = WrapPoint::new(rows.end, 0); - let mut transforms = self.transforms.cursor::<(WrapPoint, CharPoint)>(&()); + let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>(&()); transforms.seek(&output_start, Bias::Right, &()); - let mut input_start = CharPoint(transforms.start().1 .0); + let mut input_start = TabPoint(transforms.start().1 .0); if transforms.item().map_or(false, |t| t.is_isomorphic()) { input_start.0 += output_start.0 - transforms.start().0 .0; } let input_end = self - .to_char_point(output_end) - .min(self.char_snapshot.max_point()); + .to_tab_point(output_end) + .min(self.tab_snapshot.max_point()); WrapChunks { - input_chunks: self.char_snapshot.chunks( + input_chunks: self.tab_snapshot.chunks( input_start..input_end, language_aware, highlights, @@ -627,7 +623,7 @@ impl WrapSnapshot { } pub fn line_len(&self, row: u32) -> u32 { - let mut cursor = self.transforms.cursor::<(WrapPoint, CharPoint)>(&()); + let mut cursor = self.transforms.cursor::<(WrapPoint, TabPoint)>(&()); cursor.seek(&WrapPoint::new(row + 1, 0), Bias::Left, &()); if cursor .item() @@ -635,7 +631,7 @@ impl WrapSnapshot { { let overshoot = row - cursor.start().0.row(); let tab_row = cursor.start().1.row() + overshoot; - let tab_line_len = self.char_snapshot.line_len(tab_row); + let tab_line_len = self.tab_snapshot.line_len(tab_row); if overshoot == 0 { cursor.start().0.column() + (tab_line_len - cursor.start().1.column()) } else { @@ -652,17 +648,15 @@ impl WrapSnapshot { let start = WrapPoint::new(rows.start, 0); let end = WrapPoint::new(rows.end, 0); - let mut cursor = self.transforms.cursor::<(WrapPoint, CharPoint)>(&()); + let mut cursor = self.transforms.cursor::<(WrapPoint, TabPoint)>(&()); cursor.seek(&start, Bias::Right, &()); if let Some(transform) = cursor.item() { let start_in_transform = start.0 - cursor.start().0 .0; let end_in_transform = cmp::min(end, cursor.end(&()).0).0 - cursor.start().0 .0; if transform.is_isomorphic() { - let char_start = CharPoint(cursor.start().1 .0 + start_in_transform); - let char_end = CharPoint(cursor.start().1 .0 + end_in_transform); - summary += &self - .char_snapshot - .text_summary_for_range(char_start..char_end); + let tab_start = TabPoint(cursor.start().1 .0 + start_in_transform); + let tab_end = TabPoint(cursor.start().1 .0 + end_in_transform); + summary += &self.tab_snapshot.text_summary_for_range(tab_start..tab_end); } else { debug_assert_eq!(start_in_transform.row, end_in_transform.row); let indent_len = end_in_transform.column - start_in_transform.column; @@ -687,9 +681,9 @@ impl WrapSnapshot { let end_in_transform = end.0 - cursor.start().0 .0; if transform.is_isomorphic() { let char_start = cursor.start().1; - let char_end = CharPoint(char_start.0 + end_in_transform); + let char_end = TabPoint(char_start.0 + end_in_transform); summary += &self - .char_snapshot + .tab_snapshot .text_summary_for_range(char_start..char_end); } else { debug_assert_eq!(end_in_transform, Point::new(1, 0)); @@ -724,14 +718,14 @@ impl WrapSnapshot { } pub fn buffer_rows(&self, start_row: u32) -> WrapBufferRows { - let mut transforms = self.transforms.cursor::<(WrapPoint, CharPoint)>(&()); + let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>(&()); transforms.seek(&WrapPoint::new(start_row, 0), Bias::Left, &()); let mut input_row = transforms.start().1.row(); if transforms.item().map_or(false, |t| t.is_isomorphic()) { input_row += start_row - transforms.start().0.row(); } let soft_wrapped = transforms.item().map_or(false, |t| !t.is_isomorphic()); - let mut input_buffer_rows = self.char_snapshot.buffer_rows(input_row); + let mut input_buffer_rows = self.tab_snapshot.buffer_rows(input_row); let input_buffer_row = input_buffer_rows.next().unwrap(); WrapBufferRows { transforms, @@ -743,26 +737,26 @@ impl WrapSnapshot { } } - pub fn to_char_point(&self, point: WrapPoint) -> CharPoint { - let mut cursor = self.transforms.cursor::<(WrapPoint, CharPoint)>(&()); + pub fn to_tab_point(&self, point: WrapPoint) -> TabPoint { + let mut cursor = self.transforms.cursor::<(WrapPoint, TabPoint)>(&()); cursor.seek(&point, Bias::Right, &()); - let mut char_point = cursor.start().1 .0; + let mut tab_point = cursor.start().1 .0; if cursor.item().map_or(false, |t| t.is_isomorphic()) { - char_point += point.0 - cursor.start().0 .0; + tab_point += point.0 - cursor.start().0 .0; } - CharPoint(char_point) + TabPoint(tab_point) } pub fn to_point(&self, point: WrapPoint, bias: Bias) -> Point { - self.char_snapshot.to_point(self.to_char_point(point), bias) + self.tab_snapshot.to_point(self.to_tab_point(point), bias) } pub fn make_wrap_point(&self, point: Point, bias: Bias) -> WrapPoint { - self.char_point_to_wrap_point(self.char_snapshot.make_char_point(point, bias)) + self.tab_point_to_wrap_point(self.tab_snapshot.make_tab_point(point, bias)) } - pub fn char_point_to_wrap_point(&self, point: CharPoint) -> WrapPoint { - let mut cursor = self.transforms.cursor::<(CharPoint, WrapPoint)>(&()); + pub fn tab_point_to_wrap_point(&self, point: TabPoint) -> WrapPoint { + let mut cursor = self.transforms.cursor::<(TabPoint, WrapPoint)>(&()); cursor.seek(&point, Bias::Right, &()); WrapPoint(cursor.start().1 .0 + (point.0 - cursor.start().0 .0)) } @@ -777,10 +771,7 @@ impl WrapSnapshot { } } - self.char_point_to_wrap_point( - self.char_snapshot - .clip_point(self.to_char_point(point), bias), - ) + self.tab_point_to_wrap_point(self.tab_snapshot.clip_point(self.to_tab_point(point), bias)) } pub fn prev_row_boundary(&self, mut point: WrapPoint) -> u32 { @@ -790,7 +781,7 @@ impl WrapSnapshot { *point.column_mut() = 0; - let mut cursor = self.transforms.cursor::<(WrapPoint, CharPoint)>(&()); + let mut cursor = self.transforms.cursor::<(WrapPoint, TabPoint)>(&()); cursor.seek(&point, Bias::Right, &()); if cursor.item().is_none() { cursor.prev(&()); @@ -810,7 +801,7 @@ impl WrapSnapshot { pub fn next_row_boundary(&self, mut point: WrapPoint) -> Option { point.0 += Point::new(1, 0); - let mut cursor = self.transforms.cursor::<(WrapPoint, CharPoint)>(&()); + let mut cursor = self.transforms.cursor::<(WrapPoint, TabPoint)>(&()); cursor.seek(&point, Bias::Right, &()); while let Some(transform) = cursor.item() { if transform.is_isomorphic() && cursor.start().1.column() == 0 { @@ -842,8 +833,8 @@ impl WrapSnapshot { #[cfg(test)] { assert_eq!( - CharPoint::from(self.transforms.summary().input.lines), - self.char_snapshot.max_point() + TabPoint::from(self.transforms.summary().input.lines), + self.tab_snapshot.max_point() ); { @@ -856,18 +847,18 @@ impl WrapSnapshot { } let text = language::Rope::from(self.text().as_str()); - let mut input_buffer_rows = self.char_snapshot.buffer_rows(0); + let mut input_buffer_rows = self.tab_snapshot.buffer_rows(0); let mut expected_buffer_rows = Vec::new(); let mut prev_tab_row = 0; for display_row in 0..=self.max_point().row() { - let char_point = self.to_char_point(WrapPoint::new(display_row, 0)); - if char_point.row() == prev_tab_row && display_row != 0 { + let tab_point = self.to_tab_point(WrapPoint::new(display_row, 0)); + if tab_point.row() == prev_tab_row && display_row != 0 { expected_buffer_rows.push(None); } else { expected_buffer_rows.push(input_buffer_rows.next().unwrap()); } - prev_tab_row = char_point.row(); + prev_tab_row = tab_point.row(); assert_eq!(self.line_len(display_row), text.line_len(display_row)); } @@ -889,14 +880,14 @@ impl<'a> WrapChunks<'a> { let output_start = WrapPoint::new(rows.start, 0); let output_end = WrapPoint::new(rows.end, 0); self.transforms.seek(&output_start, Bias::Right, &()); - let mut input_start = CharPoint(self.transforms.start().1 .0); + let mut input_start = TabPoint(self.transforms.start().1 .0); if self.transforms.item().map_or(false, |t| t.is_isomorphic()) { input_start.0 += output_start.0 - self.transforms.start().0 .0; } let input_end = self .snapshot - .to_char_point(output_end) - .min(self.snapshot.char_snapshot.max_point()); + .to_tab_point(output_end) + .min(self.snapshot.tab_snapshot.max_point()); self.input_chunks.seek(input_start..input_end); self.input_chunk = Chunk::default(); self.output_position = output_start; @@ -951,11 +942,13 @@ impl<'a> Iterator for WrapChunks<'a> { } else { *self.output_position.column_mut() += char_len as u32; } + if self.output_position >= transform_end { self.transforms.next(&()); break; } } + let (prefix, suffix) = self.input_chunk.text.split_at(input_len); self.input_chunk.text = suffix; Some(Chunk { @@ -1110,7 +1103,7 @@ impl sum_tree::Summary for TransformSummary { } } -impl<'a> sum_tree::Dimension<'a, TransformSummary> for CharPoint { +impl<'a> sum_tree::Dimension<'a, TransformSummary> for TabPoint { fn zero(_cx: &()) -> Self { Default::default() } @@ -1120,7 +1113,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for CharPoint { } } -impl<'a> sum_tree::SeekTarget<'a, TransformSummary, TransformSummary> for CharPoint { +impl<'a> sum_tree::SeekTarget<'a, TransformSummary, TransformSummary> for TabPoint { fn cmp(&self, cursor_location: &TransformSummary, _: &()) -> std::cmp::Ordering { Ord::cmp(&self.0, &cursor_location.input.lines) } @@ -1168,7 +1161,7 @@ fn consolidate_wrap_edits(edits: Vec) -> Vec { mod tests { use super::*; use crate::{ - display_map::{char_map::CharMap, fold_map::FoldMap, inlay_map::InlayMap}, + display_map::{fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap}, MultiBuffer, }; use gpui::{font, px, test::observe}; @@ -1220,9 +1213,9 @@ mod tests { log::info!("InlayMap text: {:?}", inlay_snapshot.text()); let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot.clone()); log::info!("FoldMap text: {:?}", fold_snapshot.text()); - let (mut char_map, _) = CharMap::new(fold_snapshot.clone(), tab_size); - let tabs_snapshot = char_map.set_max_expansion_column(32); - log::info!("CharMap text: {:?}", tabs_snapshot.text()); + let (mut tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size); + let tabs_snapshot = tab_map.set_max_expansion_column(32); + log::info!("TabMap text: {:?}", tabs_snapshot.text()); let mut line_wrapper = text_system.line_wrapper(font.clone(), font_size); let unwrapped_text = tabs_snapshot.text(); @@ -1268,7 +1261,7 @@ mod tests { 20..=39 => { for (fold_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) { let (tabs_snapshot, tab_edits) = - char_map.sync(fold_snapshot, fold_edits, tab_size); + tab_map.sync(fold_snapshot, fold_edits, tab_size); let (mut snapshot, wrap_edits) = wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx)); snapshot.check_invariants(); @@ -1281,7 +1274,7 @@ mod tests { inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng); let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits); let (tabs_snapshot, tab_edits) = - char_map.sync(fold_snapshot, fold_edits, tab_size); + tab_map.sync(fold_snapshot, fold_edits, tab_size); let (mut snapshot, wrap_edits) = wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx)); snapshot.check_invariants(); @@ -1305,8 +1298,8 @@ mod tests { log::info!("InlayMap text: {:?}", inlay_snapshot.text()); let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits); log::info!("FoldMap text: {:?}", fold_snapshot.text()); - let (tabs_snapshot, tab_edits) = char_map.sync(fold_snapshot, fold_edits, tab_size); - log::info!("CharMap text: {:?}", tabs_snapshot.text()); + let (tabs_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size); + log::info!("TabMap text: {:?}", tabs_snapshot.text()); let unwrapped_text = tabs_snapshot.text(); let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper); @@ -1352,7 +1345,7 @@ mod tests { if tab_size.get() == 1 || !wrapped_snapshot - .char_snapshot + .tab_snapshot .fold_snapshot .text() .contains('\t') diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 753b7f246d..7402badc1e 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -68,7 +68,6 @@ use sum_tree::Bias; use theme::{ActiveTheme, Appearance, PlayerColor}; use ui::prelude::*; use ui::{h_flex, ButtonLike, ButtonStyle, ContextMenu, Tooltip}; -use unicode_segmentation::UnicodeSegmentation; use util::RangeExt; use util::ResultExt; use workspace::{item::Item, Workspace}; @@ -1026,21 +1025,23 @@ impl EditorElement { } let block_text = if let CursorShape::Block = selection.cursor_shape { snapshot - .grapheme_at(cursor_position) + .display_chars_at(cursor_position) + .next() .or_else(|| { if cursor_column == 0 { - snapshot.placeholder_text().and_then(|s| { - s.graphemes(true).next().map(|s| s.to_owned()) - }) + snapshot + .placeholder_text() + .and_then(|s| s.chars().next()) + .map(|c| (c, cursor_position)) } else { None } }) - .and_then(|grapheme| { - let text = if grapheme == "\n" { + .and_then(|(character, _)| { + let text = if character == '\n' { SharedString::from(" ") } else { - SharedString::from(grapheme) + SharedString::from(character.to_string()) }; let len = text.len(); diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 688ebf57bb..9200dd7b8c 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -1,7 +1,6 @@ use crate::{ display_map::{InlayOffset, ToDisplayPoint}, hover_links::{InlayHighlight, RangeInEditor}, - is_invisible, scroll::ScrollAmount, Anchor, AnchorRangeExt, DisplayPoint, DisplayRow, Editor, EditorSettings, EditorSnapshot, Hover, RangeToAnchorExt, @@ -12,7 +11,7 @@ use gpui::{ StyleRefinement, Styled, Task, TextStyleRefinement, View, ViewContext, }; use itertools::Itertools; -use language::{Diagnostic, DiagnosticEntry, Language, LanguageRegistry}; +use language::{DiagnosticEntry, Language, LanguageRegistry}; use lsp::DiagnosticSeverity; use markdown::{Markdown, MarkdownStyle}; use multi_buffer::ToOffset; @@ -200,6 +199,7 @@ fn show_hover( if editor.pending_rename.is_some() { return None; } + let snapshot = editor.snapshot(cx); let (buffer, buffer_position) = editor @@ -259,7 +259,7 @@ fn show_hover( } // If there's a diagnostic, assign it on the hover state and notify - let mut local_diagnostic = snapshot + let local_diagnostic = snapshot .buffer_snapshot .diagnostics_in_range::<_, usize>(anchor..anchor, false) // Find the entry with the most specific range @@ -281,42 +281,6 @@ fn show_hover( }) }); - if let Some(invisible) = snapshot - .buffer_snapshot - .chars_at(anchor) - .next() - .filter(|&c| is_invisible(c)) - { - let after = snapshot.buffer_snapshot.anchor_after( - anchor.to_offset(&snapshot.buffer_snapshot) + invisible.len_utf8(), - ); - local_diagnostic = Some(DiagnosticEntry { - diagnostic: Diagnostic { - severity: DiagnosticSeverity::HINT, - message: format!("Unicode character U+{:02X}", invisible as u32), - ..Default::default() - }, - range: anchor..after, - }) - } else if let Some(invisible) = snapshot - .buffer_snapshot - .reversed_chars_at(anchor) - .next() - .filter(|&c| is_invisible(c)) - { - let before = snapshot.buffer_snapshot.anchor_before( - anchor.to_offset(&snapshot.buffer_snapshot) - invisible.len_utf8(), - ); - local_diagnostic = Some(DiagnosticEntry { - diagnostic: Diagnostic { - severity: DiagnosticSeverity::HINT, - message: format!("Unicode character U+{:02X}", invisible as u32), - ..Default::default() - }, - range: before..anchor, - }) - } - let diagnostic_popover = if let Some(local_diagnostic) = local_diagnostic { let text = match local_diagnostic.diagnostic.source { Some(ref source) => { @@ -324,6 +288,7 @@ fn show_hover( } None => local_diagnostic.diagnostic.message.clone(), }; + let mut border_color: Option = None; let mut background_color: Option = None; @@ -379,6 +344,7 @@ fn show_hover( Markdown::new_text(text, markdown_style.clone(), None, cx, None) }) .ok(); + Some(DiagnosticPopover { local_diagnostic, primary_diagnostic, @@ -466,6 +432,7 @@ fn show_hover( cx.notify(); cx.refresh(); })?; + anyhow::Ok(()) } .log_err() diff --git a/crates/gpui/src/text_system/line.rs b/crates/gpui/src/text_system/line.rs index ff5d91f022..240654e57e 100644 --- a/crates/gpui/src/text_system/line.rs +++ b/crates/gpui/src/text_system/line.rs @@ -1,7 +1,6 @@ use crate::{ - black, fill, point, px, size, Bounds, Half, Hsla, LineLayout, Pixels, Point, Result, - SharedString, StrikethroughStyle, UnderlineStyle, WindowContext, WrapBoundary, - WrappedLineLayout, + black, fill, point, px, size, Bounds, Hsla, LineLayout, Pixels, Point, Result, SharedString, + StrikethroughStyle, UnderlineStyle, WindowContext, WrapBoundary, WrappedLineLayout, }; use derive_more::{Deref, DerefMut}; use smallvec::SmallVec; @@ -130,9 +129,8 @@ fn paint_line( let text_system = cx.text_system().clone(); let mut glyph_origin = origin; let mut prev_glyph_position = Point::default(); - let mut max_glyph_size = size(px(0.), px(0.)); for (run_ix, run) in layout.runs.iter().enumerate() { - max_glyph_size = text_system.bounding_box(run.font_id, layout.font_size).size; + let max_glyph_size = text_system.bounding_box(run.font_id, layout.font_size).size; for (glyph_ix, glyph) in run.glyphs.iter().enumerate() { glyph_origin.x += glyph.position.x - prev_glyph_position.x; @@ -141,9 +139,6 @@ fn paint_line( wraps.next(); if let Some((background_origin, background_color)) = current_background.as_mut() { - if glyph_origin.x == background_origin.x { - background_origin.x -= max_glyph_size.width.half() - } cx.paint_quad(fill( Bounds { origin: *background_origin, @@ -155,9 +150,6 @@ fn paint_line( background_origin.y += line_height; } if let Some((underline_origin, underline_style)) = current_underline.as_mut() { - if glyph_origin.x == underline_origin.x { - underline_origin.x -= max_glyph_size.width.half(); - }; cx.paint_underline( *underline_origin, glyph_origin.x - underline_origin.x, @@ -169,9 +161,6 @@ fn paint_line( if let Some((strikethrough_origin, strikethrough_style)) = current_strikethrough.as_mut() { - if glyph_origin.x == strikethrough_origin.x { - strikethrough_origin.x -= max_glyph_size.width.half(); - }; cx.paint_strikethrough( *strikethrough_origin, glyph_origin.x - strikethrough_origin.x, @@ -190,18 +179,7 @@ fn paint_line( let mut finished_underline: Option<(Point, UnderlineStyle)> = None; let mut finished_strikethrough: Option<(Point, StrikethroughStyle)> = None; if glyph.index >= run_end { - let mut style_run = decoration_runs.next(); - - // ignore style runs that apply to a partial glyph - while let Some(run) = style_run { - if glyph.index < run_end + (run.len as usize) { - break; - } - run_end += run.len as usize; - style_run = decoration_runs.next(); - } - - if let Some(style_run) = style_run { + if let Some(style_run) = decoration_runs.next() { if let Some((_, background_color)) = &mut current_background { if style_run.background_color.as_ref() != Some(background_color) { finished_background = current_background.take(); @@ -262,14 +240,10 @@ fn paint_line( } if let Some((background_origin, background_color)) = finished_background { - let mut width = glyph_origin.x - background_origin.x; - if width == px(0.) { - width = px(5.) - }; cx.paint_quad(fill( Bounds { origin: background_origin, - size: size(width, line_height), + size: size(glyph_origin.x - background_origin.x, line_height), }, background_color, )); @@ -325,10 +299,7 @@ fn paint_line( last_line_end_x -= glyph.position.x; } - if let Some((mut background_origin, background_color)) = current_background.take() { - if last_line_end_x == background_origin.x { - background_origin.x -= max_glyph_size.width.half() - }; + if let Some((background_origin, background_color)) = current_background.take() { cx.paint_quad(fill( Bounds { origin: background_origin, @@ -338,10 +309,7 @@ fn paint_line( )); } - if let Some((mut underline_start, underline_style)) = current_underline.take() { - if last_line_end_x == underline_start.x { - underline_start.x -= max_glyph_size.width.half() - }; + if let Some((underline_start, underline_style)) = current_underline.take() { cx.paint_underline( underline_start, last_line_end_x - underline_start.x, @@ -349,10 +317,7 @@ fn paint_line( ); } - if let Some((mut strikethrough_start, strikethrough_style)) = current_strikethrough.take() { - if last_line_end_x == strikethrough_start.x { - strikethrough_start.x -= max_glyph_size.width.half() - }; + if let Some((strikethrough_start, strikethrough_style)) = current_strikethrough.take() { cx.paint_strikethrough( strikethrough_start, last_line_end_x - strikethrough_start.x, diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 06492a0c58..26fb620ac1 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -501,8 +501,6 @@ pub struct Chunk<'a> { pub is_unnecessary: bool, /// Whether this chunk of text was originally a tab character. pub is_tab: bool, - /// Whether this chunk of text is an invisible character. - pub is_invisible: bool, /// An optional recipe for how the chunk should be presented. pub renderer: Option, } @@ -4213,6 +4211,7 @@ impl<'a> Iterator for BufferChunks<'a> { if self.range.start == self.chunks.offset() + chunk.len() { self.chunks.next().unwrap(); } + Some(Chunk { text: slice, syntax_highlight_id: highlight_id,