From df41435d1a85c7263799367817ba5629149e9f60 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 11 May 2024 00:06:51 +0300 Subject: [PATCH] Introduce DisplayRow, MultiBufferRow newtypes and BufferRow type alias (#11656) Part of https://github.com/zed-industries/zed/issues/8081 To avoid confusion and bugs when converting between various row `u32`'s, use different types for each. Further PRs should split `Point` into buffer and multi buffer variants and make the code more readable. Release Notes: - N/A --------- Co-authored-by: Piotr --- Cargo.lock | 3 + crates/assistant/src/assistant_panel.rs | 12 +- crates/assistant/src/codegen.rs | 3 +- crates/collab/Cargo.toml | 1 + crates/collab/src/tests/editor_tests.rs | 64 +- crates/diagnostics/src/diagnostics_tests.rs | 83 +- crates/editor/src/actions.rs | 6 +- crates/editor/src/display_map.rs | 286 ++++--- crates/editor/src/display_map/block_map.rs | 54 +- crates/editor/src/display_map/fold_map.rs | 10 +- crates/editor/src/display_map/inlay_map.rs | 20 +- crates/editor/src/editor.rs | 396 +++++---- crates/editor/src/editor_tests.rs | 776 ++++++++++-------- crates/editor/src/element.rs | 398 +++++---- crates/editor/src/git.rs | 72 +- crates/editor/src/git/blame.rs | 15 +- crates/editor/src/hover_popover.rs | 6 +- crates/editor/src/hunk_diff.rs | 43 +- crates/editor/src/movement.rs | 87 +- crates/editor/src/scroll.rs | 12 +- crates/editor/src/scroll/actions.rs | 5 +- crates/editor/src/scroll/autoscroll.rs | 30 +- crates/editor/src/selections_collection.rs | 5 +- crates/editor/src/test.rs | 41 +- crates/editor/src/test/editor_test_context.rs | 3 +- crates/git/src/diff.rs | 12 - crates/go_to_line/src/go_to_line.rs | 1 + crates/language/src/buffer.rs | 4 +- crates/multi_buffer/Cargo.toml | 1 + crates/multi_buffer/src/multi_buffer.rs | 169 ++-- crates/outline/src/outline.rs | 1 + crates/search/src/buffer_search.rs | 84 +- crates/search/src/project_search.rs | 20 +- crates/vim/Cargo.toml | 1 + crates/vim/src/motion.rs | 53 +- crates/vim/src/normal.rs | 7 +- crates/vim/src/normal/case.rs | 9 +- crates/vim/src/normal/delete.rs | 5 +- crates/vim/src/normal/paste.rs | 5 +- crates/vim/src/normal/scroll.rs | 12 +- crates/vim/src/normal/search.rs | 4 +- crates/vim/src/object.rs | 28 +- crates/vim/src/test.rs | 4 +- crates/vim/src/utils.rs | 9 +- crates/vim/src/visual.rs | 21 +- crates/zed/src/zed.rs | 65 +- 46 files changed, 1726 insertions(+), 1220 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0a6180b31..7b1ce50a8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2325,6 +2325,7 @@ dependencies = [ "log", "lsp", "menu", + "multi_buffer", "nanoid", "node_runtime", "notifications", @@ -6282,6 +6283,7 @@ dependencies = [ "log", "parking_lot", "rand 0.8.5", + "serde", "settings", "smallvec", "sum_tree", @@ -11315,6 +11317,7 @@ dependencies = [ "language", "log", "lsp", + "multi_buffer", "nvim-rs", "parking_lot", "regex", diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 499feae388..039dbf443f 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -18,7 +18,7 @@ use editor::{ }, scroll::{Autoscroll, AutoscrollStrategy}, Anchor, Editor, EditorElement, EditorEvent, EditorStyle, MultiBuffer, MultiBufferSnapshot, - ToOffset as _, ToPoint, + RowExt, ToOffset as _, ToPoint, }; use file_icons::FileIcons; use fs::Fs; @@ -32,6 +32,7 @@ use gpui::{ View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace, WindowContext, }; use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset as _}; +use multi_buffer::MultiBufferRow; use parking_lot::Mutex; use project::Project; use search::{buffer_search::DivRegistrar, BufferSearchBar}; @@ -306,7 +307,7 @@ impl AssistantPanel { if point_selection.end.column == 0 { point_selection.end.row -= 1; } - point_selection.end.column = snapshot.line_len(point_selection.end.row); + point_selection.end.column = snapshot.line_len(MultiBufferRow(point_selection.end.row)); } let codegen_kind = if point_selection.start == point_selection.end { @@ -2168,7 +2169,7 @@ impl ConversationEditor { let snapshot = editor.snapshot(cx); let cursor_point = scroll_position.cursor.to_display_point(&snapshot); let scroll_top = - cursor_point.row() as f32 - scroll_position.offset_before_cursor.y; + cursor_point.row().as_f32() - scroll_position.offset_before_cursor.y; editor.set_scroll_position( point(scroll_position.offset_before_cursor.x, scroll_top), cx, @@ -2236,7 +2237,10 @@ impl ConversationEditor { self.editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); let cursor = editor.selections.newest_anchor().head(); - let cursor_row = cursor.to_display_point(&snapshot.display_snapshot).row() as f32; + let cursor_row = cursor + .to_display_point(&snapshot.display_snapshot) + .row() + .as_f32(); let scroll_position = editor .scroll_manager .anchor() diff --git a/crates/assistant/src/codegen.rs b/crates/assistant/src/codegen.rs index 5a6427467c..6f1b975ac7 100644 --- a/crates/assistant/src/codegen.rs +++ b/crates/assistant/src/codegen.rs @@ -7,6 +7,7 @@ use editor::{Anchor, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint}; use futures::{channel::mpsc, SinkExt, Stream, StreamExt}; use gpui::{EventEmitter, Model, ModelContext, Task}; use language::{Rope, TransactionId}; +use multi_buffer::MultiBufferRow; use std::{cmp, future, ops::Range}; pub enum Event { @@ -100,7 +101,7 @@ impl Codegen { .suggested_indents(selection_start.row..selection_start.row + 1, cx) .into_values() .next() - .unwrap_or_else(|| snapshot.indent_size_for_line(selection_start.row)); + .unwrap_or_else(|| snapshot.indent_size_for_line(MultiBufferRow(selection_start.row))); let response = CompletionProvider::global(cx).complete(prompt); self.generation = cx.spawn(|this, mut cx| { diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index b3aeffb2ef..77e6c11a0f 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -90,6 +90,7 @@ language = { workspace = true, features = ["test-support"] } live_kit_client = { workspace = true, features = ["test-support"] } lsp = { workspace = true, features = ["test-support"] } menu.workspace = true +multi_buffer = { workspace = true, features = ["test-support"] } node_runtime.workspace = true notifications = { workspace = true, features = ["test-support"] } pretty_assertions.workspace = true diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs index c19692789e..fa75b38530 100644 --- a/crates/collab/src/tests/editor_tests.rs +++ b/crates/collab/src/tests/editor_tests.rs @@ -9,6 +9,7 @@ use editor::{ ConfirmCodeAction, ConfirmCompletion, ConfirmRename, ContextMenuFirst, Redo, Rename, RevertSelectedHunks, ToggleCodeActions, Undo, }, + display_map::DisplayRow, test::{ editor_hunks, editor_test_context::{AssertionContextManager, EditorTestContext}, @@ -24,6 +25,7 @@ use language::{ language_settings::{AllLanguageSettings, InlayHintSettings}, FakeLspAdapter, }; +use multi_buffer::MultiBufferRow; use project::{ project_settings::{InlineBlameSettings, ProjectSettings}, SERVER_PROGRESS_DEBOUNCE_TIMEOUT, @@ -2114,14 +2116,30 @@ struct Row10;"#}; assert_eq!( all_hunks, vec![ - ("".to_string(), DiffHunkStatus::Added, 1..3), - ("struct Row2;\n".to_string(), DiffHunkStatus::Removed, 4..4), - ("struct Row5;\n".to_string(), DiffHunkStatus::Modified, 6..7), - ("struct Row8;\n".to_string(), DiffHunkStatus::Removed, 9..9), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(1)..DisplayRow(3) + ), + ( + "struct Row2;\n".to_string(), + DiffHunkStatus::Removed, + DisplayRow(4)..DisplayRow(4) + ), + ( + "struct Row5;\n".to_string(), + DiffHunkStatus::Modified, + DisplayRow(6)..DisplayRow(7) + ), + ( + "struct Row8;\n".to_string(), + DiffHunkStatus::Removed, + DisplayRow(9)..DisplayRow(9) + ), ( "struct Row10;".to_string(), DiffHunkStatus::Modified, - 10..10, + DisplayRow(10)..DisplayRow(10), ), ] ); @@ -2133,23 +2151,35 @@ struct Row10;"#}; let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![1..=2, 8..=8], + vec![DisplayRow(1)..=DisplayRow(2), DisplayRow(8)..=DisplayRow(8)], ); assert_eq!( all_hunks, vec![ - ("".to_string(), DiffHunkStatus::Added, 1..3), - ("struct Row2;\n".to_string(), DiffHunkStatus::Removed, 5..5), - ("struct Row5;\n".to_string(), DiffHunkStatus::Modified, 8..9), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(1)..DisplayRow(3) + ), + ( + "struct Row2;\n".to_string(), + DiffHunkStatus::Removed, + DisplayRow(5)..DisplayRow(5) + ), + ( + "struct Row5;\n".to_string(), + DiffHunkStatus::Modified, + DisplayRow(8)..DisplayRow(9) + ), ( "struct Row8;\n".to_string(), DiffHunkStatus::Removed, - 12..12 + DisplayRow(12)..DisplayRow(12) ), ( "struct Row10;".to_string(), DiffHunkStatus::Modified, - 13..13, + DisplayRow(13)..DisplayRow(13), ), ] ); @@ -2173,7 +2203,7 @@ struct Row10;"#}; vec![( "struct Row10;".to_string(), DiffHunkStatus::Modified, - 10..10, + DisplayRow(10)..DisplayRow(10), )] ); assert_eq!(all_expanded_hunks, Vec::new()); @@ -2184,14 +2214,14 @@ struct Row10;"#}; let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![5..=5] + vec![DisplayRow(5)..=DisplayRow(5)] ); assert_eq!( all_hunks, vec![( "struct Row10;".to_string(), DiffHunkStatus::Modified, - 10..10, + DisplayRow(10)..DisplayRow(10), )] ); assert_eq!(all_expanded_hunks, Vec::new()); @@ -2330,7 +2360,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA let blame = editor_b.blame().expect("editor_b should have blame now"); let entries = blame.update(cx, |blame, cx| { blame - .blame_for_rows((0..4).map(Some), cx) + .blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx) .collect::>() }); @@ -2369,7 +2399,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA let blame = editor_b.blame().expect("editor_b should have blame now"); let entries = blame.update(cx, |blame, cx| { blame - .blame_for_rows((0..4).map(Some), cx) + .blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx) .collect::>() }); @@ -2396,7 +2426,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA let blame = editor_b.blame().expect("editor_b should have blame now"); let entries = blame.update(cx, |blame, cx| { blame - .blame_for_rows((0..4).map(Some), cx) + .blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx) .collect::>() }); diff --git a/crates/diagnostics/src/diagnostics_tests.rs b/crates/diagnostics/src/diagnostics_tests.rs index a1bbd26a2b..f456020e84 100644 --- a/crates/diagnostics/src/diagnostics_tests.rs +++ b/crates/diagnostics/src/diagnostics_tests.rs @@ -1,7 +1,7 @@ use super::*; use collections::HashMap; use editor::{ - display_map::{BlockContext, TransformBlock}, + display_map::{BlockContext, DisplayRow, TransformBlock}, DisplayPoint, GutterDimensions, }; use gpui::{px, AvailableSpace, Stateful, TestAppContext, VisualTestContext}; @@ -158,11 +158,11 @@ async fn test_diagnostics(cx: &mut TestAppContext) { assert_eq!( editor_blocks(&editor, cx), [ - (0, "path header block".into()), - (2, "diagnostic header".into()), - (15, "collapsed context".into()), - (16, "diagnostic header".into()), - (25, "collapsed context".into()), + (DisplayRow(0), "path header block".into()), + (DisplayRow(2), "diagnostic header".into()), + (DisplayRow(15), "collapsed context".into()), + (DisplayRow(16), "diagnostic header".into()), + (DisplayRow(25), "collapsed context".into()), ] ); assert_eq!( @@ -210,7 +210,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) { editor.update(cx, |editor, cx| { assert_eq!( editor.selections.display_ranges(cx), - [DisplayPoint::new(12, 6)..DisplayPoint::new(12, 6)] + [DisplayPoint::new(DisplayRow(12), 6)..DisplayPoint::new(DisplayRow(12), 6)] ); }); @@ -243,13 +243,13 @@ async fn test_diagnostics(cx: &mut TestAppContext) { assert_eq!( editor_blocks(&editor, cx), [ - (0, "path header block".into()), - (2, "diagnostic header".into()), - (7, "path header block".into()), - (9, "diagnostic header".into()), - (22, "collapsed context".into()), - (23, "diagnostic header".into()), - (32, "collapsed context".into()), + (DisplayRow(0), "path header block".into()), + (DisplayRow(2), "diagnostic header".into()), + (DisplayRow(7), "path header block".into()), + (DisplayRow(9), "diagnostic header".into()), + (DisplayRow(22), "collapsed context".into()), + (DisplayRow(23), "diagnostic header".into()), + (DisplayRow(32), "collapsed context".into()), ] ); @@ -309,7 +309,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) { editor.update(cx, |editor, cx| { assert_eq!( editor.selections.display_ranges(cx), - [DisplayPoint::new(19, 6)..DisplayPoint::new(19, 6)] + [DisplayPoint::new(DisplayRow(19), 6)..DisplayPoint::new(DisplayRow(19), 6)] ); }); @@ -355,15 +355,15 @@ async fn test_diagnostics(cx: &mut TestAppContext) { assert_eq!( editor_blocks(&editor, cx), [ - (0, "path header block".into()), - (2, "diagnostic header".into()), - (7, "collapsed context".into()), - (8, "diagnostic header".into()), - (13, "path header block".into()), - (15, "diagnostic header".into()), - (28, "collapsed context".into()), - (29, "diagnostic header".into()), - (38, "collapsed context".into()), + (DisplayRow(0), "path header block".into()), + (DisplayRow(2), "diagnostic header".into()), + (DisplayRow(7), "collapsed context".into()), + (DisplayRow(8), "diagnostic header".into()), + (DisplayRow(13), "path header block".into()), + (DisplayRow(15), "diagnostic header".into()), + (DisplayRow(28), "collapsed context".into()), + (DisplayRow(29), "diagnostic header".into()), + (DisplayRow(38), "collapsed context".into()), ] ); @@ -493,8 +493,8 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) { assert_eq!( editor_blocks(&editor, cx), [ - (0, "path header block".into()), - (2, "diagnostic header".into()), + (DisplayRow(0), "path header block".into()), + (DisplayRow(2), "diagnostic header".into()), ] ); assert_eq!( @@ -539,10 +539,10 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) { assert_eq!( editor_blocks(&editor, cx), [ - (0, "path header block".into()), - (2, "diagnostic header".into()), - (6, "collapsed context".into()), - (7, "diagnostic header".into()), + (DisplayRow(0), "path header block".into()), + (DisplayRow(2), "diagnostic header".into()), + (DisplayRow(6), "collapsed context".into()), + (DisplayRow(7), "diagnostic header".into()), ] ); assert_eq!( @@ -605,10 +605,10 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) { assert_eq!( editor_blocks(&editor, cx), [ - (0, "path header block".into()), - (2, "diagnostic header".into()), - (7, "collapsed context".into()), - (8, "diagnostic header".into()), + (DisplayRow(0), "path header block".into()), + (DisplayRow(2), "diagnostic header".into()), + (DisplayRow(7), "collapsed context".into()), + (DisplayRow(8), "diagnostic header".into()), ] ); assert_eq!( @@ -661,10 +661,10 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) { assert_eq!( editor_blocks(&editor, cx), [ - (0, "path header block".into()), - (2, "diagnostic header".into()), - (7, "collapsed context".into()), - (8, "diagnostic header".into()), + (DisplayRow(0), "path header block".into()), + (DisplayRow(2), "diagnostic header".into()), + (DisplayRow(7), "collapsed context".into()), + (DisplayRow(8), "diagnostic header".into()), ] ); assert_eq!( @@ -958,14 +958,17 @@ fn random_diagnostic( } } -fn editor_blocks(editor: &View, cx: &mut VisualTestContext) -> Vec<(u32, SharedString)> { +fn editor_blocks( + editor: &View, + cx: &mut VisualTestContext, +) -> Vec<(DisplayRow, SharedString)> { let mut blocks = Vec::new(); cx.draw(gpui::Point::default(), AvailableSpace::min_size(), |cx| { editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); blocks.extend( snapshot - .blocks_in_range(0..snapshot.max_point().row()) + .blocks_in_range(DisplayRow(0)..snapshot.max_point().row()) .enumerate() .filter_map(|(ix, (row, block))| { let name: SharedString = match block { diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index a3fe74c3c2..9d36f078c2 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -54,7 +54,7 @@ pub struct SelectToEndOfLine { pub struct ToggleCodeActions { // Display row from which the action was deployed. #[serde(default)] - pub deployed_from_indicator: Option, + pub deployed_from_indicator: Option, } #[derive(PartialEq, Clone, Deserialize, Default)] @@ -77,12 +77,12 @@ pub struct ToggleComments { #[derive(PartialEq, Clone, Deserialize, Default)] pub struct FoldAt { - pub buffer_row: u32, + pub buffer_row: MultiBufferRow, } #[derive(PartialEq, Clone, Deserialize, Default)] pub struct UnfoldAt { - pub buffer_row: u32, + pub buffer_row: MultiBufferRow, } #[derive(PartialEq, Clone, Deserialize, Default)] diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index fdb62bc33c..65794a45cc 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -23,8 +23,8 @@ mod inlay_map; mod tab_map; mod wrap_map; -use crate::EditorStyle; use crate::{hover_links::InlayHighlight, movement::TextLayoutDetails, InlayId}; +use crate::{EditorStyle, RowExt}; pub use block_map::{BlockMap, BlockPoint}; use collections::{HashMap, HashSet}; use fold_map::FoldMap; @@ -34,7 +34,11 @@ use language::{ language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription, }; use lsp::DiagnosticSeverity; -use multi_buffer::{Anchor, AnchorRangeExt, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint}; +use multi_buffer::{ + Anchor, AnchorRangeExt, MultiBuffer, MultiBufferPoint, MultiBufferRow, MultiBufferSnapshot, + ToOffset, ToPoint, +}; +use serde::Deserialize; use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc}; use sum_tree::{Bias, TreeMap}; use tab_map::TabMap; @@ -42,10 +46,11 @@ use tab_map::TabMap; use wrap_map::WrapMap; pub use block_map::{ - BlockBufferRows as DisplayBufferRows, BlockChunks as DisplayChunks, BlockContext, - BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock, + BlockBufferRows, BlockChunks as DisplayChunks, BlockContext, BlockDisposition, BlockId, + BlockProperties, BlockStyle, RenderBlock, TransformBlock, }; +use self::block_map::BlockRow; pub use self::fold_map::{Fold, FoldId, FoldPoint}; pub use self::inlay_map::{InlayOffset, InlayPoint}; pub(crate) use inlay_map::Inlay; @@ -65,6 +70,17 @@ pub trait ToDisplayPoint { type TextHighlights = TreeMap, Arc<(HighlightStyle, Vec>)>>; type InlayHighlights = TreeMap>; +#[derive(Clone)] +pub struct DisplayBufferRows<'a>(BlockBufferRows<'a>); + +impl<'a> Iterator for DisplayBufferRows<'a> { + type Item = Option; + + fn next(&mut self) -> Option { + self.0.next().map(|row| row.map(|r| DisplayRow(r.0))) + } +} + /// Decides how text in a [`MultiBuffer`] should be displayed in a buffer, handling inlay hints, /// folding, hard tabs, soft wrapping, custom blocks (like diagnostics), and highlighting. /// @@ -382,15 +398,15 @@ impl DisplaySnapshot { self.buffer_snapshot.len() == 0 } - pub fn buffer_rows(&self, start_row: u32) -> DisplayBufferRows { - self.block_snapshot.buffer_rows(start_row) + pub fn display_rows(&self, start_row: DisplayRow) -> DisplayBufferRows { + DisplayBufferRows(self.block_snapshot.buffer_rows(BlockRow(start_row.0))) } - pub fn max_buffer_row(&self) -> u32 { + pub fn max_buffer_row(&self) -> MultiBufferRow { self.buffer_snapshot.max_buffer_row() } - pub fn prev_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) { + pub fn prev_line_boundary(&self, mut point: MultiBufferPoint) -> (Point, DisplayPoint) { loop { let mut inlay_point = self.inlay_snapshot.to_inlay_point(point); let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Left); @@ -408,7 +424,7 @@ impl DisplaySnapshot { } } - pub fn next_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) { + pub fn next_line_boundary(&self, mut point: MultiBufferPoint) -> (Point, DisplayPoint) { loop { let mut inlay_point = self.inlay_snapshot.to_inlay_point(point); let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Right); @@ -429,13 +445,14 @@ impl DisplaySnapshot { // used by line_mode selections and tries to match vim behaviour pub fn expand_to_line(&self, range: Range) -> Range { let new_start = if range.start.row == 0 { - Point::new(0, 0) - } else if range.start.row == self.max_buffer_row() - || (range.end.column > 0 && range.end.row == self.max_buffer_row()) + MultiBufferPoint::new(0, 0) + } else if range.start.row == self.max_buffer_row().0 + || (range.end.column > 0 && range.end.row == self.max_buffer_row().0) { - Point::new( + MultiBufferPoint::new( range.start.row - 1, - self.buffer_snapshot.line_len(range.start.row - 1), + self.buffer_snapshot + .line_len(MultiBufferRow(range.start.row - 1)), ) } else { self.prev_line_boundary(range.start).0 @@ -443,9 +460,9 @@ impl DisplaySnapshot { let new_end = if range.end.column == 0 { range.end - } else if range.end.row < self.max_buffer_row() { + } else if range.end.row < self.max_buffer_row().0 { self.buffer_snapshot - .clip_point(Point::new(range.end.row + 1, 0), Bias::Left) + .clip_point(MultiBufferPoint::new(range.end.row + 1, 0), Bias::Left) } else { self.buffer_snapshot.max_point() }; @@ -453,7 +470,7 @@ impl DisplaySnapshot { new_start..new_end } - fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint { + 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 tab_point = self.tab_snapshot.to_tab_point(fold_point); @@ -509,10 +526,10 @@ impl DisplaySnapshot { } /// Returns text chunks starting at the given display row until the end of the file - pub fn text_chunks(&self, display_row: u32) -> impl Iterator { + pub fn text_chunks(&self, display_row: DisplayRow) -> impl Iterator { self.block_snapshot .chunks( - display_row..self.max_point().row() + 1, + display_row.0..self.max_point().row().next_row().0, false, Highlights::default(), ) @@ -520,8 +537,8 @@ impl DisplaySnapshot { } /// Returns text chunks starting at the end of the given display row in reverse until the start of the file - pub fn reverse_text_chunks(&self, display_row: u32) -> impl Iterator { - (0..=display_row).rev().flat_map(|row| { + pub fn reverse_text_chunks(&self, display_row: DisplayRow) -> impl Iterator { + (0..=display_row.0).rev().flat_map(|row| { self.block_snapshot .chunks(row..row + 1, false, Highlights::default()) .map(|h| h.text) @@ -533,12 +550,12 @@ impl DisplaySnapshot { pub fn chunks( &self, - display_rows: Range, + display_rows: Range, language_aware: bool, highlight_styles: HighlightStyles, ) -> DisplayChunks<'_> { self.block_snapshot.chunks( - display_rows, + display_rows.start.0..display_rows.end.0, language_aware, Highlights { text_highlights: Some(&self.text_highlights), @@ -550,7 +567,7 @@ impl DisplaySnapshot { pub fn highlighted_chunks<'a>( &'a self, - display_rows: Range, + display_rows: Range, language_aware: bool, editor_style: &'a EditorStyle, ) -> impl Iterator> { @@ -610,7 +627,7 @@ impl DisplaySnapshot { pub fn layout_row( &self, - display_row: u32, + display_row: DisplayRow, TextLayoutDetails { text_system, editor_style, @@ -623,7 +640,7 @@ impl DisplaySnapshot { let mut runs = Vec::new(); let mut line = String::new(); - let range = display_row..display_row + 1; + let range = display_row..display_row.next_row(); for chunk in self.highlighted_chunks(range, false, &editor_style) { line.push_str(chunk.chunk); @@ -663,7 +680,7 @@ impl DisplaySnapshot { pub fn display_column_for_x( &self, - display_row: u32, + display_row: DisplayRow, x: Pixels, details: &TextLayoutDetails, ) -> u32 { @@ -732,7 +749,7 @@ impl DisplaySnapshot { pub fn clip_at_line_end(&self, point: DisplayPoint) -> DisplayPoint { let mut point = point.0; - if point.column == self.line_len(point.row) { + if point.column == self.line_len(DisplayRow(point.row)) { point.column = point.column.saturating_sub(1); point = self.block_snapshot.clip_point(point, Bias::Left); } @@ -748,36 +765,38 @@ impl DisplaySnapshot { pub fn blocks_in_range( &self, - rows: Range, - ) -> impl Iterator { - self.block_snapshot.blocks_in_range(rows) + rows: Range, + ) -> impl Iterator { + self.block_snapshot + .blocks_in_range(rows.start.0..rows.end.0) + .map(|(row, block)| (DisplayRow(row), block)) } pub fn intersects_fold(&self, offset: T) -> bool { self.fold_snapshot.intersects_fold(offset) } - pub fn is_line_folded(&self, buffer_row: u32) -> bool { + pub fn is_line_folded(&self, buffer_row: MultiBufferRow) -> bool { self.fold_snapshot.is_line_folded(buffer_row) } - pub fn is_block_line(&self, display_row: u32) -> bool { - self.block_snapshot.is_block_line(display_row) + pub fn is_block_line(&self, display_row: DisplayRow) -> bool { + self.block_snapshot.is_block_line(BlockRow(display_row.0)) } - pub fn soft_wrap_indent(&self, display_row: u32) -> Option { + pub fn soft_wrap_indent(&self, display_row: DisplayRow) -> Option { let wrap_row = self .block_snapshot - .to_wrap_point(BlockPoint::new(display_row, 0)) + .to_wrap_point(BlockPoint::new(display_row.0, 0)) .row(); self.wrap_snapshot.soft_wrap_indent(wrap_row) } pub fn text(&self) -> String { - self.text_chunks(0).collect() + self.text_chunks(DisplayRow(0)).collect() } - pub fn line(&self, display_row: u32) -> String { + pub fn line(&self, display_row: DisplayRow) -> String { let mut result = String::new(); for chunk in self.text_chunks(display_row) { if let Some(ix) = chunk.find('\n') { @@ -790,7 +809,7 @@ impl DisplaySnapshot { result } - pub fn line_indent_for_buffer_row(&self, buffer_row: u32) -> (u32, bool) { + pub fn line_indent_for_buffer_row(&self, buffer_row: MultiBufferRow) -> (u32, bool) { let (buffer, range) = self .buffer_snapshot .buffer_line_for_row(buffer_row) @@ -812,15 +831,15 @@ impl DisplaySnapshot { (indent_size, is_blank) } - pub fn line_len(&self, row: u32) -> u32 { - self.block_snapshot.line_len(row) + pub fn line_len(&self, row: DisplayRow) -> u32 { + self.block_snapshot.line_len(BlockRow(row.0)) } - pub fn longest_row(&self) -> u32 { - self.block_snapshot.longest_row() + pub fn longest_row(&self) -> DisplayRow { + DisplayRow(self.block_snapshot.longest_row()) } - pub fn fold_for_line(&self, buffer_row: u32) -> Option { + pub fn fold_for_line(&self, buffer_row: MultiBufferRow) -> Option { if self.is_line_folded(buffer_row) { Some(FoldStatus::Folded) } else if self.is_foldable(buffer_row) { @@ -830,7 +849,7 @@ impl DisplaySnapshot { } } - pub fn is_foldable(&self, buffer_row: u32) -> bool { + pub fn is_foldable(&self, buffer_row: MultiBufferRow) -> bool { let max_row = self.buffer_snapshot.max_buffer_row(); if buffer_row >= max_row { return false; @@ -841,8 +860,9 @@ impl DisplaySnapshot { return false; } - for next_row in (buffer_row + 1)..=max_row { - let (next_indent_size, next_line_is_blank) = self.line_indent_for_buffer_row(next_row); + for next_row in (buffer_row.0 + 1)..=max_row.0 { + let (next_indent_size, next_line_is_blank) = + self.line_indent_for_buffer_row(MultiBufferRow(next_row)); if next_indent_size > indent_size { return true; } else if !next_line_is_blank { @@ -853,20 +873,22 @@ impl DisplaySnapshot { false } - pub fn foldable_range(&self, buffer_row: u32) -> Option> { - let start = Point::new(buffer_row, self.buffer_snapshot.line_len(buffer_row)); - if self.is_foldable(start.row) && !self.is_line_folded(start.row) { + pub fn foldable_range(&self, buffer_row: MultiBufferRow) -> Option> { + let start = MultiBufferPoint::new(buffer_row.0, self.buffer_snapshot.line_len(buffer_row)); + if self.is_foldable(MultiBufferRow(start.row)) + && !self.is_line_folded(MultiBufferRow(start.row)) + { let (start_indent, _) = self.line_indent_for_buffer_row(buffer_row); let max_point = self.buffer_snapshot.max_point(); let mut end = None; - for row in (buffer_row + 1)..=max_point.row { - let (indent, is_blank) = self.line_indent_for_buffer_row(row); + for row in (buffer_row.0 + 1)..=max_point.row { + let (indent, is_blank) = self.line_indent_for_buffer_row(MultiBufferRow(row)); if !is_blank && indent <= start_indent { let prev_row = row - 1; end = Some(Point::new( prev_row, - self.buffer_snapshot.line_len(prev_row), + self.buffer_snapshot.line_len(MultiBufferRow(prev_row)), )); break; } @@ -903,27 +925,31 @@ impl Debug for DisplayPoint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( "DisplayPoint({}, {})", - self.row(), + self.row().0, self.column() )) } } +#[derive(Debug, Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq, Deserialize, Hash)] +#[serde(transparent)] +pub struct DisplayRow(pub u32); + impl DisplayPoint { - pub fn new(row: u32, column: u32) -> Self { - Self(BlockPoint(Point::new(row, column))) + pub fn new(row: DisplayRow, column: u32) -> Self { + Self(BlockPoint(Point::new(row.0, column))) } pub fn zero() -> Self { - Self::new(0, 0) + Self::new(DisplayRow(0), 0) } pub fn is_zero(&self) -> bool { self.0.is_zero() } - pub fn row(self) -> u32 { - self.0.row + pub fn row(self) -> DisplayRow { + DisplayRow(self.0.row) } pub fn column(self) -> u32 { @@ -1171,7 +1197,7 @@ pub mod tests { let buffer = &snapshot.buffer_snapshot; for _ in 0..5 { let row = rng.gen_range(0..=buffer.max_point().row); - let column = rng.gen_range(0..=buffer.line_len(row)); + let column = rng.gen_range(0..=buffer.line_len(MultiBufferRow(row))); let point = buffer.clip_point(Point::new(row, column), Left); let (prev_buffer_bound, prev_display_bound) = snapshot.prev_line_boundary(point); @@ -1216,12 +1242,12 @@ pub mod tests { } // Movement - let min_point = snapshot.clip_point(DisplayPoint::new(0, 0), Left); + let min_point = snapshot.clip_point(DisplayPoint::new(DisplayRow(0), 0), Left); let max_point = snapshot.clip_point(snapshot.max_point(), Right); for _ in 0..5 { - let row = rng.gen_range(0..=snapshot.max_point().row()); - let column = rng.gen_range(0..=snapshot.line_len(row)); - let point = snapshot.clip_point(DisplayPoint::new(row, column), Left); + let row = rng.gen_range(0..=snapshot.max_point().row().0); + let column = rng.gen_range(0..=snapshot.line_len(DisplayRow(row))); + let point = snapshot.clip_point(DisplayPoint::new(DisplayRow(row), column), Left); log::info!("Moving from point {:?}", point); @@ -1288,63 +1314,64 @@ pub mod tests { let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!( - snapshot.text_chunks(0).collect::(), + snapshot.text_chunks(DisplayRow(0)).collect::(), "one two \nthree four \nfive\nsix seven \neight" ); assert_eq!( - snapshot.clip_point(DisplayPoint::new(0, 8), Bias::Left), - DisplayPoint::new(0, 7) + snapshot.clip_point(DisplayPoint::new(DisplayRow(0), 8), Bias::Left), + DisplayPoint::new(DisplayRow(0), 7) ); assert_eq!( - snapshot.clip_point(DisplayPoint::new(0, 8), Bias::Right), - DisplayPoint::new(1, 0) + snapshot.clip_point(DisplayPoint::new(DisplayRow(0), 8), Bias::Right), + DisplayPoint::new(DisplayRow(1), 0) ); assert_eq!( - movement::right(&snapshot, DisplayPoint::new(0, 7)), - DisplayPoint::new(1, 0) + movement::right(&snapshot, DisplayPoint::new(DisplayRow(0), 7)), + DisplayPoint::new(DisplayRow(1), 0) ); assert_eq!( - movement::left(&snapshot, DisplayPoint::new(1, 0)), - DisplayPoint::new(0, 7) + movement::left(&snapshot, DisplayPoint::new(DisplayRow(1), 0)), + DisplayPoint::new(DisplayRow(0), 7) ); - let x = snapshot.x_for_display_point(DisplayPoint::new(1, 10), &text_layout_details); + let x = snapshot + .x_for_display_point(DisplayPoint::new(DisplayRow(1), 10), &text_layout_details); assert_eq!( movement::up( &snapshot, - DisplayPoint::new(1, 10), + DisplayPoint::new(DisplayRow(1), 10), SelectionGoal::None, false, &text_layout_details, ), ( - DisplayPoint::new(0, 7), + DisplayPoint::new(DisplayRow(0), 7), SelectionGoal::HorizontalPosition(x.0) ) ); assert_eq!( movement::down( &snapshot, - DisplayPoint::new(0, 7), + DisplayPoint::new(DisplayRow(0), 7), SelectionGoal::HorizontalPosition(x.0), false, &text_layout_details ), ( - DisplayPoint::new(1, 10), + DisplayPoint::new(DisplayRow(1), 10), SelectionGoal::HorizontalPosition(x.0) ) ); assert_eq!( movement::down( &snapshot, - DisplayPoint::new(1, 10), + DisplayPoint::new(DisplayRow(1), 10), SelectionGoal::HorizontalPosition(x.0), false, &text_layout_details ), ( - DisplayPoint::new(2, 4), + DisplayPoint::new(DisplayRow(2), 4), SelectionGoal::HorizontalPosition(x.0) ) ); @@ -1356,7 +1383,7 @@ pub mod tests { let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!( - snapshot.text_chunks(1).collect::(), + snapshot.text_chunks(DisplayRow(1)).collect::(), "three four \nfive\nsix and \nseven eight" ); @@ -1367,7 +1394,7 @@ pub mod tests { let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!( - snapshot.text_chunks(1).collect::(), + snapshot.text_chunks(DisplayRow(1)).collect::(), "three \nfour five\nsix and \nseven \neight" ) }); @@ -1388,9 +1415,18 @@ pub mod tests { buffer.update(cx, |buffer, cx| { buffer.edit( vec![ - (Point::new(1, 0)..Point::new(1, 0), "\t"), - (Point::new(1, 1)..Point::new(1, 1), "\t"), - (Point::new(2, 1)..Point::new(2, 1), "\t"), + ( + MultiBufferPoint::new(1, 0)..MultiBufferPoint::new(1, 0), + "\t", + ), + ( + MultiBufferPoint::new(1, 1)..MultiBufferPoint::new(1, 1), + "\t", + ), + ( + MultiBufferPoint::new(2, 1)..MultiBufferPoint::new(2, 1), + "\t", + ), ], None, cx, @@ -1399,7 +1435,7 @@ pub mod tests { assert_eq!( map.update(cx, |map, cx| map.snapshot(cx)) - .text_chunks(1) + .text_chunks(DisplayRow(1)) .collect::() .lines() .next(), @@ -1407,7 +1443,7 @@ pub mod tests { ); assert_eq!( map.update(cx, |map, cx| map.snapshot(cx)) - .text_chunks(2) + .text_chunks(DisplayRow(2)) .collect::() .lines() .next(), @@ -1462,7 +1498,7 @@ pub mod tests { let map = cx .new_model(|cx| DisplayMap::new(buffer, font("Helvetica"), font_size, None, 1, 1, cx)); assert_eq!( - cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)), + cx.update(|cx| syntax_chunks(DisplayRow(0)..DisplayRow(5), &map, &theme, cx)), vec![ ("fn ".to_string(), None), ("outer".to_string(), Some(Hsla::blue())), @@ -1473,7 +1509,7 @@ pub mod tests { ] ); assert_eq!( - cx.update(|cx| syntax_chunks(3..5, &map, &theme, cx)), + cx.update(|cx| syntax_chunks(DisplayRow(3)..DisplayRow(5), &map, &theme, cx)), vec![ (" fn ".to_string(), Some(Hsla::red())), ("inner".to_string(), Some(Hsla::blue())), @@ -1482,10 +1518,13 @@ pub mod tests { ); map.update(cx, |map, cx| { - map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx) + map.fold( + vec![MultiBufferPoint::new(0, 6)..MultiBufferPoint::new(3, 2)], + cx, + ) }); assert_eq!( - cx.update(|cx| syntax_chunks(0..2, &map, &theme, cx)), + cx.update(|cx| syntax_chunks(DisplayRow(0)..DisplayRow(2), &map, &theme, cx)), vec![ ("fn ".to_string(), None), ("out".to_string(), Some(Hsla::blue())), @@ -1548,7 +1587,7 @@ pub mod tests { DisplayMap::new(buffer, font("Courier"), font_size, Some(px(40.0)), 1, 1, cx) }); assert_eq!( - cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)), + cx.update(|cx| syntax_chunks(DisplayRow(0)..DisplayRow(5), &map, &theme, cx)), [ ("fn \n".to_string(), None), ("oute\nr".to_string(), Some(Hsla::blue())), @@ -1556,15 +1595,18 @@ pub mod tests { ] ); assert_eq!( - cx.update(|cx| syntax_chunks(3..5, &map, &theme, cx)), + cx.update(|cx| syntax_chunks(DisplayRow(3)..DisplayRow(5), &map, &theme, cx)), [("{}\n\n".to_string(), None)] ); map.update(cx, |map, cx| { - map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx) + map.fold( + vec![MultiBufferPoint::new(0, 6)..MultiBufferPoint::new(3, 2)], + cx, + ) }); assert_eq!( - cx.update(|cx| syntax_chunks(1..4, &map, &theme, cx)), + cx.update(|cx| syntax_chunks(DisplayRow(1)..DisplayRow(4), &map, &theme, cx)), [ ("out".to_string(), Some(Hsla::blue())), ("ā‹Æ\n".to_string(), None), @@ -1636,7 +1678,7 @@ pub mod tests { }); assert_eq!( - cx.update(|cx| chunks(0..10, &map, &theme, cx)), + cx.update(|cx| chunks(DisplayRow(0)..DisplayRow(10), &map, &theme, cx)), [ ("const ".to_string(), None, None), ("a".to_string(), None, Some(Hsla::blue())), @@ -1732,45 +1774,57 @@ pub mod tests { let map = map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!(map.text(), "āœ… Ī±\nĪ² \nšŸ€Ī² Ī³"); assert_eq!( - map.text_chunks(0).collect::(), + map.text_chunks(DisplayRow(0)).collect::(), "āœ… Ī±\nĪ² \nšŸ€Ī² Ī³" ); - assert_eq!(map.text_chunks(1).collect::(), "Ī² \nšŸ€Ī² Ī³"); - assert_eq!(map.text_chunks(2).collect::(), "šŸ€Ī² Ī³"); + assert_eq!( + map.text_chunks(DisplayRow(1)).collect::(), + "Ī² \nšŸ€Ī² Ī³" + ); + assert_eq!( + map.text_chunks(DisplayRow(2)).collect::(), + "šŸ€Ī² Ī³" + ); - let point = Point::new(0, "āœ…\t\t".len() as u32); - let display_point = DisplayPoint::new(0, "āœ… ".len() as u32); + let point = MultiBufferPoint::new(0, "āœ…\t\t".len() as u32); + let display_point = DisplayPoint::new(DisplayRow(0), "āœ… ".len() as u32); assert_eq!(point.to_display_point(&map), display_point); assert_eq!(display_point.to_point(&map), point); - let point = Point::new(1, "Ī²\t".len() as u32); - let display_point = DisplayPoint::new(1, "Ī² ".len() as u32); + let point = MultiBufferPoint::new(1, "Ī²\t".len() as u32); + let display_point = DisplayPoint::new(DisplayRow(1), "Ī² ".len() as u32); assert_eq!(point.to_display_point(&map), display_point); assert_eq!(display_point.to_point(&map), point,); - let point = Point::new(2, "šŸ€Ī²\t\t".len() as u32); - let display_point = DisplayPoint::new(2, "šŸ€Ī² ".len() as u32); + let point = MultiBufferPoint::new(2, "šŸ€Ī²\t\t".len() as u32); + let display_point = DisplayPoint::new(DisplayRow(2), "šŸ€Ī² ".len() as u32); assert_eq!(point.to_display_point(&map), display_point); assert_eq!(display_point.to_point(&map), point,); // Display points inside of expanded tabs assert_eq!( - DisplayPoint::new(0, "āœ… ".len() as u32).to_point(&map), - Point::new(0, "āœ…\t".len() as u32), + DisplayPoint::new(DisplayRow(0), "āœ… ".len() as u32).to_point(&map), + MultiBufferPoint::new(0, "āœ…\t".len() as u32), ); assert_eq!( - DisplayPoint::new(0, "āœ… ".len() as u32).to_point(&map), - Point::new(0, "āœ…".len() as u32), + DisplayPoint::new(DisplayRow(0), "āœ… ".len() as u32).to_point(&map), + MultiBufferPoint::new(0, "āœ…".len() as u32), ); // Clipping display points inside of multi-byte characters assert_eq!( - map.clip_point(DisplayPoint::new(0, "āœ…".len() as u32 - 1), Left), - DisplayPoint::new(0, 0) + map.clip_point( + DisplayPoint::new(DisplayRow(0), "āœ…".len() as u32 - 1), + Left + ), + DisplayPoint::new(DisplayRow(0), 0) ); assert_eq!( - map.clip_point(DisplayPoint::new(0, "āœ…".len() as u32 - 1), Bias::Right), - DisplayPoint::new(0, "āœ…".len() as u32) + map.clip_point( + DisplayPoint::new(DisplayRow(0), "āœ…".len() as u32 - 1), + Bias::Right + ), + DisplayPoint::new(DisplayRow(0), "āœ…".len() as u32) ); } @@ -1785,12 +1839,12 @@ pub mod tests { }); assert_eq!( map.update(cx, |map, cx| map.snapshot(cx)).max_point(), - DisplayPoint::new(1, 11) + DisplayPoint::new(DisplayRow(1), 11) ) } fn syntax_chunks( - rows: Range, + rows: Range, map: &Model, theme: &SyntaxTheme, cx: &mut AppContext, @@ -1802,7 +1856,7 @@ pub mod tests { } fn chunks( - rows: Range, + rows: Range, map: &Model, theme: &SyntaxTheme, cx: &mut AppContext, diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 6cadf67845..2ec868fc6a 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -6,7 +6,7 @@ use crate::{EditorStyle, GutterDimensions}; use collections::{Bound, HashMap, HashSet}; use gpui::{AnyElement, Pixels, WindowContext}; use language::{BufferSnapshot, Chunk, Patch, Point}; -use multi_buffer::{Anchor, ExcerptId, ExcerptRange, ToPoint as _}; +use multi_buffer::{Anchor, ExcerptId, ExcerptRange, MultiBufferRow, ToPoint as _}; use parking_lot::Mutex; use std::{ cell::RefCell, @@ -50,7 +50,7 @@ pub struct BlockId(usize); pub struct BlockPoint(pub Point); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] -struct BlockRow(u32); +pub struct BlockRow(pub(super) u32); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] struct WrapRow(u32); @@ -163,7 +163,7 @@ pub struct BlockChunks<'a> { pub struct BlockBufferRows<'a> { transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>, input_buffer_rows: wrap_map::WrapBufferRows<'a>, - output_row: u32, + output_row: BlockRow, started: bool, } @@ -357,7 +357,7 @@ impl BlockMap { match block.disposition { BlockDisposition::Above => position.column = 0, BlockDisposition::Below => { - position.column = buffer.line_len(position.row) + position.column = buffer.line_len(MultiBufferRow(position.row)) } } let position = wrap_snapshot.make_wrap_point(position, Bias::Left); @@ -372,7 +372,7 @@ impl BlockMap { ( wrap_snapshot .make_wrap_point( - Point::new(excerpt_boundary.row, 0), + Point::new(excerpt_boundary.row.0, 0), Bias::Left, ) .row(), @@ -633,12 +633,12 @@ impl BlockSnapshot { } } - pub fn buffer_rows(&self, start_row: u32) -> BlockBufferRows { + pub(super) fn buffer_rows(&self, start_row: BlockRow) -> BlockBufferRows { let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(); - cursor.seek(&BlockRow(start_row), Bias::Right, &()); + cursor.seek(&start_row, Bias::Right, &()); let (output_start, input_start) = cursor.start(); let overshoot = if cursor.item().map_or(false, |t| t.is_isomorphic()) { - start_row - output_start.0 + start_row.0 - output_start.0 } else { 0 }; @@ -676,7 +676,7 @@ impl BlockSnapshot { pub fn max_point(&self) -> BlockPoint { let row = self.transforms.summary().output_rows - 1; - BlockPoint::new(row, self.line_len(row)) + BlockPoint::new(row, self.line_len(BlockRow(row))) } pub fn longest_row(&self) -> u32 { @@ -684,12 +684,12 @@ impl BlockSnapshot { self.to_block_point(WrapPoint::new(input_row, 0)).row } - pub fn line_len(&self, row: u32) -> u32 { + pub(super) fn line_len(&self, row: BlockRow) -> u32 { let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(); - cursor.seek(&BlockRow(row), Bias::Right, &()); + cursor.seek(&BlockRow(row.0), Bias::Right, &()); if let Some(transform) = cursor.item() { let (output_start, input_start) = cursor.start(); - let overshoot = row - output_start.0; + let overshoot = row.0 - output_start.0; if transform.block.is_some() { 0 } else { @@ -700,9 +700,9 @@ impl BlockSnapshot { } } - pub fn is_block_line(&self, row: u32) -> bool { + pub(super) fn is_block_line(&self, row: BlockRow) -> bool { let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(); - cursor.seek(&BlockRow(row), Bias::Right, &()); + cursor.seek(&row, Bias::Right, &()); cursor.item().map_or(false, |t| t.block.is_some()) } @@ -881,16 +881,16 @@ impl<'a> Iterator for BlockChunks<'a> { } impl<'a> Iterator for BlockBufferRows<'a> { - type Item = Option; + type Item = Option; fn next(&mut self) -> Option { if self.started { - self.output_row += 1; + self.output_row.0 += 1; } else { self.started = true; } - if self.output_row >= self.transforms.end(&()).0 .0 { + if self.output_row.0 >= self.transforms.end(&()).0 .0 { self.transforms.next(&()); } @@ -898,7 +898,7 @@ impl<'a> Iterator for BlockBufferRows<'a> { if transform.block.is_some() { Some(None) } else { - Some(self.input_buffer_rows.next().unwrap()) + Some(self.input_buffer_rows.next().unwrap().map(BlockRow)) } } } @@ -1154,7 +1154,10 @@ mod tests { ); assert_eq!( - snapshot.buffer_rows(0).collect::>(), + snapshot + .buffer_rows(BlockRow(0)) + .map(|row| row.map(|r| r.0)) + .collect::>(), &[ Some(0), None, @@ -1394,7 +1397,7 @@ mod tests { position.column = 0; } BlockDisposition::Below => { - position.column = buffer_snapshot.line_len(position.row); + position.column = buffer_snapshot.line_len(MultiBufferRow(position.row)); } }; let row = wraps_snapshot.make_wrap_point(position, Bias::Left).row(); @@ -1410,7 +1413,7 @@ mod tests { expected_blocks.extend(buffer_snapshot.excerpt_boundaries_in_range(0..).map( |boundary| { let position = - wraps_snapshot.make_wrap_point(Point::new(boundary.row, 0), Bias::Left); + wraps_snapshot.make_wrap_point(Point::new(boundary.row.0, 0), Bias::Left); ( position.row(), ExpectedBlock::ExcerptHeader { @@ -1427,7 +1430,9 @@ mod tests { expected_blocks.sort_unstable(); let mut sorted_blocks_iter = expected_blocks.into_iter().peekable(); - let input_buffer_rows = buffer_snapshot.buffer_rows(0).collect::>(); + let input_buffer_rows = buffer_snapshot + .buffer_rows(MultiBufferRow(0)) + .collect::>(); let mut expected_buffer_rows = Vec::new(); let mut expected_text = String::new(); let mut expected_block_positions = Vec::new(); @@ -1498,7 +1503,8 @@ mod tests { ); assert_eq!( blocks_snapshot - .buffer_rows(start_row as u32) + .buffer_rows(BlockRow(start_row as u32)) + .map(|row| row.map(|r| r.0)) .collect::>(), &expected_buffer_rows[start_row..] ); @@ -1518,7 +1524,7 @@ mod tests { let row = row as u32; assert_eq!( - blocks_snapshot.line_len(row), + blocks_snapshot.line_len(BlockRow(row)), line.len() as u32, "invalid line len for row {}", row diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index e773bc8604..337395bacd 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -4,7 +4,7 @@ use super::{ }; use gpui::{ElementId, HighlightStyle, Hsla}; use language::{Chunk, Edit, Point, TextSummary}; -use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset}; +use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset}; use std::{ cmp::{self, Ordering}, iter, @@ -629,17 +629,17 @@ impl FoldSnapshot { cursor.item().map_or(false, |t| t.output_text.is_some()) } - pub fn is_line_folded(&self, buffer_row: u32) -> bool { + pub fn is_line_folded(&self, buffer_row: MultiBufferRow) -> bool { let mut inlay_point = self .inlay_snapshot - .to_inlay_point(Point::new(buffer_row, 0)); + .to_inlay_point(Point::new(buffer_row.0, 0)); let mut cursor = self.transforms.cursor::(); cursor.seek(&inlay_point, Bias::Right, &()); loop { match cursor.item() { Some(transform) => { let buffer_point = self.inlay_snapshot.to_buffer_point(inlay_point); - if buffer_point.row != buffer_row { + if buffer_point.row != buffer_row.0 { return false; } else if transform.output_text.is_some() { return true; @@ -1549,7 +1549,7 @@ mod tests { .collect::>(); for row in 0..=buffer_snapshot.max_point().row { assert_eq!( - snapshot.is_line_folded(row), + snapshot.is_line_folded(MultiBufferRow(row)), folded_buffer_rows.contains(&row), "expected buffer row {}{} to be folded", row, diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index 387885b406..214b7aa4e7 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -2,7 +2,9 @@ use crate::{HighlightStyles, InlayId}; use collections::{BTreeMap, BTreeSet}; use gpui::HighlightStyle; use language::{Chunk, Edit, Point, TextSummary}; -use multi_buffer::{Anchor, MultiBufferChunks, MultiBufferRows, MultiBufferSnapshot, ToOffset}; +use multi_buffer::{ + Anchor, MultiBufferChunks, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, ToOffset, +}; use std::{ any::TypeId, cmp, @@ -182,7 +184,7 @@ pub struct InlayBufferRows<'a> { transforms: Cursor<'a, Transform, (InlayPoint, Point)>, buffer_rows: MultiBufferRows<'a>, inlay_row: u32, - max_buffer_row: u32, + max_buffer_row: MultiBufferRow, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -375,7 +377,7 @@ impl<'a> InlayBufferRows<'a> { self.transforms.seek(&inlay_point, Bias::Left, &()); let mut buffer_point = self.transforms.start().1; - let buffer_row = if row == 0 { + let buffer_row = MultiBufferRow(if row == 0 { 0 } else { match self.transforms.item() { @@ -383,9 +385,9 @@ impl<'a> InlayBufferRows<'a> { buffer_point += inlay_point.0 - self.transforms.start().0 .0; buffer_point.row } - _ => cmp::min(buffer_point.row + 1, self.max_buffer_row), + _ => cmp::min(buffer_point.row + 1, self.max_buffer_row.0), } - }; + }); self.inlay_row = inlay_point.row(); self.buffer_rows.seek(buffer_row); } @@ -986,17 +988,17 @@ impl InlaySnapshot { let inlay_point = InlayPoint::new(row, 0); cursor.seek(&inlay_point, Bias::Left, &()); - let max_buffer_row = self.buffer.max_point().row; + let max_buffer_row = MultiBufferRow(self.buffer.max_point().row); let mut buffer_point = cursor.start().1; let buffer_row = if row == 0 { - 0 + MultiBufferRow(0) } else { match cursor.item() { Some(Transform::Isomorphic(_)) => { buffer_point += inlay_point.0 - cursor.start().0 .0; - buffer_point.row + MultiBufferRow(buffer_point.row) } - _ => cmp::min(buffer_point.row + 1, max_buffer_row), + _ => cmp::min(MultiBufferRow(buffer_point.row + 1), max_buffer_row), } }; diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index f84154087b..ff43c9f1d9 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -86,18 +86,18 @@ use language::{ CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId, }; -use language::{Runnable, RunnableRange}; +use language::{BufferRow, Runnable, RunnableRange}; use task::{ResolvedTask, TaskTemplate, TaskVariables}; use hover_links::{HoverLink, HoveredLinkState, InlayHighlight}; use lsp::{DiagnosticSeverity, LanguageServerId}; use mouse_context_menu::MouseContextMenu; use movement::TextLayoutDetails; -use multi_buffer::ToOffsetUtf16; pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, }; +use multi_buffer::{MultiBufferPoint, MultiBufferRow, ToOffsetUtf16}; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock}; use project::project_settings::{GitGutterSetting, ProjectSettings}; @@ -410,7 +410,7 @@ struct RunnableTasks { #[derive(Clone)] struct ResolvedTasks { templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>, - position: text::Point, + position: Anchor, } /// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`] @@ -505,7 +505,7 @@ pub struct Editor { >, last_bounds: Option>, expect_bounds_change: Option>, - tasks: HashMap<(BufferId, u32), (usize, RunnableTasks)>, + tasks: HashMap<(BufferId, BufferRow), (usize, RunnableTasks)>, tasks_update_task: Option>, } @@ -804,7 +804,7 @@ impl ContextMenu { enum ContextMenuOrigin { EditorPoint(DisplayPoint), - GutterIndicator(u32), + GutterIndicator(DisplayRow), } #[derive(Clone)] @@ -1299,7 +1299,7 @@ struct CodeActionsMenu { buffer: Model, selected_item: usize, scroll_handle: UniformListScrollHandle, - deployed_from_indicator: Option, + deployed_from_indicator: Option, } impl CodeActionsMenu { @@ -2498,7 +2498,8 @@ impl Editor { let end_column = cmp::max(tail.column(), goal_column); let reversed = start_column < tail.column(); - let selection_ranges = (start_row..=end_row) + let selection_ranges = (start_row.0..=end_row.0) + .map(DisplayRow) .filter_map(|row| { if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) { let start = display_map @@ -2898,7 +2899,8 @@ impl Editor { .iter() .map(|selection| { let start_point = selection.start.to_point(&buffer); - let mut indent = buffer.indent_size_for_line(start_point.row); + let mut indent = + buffer.indent_size_for_line(MultiBufferRow(start_point.row)); indent.len = cmp::min(indent.len, start_point.column); let start = selection.start; let end = selection.end; @@ -2951,7 +2953,7 @@ impl Editor { let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?; let (snapshot, range) = - buffer.buffer_line_for_row(start_point.row)?; + buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?; let mut index_of_first_non_whitespace = 0; let comment_candidate = snapshot @@ -3015,7 +3017,7 @@ impl Editor { let mut cursor = new_selection.end.to_point(&buffer); if extra_newline_inserted { cursor.row -= 1; - cursor.column = buffer.line_len(cursor.row); + cursor.column = buffer.line_len(MultiBufferRow(cursor.row)); } new_selection.map(|_| cursor) }) @@ -3075,7 +3077,7 @@ impl Editor { IndentKind::Space => " ".repeat(indent.len as usize), IndentKind::Tab => "\t".repeat(indent.len as usize), }; - let point = Point::new(row, 0); + let point = Point::new(row.0, 0); indent_edits.push((point..point, text)); } } @@ -3135,7 +3137,7 @@ impl Editor { IndentKind::Space => " ".repeat(indent.len as usize), IndentKind::Tab => "\t".repeat(indent.len as usize), }; - let point = Point::new(row, 0); + let point = Point::new(row.0, 0); indent_edits.push((point..point, text)); } } @@ -3852,17 +3854,13 @@ impl Editor { let spawned_test_task = this.update(&mut cx, |this, cx| { if this.focus_handle.is_focused(cx) { - let display_row = action + let multibuffer_point = action .deployed_from_indicator - .map(|row| { - DisplayPoint::new(row, 0) - .to_point(&snapshot.display_snapshot) - .row - }) - .unwrap_or_else(|| this.selections.newest::(cx).head().row); + .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot)) + .unwrap_or_else(|| this.selections.newest::(cx).head()); let (buffer, buffer_row) = snapshot .buffer_snapshot - .buffer_line_for_row(display_row) + .buffer_line_for_row(MultiBufferRow(multibuffer_point.row)) .and_then(|(buffer_snapshot, range)| { this.buffer .read(cx) @@ -3934,7 +3932,9 @@ impl Editor { .map(|task| (kind.clone(), task)) }) .collect(), - position: Point::new(buffer_row, tasks.1.column), + position: snapshot + .buffer_snapshot + .anchor_before(Point::new(multibuffer_point.row, tasks.1.column)), }) }); let spawn_straight_away = tasks @@ -4496,7 +4496,7 @@ impl Editor { fn render_code_actions_indicator( &self, _style: &EditorStyle, - row: u32, + row: DisplayRow, is_active: bool, cx: &mut ViewContext, ) -> Option { @@ -4525,7 +4525,7 @@ impl Editor { self.tasks.clear() } - fn insert_tasks(&mut self, key: (BufferId, u32), value: (usize, RunnableTasks)) { + fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: (usize, RunnableTasks)) { if let Some(_) = self.tasks.insert(key, value) { // This case should hopefully be rare, but just in case... log::error!("multiple different run targets found on a single line, only the last target will be rendered") @@ -4536,7 +4536,7 @@ impl Editor { &self, _style: &EditorStyle, is_active: bool, - row: u32, + row: DisplayRow, cx: &mut ViewContext, ) -> IconButton { IconButton::new("code_actions_indicator", ui::IconName::Play) @@ -4556,7 +4556,7 @@ impl Editor { pub fn render_fold_indicators( &mut self, - fold_data: Vec>, + fold_data: Vec>, _style: &EditorStyle, gutter_hovered: bool, _line_height: Pixels, @@ -4775,7 +4775,7 @@ impl Editor { pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext) { self.transact(cx, |this, cx| { this.select_autoclose_pair(cx); - let mut selections = this.selections.all::(cx); + let mut selections = this.selections.all::(cx); if !this.selections.line_mode { let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx)); for selection in &mut selections { @@ -4786,7 +4786,7 @@ impl Editor { .to_point(&display_map); if let Some((buffer, line_buffer_range)) = display_map .buffer_snapshot - .buffer_line_for_row(old_head.row) + .buffer_line_for_row(MultiBufferRow(old_head.row)) { let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row); @@ -4800,7 +4800,7 @@ impl Editor { let indent_len = indent_len.get(); new_head = cmp::min( new_head, - Point::new( + MultiBufferPoint::new( old_head.row, ((old_head.column - 1) / indent_len) * indent_len, ), @@ -4875,8 +4875,10 @@ impl Editor { // If the selection is empty and the cursor is in the leading whitespace before the // suggested indentation, then auto-indent the line. let cursor = selection.head(); - let current_indent = snapshot.indent_size_for_line(cursor.row); - if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() { + let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row)); + if let Some(suggested_indent) = + suggested_indents.get(&MultiBufferRow(cursor.row)).copied() + { if cursor.column < suggested_indent.len && cursor.column <= current_indent.len && current_indent.len <= suggested_indent.len @@ -4996,7 +4998,7 @@ impl Editor { let mut delta_for_end_row = 0; let has_multiple_rows = start_row + 1 != end_row; for row in start_row..end_row { - let current_indent = snapshot.indent_size_for_line(row); + let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row)); let indent_delta = match (current_indent.kind, indent_kind) { (IndentKind::Space, IndentKind::Space) => { let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size); @@ -5054,11 +5056,11 @@ impl Editor { // previous selection. if let Some(last_row) = last_outdent { if last_row == rows.start { - rows.start += 1; + rows.start = rows.start.next_row(); } } let has_multiple_rows = rows.len() > 1; - for row in rows { + for row in rows.iter_rows() { let indent_size = snapshot.indent_size_for_line(row); if indent_size.len > 0 { let deletion_len = match indent_size.kind { @@ -5080,8 +5082,9 @@ impl Editor { } else { selection.start.column - deletion_len }; - deletion_ranges - .push(Point::new(row, start)..Point::new(row, start + deletion_len)); + deletion_ranges.push( + Point::new(row.0, start)..Point::new(row.0, start + deletion_len), + ); last_outdent = Some(row); } } @@ -5127,23 +5130,23 @@ impl Editor { } let buffer = &display_map.buffer_snapshot; - let mut edit_start = Point::new(rows.start, 0).to_offset(buffer); + let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer); let edit_end; let cursor_buffer_row; - if buffer.max_point().row >= rows.end { + if buffer.max_point().row >= rows.end.0 { // If there's a line after the range, delete the \n from the end of the row range // and position the cursor on the next line. - edit_end = Point::new(rows.end, 0).to_offset(buffer); + edit_end = Point::new(rows.end.0, 0).to_offset(buffer); cursor_buffer_row = rows.end; } else { // If there isn't a line after the range, delete the \n from the line before the // start of the row range and position the cursor there. edit_start = edit_start.saturating_sub(1); edit_end = buffer.len(); - cursor_buffer_row = rows.start.saturating_sub(1); + cursor_buffer_row = rows.start.previous_row(); } - let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map); + let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map); *cursor.column_mut() = cmp::min(goal_display_column, display_map.line_len(cursor.row())); @@ -5190,13 +5193,13 @@ impl Editor { if self.read_only(cx) { return; } - let mut row_ranges = Vec::>::new(); + let mut row_ranges = Vec::>::new(); for selection in self.selections.all::(cx) { - let start = selection.start.row; + let start = MultiBufferRow(selection.start.row); let end = if selection.start.row == selection.end.row { - selection.start.row + 1 + MultiBufferRow(selection.start.row + 1) } else { - selection.end.row + MultiBufferRow(selection.end.row) }; if let Some(last_row_range) = row_ranges.last_mut() { @@ -5212,20 +5215,21 @@ impl Editor { let mut cursor_positions = Vec::new(); for row_range in &row_ranges { let anchor = snapshot.anchor_before(Point::new( - row_range.end - 1, - snapshot.line_len(row_range.end - 1), + row_range.end.previous_row().0, + snapshot.line_len(row_range.end.previous_row()), )); cursor_positions.push(anchor..anchor); } self.transact(cx, |this, cx| { for row_range in row_ranges.into_iter().rev() { - for row in row_range.rev() { - let end_of_line = Point::new(row, snapshot.line_len(row)); - let indent = snapshot.indent_size_for_line(row + 1); - let start_of_next_line = Point::new(row + 1, indent.len); + for row in row_range.iter_rows().rev() { + let end_of_line = Point::new(row.0, snapshot.line_len(row)); + let next_line_row = row.next_row(); + let indent = snapshot.indent_size_for_line(next_line_row); + let start_of_next_line = Point::new(next_line_row.0, indent.len); - let replace = if snapshot.line_len(row + 1) > indent.len { + let replace = if snapshot.line_len(next_line_row) > indent.len { " " } else { "" @@ -5342,7 +5346,7 @@ impl Editor { fn prepare_revert_change( revert_changes: &mut HashMap, Rope)>>, multi_buffer: &MultiBuffer, - hunk: &DiffHunk, + hunk: &DiffHunk, cx: &mut AppContext, ) -> Option<()> { let buffer = multi_buffer.buffer(hunk.buffer_id)?; @@ -5396,8 +5400,11 @@ impl Editor { &mut selections, ); - let start_point = Point::new(start_row, 0); - let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1)); + let start_point = Point::new(start_row.0, 0); + let end_point = Point::new( + end_row.previous_row().0, + buffer.line_len(end_row.previous_row()), + ); let text = buffer .text_for_range(start_point..end_point) .collect::(); @@ -5411,8 +5418,9 @@ impl Editor { edits.push((start_point..end_point, lines.join("\n"))); // Selections must change based on added and removed line count - let start_row = start_point.row + added_lines as u32 - removed_lines as u32; - let end_row = start_row + lines_after.saturating_sub(1) as u32; + let start_row = + MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32); + let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32); new_selections.push(Selection { id: selection.id, start: start_row, @@ -5438,8 +5446,8 @@ impl Editor { let new_selections = new_selections .iter() .map(|s| { - let start_point = Point::new(s.start, 0); - let end_point = Point::new(s.end, buffer.line_len(s.end)); + let start_point = Point::new(s.start.0, 0); + let end_point = Point::new(s.end.0, buffer.line_len(s.end)); Selection { id: s.id, start: buffer.point_to_offset(start_point), @@ -5602,14 +5610,17 @@ impl Editor { // Copy the text from the selected row region and splice it either at the start // or end of the region. - let start = Point::new(rows.start, 0); - let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1)); + let start = Point::new(rows.start.0, 0); + let end = Point::new( + rows.end.previous_row().0, + buffer.line_len(rows.end.previous_row()), + ); let text = buffer .text_for_range(start..end) .chain(Some("\n")) .collect::(); let insert_location = if upwards { - Point::new(rows.end, 0) + Point::new(rows.end.0, 0) } else { start }; @@ -5656,11 +5667,17 @@ impl Editor { ); // Move the text spanned by the row range to be before the line preceding the row range - if start_row > 0 { - let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1)) - ..Point::new(end_row - 1, buffer.line_len(end_row - 1)); + if start_row.0 > 0 { + let range_to_move = Point::new( + start_row.previous_row().0, + buffer.line_len(start_row.previous_row()), + ) + ..Point::new( + end_row.previous_row().0, + buffer.line_len(end_row.previous_row()), + ); let insertion_point = display_map - .prev_line_boundary(Point::new(start_row - 1, 0)) + .prev_line_boundary(Point::new(start_row.previous_row().0, 0)) .0; // Don't move lines across excerpts @@ -5754,9 +5771,12 @@ impl Editor { ); // Move the text spanned by the row range to be after the last line of the row range - if end_row <= buffer.max_point().row { - let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0); - let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0; + if end_row.0 <= buffer.max_point().row { + let range_to_move = + MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0); + let insertion_point = display_map + .next_line_boundary(MultiBufferPoint::new(end_row.0, 0)) + .0; // Don't move lines across excerpt boundaries if buffer @@ -5906,7 +5926,9 @@ impl Editor { clipboard_selections.push(ClipboardSelection { len, is_entire_line, - first_line_indent: buffer.indent_size_for_line(selection.start.row).len, + first_line_indent: buffer + .indent_size_for_line(MultiBufferRow(selection.start.row)) + .len, }); } } @@ -5950,7 +5972,7 @@ impl Editor { clipboard_selections.push(ClipboardSelection { len, is_entire_line, - first_line_indent: buffer.indent_size_for_line(start.row).len, + first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len, }); } } @@ -6847,8 +6869,8 @@ impl Editor { let max_point = display_map.buffer_snapshot.max_point(); for selection in &mut selections { let rows = selection.spanned_rows(true, &display_map); - selection.start = Point::new(rows.start, 0); - selection.end = cmp::min(max_point, Point::new(rows.end, 0)); + selection.start = Point::new(rows.start.0, 0); + selection.end = cmp::min(max_point, Point::new(rows.end.0, 0)); selection.reversed = false; } self.change_selections(Some(Autoscroll::fit()), cx, |s| { @@ -6868,7 +6890,7 @@ impl Editor { let buffer = self.buffer.read(cx).read(cx); for selection in selections { for row in selection.start.row..selection.end.row { - let cursor = Point::new(row, buffer.line_len(row)); + let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row))); new_selection_ranges.push(cursor..cursor); } new_selection_ranges.push(selection.end..selection.end); @@ -6903,10 +6925,10 @@ impl Editor { selections.clear(); let mut stack = Vec::new(); - for row in range.start.row()..=range.end.row() { + for row in range.start.row().0..=range.end.row().0 { if let Some(selection) = self.selections.build_columnar_selection( &display_map, - row, + DisplayRow(row), &positions, oldest_selection.reversed, &text_layout_details, @@ -6927,7 +6949,7 @@ impl Editor { let mut new_selections = Vec::new(); if above == state.above { let end_row = if above { - 0 + DisplayRow(0) } else { display_map.max_point().row() }; @@ -6950,9 +6972,9 @@ impl Editor { while row != end_row { if above { - row -= 1; + row.0 -= 1; } else { - row += 1; + row.0 += 1; } if let Some(new_selection) = self.selections.build_columnar_selection( @@ -7386,7 +7408,7 @@ impl Editor { pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext) { let text_layout_details = &self.text_layout_details(cx); self.transact(cx, |this, cx| { - let mut selections = this.selections.all::(cx); + let mut selections = this.selections.all::(cx); let mut edits = Vec::new(); let mut selection_edit_ranges = Vec::new(); let mut last_toggled_row = None; @@ -7396,11 +7418,11 @@ impl Editor { fn comment_prefix_range( snapshot: &MultiBufferSnapshot, - row: u32, + row: MultiBufferRow, comment_prefix: &str, comment_prefix_whitespace: &str, ) -> Range { - let start = Point::new(row, snapshot.indent_size_for_line(row).len); + let start = Point::new(row.0, snapshot.indent_size_for_line(row).len); let mut line_bytes = snapshot .bytes_in_range(start..snapshot.max_point()) @@ -7431,11 +7453,11 @@ impl Editor { fn comment_suffix_range( snapshot: &MultiBufferSnapshot, - row: u32, + row: MultiBufferRow, comment_suffix: &str, comment_suffix_has_leading_space: bool, ) -> Range { - let end = Point::new(row, snapshot.line_len(row)); + let end = Point::new(row.0, snapshot.line_len(row)); let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32); let mut line_end_bytes = snapshot @@ -7464,7 +7486,9 @@ impl Editor { // TODO: Handle selections that cross excerpts for selection in &mut selections { - let start_column = snapshot.indent_size_for_line(selection.start.row).len; + let start_column = snapshot + .indent_size_for_line(MultiBufferRow(selection.start.row)) + .len; let language = if let Some(language) = snapshot.language_scope_at(Point::new(selection.start.row, start_column)) { @@ -7477,15 +7501,15 @@ impl Editor { // If multiple selections contain a given row, avoid processing that // row more than once. - let mut start_row = selection.start.row; + let mut start_row = MultiBufferRow(selection.start.row); if last_toggled_row == Some(start_row) { - start_row += 1; + start_row = start_row.next_row(); } let end_row = if selection.end.row > selection.start.row && selection.end.column == 0 { - selection.end.row - 1 + MultiBufferRow(selection.end.row - 1) } else { - selection.end.row + MultiBufferRow(selection.end.row) }; last_toggled_row = Some(end_row); @@ -7506,7 +7530,8 @@ impl Editor { let mut all_selection_lines_are_comments = true; - for row in start_row..=end_row { + for row in start_row.0..=end_row.0 { + let row = MultiBufferRow(row); if start_row < end_row && snapshot.is_line_blank(row) { continue; } @@ -7596,7 +7621,7 @@ impl Editor { let snapshot = this.buffer.read(cx).read(cx); for selection in &mut selections { while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() { - match row.cmp(&selection.end.row) { + match row.cmp(&MultiBufferRow(selection.end.row)) { Ordering::Less => { suffixes_inserted.next(); continue; @@ -7782,7 +7807,7 @@ impl Editor { let row = snapshot .buffer_snapshot - .buffer_line_for_row(point.row)? + .buffer_line_for_row(MultiBufferRow(point.row))? .1 .start .row; @@ -8060,9 +8085,9 @@ impl Editor { &snapshot, selection.head(), false, - snapshot - .buffer_snapshot - .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX), + snapshot.buffer_snapshot.git_diff_hunks_in_range( + MultiBufferRow(selection.head().row + 1)..MultiBufferRow::MAX, + ), cx, ) { let wrapped_point = Point::zero(); @@ -8070,9 +8095,9 @@ impl Editor { &snapshot, wrapped_point, true, - snapshot - .buffer_snapshot - .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX), + snapshot.buffer_snapshot.git_diff_hunks_in_range( + MultiBufferRow(wrapped_point.row + 1)..MultiBufferRow::MAX, + ), cx, ); } @@ -8088,9 +8113,9 @@ impl Editor { &snapshot, selection.head(), false, - snapshot - .buffer_snapshot - .git_diff_hunks_in_range_rev(0..selection.head().row), + snapshot.buffer_snapshot.git_diff_hunks_in_range_rev( + MultiBufferRow(0)..MultiBufferRow(selection.head().row), + ), cx, ) { let wrapped_point = snapshot.buffer_snapshot.max_point(); @@ -8098,9 +8123,9 @@ impl Editor { &snapshot, wrapped_point, true, - snapshot - .buffer_snapshot - .git_diff_hunks_in_range_rev(0..wrapped_point.row), + snapshot.buffer_snapshot.git_diff_hunks_in_range_rev( + MultiBufferRow(0)..MultiBufferRow(wrapped_point.row), + ), cx, ); } @@ -8111,7 +8136,7 @@ impl Editor { snapshot: &DisplaySnapshot, initial_point: Point, is_wrapped: bool, - hunks: impl Iterator>, + hunks: impl Iterator>, cx: &mut ViewContext, ) -> bool { let display_point = initial_point.to_display_point(snapshot); @@ -8972,11 +8997,11 @@ impl Editor { let mut primary_message = None; let mut group_end = Point::zero(); let diagnostic_group = buffer - .diagnostic_group::(group_id) + .diagnostic_group::(group_id) .filter_map(|entry| { - if snapshot.is_line_folded(entry.range.start.row) + if snapshot.is_line_folded(MultiBufferRow(entry.range.start.row)) && (entry.range.start.row == entry.range.end.row - || snapshot.is_line_folded(entry.range.end.row)) + || snapshot.is_line_folded(MultiBufferRow(entry.range.end.row))) { return None; } @@ -9117,7 +9142,7 @@ impl Editor { let buffer_start_row = range.start.row; for row in (0..=range.end.row).rev() { - let fold_range = display_map.foldable_range(row); + let fold_range = display_map.foldable_range(MultiBufferRow(row)); if let Some(fold_range) = fold_range { if fold_range.end.row >= buffer_start_row { @@ -9159,7 +9184,7 @@ impl Editor { let mut start = range.start.to_point(&display_map); let mut end = range.end.to_point(&display_map); start.column = 0; - end.column = buffer.line_len(end.row); + end.column = buffer.line_len(MultiBufferRow(end.row)); start..end }) .collect::>(); @@ -9170,9 +9195,9 @@ impl Editor { pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let intersection_range = Point::new(unfold_at.buffer_row, 0) + let intersection_range = Point::new(unfold_at.buffer_row.0, 0) ..Point::new( - unfold_at.buffer_row, + unfold_at.buffer_row.0, display_map.buffer_snapshot.line_len(unfold_at.buffer_row), ); @@ -9192,7 +9217,12 @@ impl Editor { let ranges = selections.into_iter().map(|s| { if line_mode { let start = Point::new(s.start.row, 0); - let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row)); + let end = Point::new( + s.end.row, + display_map + .buffer_snapshot + .line_len(MultiBufferRow(s.end.row)), + ); start..end } else { s.start..s.end @@ -9330,7 +9360,7 @@ impl Editor { } } - pub fn longest_row(&self, cx: &mut AppContext) -> u32 { + pub fn longest_row(&self, cx: &mut AppContext) -> DisplayRow { self.display_map .update(cx, |map, cx| map.snapshot(cx)) .longest_row() @@ -9595,7 +9625,7 @@ impl Editor { let cursor_anchor = self.selections.newest_anchor().head(); let snapshot = self.buffer.read(cx).snapshot(cx); - let buffer_row = cursor_anchor.to_point(&snapshot).row; + let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row); snapshot.line_len(buffer_row) == 0 } @@ -9776,7 +9806,7 @@ impl Editor { &mut self, exclude_highlights: HashSet, cx: &mut WindowContext, - ) -> BTreeMap { + ) -> BTreeMap { let snapshot = self.snapshot(cx); let mut used_highlight_orders = HashMap::default(); self.highlighted_rows @@ -9784,21 +9814,21 @@ impl Editor { .filter(|(type_id, _)| !exclude_highlights.contains(type_id)) .flat_map(|(_, highlighted_rows)| highlighted_rows.iter()) .fold( - BTreeMap::::new(), + BTreeMap::::new(), |mut unique_rows, (highlight_order, anchor_range, hsla)| { let start_row = anchor_range.start().to_display_point(&snapshot).row(); let end_row = anchor_range.end().to_display_point(&snapshot).row(); - for row in start_row..=end_row { + for row in start_row.0..=end_row.0 { let used_index = used_highlight_orders.entry(row).or_insert(*highlight_order); if highlight_order >= used_index { *used_index = *highlight_order; match hsla { Some(hsla) => { - unique_rows.insert(row, *hsla); + unique_rows.insert(DisplayRow(row), *hsla); } None => { - unique_rows.remove(&row); + unique_rows.remove(&DisplayRow(row)); } } } @@ -10640,15 +10670,15 @@ impl Editor { fn hunks_for_selections( multi_buffer_snapshot: &MultiBufferSnapshot, selections: &[Selection], -) -> Vec> { +) -> Vec> { let mut hunks = Vec::with_capacity(selections.len()); let mut processed_buffer_rows: HashMap>> = HashMap::default(); - let display_rows_for_selections = selections.iter().map(|selection| { + let buffer_rows_for_selections = selections.iter().map(|selection| { let head = selection.head(); let tail = selection.tail(); - let start = tail.to_point(&multi_buffer_snapshot).row; - let end = head.to_point(&multi_buffer_snapshot).row; + let start = MultiBufferRow(tail.to_point(&multi_buffer_snapshot).row); + let end = MultiBufferRow(head.to_point(&multi_buffer_snapshot).row); if start > end { end..start } else { @@ -10656,12 +10686,13 @@ fn hunks_for_selections( } }); - for selected_multi_buffer_rows in display_rows_for_selections { - let query_rows = selected_multi_buffer_rows.start..selected_multi_buffer_rows.end + 1; + for selected_multi_buffer_rows in buffer_rows_for_selections { + let query_rows = + selected_multi_buffer_rows.start..selected_multi_buffer_rows.end.next_row(); for hunk in multi_buffer_snapshot.git_diff_hunks_in_range(query_rows.clone()) { // Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it // when the caret is just above or just below the deleted hunk. - let allow_adjacent = hunk.status() == DiffHunkStatus::Removed; + let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed; let related_to_selection = if allow_adjacent { hunk.associated_range.overlaps(&query_rows) || hunk.associated_range.start == query_rows.end @@ -10798,13 +10829,13 @@ fn consume_contiguous_rows( selection: &Selection, display_map: &DisplaySnapshot, selections: &mut std::iter::Peekable>>, -) -> (u32, u32) { +) -> (MultiBufferRow, MultiBufferRow) { contiguous_row_selections.push(selection.clone()); - let start_row = selection.start.row; + let start_row = MultiBufferRow(selection.start.row); let mut end_row = ending_row(selection, display_map); while let Some(next_selection) = selections.peek() { - if next_selection.start.row <= end_row { + if next_selection.start.row <= end_row.0 { end_row = ending_row(next_selection, display_map); contiguous_row_selections.push(selections.next().unwrap().clone()); } else { @@ -10814,11 +10845,11 @@ fn consume_contiguous_rows( (start_row, end_row) } -fn ending_row(next_selection: &Selection, display_map: &DisplaySnapshot) -> u32 { +fn ending_row(next_selection: &Selection, display_map: &DisplaySnapshot) -> MultiBufferRow { if next_selection.end.column > 0 || next_selection.is_empty() { - display_map.next_line_boundary(next_selection.end).0.row + 1 + MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1) } else { - next_selection.end.row + MultiBufferRow(next_selection.end.row) } } @@ -11300,7 +11331,7 @@ impl ViewInputHandler for Editor { let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot); let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left + self.gutter_dimensions.width; - let y = line_height * (start.row() as f32 - scroll_position.y); + let y = line_height * (start.row().as_f32() - scroll_position.y); Some(Bounds { origin: element_bounds.origin + point(x, y), @@ -11311,8 +11342,11 @@ impl ViewInputHandler for Editor { trait SelectionExt { fn display_range(&self, map: &DisplaySnapshot) -> Range; - fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot) - -> Range; + fn spanned_rows( + &self, + include_end_if_at_line_start: bool, + map: &DisplaySnapshot, + ) -> Range; } impl SelectionExt for Selection { @@ -11336,7 +11370,7 @@ impl SelectionExt for Selection { &self, include_end_if_at_line_start: bool, map: &DisplaySnapshot, - ) -> Range { + ) -> Range { let start = self.start.to_point(&map.buffer_snapshot); let mut end = self.end.to_point(&map.buffer_snapshot); if !include_end_if_at_line_start && start.row != end.row && end.column == 0 { @@ -11345,7 +11379,7 @@ impl SelectionExt for Selection { let buffer_start = map.prev_line_boundary(start).0; let buffer_end = map.next_line_boundary(end).0; - buffer_start.row..buffer_end.row + 1 + MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1) } } @@ -11609,3 +11643,91 @@ impl RangeToAnchorExt for Range { } } } + +pub trait RowExt { + fn as_f32(&self) -> f32; + + fn next_row(&self) -> Self; + + fn previous_row(&self) -> Self; + + fn minus(&self, other: Self) -> u32; +} + +impl RowExt for DisplayRow { + fn as_f32(&self) -> f32 { + self.0 as f32 + } + + fn next_row(&self) -> Self { + Self(self.0 + 1) + } + + fn previous_row(&self) -> Self { + Self(self.0.saturating_sub(1)) + } + + fn minus(&self, other: Self) -> u32 { + self.0 - other.0 + } +} + +impl RowExt for MultiBufferRow { + fn as_f32(&self) -> f32 { + self.0 as f32 + } + + fn next_row(&self) -> Self { + Self(self.0 + 1) + } + + fn previous_row(&self) -> Self { + Self(self.0.saturating_sub(1)) + } + + fn minus(&self, other: Self) -> u32 { + self.0 - other.0 + } +} + +trait RowRangeExt { + type Row; + + fn len(&self) -> usize; + + fn iter_rows(&self) -> impl DoubleEndedIterator; +} + +impl RowRangeExt for Range { + type Row = MultiBufferRow; + + fn len(&self) -> usize { + (self.end.0 - self.start.0) as usize + } + + fn iter_rows(&self) -> impl DoubleEndedIterator { + (self.start.0..self.end.0).map(MultiBufferRow) + } +} + +impl RowRangeExt for Range { + type Row = DisplayRow; + + fn len(&self) -> usize { + (self.end.0 - self.start.0) as usize + } + + fn iter_rows(&self) -> impl DoubleEndedIterator { + (self.start.0..self.end.0).map(DisplayRow) + } +} + +fn hunk_status(hunk: &DiffHunk) -> DiffHunkStatus { + if hunk.diff_base_byte_range.is_empty() { + DiffHunkStatus::Added + } else if hunk.associated_range.is_empty() { + DiffHunkStatus::Removed + } else { + DiffHunkStatus::Modified + } +} diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 01d0a390da..c6b27afbab 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -333,18 +333,18 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { }); _ = editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); + view.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, cx); }); assert_eq!( editor .update(cx, |view, cx| view.selections.display_ranges(cx)) .unwrap(), - [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] + [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(2), 2)] ); _ = editor.update(cx, |view, cx| { view.update_selection( - DisplayPoint::new(3, 3), + DisplayPoint::new(DisplayRow(3), 3), 0, gpui::Point::::default(), cx, @@ -355,12 +355,12 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { editor .update(cx, |view, cx| view.selections.display_ranges(cx)) .unwrap(), - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3)] ); _ = editor.update(cx, |view, cx| { view.update_selection( - DisplayPoint::new(1, 1), + DisplayPoint::new(DisplayRow(1), 1), 0, gpui::Point::::default(), cx, @@ -371,13 +371,13 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { editor .update(cx, |view, cx| view.selections.display_ranges(cx)) .unwrap(), - [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] + [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(1), 1)] ); _ = editor.update(cx, |view, cx| { view.end_selection(cx); view.update_selection( - DisplayPoint::new(3, 3), + DisplayPoint::new(DisplayRow(3), 3), 0, gpui::Point::::default(), cx, @@ -388,13 +388,13 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { editor .update(cx, |view, cx| view.selections.display_ranges(cx)) .unwrap(), - [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] + [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(1), 1)] ); _ = editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(3, 3), true, 1, cx); + view.begin_selection(DisplayPoint::new(DisplayRow(3), 3), true, 1, cx); view.update_selection( - DisplayPoint::new(0, 0), + DisplayPoint::new(DisplayRow(0), 0), 0, gpui::Point::::default(), cx, @@ -406,8 +406,8 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { .update(cx, |view, cx| view.selections.display_ranges(cx)) .unwrap(), [ - DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0) + DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(3), 3)..DisplayPoint::new(DisplayRow(0), 0) ] ); @@ -419,7 +419,7 @@ fn test_selection_with_mouse(cx: &mut TestAppContext) { editor .update(cx, |view, cx| view.selections.display_ranges(cx)) .unwrap(), - [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)] + [DisplayPoint::new(DisplayRow(3), 3)..DisplayPoint::new(DisplayRow(0), 0)] ); } @@ -433,37 +433,37 @@ fn test_canceling_pending_selection(cx: &mut TestAppContext) { }); _ = view.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); + view.begin_selection(DisplayPoint::new(DisplayRow(2), 2), false, 1, cx); assert_eq!( view.selections.display_ranges(cx), - [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] + [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(2), 2)] ); }); _ = view.update(cx, |view, cx| { view.update_selection( - DisplayPoint::new(3, 3), + DisplayPoint::new(DisplayRow(3), 3), 0, gpui::Point::::default(), cx, ); assert_eq!( view.selections.display_ranges(cx), - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3)] ); }); _ = view.update(cx, |view, cx| { view.cancel(&Cancel, cx); view.update_selection( - DisplayPoint::new(1, 1), + DisplayPoint::new(DisplayRow(1), 1), 0, gpui::Point::::default(), cx, ); assert_eq!( view.selections.display_ranges(cx), - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + [DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3)] ); }); } @@ -566,51 +566,57 @@ async fn test_navigation_history(cx: &mut TestAppContext) { // Move the cursor a small distance. // Nothing is added to the navigation history. editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0) + ]) }); editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0) + ]) }); assert!(pop_history(&mut editor, cx).is_none()); // Move the cursor a large distance. // The history can jump back to the previous position. editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(13, 0)..DisplayPoint::new(13, 3)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(13), 0)..DisplayPoint::new(DisplayRow(13), 3) + ]) }); let nav_entry = pop_history(&mut editor, cx).unwrap(); editor.navigate(nav_entry.data.unwrap(), cx); assert_eq!(nav_entry.item.id(), cx.entity_id()); assert_eq!( editor.selections.display_ranges(cx), - &[DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)] + &[DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0)] ); assert!(pop_history(&mut editor, cx).is_none()); // Move the cursor a small distance via the mouse. // Nothing is added to the navigation history. - editor.begin_selection(DisplayPoint::new(5, 0), false, 1, cx); + editor.begin_selection(DisplayPoint::new(DisplayRow(5), 0), false, 1, cx); editor.end_selection(cx); assert_eq!( editor.selections.display_ranges(cx), - &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)] + &[DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(5), 0)] ); assert!(pop_history(&mut editor, cx).is_none()); // Move the cursor a large distance via the mouse. // The history can jump back to the previous position. - editor.begin_selection(DisplayPoint::new(15, 0), false, 1, cx); + editor.begin_selection(DisplayPoint::new(DisplayRow(15), 0), false, 1, cx); editor.end_selection(cx); assert_eq!( editor.selections.display_ranges(cx), - &[DisplayPoint::new(15, 0)..DisplayPoint::new(15, 0)] + &[DisplayPoint::new(DisplayRow(15), 0)..DisplayPoint::new(DisplayRow(15), 0)] ); let nav_entry = pop_history(&mut editor, cx).unwrap(); editor.navigate(nav_entry.data.unwrap(), cx); assert_eq!(nav_entry.item.id(), cx.entity_id()); assert_eq!( editor.selections.display_ranges(cx), - &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)] + &[DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(5), 0)] ); assert!(pop_history(&mut editor, cx).is_none()); @@ -649,7 +655,7 @@ async fn test_navigation_history(cx: &mut TestAppContext) { ); assert_eq!( editor.scroll_position(cx), - gpui::Point::new(0., editor.max_point(cx).row() as f32) + gpui::Point::new(0., editor.max_point(cx).row().as_f32()) ); editor @@ -667,18 +673,18 @@ fn test_cancel(cx: &mut TestAppContext) { }); _ = view.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(3, 4), false, 1, cx); + view.begin_selection(DisplayPoint::new(DisplayRow(3), 4), false, 1, cx); view.update_selection( - DisplayPoint::new(1, 1), + DisplayPoint::new(DisplayRow(1), 1), 0, gpui::Point::::default(), cx, ); view.end_selection(cx); - view.begin_selection(DisplayPoint::new(0, 1), true, 1, cx); + view.begin_selection(DisplayPoint::new(DisplayRow(0), 1), true, 1, cx); view.update_selection( - DisplayPoint::new(0, 3), + DisplayPoint::new(DisplayRow(0), 3), 0, gpui::Point::::default(), cx, @@ -687,8 +693,8 @@ fn test_cancel(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 3), + DisplayPoint::new(DisplayRow(3), 4)..DisplayPoint::new(DisplayRow(1), 1), ] ); }); @@ -697,7 +703,7 @@ fn test_cancel(cx: &mut TestAppContext) { view.cancel(&Cancel, cx); assert_eq!( view.selections.display_ranges(cx), - [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)] + [DisplayPoint::new(DisplayRow(3), 4)..DisplayPoint::new(DisplayRow(1), 1)] ); }); @@ -705,7 +711,7 @@ fn test_cancel(cx: &mut TestAppContext) { view.cancel(&Cancel, cx); assert_eq!( view.selections.display_ranges(cx), - [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)] + [DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1)] ); }); } @@ -741,7 +747,9 @@ fn test_fold_action(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)]); + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(8), 0)..DisplayPoint::new(DisplayRow(12), 0) + ]); }); view.fold(&Fold, cx); assert_eq!( @@ -820,58 +828,60 @@ fn test_move_cursor(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] + &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); view.move_down(&MoveDown, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] + &[DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0)] ); view.move_right(&MoveRight, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] + &[DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 4)] ); view.move_left(&MoveLeft, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] + &[DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0)] ); view.move_up(&MoveUp, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] + &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); view.move_to_end(&MoveToEnd, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)] + &[DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 6)] ); view.move_to_beginning(&MoveToBeginning, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] + &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); view.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)]); + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 2) + ]); }); view.select_to_beginning(&SelectToBeginning, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)] + &[DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 0)] ); view.select_to_end(&SelectToEnd, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)] + &[DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(5), 6)] ); }); } @@ -1060,8 +1070,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 4), ]); }); }); @@ -1071,8 +1081,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), ] ); }); @@ -1082,8 +1092,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), ] ); }); @@ -1093,8 +1103,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), ] ); }); @@ -1104,8 +1114,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), + DisplayPoint::new(DisplayRow(1), 5)..DisplayPoint::new(DisplayRow(1), 5), ] ); }); @@ -1116,8 +1126,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), + DisplayPoint::new(DisplayRow(1), 5)..DisplayPoint::new(DisplayRow(1), 5), ] ); }); @@ -1133,8 +1143,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 2), ] ); }); @@ -1149,8 +1159,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 0), ] ); }); @@ -1165,8 +1175,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 2), ] ); }); @@ -1181,8 +1191,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 3), + DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 5), ] ); }); @@ -1193,8 +1203,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 4), ] ); }); @@ -1205,8 +1215,8 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), ] ); }); @@ -1246,41 +1256,45 @@ fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) { // First, let's assert behavior on the first line, that was not soft-wrapped. // Start the cursor at the `k` on the first line view.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7)]); + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 7)..DisplayPoint::new(DisplayRow(0), 7) + ]); }); // Moving to the beginning of the line should put us at the beginning of the line. view.move_to_beginning_of_line(&move_to_beg, cx); assert_eq!( - vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),], + vec![DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0),], view.selections.display_ranges(cx) ); // Moving to the end of the line should put us at the end of the line. view.move_to_end_of_line(&move_to_end, cx); assert_eq!( - vec![DisplayPoint::new(0, 16)..DisplayPoint::new(0, 16),], + vec![DisplayPoint::new(DisplayRow(0), 16)..DisplayPoint::new(DisplayRow(0), 16),], view.selections.display_ranges(cx) ); // Now, let's assert behavior on the second line, that ended up being soft-wrapped. // Start the cursor at the last line (`y` that was wrapped to a new line) view.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0)]); + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 0) + ]); }); // Moving to the beginning of the line should put us at the start of the second line of // display text, i.e., the `j`. view.move_to_beginning_of_line(&move_to_beg, cx); assert_eq!( - vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),], + vec![DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0),], view.selections.display_ranges(cx) ); // Moving to the beginning of the line again should be a no-op. view.move_to_beginning_of_line(&move_to_beg, cx); assert_eq!( - vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),], + vec![DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0),], view.selections.display_ranges(cx) ); @@ -1288,14 +1302,14 @@ fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) { // next display line. view.move_to_end_of_line(&move_to_end, cx); assert_eq!( - vec![DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),], + vec![DisplayPoint::new(DisplayRow(2), 5)..DisplayPoint::new(DisplayRow(2), 5),], view.selections.display_ranges(cx) ); // Moving to the end of the line again should be a no-op. view.move_to_end_of_line(&move_to_end, cx); assert_eq!( - vec![DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),], + vec![DisplayPoint::new(DisplayRow(2), 5)..DisplayPoint::new(DisplayRow(2), 5),], view.selections.display_ranges(cx) ); }); @@ -1312,8 +1326,8 @@ fn test_prev_next_word_boundary(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11), - DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4), + DisplayPoint::new(DisplayRow(0), 11)..DisplayPoint::new(DisplayRow(0), 11), + DisplayPoint::new(DisplayRow(2), 4)..DisplayPoint::new(DisplayRow(2), 4), ]) }); @@ -1370,43 +1384,45 @@ fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) { ); view.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(1, 7)..DisplayPoint::new(1, 7)]); + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(1), 7)..DisplayPoint::new(DisplayRow(1), 7) + ]); }); view.move_to_next_word_end(&MoveToNextWordEnd, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(1, 9)..DisplayPoint::new(1, 9)] + &[DisplayPoint::new(DisplayRow(1), 9)..DisplayPoint::new(DisplayRow(1), 9)] ); view.move_to_next_word_end(&MoveToNextWordEnd, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)] + &[DisplayPoint::new(DisplayRow(1), 14)..DisplayPoint::new(DisplayRow(1), 14)] ); view.move_to_next_word_end(&MoveToNextWordEnd, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)] + &[DisplayPoint::new(DisplayRow(2), 4)..DisplayPoint::new(DisplayRow(2), 4)] ); view.move_to_next_word_end(&MoveToNextWordEnd, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(2, 8)..DisplayPoint::new(2, 8)] + &[DisplayPoint::new(DisplayRow(2), 8)..DisplayPoint::new(DisplayRow(2), 8)] ); view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)] + &[DisplayPoint::new(DisplayRow(2), 4)..DisplayPoint::new(DisplayRow(2), 4)] ); view.move_to_previous_word_start(&MoveToPreviousWordStart, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)] + &[DisplayPoint::new(DisplayRow(1), 14)..DisplayPoint::new(DisplayRow(1), 14)] ); }); } @@ -1806,9 +1822,9 @@ fn test_delete_to_word_boundary(cx: &mut TestAppContext) { view.change_selections(None, cx, |s| { s.select_display_ranges([ // an empty selection - the preceding word fragment is deleted - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), // characters selected - they are deleted - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 12), + DisplayPoint::new(DisplayRow(0), 9)..DisplayPoint::new(DisplayRow(0), 12), ]) }); view.delete_to_previous_word_start(&DeleteToPreviousWordStart, cx); @@ -1819,9 +1835,9 @@ fn test_delete_to_word_boundary(cx: &mut TestAppContext) { view.change_selections(None, cx, |s| { s.select_display_ranges([ // an empty selection - the following word fragment is deleted - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), // characters selected - they are deleted - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 10), + DisplayPoint::new(DisplayRow(0), 9)..DisplayPoint::new(DisplayRow(0), 10), ]) }); view.delete_to_next_word_end(&DeleteToNextWordEnd, cx); @@ -1841,9 +1857,9 @@ fn test_newline(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - DisplayPoint::new(1, 6)..DisplayPoint::new(1, 6), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), + DisplayPoint::new(DisplayRow(1), 6)..DisplayPoint::new(DisplayRow(1), 6), ]) }); @@ -2603,9 +2619,9 @@ fn test_delete_line(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0), ]) }); view.delete_line(&DeleteLine, cx); @@ -2613,8 +2629,8 @@ fn test_delete_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1) + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1) ] ); }); @@ -2625,13 +2641,15 @@ fn test_delete_line(cx: &mut TestAppContext) { }); _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(0), 1) + ]) }); view.delete_line(&DeleteLine, cx); assert_eq!(view.display_text(cx), "ghi\n"); assert_eq!( view.selections.display_ranges(cx), - vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] + vec![DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1)] ); }); } @@ -2843,7 +2861,7 @@ async fn test_custom_newlines_cause_no_false_positive_diffs( .buffer() .read(cx) .snapshot(cx) - .git_diff_hunks_in_range(0..u32::MAX) + .git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX) .collect::>(), Vec::new(), "Should not have any diffs for files with custom newlines" @@ -3284,10 +3302,10 @@ fn test_duplicate_line(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), + DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0), ]) }); view.duplicate_line_down(&DuplicateLineDown, cx); @@ -3295,10 +3313,10 @@ fn test_duplicate_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2), + DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0), + DisplayPoint::new(DisplayRow(6), 0)..DisplayPoint::new(DisplayRow(6), 0), ] ); }); @@ -3310,8 +3328,8 @@ fn test_duplicate_line(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), ]) }); view.duplicate_line_down(&DuplicateLineDown, cx); @@ -3319,8 +3337,8 @@ fn test_duplicate_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1), - DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1), + DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(4), 1), + DisplayPoint::new(DisplayRow(4), 2)..DisplayPoint::new(DisplayRow(5), 1), ] ); }); @@ -3334,10 +3352,10 @@ fn test_duplicate_line(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), + DisplayPoint::new(DisplayRow(3), 0)..DisplayPoint::new(DisplayRow(3), 0), ]) }); view.duplicate_line_up(&DuplicateLineUp, cx); @@ -3345,10 +3363,10 @@ fn test_duplicate_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), - DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 0), + DisplayPoint::new(DisplayRow(6), 0)..DisplayPoint::new(DisplayRow(6), 0), ] ); }); @@ -3360,8 +3378,8 @@ fn test_duplicate_line(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), ]) }); view.duplicate_line_up(&DuplicateLineUp, cx); @@ -3369,8 +3387,8 @@ fn test_duplicate_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), ] ); }); @@ -3396,10 +3414,10 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { ); view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2), + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 1), + DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(4), 3), + DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(5), 2), ]) }); assert_eq!( @@ -3415,10 +3433,10 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), - DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1), + DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3), + DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(4), 2) ] ); }); @@ -3432,10 +3450,10 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) + DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 1), + DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(4), 3), + DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(5), 2) ] ); }); @@ -3449,10 +3467,10 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) + DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1), + DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 1), + DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(4), 3), + DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(5), 2) ] ); }); @@ -3466,10 +3484,10 @@ fn test_move_line_up_down(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), - DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) + DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1), + DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 3), + DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(4), 2) ] ); }); @@ -3808,7 +3826,7 @@ fn test_select_all(cx: &mut TestAppContext) { view.select_all(&SelectAll, cx); assert_eq!( view.selections.display_ranges(cx), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)] + &[DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(2), 3)] ); }); } @@ -3824,18 +3842,18 @@ fn test_select_line(cx: &mut TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), + DisplayPoint::new(DisplayRow(4), 2)..DisplayPoint::new(DisplayRow(4), 2), ]) }); view.select_line(&SelectLine, cx); assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0), - DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(2), 0), + DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(5), 0), ] ); }); @@ -3845,8 +3863,8 @@ fn test_select_line(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(3), 0), + DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(5), 5), ] ); }); @@ -3855,7 +3873,7 @@ fn test_select_line(cx: &mut TestAppContext) { view.select_line(&SelectLine, cx); assert_eq!( view.selections.display_ranges(cx), - vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)] + vec![DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(5), 5)] ); }); } @@ -3880,10 +3898,10 @@ fn test_split_selection_into_lines(cx: &mut TestAppContext) { ); view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), + DisplayPoint::new(DisplayRow(4), 4)..DisplayPoint::new(DisplayRow(4), 4), ]) }); assert_eq!(view.display_text(cx), "aaā‹Æbbb\ncccā‹Æeeee\nfffff\nggggg\nā‹Æi"); @@ -3898,17 +3916,19 @@ fn test_split_selection_into_lines(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), - DisplayPoint::new(5, 4)..DisplayPoint::new(5, 4) + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 0), + DisplayPoint::new(DisplayRow(5), 4)..DisplayPoint::new(DisplayRow(5), 4) ] ); }); _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(5, 0)..DisplayPoint::new(0, 1)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(0), 1) + ]) }); view.split_selection_into_lines(&SplitSelectionIntoLines, cx); assert_eq!( @@ -3918,14 +3938,14 @@ fn test_split_selection_into_lines(cx: &mut TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 5)..DisplayPoint::new(0, 5), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), - DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5), - DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5), - DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5), - DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5), - DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5), - DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0) + DisplayPoint::new(DisplayRow(0), 5)..DisplayPoint::new(DisplayRow(0), 5), + DisplayPoint::new(DisplayRow(1), 5)..DisplayPoint::new(DisplayRow(1), 5), + DisplayPoint::new(DisplayRow(2), 5)..DisplayPoint::new(DisplayRow(2), 5), + DisplayPoint::new(DisplayRow(3), 5)..DisplayPoint::new(DisplayRow(3), 5), + DisplayPoint::new(DisplayRow(4), 5)..DisplayPoint::new(DisplayRow(4), 5), + DisplayPoint::new(DisplayRow(5), 5)..DisplayPoint::new(DisplayRow(5), 5), + DisplayPoint::new(DisplayRow(6), 5)..DisplayPoint::new(DisplayRow(6), 5), + DisplayPoint::new(DisplayRow(7), 0)..DisplayPoint::new(DisplayRow(7), 0) ] ); }); @@ -4429,9 +4449,9 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), - DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), - DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + DisplayPoint::new(DisplayRow(0), 25)..DisplayPoint::new(DisplayRow(0), 25), + DisplayPoint::new(DisplayRow(2), 24)..DisplayPoint::new(DisplayRow(2), 12), + DisplayPoint::new(DisplayRow(3), 18)..DisplayPoint::new(DisplayRow(3), 18), ]); }); view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx); @@ -4439,9 +4459,9 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { assert_eq!( view.update(cx, |view, cx| { view.selections.display_ranges(cx) }), &[ - DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), - DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), - DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), + DisplayPoint::new(DisplayRow(0), 23)..DisplayPoint::new(DisplayRow(0), 27), + DisplayPoint::new(DisplayRow(2), 35)..DisplayPoint::new(DisplayRow(2), 7), + DisplayPoint::new(DisplayRow(3), 15)..DisplayPoint::new(DisplayRow(3), 21), ] ); @@ -4451,8 +4471,8 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), &[ - DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), - DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), + DisplayPoint::new(DisplayRow(0), 16)..DisplayPoint::new(DisplayRow(0), 28), + DisplayPoint::new(DisplayRow(4), 1)..DisplayPoint::new(DisplayRow(2), 0), ] ); @@ -4461,7 +4481,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { }); assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), - &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)] + &[DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); // Trying to expand the selected syntax node one more time has no effect. @@ -4470,7 +4490,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { }); assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), - &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)] + &[DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(0), 0)] ); _ = view.update(cx, |view, cx| { @@ -4479,8 +4499,8 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), &[ - DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), - DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), + DisplayPoint::new(DisplayRow(0), 16)..DisplayPoint::new(DisplayRow(0), 28), + DisplayPoint::new(DisplayRow(4), 1)..DisplayPoint::new(DisplayRow(2), 0), ] ); @@ -4490,9 +4510,9 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), &[ - DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), - DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), - DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), + DisplayPoint::new(DisplayRow(0), 23)..DisplayPoint::new(DisplayRow(0), 27), + DisplayPoint::new(DisplayRow(2), 35)..DisplayPoint::new(DisplayRow(2), 7), + DisplayPoint::new(DisplayRow(3), 15)..DisplayPoint::new(DisplayRow(3), 21), ] ); @@ -4502,9 +4522,9 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), &[ - DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), - DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), - DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + DisplayPoint::new(DisplayRow(0), 25)..DisplayPoint::new(DisplayRow(0), 25), + DisplayPoint::new(DisplayRow(2), 24)..DisplayPoint::new(DisplayRow(2), 12), + DisplayPoint::new(DisplayRow(3), 18)..DisplayPoint::new(DisplayRow(3), 18), ] ); @@ -4515,9 +4535,9 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), &[ - DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), - DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), - DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + DisplayPoint::new(DisplayRow(0), 25)..DisplayPoint::new(DisplayRow(0), 25), + DisplayPoint::new(DisplayRow(2), 24)..DisplayPoint::new(DisplayRow(2), 12), + DisplayPoint::new(DisplayRow(3), 18)..DisplayPoint::new(DisplayRow(3), 18), ] ); @@ -4537,9 +4557,9 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) { assert_eq!( view.update(cx, |view, cx| view.selections.display_ranges(cx)), &[ - DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), - DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), - DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23), + DisplayPoint::new(DisplayRow(0), 16)..DisplayPoint::new(DisplayRow(0), 28), + DisplayPoint::new(DisplayRow(2), 35)..DisplayPoint::new(DisplayRow(2), 7), + DisplayPoint::new(DisplayRow(3), 4)..DisplayPoint::new(DisplayRow(3), 23), ] ); } @@ -5247,9 +5267,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1), + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 1), ]) }); @@ -5268,9 +5288,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 4), - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 4), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 4) + DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 4), + DisplayPoint::new(DisplayRow(1), 3)..DisplayPoint::new(DisplayRow(1), 4), + DisplayPoint::new(DisplayRow(2), 3)..DisplayPoint::new(DisplayRow(2), 4) ] ); @@ -5289,9 +5309,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1) + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 1) ] ); @@ -5310,9 +5330,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1) + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1) ] ); @@ -5329,9 +5349,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1) + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 1) ] ); @@ -5350,9 +5370,9 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { assert_eq!( view.selections.display_ranges(cx), [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1) + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(1), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(2), 1)..DisplayPoint::new(DisplayRow(2), 1) ] ); }); @@ -7370,9 +7390,9 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) { _ = view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3), - DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4), + DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 3), + DisplayPoint::new(DisplayRow(2), 5)..DisplayPoint::new(DisplayRow(2), 5), + DisplayPoint::new(DisplayRow(4), 4)..DisplayPoint::new(DisplayRow(4), 4), ]) }); view.newline(&Newline, cx); @@ -7447,19 +7467,19 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) { highlighted_ranges, &[ ( - DisplayPoint::new(4, 2)..DisplayPoint::new(4, 4), + DisplayPoint::new(DisplayRow(4), 2)..DisplayPoint::new(DisplayRow(4), 4), Hsla::red(), ), ( - DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5), + DisplayPoint::new(DisplayRow(6), 3)..DisplayPoint::new(DisplayRow(6), 5), Hsla::red(), ), ( - DisplayPoint::new(3, 2)..DisplayPoint::new(3, 5), + DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(3), 5), Hsla::green(), ), ( - DisplayPoint::new(5, 3)..DisplayPoint::new(5, 6), + DisplayPoint::new(DisplayRow(5), 3)..DisplayPoint::new(DisplayRow(5), 6), Hsla::green(), ), ] @@ -7471,7 +7491,7 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) { cx.theme().colors(), ), &[( - DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5), + DisplayPoint::new(DisplayRow(6), 3)..DisplayPoint::new(DisplayRow(6), 5), Hsla::red(), )] ); @@ -7597,7 +7617,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) { // Creating a pending selection that precedes another selection _ = leader.update(cx, |leader, cx| { leader.change_selections(None, cx, |s| s.select_ranges([1..1])); - leader.begin_selection(DisplayPoint::new(0, 0), true, 1, cx); + leader.begin_selection(DisplayPoint::new(DisplayRow(0), 0), true, 1, cx); }); follower .update(cx, |follower, cx| { @@ -7613,7 +7633,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) { // Extend the pending selection so that it surrounds another selection _ = leader.update(cx, |leader, cx| { - leader.extend_selection(DisplayPoint::new(0, 2), 1, cx); + leader.extend_selection(DisplayPoint::new(DisplayRow(0), 2), 1, cx); }); follower .update(cx, |follower, cx| { @@ -9497,19 +9517,23 @@ async fn test_toggle_hunk_diff(executor: BackgroundExecutor, cx: &mut gpui::Test ( "use some::mod;\n".to_string(), DiffHunkStatus::Modified, - 0..1, + DisplayRow(0)..DisplayRow(1), ), ( "const A: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 2..2, + DisplayRow(2)..DisplayRow(2), ), ( " println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, - 4..5, + DisplayRow(4)..DisplayRow(5), + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(6)..DisplayRow(7), ), - ("".to_string(), DiffHunkStatus::Added, 6..7), ]; cx.update_editor(|editor, cx| { let snapshot = editor.snapshot(cx); @@ -9544,16 +9568,16 @@ async fn test_toggle_hunk_diff(executor: BackgroundExecutor, cx: &mut gpui::Test let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![1..=1, 7..=7, 9..=9], + vec![DisplayRow(1)..=DisplayRow(1), DisplayRow(7)..=DisplayRow(7), DisplayRow(9)..=DisplayRow(9)], "After expanding, all git additions should be highlighted for Modified (split into added and removed) and Added hunks" ); assert_eq!( all_hunks, vec![ - ("use some::mod;\n".to_string(), DiffHunkStatus::Modified, 1..2), - ("const A: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, 4..4), - (" println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, 7..8), - ("".to_string(), DiffHunkStatus::Added, 9..10), + ("use some::mod;\n".to_string(), DiffHunkStatus::Modified, DisplayRow(1)..DisplayRow(2)), + ("const A: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, DisplayRow(4)..DisplayRow(4)), + (" println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, DisplayRow(7)..DisplayRow(8)), + ("".to_string(), DiffHunkStatus::Added, DisplayRow(9)..DisplayRow(10)), ], "After expanding, all hunks' display rows should have shifted by the amount of deleted lines added \ (from modified and removed hunks)" @@ -9641,19 +9665,23 @@ async fn test_toggled_diff_base_change( ( "use some::mod1;\n".to_string(), DiffHunkStatus::Removed, - 0..0 + DisplayRow(0)..DisplayRow(0) ), ( "const B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 3..3 + DisplayRow(3)..DisplayRow(3) ), ( "fn main(Ė‡) {\n println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, - 5..7 + DisplayRow(5)..DisplayRow(7) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(9)..DisplayRow(11) ), - ("".to_string(), DiffHunkStatus::Added, 9..11), ] ); }); @@ -9685,16 +9713,16 @@ async fn test_toggled_diff_base_change( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![9..=10, 13..=14], + vec![DisplayRow(9)..=DisplayRow(10), DisplayRow(13)..=DisplayRow(14)], "After expanding, all git additions should be highlighted for Modified (split into added and removed) and Added hunks" ); assert_eq!( all_hunks, vec![ - ("use some::mod1;\n".to_string(), DiffHunkStatus::Removed, 1..1), - ("const B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, 5..5), - ("fn main(Ė‡) {\n println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, 9..11), - ("".to_string(), DiffHunkStatus::Added, 13..15), + ("use some::mod1;\n".to_string(), DiffHunkStatus::Removed, DisplayRow(1)..DisplayRow(1)), + ("const B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, DisplayRow(5)..DisplayRow(5)), + ("fn main(Ė‡) {\n println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, DisplayRow(9)..DisplayRow(11)), + ("".to_string(), DiffHunkStatus::Added, DisplayRow(13)..DisplayRow(15)), ], "After expanding, all hunks' display rows should have shifted by the amount of deleted lines added \ (from modified and removed hunks)" @@ -9727,7 +9755,7 @@ async fn test_toggled_diff_base_change( vec![( "new diff base!".to_string(), DiffHunkStatus::Modified, - 0..snapshot.display_snapshot.max_point().row() + DisplayRow(0)..snapshot.display_snapshot.max_point().row() )], "After diff base is changed, hunks should update" ); @@ -9801,24 +9829,32 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test ( "use some::mod1;\n".to_string(), DiffHunkStatus::Removed, - 0..0 + DisplayRow(0)..DisplayRow(0) ), ( "const B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 3..3 + DisplayRow(3)..DisplayRow(3) ), ( "fn main(Ė‡) {\n println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, - 5..7 + DisplayRow(5)..DisplayRow(7) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(9)..DisplayRow(11) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(15)..DisplayRow(16) ), - ("".to_string(), DiffHunkStatus::Added, 9..11), - ("".to_string(), DiffHunkStatus::Added, 15..16), ( "fn another2() {\n".to_string(), DiffHunkStatus::Removed, - 18..18 + DisplayRow(18)..DisplayRow(18) ), ] ); @@ -9859,7 +9895,11 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![9..=10, 13..=14, 19..=19] + vec![ + DisplayRow(9)..=DisplayRow(10), + DisplayRow(13)..=DisplayRow(14), + DisplayRow(19)..=DisplayRow(19) + ] ); assert_eq!( all_hunks, @@ -9867,24 +9907,32 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test ( "use some::mod1;\n".to_string(), DiffHunkStatus::Removed, - 1..1 + DisplayRow(1)..DisplayRow(1) ), ( "const B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 5..5 + DisplayRow(5)..DisplayRow(5) ), ( "fn main(Ė‡) {\n println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, - 9..11 + DisplayRow(9)..DisplayRow(11) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(13)..DisplayRow(15) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(19)..DisplayRow(20) ), - ("".to_string(), DiffHunkStatus::Added, 13..15), - ("".to_string(), DiffHunkStatus::Added, 19..20), ( "fn another2() {\n".to_string(), DiffHunkStatus::Removed, - 23..23 + DisplayRow(23)..DisplayRow(23) ), ], ); @@ -9924,7 +9972,7 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![0..=0, 5..=5], + vec![DisplayRow(0)..=DisplayRow(0), DisplayRow(5)..=DisplayRow(5)], "Only one hunk is left not folded, its highlight should be visible" ); assert_eq!( @@ -9933,24 +9981,32 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test ( "use some::mod1;\n".to_string(), DiffHunkStatus::Removed, - 0..0 + DisplayRow(0)..DisplayRow(0) ), ( "const B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 0..0 + DisplayRow(0)..DisplayRow(0) ), ( "fn main(Ė‡) {\n println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, - 0..0 + DisplayRow(0)..DisplayRow(0) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(0)..DisplayRow(1) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(5)..DisplayRow(6) ), - ("".to_string(), DiffHunkStatus::Added, 0..1), - ("".to_string(), DiffHunkStatus::Added, 5..6), ( "fn another2() {\n".to_string(), DiffHunkStatus::Removed, - 9..9 + DisplayRow(9)..DisplayRow(9) ), ], "Hunk list should still return shifted folded hunks" @@ -9958,11 +10014,15 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test assert_eq!( all_expanded_hunks, vec![ - ("".to_string(), DiffHunkStatus::Added, 5..6), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(5)..DisplayRow(6) + ), ( "fn another2() {\n".to_string(), DiffHunkStatus::Removed, - 9..9 + DisplayRow(9)..DisplayRow(9) ), ], "Only non-folded hunks should be left expanded" @@ -10005,7 +10065,11 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![9..=10, 13..=14, 19..=19], + vec![ + DisplayRow(9)..=DisplayRow(10), + DisplayRow(13)..=DisplayRow(14), + DisplayRow(19)..=DisplayRow(19) + ], "After unfolding, all hunk diffs should be visible again" ); assert_eq!( @@ -10014,24 +10078,32 @@ async fn test_fold_unfold_diff(executor: BackgroundExecutor, cx: &mut gpui::Test ( "use some::mod1;\n".to_string(), DiffHunkStatus::Removed, - 1..1 + DisplayRow(1)..DisplayRow(1) ), ( "const B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 5..5 + DisplayRow(5)..DisplayRow(5) ), ( "fn main(Ė‡) {\n println!(\"hello\");\n".to_string(), DiffHunkStatus::Modified, - 9..11 + DisplayRow(9)..DisplayRow(11) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(13)..DisplayRow(15) + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(19)..DisplayRow(20) ), - ("".to_string(), DiffHunkStatus::Added, 13..15), - ("".to_string(), DiffHunkStatus::Added, 19..20), ( "fn another2() {\n".to_string(), DiffHunkStatus::Removed, - 23..23 + DisplayRow(23)..DisplayRow(23) ), ], ); @@ -10158,14 +10230,38 @@ async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext) cx.executor().run_until_parked(); let expected_all_hunks = vec![ - ("bbbb\n".to_string(), DiffHunkStatus::Removed, 3..3), - ("nnnn\n".to_string(), DiffHunkStatus::Modified, 16..17), - ("".to_string(), DiffHunkStatus::Added, 31..32), + ( + "bbbb\n".to_string(), + DiffHunkStatus::Removed, + DisplayRow(3)..DisplayRow(3), + ), + ( + "nnnn\n".to_string(), + DiffHunkStatus::Modified, + DisplayRow(16)..DisplayRow(17), + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(31)..DisplayRow(32), + ), ]; let expected_all_hunks_shifted = vec![ - ("bbbb\n".to_string(), DiffHunkStatus::Removed, 4..4), - ("nnnn\n".to_string(), DiffHunkStatus::Modified, 18..19), - ("".to_string(), DiffHunkStatus::Added, 33..34), + ( + "bbbb\n".to_string(), + DiffHunkStatus::Removed, + DisplayRow(4)..DisplayRow(4), + ), + ( + "nnnn\n".to_string(), + DiffHunkStatus::Modified, + DisplayRow(18)..DisplayRow(19), + ), + ( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(33)..DisplayRow(34), + ), ]; multi_buffer_editor.update(cx, |editor, cx| { @@ -10188,7 +10284,10 @@ async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext) let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![18..=18, 33..=33], + vec![ + DisplayRow(18)..=DisplayRow(18), + DisplayRow(33)..=DisplayRow(33) + ], ); assert_eq!(all_hunks, expected_all_hunks_shifted); assert_eq!(all_hunks, all_expanded_hunks); @@ -10217,7 +10316,10 @@ async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext) let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![18..=18, 33..=33], + vec![ + DisplayRow(18)..=DisplayRow(18), + DisplayRow(33)..=DisplayRow(33) + ], ); assert_eq!(all_hunks, expected_all_hunks_shifted); assert_eq!(all_hunks, all_expanded_hunks); @@ -10286,7 +10388,11 @@ async fn test_edits_around_toggled_additions( let all_hunks = editor_hunks(editor, &snapshot, cx); assert_eq!( all_hunks, - vec![("".to_string(), DiffHunkStatus::Added, 4..7)] + vec![( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(4)..DisplayRow(7) + )] ); }); cx.update_editor(|editor, cx| { @@ -10317,11 +10423,15 @@ async fn test_edits_around_toggled_additions( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( all_hunks, - vec![("".to_string(), DiffHunkStatus::Added, 4..7)] + vec![( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(4)..DisplayRow(7) + )] ); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![4..=6] + vec![DisplayRow(4)..=DisplayRow(6)] ); assert_eq!(all_hunks, all_expanded_hunks); }); @@ -10353,11 +10463,15 @@ async fn test_edits_around_toggled_additions( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( all_hunks, - vec![("".to_string(), DiffHunkStatus::Added, 4..8)] + vec![( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(4)..DisplayRow(8) + )] ); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![4..=6], + vec![DisplayRow(4)..=DisplayRow(6)], "Edited hunk should have one more line added" ); assert_eq!( @@ -10394,11 +10508,15 @@ async fn test_edits_around_toggled_additions( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( all_hunks, - vec![("".to_string(), DiffHunkStatus::Added, 4..9)] + vec![( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(4)..DisplayRow(9) + )] ); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![4..=6], + vec![DisplayRow(4)..=DisplayRow(6)], "Edited hunk should have one more line added" ); assert_eq!(all_hunks, all_expanded_hunks); @@ -10434,11 +10552,15 @@ async fn test_edits_around_toggled_additions( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( all_hunks, - vec![("".to_string(), DiffHunkStatus::Added, 4..8)] + vec![( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(4)..DisplayRow(8) + )] ); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![4..=6], + vec![DisplayRow(4)..=DisplayRow(6)], "Deleting a line should shrint the hunk" ); assert_eq!( @@ -10478,11 +10600,15 @@ async fn test_edits_around_toggled_additions( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( all_hunks, - vec![("".to_string(), DiffHunkStatus::Added, 5..6)] + vec![( + "".to_string(), + DiffHunkStatus::Added, + DisplayRow(5)..DisplayRow(6) + )] ); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![5..=5] + vec![DisplayRow(5)..=DisplayRow(5)] ); assert_eq!(all_hunks, all_expanded_hunks); }); @@ -10514,12 +10640,12 @@ async fn test_edits_around_toggled_additions( ( "use some::mod1;\nuse some::mod2;\n".to_string(), DiffHunkStatus::Removed, - 0..0 + DisplayRow(0)..DisplayRow(0) ), ( "const A: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 2..2 + DisplayRow(2)..DisplayRow(2) ) ] ); @@ -10533,7 +10659,7 @@ async fn test_edits_around_toggled_additions( vec![( "const A: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 2..2 + DisplayRow(2)..DisplayRow(2) )], "Should open hunks that were adjacent to the stale addition one" ); @@ -10594,7 +10720,7 @@ async fn test_edits_around_toggled_deletions( vec![( "const A: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 3..3 + DisplayRow(3)..DisplayRow(3) )] ); }); @@ -10629,7 +10755,7 @@ async fn test_edits_around_toggled_deletions( vec![( "const A: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 4..4 + DisplayRow(4)..DisplayRow(4) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -10669,7 +10795,7 @@ async fn test_edits_around_toggled_deletions( vec![( "const A: u32 = 42;\nconst B: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 5..5 + DisplayRow(5)..DisplayRow(5) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -10704,7 +10830,7 @@ async fn test_edits_around_toggled_deletions( vec![( "const A: u32 = 42;\nconst B: u32 = 42;\nconst C: u32 = 42;\n".to_string(), DiffHunkStatus::Removed, - 6..6 + DisplayRow(6)..DisplayRow(6) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -10738,12 +10864,12 @@ async fn test_edits_around_toggled_deletions( vec![( "const A: u32 = 42;\nconst B: u32 = 42;\nconst C: u32 = 42;\n\n".to_string(), DiffHunkStatus::Modified, - 7..8 + DisplayRow(7)..DisplayRow(8) )] ); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![7..=7], + vec![DisplayRow(7)..=DisplayRow(7)], "Modified expanded hunks should display additions and highlight their background" ); assert_eq!(all_hunks, all_expanded_hunks); @@ -10805,7 +10931,7 @@ async fn test_edits_around_toggled_modifications( vec![( "const C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 5..6 + DisplayRow(5)..DisplayRow(6) )] ); }); @@ -10837,14 +10963,14 @@ async fn test_edits_around_toggled_modifications( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![6..=6], + vec![DisplayRow(6)..=DisplayRow(6)], ); assert_eq!( all_hunks, vec![( "const C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 6..7 + DisplayRow(6)..DisplayRow(7) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -10880,7 +11006,7 @@ async fn test_edits_around_toggled_modifications( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![6..=6], + vec![DisplayRow(6)..=DisplayRow(6)], "Modified hunk should grow highlighted lines on more text additions" ); assert_eq!( @@ -10888,7 +11014,7 @@ async fn test_edits_around_toggled_modifications( vec![( "const C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 6..9 + DisplayRow(6)..DisplayRow(9) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -10926,14 +11052,14 @@ async fn test_edits_around_toggled_modifications( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![6..=8], + vec![DisplayRow(6)..=DisplayRow(8)], ); assert_eq!( all_hunks, vec![( "const B: u32 = 42;\nconst C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 6..9 + DisplayRow(6)..DisplayRow(9) )], "Modified hunk should grow deleted lines on text deletions above" ); @@ -10970,7 +11096,7 @@ async fn test_edits_around_toggled_modifications( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![6..=9], + vec![DisplayRow(6)..=DisplayRow(9)], "Modified hunk should grow deleted lines on text modifications above" ); assert_eq!( @@ -10978,7 +11104,7 @@ async fn test_edits_around_toggled_modifications( vec![( "const A: u32 = 42;\nconst B: u32 = 42;\nconst C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 6..10 + DisplayRow(6)..DisplayRow(10) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -11014,7 +11140,7 @@ async fn test_edits_around_toggled_modifications( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![6..=8], + vec![DisplayRow(6)..=DisplayRow(8)], "Modified hunk should grow shrink lines on modification lines removal" ); assert_eq!( @@ -11022,7 +11148,7 @@ async fn test_edits_around_toggled_modifications( vec![( "const A: u32 = 42;\nconst B: u32 = 42;\nconst C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 6..9 + DisplayRow(6)..DisplayRow(9) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -11064,7 +11190,7 @@ async fn test_edits_around_toggled_modifications( "const A: u32 = 42;\nconst B: u32 = 42;\nconst C: u32 = 42;\nconst D: u32 = 42;\n" .to_string(), DiffHunkStatus::Removed, - 7..7 + DisplayRow(7)..DisplayRow(7) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -11126,7 +11252,7 @@ async fn test_multiple_expanded_hunks_merge( vec![( "const C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 5..6 + DisplayRow(5)..DisplayRow(6) )] ); }); @@ -11158,14 +11284,14 @@ async fn test_multiple_expanded_hunks_merge( let all_expanded_hunks = expanded_hunks(&editor, &snapshot, cx); assert_eq!( expanded_hunks_background_highlights(editor, cx), - vec![6..=6], + vec![DisplayRow(6)..=DisplayRow(6)], ); assert_eq!( all_hunks, vec![( "const C: u32 = 42;\n".to_string(), DiffHunkStatus::Modified, - 6..7 + DisplayRow(6)..DisplayRow(7) )] ); assert_eq!(all_hunks, all_expanded_hunks); @@ -11198,7 +11324,7 @@ async fn test_multiple_expanded_hunks_merge( } fn empty_range(row: usize, column: usize) -> Range { - let point = DisplayPoint::new(row as u32, column as u32); + let point = DisplayPoint::new(DisplayRow(row as u32), column as u32); point..point } @@ -11367,16 +11493,10 @@ fn assert_hunk_revert( cx.executor().run_until_parked(); let reverted_hunk_statuses = cx.update_editor(|editor, cx| { - let snapshot = editor - .buffer() - .read(cx) - .as_singleton() - .unwrap() - .read(cx) - .snapshot(); + let snapshot = editor.buffer().read(cx).snapshot(cx); let reverted_hunk_statuses = snapshot - .git_diff_hunks_in_row_range(0..u32::MAX) - .map(|hunk| hunk.status()) + .git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX) + .map(|hunk| hunk_status(&hunk)) .collect::>(); editor.revert_selected_hunks(&RevertSelectedHunks, cx); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 93653f45de..66a46425dc 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -9,14 +9,15 @@ use crate::{ hover_popover::{ self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT, }, + hunk_status, items::BufferSearchHighlights, mouse_context_menu::{self, MouseContextMenu}, scroll::scroll_amount::ScrollAmount, - CodeActionsMenu, CursorShape, DisplayPoint, DocumentHighlightRead, DocumentHighlightWrite, - Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, - GutterDimensions, HalfPageDown, HalfPageUp, HoveredCursor, HunkToExpand, LineDown, LineUp, - OpenExcerpts, PageDown, PageUp, Point, SelectPhase, Selection, SoftWrap, ToPoint, - CURSORS_VISIBLE_FOR, MAX_LINE_LEN, + CodeActionsMenu, CursorShape, DisplayPoint, DisplayRow, DocumentHighlightRead, + DocumentHighlightWrite, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, + ExpandExcerpts, GutterDimensions, HalfPageDown, HalfPageUp, HoveredCursor, HunkToExpand, + LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, + Selection, SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN, }; use anyhow::Result; use client::ParticipantIndex; @@ -35,7 +36,7 @@ use gpui::{ use itertools::Itertools; use language::language_settings::ShowWhitespaceSetting; use lsp::DiagnosticSeverity; -use multi_buffer::Anchor; +use multi_buffer::{Anchor, MultiBufferPoint, MultiBufferRow}; use project::{ project_settings::{GitGutterSetting, ProjectSettings}, ProjectPath, @@ -64,7 +65,7 @@ struct SelectionLayout { is_newest: bool, is_local: bool, range: Range, - active_rows: Range, + active_rows: Range, user_name: Option, } @@ -98,16 +99,19 @@ impl SelectionLayout { { if head.column() > 0 { head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left) - } else if head.row() > 0 && head != map.max_point() { + } else if head.row().0 > 0 && head != map.max_point() { head = map.clip_point( - DisplayPoint::new(head.row() - 1, map.line_len(head.row() - 1)), + DisplayPoint::new( + head.row().previous_row(), + map.line_len(head.row().previous_row()), + ), Bias::Left, ); // updating range.end is a no-op unless you're cursor is // on the newline containing a multi-buffer divider // in which case the clip_point may have moved the head up // an additional row. - range.end = DisplayPoint::new(head.row() + 1, 0); + range.end = DisplayPoint::new(head.row().next_row(), 0); active_rows.end = head.row(); } } @@ -129,6 +133,8 @@ pub struct EditorElement { style: EditorStyle, } +type DisplayRowDelta = u32; + impl EditorElement { pub fn new(editor: &View, style: EditorStyle) -> Self { Self { @@ -706,12 +712,12 @@ impl EditorElement { start_anchor: Anchor, end_anchor: Anchor, snapshot: &EditorSnapshot, - start_row: u32, - end_row: u32, + start_row: DisplayRow, + end_row: DisplayRow, cx: &mut WindowContext, ) -> ( Vec<(PlayerColor, Vec)>, - BTreeMap, + BTreeMap, Option, ) { let mut selections: Vec<(PlayerColor, Vec)> = Vec::new(); @@ -743,10 +749,11 @@ impl EditorElement { newest_selection_head = Some(layout.head); } - for row in cmp::max(layout.active_rows.start, start_row) - ..=cmp::min(layout.active_rows.end, end_row) + for row in cmp::max(layout.active_rows.start.0, start_row.0) + ..=cmp::min(layout.active_rows.end.0, end_row.0) { - let contains_non_empty_selection = active_rows.entry(row).or_insert(!is_empty); + let contains_non_empty_selection = + active_rows.entry(DisplayRow(row)).or_insert(!is_empty); *contains_non_empty_selection |= !is_empty; } layouts.push(layout); @@ -826,7 +833,7 @@ impl EditorElement { snapshot: &EditorSnapshot, content_origin: gpui::Point, visible_anchor_range: Range, - visible_display_row_range: Range, + visible_display_row_range: Range, scroll_pixel_position: gpui::Point, line_height: Pixels, line_layouts: &[LineWithInvisibles], @@ -842,13 +849,14 @@ impl EditorElement { let row = display_range.start.row(); debug_assert!(row < visible_display_row_range.end); let line_layout = line_layouts - .get((row - visible_display_row_range.start) as usize) + .get(row.minus(visible_display_row_range.start) as usize) .map(|l| &l.line)?; let start_x = content_origin.x + line_layout.x_for_index(display_range.start.column() as usize) - scroll_pixel_position.x; - let start_y = content_origin.y + row as f32 * line_height - scroll_pixel_position.y; + let start_y = + content_origin.y + row.as_f32() * line_height - scroll_pixel_position.y; let end_x = content_origin.x + line_layout.x_for_index(display_range.end.column() as usize) - scroll_pixel_position.x; @@ -927,7 +935,7 @@ impl EditorElement { &self, snapshot: &EditorSnapshot, selections: &[(PlayerColor, Vec)], - visible_display_row_range: Range, + visible_display_row_range: Range, line_layouts: &[LineWithInvisibles], text_hitbox: &Hitbox, content_origin: gpui::Point, @@ -951,7 +959,7 @@ impl EditorElement { } let cursor_row_layout = &line_layouts - [(cursor_position.row() - visible_display_row_range.start) as usize] + [cursor_position.row().minus(visible_display_row_range.start) as usize] .line; let cursor_column = cursor_position.column() as usize; @@ -999,7 +1007,8 @@ impl EditorElement { }; let x = cursor_character_x - scroll_pixel_position.x; - let y = (cursor_position.row() as f32 - scroll_pixel_position.y / line_height) + let y = (cursor_position.row().as_f32() + - scroll_pixel_position.y / line_height) * line_height; if selection.is_newest { editor.pixel_position_of_newest_cursor = Some(point( @@ -1009,7 +1018,7 @@ impl EditorElement { if autoscroll_containing_element { let top = text_hitbox.origin.y - + (cursor_position.row() as f32 - scroll_position.y - 3.).max(0.) + + (cursor_position.row().as_f32() - scroll_position.y - 3.).max(0.) * line_height; let left = text_hitbox.origin.x + (cursor_position.column() as f32 - scroll_position.x - 3.) @@ -1017,7 +1026,7 @@ impl EditorElement { * em_width; let bottom = text_hitbox.origin.y - + (cursor_position.row() as f32 - scroll_position.y + 4.) + + (cursor_position.row().as_f32() - scroll_position.y + 4.) * line_height; let right = text_hitbox.origin.x + (cursor_position.column() as f32 - scroll_position.x + 4.) @@ -1040,7 +1049,7 @@ impl EditorElement { let cursor_name = selection.user_name.clone().map(|name| CursorName { string: name, color: self.style.background, - is_top_row: cursor_position.row() == 0, + is_top_row: cursor_position.row().0 == 0, }); cursor.layout(content_origin, cursor_name, cx); cursors.push(cursor); @@ -1112,10 +1121,10 @@ impl EditorElement { ); let height = bounds.size.height; - let total_rows = snapshot.max_point().row() as f32 + rows_per_page; + let total_rows = snapshot.max_point().row().as_f32() + rows_per_page; let px_per_row = height / total_rows; let thumb_height = (rows_per_page * px_per_row).max(ScrollbarLayout::MIN_THUMB_HEIGHT); - let row_height = (height - thumb_height) / snapshot.max_point().row() as f32; + let row_height = (height - thumb_height) / snapshot.max_point().row().as_f32(); Some(ScrollbarLayout { hitbox: cx.insert_hitbox(track_bounds, false), @@ -1129,7 +1138,7 @@ impl EditorElement { #[allow(clippy::too_many_arguments)] fn layout_gutter_fold_indicators( &self, - fold_statuses: Vec>, + fold_statuses: Vec>, line_height: Pixels, gutter_dimensions: &GutterDimensions, gutter_settings: crate::editor_settings::Gutter, @@ -1181,18 +1190,22 @@ impl EditorElement { &self, line_height: Pixels, gutter_hitbox: &Hitbox, - display_rows: Range, + display_rows: Range, snapshot: &EditorSnapshot, cx: &mut WindowContext, ) -> Vec<(DisplayDiffHunk, Option)> { let buffer_snapshot = &snapshot.buffer_snapshot; - let buffer_start_row = DisplayPoint::new(display_rows.start, 0) - .to_point(snapshot) - .row; - let buffer_end_row = DisplayPoint::new(display_rows.end, 0) - .to_point(snapshot) - .row; + let buffer_start_row = MultiBufferRow( + DisplayPoint::new(display_rows.start, 0) + .to_point(snapshot) + .row, + ); + let buffer_end_row = MultiBufferRow( + DisplayPoint::new(display_rows.end, 0) + .to_point(snapshot) + .row, + ); let expanded_hunk_display_rows = self.editor.update(cx, |editor, _| { editor @@ -1249,7 +1262,7 @@ impl EditorElement { #[allow(clippy::too_many_arguments)] fn layout_inline_blame( &self, - display_row: u32, + display_row: DisplayRow, display_snapshot: &DisplaySnapshot, line_layout: &LineWithInvisibles, em_width: Pixels, @@ -1273,7 +1286,7 @@ impl EditorElement { .map(|(w, _)| w.clone()); let display_point = DisplayPoint::new(display_row, 0); - let buffer_row = display_point.to_point(display_snapshot).row; + let buffer_row = MultiBufferRow(display_point.to_point(display_snapshot).row); let blame = self.editor.read(cx).blame.clone()?; let blame_entry = blame @@ -1286,7 +1299,7 @@ impl EditorElement { render_inline_blame_entry(&blame, blame_entry, &self.style, workspace, cx); let start_y = content_origin.y - + line_height * (display_row as f32 - scroll_pixel_position.y / line_height); + + line_height * (display_row.as_f32() - scroll_pixel_position.y / line_height); let start_x = { const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 6.; @@ -1315,7 +1328,7 @@ impl EditorElement { #[allow(clippy::too_many_arguments)] fn layout_blame_entries( &self, - buffer_rows: impl Iterator>, + buffer_rows: impl Iterator>, em_width: Pixels, scroll_position: gpui::Point, line_height: Pixels, @@ -1399,7 +1412,7 @@ impl EditorElement { actions .tasks .as_ref() - .map(|tasks| tasks.position.row) + .map(|tasks| tasks.position.to_display_point(snapshot).row()) .or_else(|| *deployed_from_indicator) } else { None @@ -1407,19 +1420,16 @@ impl EditorElement { editor .tasks .iter() - .filter_map(|((_, row), (multibuffer_offset, _))| { - if snapshot.is_line_folded(*row) { + .filter_map(|(_, (multibuffer_offset, _))| { + let multibuffer_point = multibuffer_offset.to_point(&snapshot.buffer_snapshot); + let multibuffer_row = MultiBufferRow(multibuffer_point.row); + if snapshot.is_line_folded(multibuffer_row) { return None; } - let display_row = snapshot - .buffer_snapshot - .offset_to_point(*multibuffer_offset) - .to_display_point(&snapshot.display_snapshot) - .row(); - + let display_row = multibuffer_point.to_display_point(snapshot).row(); let button = editor.render_run_indicator( &self.style, - Some(*row) == active_task_indicator_row, + Some(display_row) == active_task_indicator_row, display_row, cx, ); @@ -1489,10 +1499,10 @@ impl EditorElement { fn calculate_relative_line_numbers( &self, snapshot: &EditorSnapshot, - rows: &Range, - relative_to: Option, - ) -> HashMap { - let mut relative_rows: HashMap = Default::default(); + rows: &Range, + relative_to: Option, + ) -> HashMap { + let mut relative_rows: HashMap = Default::default(); let Some(relative_to) = relative_to else { return relative_rows; }; @@ -1501,17 +1511,17 @@ impl EditorElement { let end = rows.end.max(relative_to); let buffer_rows = snapshot - .buffer_rows(start) - .take(1 + (end - start) as usize) + .display_rows(start) + .take(1 + end.minus(start) as usize) .collect::>(); - let head_idx = relative_to - start; + let head_idx = relative_to.minus(start); let mut delta = 1; let mut i = head_idx + 1; while i < buffer_rows.len() as u32 { if buffer_rows[i as usize].is_some() { - if rows.contains(&(i + start)) { - relative_rows.insert(i + start, delta); + if rows.contains(&DisplayRow(i + start.0)) { + relative_rows.insert(DisplayRow(i + start.0), delta); } delta += 1; } @@ -1526,8 +1536,8 @@ impl EditorElement { while i > 0 { i -= 1; if buffer_rows[i as usize].is_some() { - if rows.contains(&(i + start)) { - relative_rows.insert(i + start, delta); + if rows.contains(&DisplayRow(i + start.0)) { + relative_rows.insert(DisplayRow(i + start.0), delta); } delta += 1; } @@ -1538,15 +1548,15 @@ impl EditorElement { fn layout_line_numbers( &self, - rows: Range, - buffer_rows: impl Iterator>, - active_rows: &BTreeMap, + rows: Range, + buffer_rows: impl Iterator>, + active_rows: &BTreeMap, newest_selection_head: Option, snapshot: &EditorSnapshot, cx: &WindowContext, ) -> ( Vec>, - Vec>, + Vec>, ) { let editor = self.editor.read(cx); let is_singleton = editor.is_singleton(cx); @@ -1581,20 +1591,20 @@ impl EditorElement { let relative_rows = self.calculate_relative_line_numbers(snapshot, &rows, relative_to); for (ix, row) in buffer_rows.into_iter().enumerate() { - let display_row = rows.start + ix as u32; + let display_row = DisplayRow(rows.start.0 + ix as u32); let (active, color) = if active_rows.contains_key(&display_row) { (true, cx.theme().colors().editor_active_line_number) } else { (false, cx.theme().colors().editor_line_number) }; - if let Some(buffer_row) = row { + if let Some(display_row) = row { if include_line_numbers { line_number.clear(); - let default_number = buffer_row + 1; + let default_number = display_row.0 + 1; let number = relative_rows - .get(&(ix as u32 + rows.start)) + .get(&DisplayRow(ix as u32 + rows.start.0)) .unwrap_or(&default_number); - write!(&mut line_number, "{}", number).unwrap(); + write!(&mut line_number, "{number}").unwrap(); let run = TextRun { len: line_number.len(), font: self.style.text.font(), @@ -1613,9 +1623,12 @@ impl EditorElement { fold_statuses.push( is_singleton .then(|| { + let multibuffer_point = + DisplayPoint::new(display_row, 0).to_point(snapshot); + let multibuffer_row = MultiBufferRow(multibuffer_point.row); snapshot - .fold_for_line(buffer_row) - .map(|fold_status| (fold_status, buffer_row, active)) + .fold_for_line(multibuffer_row) + .map(|fold_status| (fold_status, multibuffer_row, active)) }) .flatten(), ) @@ -1631,7 +1644,7 @@ impl EditorElement { fn layout_lines( &self, - rows: Range, + rows: Range, line_number_layouts: &[Option], snapshot: &EditorSnapshot, cx: &WindowContext, @@ -1650,7 +1663,7 @@ impl EditorElement { .as_ref() .map_or("", AsRef::as_ref) .split('\n') - .skip(rows.start as usize) + .skip(rows.start.0 as usize) .chain(iter::repeat("")) .take(rows.len()); placeholder_lines @@ -1689,7 +1702,7 @@ impl EditorElement { #[allow(clippy::too_many_arguments)] fn build_blocks( &self, - rows: Range, + rows: Range, snapshot: &EditorSnapshot, hitbox: &Hitbox, text_hitbox: &Hitbox, @@ -1712,7 +1725,7 @@ impl EditorElement { let render_block = |block: &TransformBlock, available_space: Size, block_id: usize, - block_row_start: u32, + block_row_start: DisplayRow, cx: &mut WindowContext| { let mut element = match block { TransformBlock::Custom(block) => { @@ -1722,7 +1735,7 @@ impl EditorElement { .to_display_point(snapshot); let anchor_x = text_x + if rows.contains(&align_to.row()) { - line_layouts[(align_to.row() - rows.start) as usize] + line_layouts[align_to.row().minus(rows.start) as usize] .line .x_for_index(align_to.column() as usize) } else { @@ -1788,7 +1801,7 @@ impl EditorElement { }; let line_offset_from_top = - block_row_start + *height as u32 + offset_from_excerpt_start + block_row_start.0 + *height as u32 + offset_from_excerpt_start - snapshot .scroll_anchor .scroll_position(&snapshot.display_snapshot) @@ -2040,7 +2053,7 @@ impl EditorElement { let mut origin = hitbox.origin + point( Pixels::ZERO, - block.row as f32 * line_height - scroll_pixel_position.y, + block.row.as_f32() * line_height - scroll_pixel_position.y, ); if !matches!(block.style, BlockStyle::Sticky) { origin += point(-scroll_pixel_position.x, Pixels::ZERO); @@ -2058,7 +2071,7 @@ impl EditorElement { hitbox: &Hitbox, text_hitbox: &Hitbox, content_origin: gpui::Point, - start_row: u32, + start_row: DisplayRow, scroll_pixel_position: gpui::Point, line_layouts: &[LineWithInvisibles], newest_selection_head: DisplayPoint, @@ -2084,21 +2097,17 @@ impl EditorElement { let (x, y) = match position { crate::ContextMenuOrigin::EditorPoint(point) => { - let cursor_row_layout = &line_layouts[(point.row() - start_row) as usize].line; + let cursor_row_layout = &line_layouts[point.row().minus(start_row) as usize].line; let x = cursor_row_layout.x_for_index(point.column() as usize) - scroll_pixel_position.x; - let y = (point.row() + 1) as f32 * line_height - scroll_pixel_position.y; + let y = point.row().next_row().as_f32() * line_height - scroll_pixel_position.y; (x, y) } crate::ContextMenuOrigin::GutterIndicator(row) => { // Context menu was spawned via a click on a gutter. Ensure it's a bit closer to the indicator than just a plain first column of the // text field. - let snapshot = self.editor.update(cx, |this, cx| this.snapshot(cx)); - let row = Point::new(row, 0) - .to_display_point(&snapshot.display_snapshot) - .row(); let x = -gutter_overshoot; - let y = (row + 1) as f32 * line_height - scroll_pixel_position.y; + let y = row.next_row().as_f32() * line_height - scroll_pixel_position.y; (x, y) } }; @@ -2143,7 +2152,7 @@ impl EditorElement { snapshot: &EditorSnapshot, hitbox: &Hitbox, text_hitbox: &Hitbox, - visible_display_row_range: Range, + visible_display_row_range: Range, content_origin: gpui::Point, scroll_pixel_position: gpui::Point, line_layouts: &[LineWithInvisibles], @@ -2184,12 +2193,12 @@ impl EditorElement { // This is safe because we check on layout whether the required row is available let hovered_row_layout = - &line_layouts[(position.row() - visible_display_row_range.start) as usize].line; + &line_layouts[position.row().minus(visible_display_row_range.start) as usize].line; // Compute Hovered Point let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_pixel_position.x; - let y = position.row() as f32 * line_height - scroll_pixel_position.y; + let y = position.row().as_f32() * line_height - scroll_pixel_position.y; let hovered_point = content_origin + point(x, y); let mut overall_height = Pixels::ZERO; @@ -2265,10 +2274,14 @@ impl EditorElement { if let EditorMode::Full = layout.mode { let mut active_rows = layout.active_rows.iter().peekable(); while let Some((start_row, contains_non_empty_selection)) = active_rows.next() { - let mut end_row = *start_row; - while active_rows.peek().map_or(false, |r| { - *r.0 == end_row + 1 && r.1 == contains_non_empty_selection - }) { + let mut end_row = start_row.0; + while active_rows + .peek() + .map_or(false, |(active_row, has_selection)| { + active_row.0 == end_row + 1 + && *has_selection == contains_non_empty_selection + }) + { active_rows.next().unwrap(); end_row += 1; } @@ -2277,12 +2290,12 @@ impl EditorElement { let origin = point( layout.hitbox.origin.x, layout.hitbox.origin.y - + (*start_row as f32 - scroll_top) + + (start_row.as_f32() - scroll_top) * layout.position_map.line_height, ); let size = size( layout.hitbox.size.width, - layout.position_map.line_height * (end_row - start_row + 1) as f32, + layout.position_map.line_height * (end_row - start_row.0 + 1) as f32, ); let active_line_bg = cx.theme().colors().editor_active_line_background; cx.paint_quad(fill(Bounds { origin, size }, active_line_bg)); @@ -2290,28 +2303,28 @@ impl EditorElement { } let mut paint_highlight = - |highlight_row_start: u32, highlight_row_end: u32, color| { + |highlight_row_start: DisplayRow, highlight_row_end: DisplayRow, color| { let origin = point( layout.hitbox.origin.x, layout.hitbox.origin.y - + (highlight_row_start as f32 - scroll_top) + + (highlight_row_start.as_f32() - scroll_top) * layout.position_map.line_height, ); let size = size( layout.hitbox.size.width, layout.position_map.line_height - * (highlight_row_end + 1 - highlight_row_start) as f32, + * highlight_row_end.next_row().minus(highlight_row_start) as f32, ); cx.paint_quad(fill(Bounds { origin, size }, color)); }; - let mut current_paint: Option<(Hsla, Range)> = None; + let mut current_paint: Option<(Hsla, Range)> = None; for (&new_row, &new_color) in &layout.highlighted_rows { match &mut current_paint { Some((current_color, current_range)) => { let current_color = *current_color; - let new_range_started = - current_color != new_color || current_range.end + 1 != new_row; + let new_range_started = current_color != new_color + || current_range.end.next_row() != new_row; if new_range_started { paint_highlight( current_range.start, @@ -2321,7 +2334,7 @@ impl EditorElement { current_paint = Some((new_color, new_row..new_row)); continue; } else { - current_range.end += 1; + current_range.end = current_range.end.next_row(); } } None => current_paint = Some((new_color, new_row..new_row)), @@ -2494,7 +2507,7 @@ impl EditorElement { match hunk { DisplayDiffHunk::Folded { display_row, .. } => { - let start_y = *display_row as f32 * line_height - scroll_top; + let start_y = display_row.as_f32() * line_height - scroll_top; let end_y = start_y + line_height; let width = 0.275 * line_height; @@ -2527,8 +2540,8 @@ impl EditorElement { }) .unwrap_or(end_row); - let start_y = start_row as f32 * line_height - scroll_top; - let end_y = end_row_in_current_excerpt as f32 * line_height - scroll_top; + let start_y = start_row.as_f32() * line_height - scroll_top; + let end_y = end_row_in_current_excerpt.as_f32() * line_height - scroll_top; let width = 0.275 * line_height; let highlight_origin = bounds.origin + point(-width, start_y); @@ -2539,7 +2552,7 @@ impl EditorElement { let row = display_row_range.start; let offset = line_height / 2.; - let start_y = row as f32 * line_height - offset - scroll_top; + let start_y = row.as_f32() * line_height - offset - scroll_top; let end_y = start_y + line_height; let width = 0.35 * line_height; @@ -2648,7 +2661,7 @@ impl EditorElement { .show_whitespaces; for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() { - let row = layout.visible_display_row_range.start + ix as u32; + let row = DisplayRow(layout.visible_display_row_range.start.0 + ix as u32); line_with_invisibles.draw( layout, row, @@ -2879,20 +2892,22 @@ impl EditorElement { if scrollbar_settings.git_diff { let marker_row_ranges = snapshot .buffer_snapshot - .git_diff_hunks_in_range(0..max_point.row) + .git_diff_hunks_in_range( + MultiBufferRow::MIN..MultiBufferRow::MAX, + ) .map(|hunk| { let start_display_row = - Point::new(hunk.associated_range.start, 0) + MultiBufferPoint::new(hunk.associated_range.start.0, 0) .to_display_point(&snapshot.display_snapshot) .row(); let mut end_display_row = - Point::new(hunk.associated_range.end, 0) + MultiBufferPoint::new(hunk.associated_range.end.0, 0) .to_display_point(&snapshot.display_snapshot) .row(); if end_display_row != start_display_row { - end_display_row -= 1; + end_display_row.0 -= 1; } - let color = match hunk.status() { + let color = match hunk_status(&hunk) { DiffHunkStatus::Added => theme.status().created, DiffHunkStatus::Modified => theme.status().modified, DiffHunkStatus::Removed => theme.status().deleted, @@ -3018,7 +3033,8 @@ impl EditorElement { let row_range = if range.end.column() == 0 { cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row) } else { - cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row) + cmp::max(range.start.row(), start_row) + ..cmp::min(range.end.row().next_row(), end_row) }; let highlighted_range = HighlightedRange { @@ -3026,13 +3042,13 @@ impl EditorElement { line_height: layout.position_map.line_height, corner_radius, start_y: layout.content_origin.y - + row_range.start as f32 * layout.position_map.line_height + + row_range.start.as_f32() * layout.position_map.line_height - layout.position_map.scroll_pixel_position.y, lines: row_range - .into_iter() + .iter_rows() .map(|row| { let line_layout = - &layout.position_map.line_layouts[(row - start_row) as usize].line; + &layout.position_map.line_layouts[row.minus(start_row) as usize].line; HighlightedRangeLine { start_x: if row == range.start.row() { layout.content_origin.x @@ -3281,14 +3297,20 @@ impl EditorElement { } fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &WindowContext) -> Pixels { - let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1; + let digit_count = snapshot + .max_buffer_row() + .next_row() + .as_f32() + .log10() + .floor() as usize + + 1; self.column_pixels(digit_count, cx) } } fn prepaint_gutter_button( button: IconButton, - row: u32, + row: DisplayRow, line_height: Pixels, gutter_dimensions: &GutterDimensions, scroll_pixel_position: gpui::Point, @@ -3312,7 +3334,7 @@ fn prepaint_gutter_button( - blame_width; x += available_width / 2.; - let mut y = row as f32 * line_height - scroll_pixel_position.y; + let mut y = row.as_f32() * line_height - scroll_pixel_position.y; y += (line_height - indicator_size.height) / 2.; button.prepaint_as_root(gutter_hitbox.origin + point(x, y), available_space, cx); @@ -3563,15 +3585,15 @@ impl LineWithInvisibles { fn draw( &self, layout: &EditorLayout, - row: u32, + row: DisplayRow, content_origin: gpui::Point, whitespace_setting: ShowWhitespaceSetting, selection_ranges: &[Range], cx: &mut WindowContext, ) { let line_height = layout.position_map.line_height; - let line_y = - line_height * (row as f32 - layout.position_map.scroll_pixel_position.y / line_height); + let line_y = line_height + * (row.as_f32() - layout.position_map.scroll_pixel_position.y / line_height); let line_origin = content_origin + gpui::point(-layout.position_map.scroll_pixel_position.x, line_y); @@ -3596,7 +3618,7 @@ impl LineWithInvisibles { layout: &EditorLayout, content_origin: gpui::Point, line_y: Pixels, - row: u32, + row: DisplayRow, line_height: Pixels, whitespace_setting: ShowWhitespaceSetting, cx: &mut WindowContext, @@ -3806,19 +3828,20 @@ impl Element for EditorElement { let mut scroll_position = snapshot.scroll_position(); // The scroll position is a fractional point, the whole number of which represents // the top of the window in terms of display rows. - let start_row = scroll_position.y as u32; + let start_row = DisplayRow(scroll_position.y as u32); let height_in_lines = bounds.size.height / line_height; let max_row = snapshot.max_point().row(); let end_row = cmp::min( (scroll_position.y + height_in_lines).ceil() as u32, - max_row + 1, + max_row.next_row().0, ); + let end_row = DisplayRow(end_row); let buffer_rows = snapshot - .buffer_rows(start_row) + .display_rows(start_row) .take((start_row..end_row).len()); - let start_anchor = if start_row == 0 { + let start_anchor = if start_row == Default::default() { Anchor::min() } else { snapshot.buffer_snapshot.anchor_before( @@ -3914,7 +3937,7 @@ impl Element for EditorElement { if let Some(newest_selection_head) = newest_selection_head { let display_row = newest_selection_head.row(); if (start_row..end_row).contains(&display_row) { - let line_layout = &line_layouts[(display_row - start_row) as usize]; + let line_layout = &line_layouts[display_row.minus(start_row) as usize]; inline_blame = self.layout_inline_blame( display_row, &snapshot.display_snapshot, @@ -3929,7 +3952,11 @@ impl Element for EditorElement { } let blamed_display_rows = self.layout_blame_entries( - buffer_rows, + buffer_rows.map(|display_row| { + display_row.map(|row| { + MultiBufferRow(DisplayPoint::new(row, 0).to_point(&snapshot).row) + }) + }), em_width, scroll_position, line_height, @@ -3940,7 +3967,7 @@ impl Element for EditorElement { let scroll_max = point( ((scroll_width - text_hitbox.size.width) / em_width).max(0.0), - max_row as f32, + max_row.as_f32(), ); self.editor.update(cx, |editor, cx| { @@ -4041,7 +4068,7 @@ impl Element for EditorElement { newest_selection_head.to_point(&snapshot.display_snapshot); let buffer = snapshot .buffer_snapshot - .buffer_line_for_row(newest_selection_point.row); + .buffer_line_for_row(MultiBufferRow(newest_selection_point.row)); if let Some((buffer, range)) = buffer { let buffer_id = buffer.remote_id(); let row = range.start.row; @@ -4263,8 +4290,6 @@ impl IntoElement for EditorElement { } } -type BufferRow = u32; - pub struct EditorLayout { position_map: Arc, hitbox: Hitbox, @@ -4275,9 +4300,9 @@ pub struct EditorLayout { scrollbar_layout: Option, mode: EditorMode, wrap_guides: SmallVec<[(Pixels, bool); 2]>, - visible_display_row_range: Range, - active_rows: BTreeMap, - highlighted_rows: BTreeMap, + visible_display_row_range: Range, + active_rows: BTreeMap, + highlighted_rows: BTreeMap, line_numbers: Vec>, display_hunks: Vec<(DisplayDiffHunk, Option)>, blamed_display_rows: Option>, @@ -4339,7 +4364,7 @@ impl ScrollbarLayout { fn marker_quads_for_ranges( &self, - row_ranges: impl IntoIterator>, + row_ranges: impl IntoIterator>, column: Option, ) -> Vec { struct MinMax { @@ -4370,7 +4395,7 @@ impl ScrollbarLayout { ) }; - let row_to_y = |row: u32| row as f32 * self.row_height; + let row_to_y = |row: DisplayRow| row.as_f32() * self.row_height; let mut pixel_ranges = row_ranges .into_iter() .map(|range| { @@ -4475,7 +4500,7 @@ impl PositionMap { (0, x) }; - let mut exact_unclipped = DisplayPoint::new(row, column); + let mut exact_unclipped = DisplayPoint::new(DisplayRow(row), column); let previous_valid = self.snapshot.clip_point(exact_unclipped, Bias::Left); let next_valid = self.snapshot.clip_point(exact_unclipped, Bias::Right); @@ -4491,14 +4516,14 @@ impl PositionMap { } struct BlockLayout { - row: u32, + row: DisplayRow, element: AnyElement, available_space: Size, style: BlockStyle, } fn layout_line( - row: u32, + row: DisplayRow, snapshot: &EditorSnapshot, style: &EditorStyle, cx: &WindowContext, @@ -4835,10 +4860,10 @@ mod tests { .update_window(*window, |_, cx| { element .layout_line_numbers( - 0..6, - (0..6).map(Some), + DisplayRow(0)..DisplayRow(6), + (0..6).map(DisplayRow).map(Some), &Default::default(), - Some(DisplayPoint::new(0, 0)), + Some(DisplayPoint::new(DisplayRow(0), 0)), &snapshot, cx, ) @@ -4850,39 +4875,51 @@ mod tests { let relative_rows = window .update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); - element.calculate_relative_line_numbers(&snapshot, &(0..6), Some(3)) + element.calculate_relative_line_numbers( + &snapshot, + &(DisplayRow(0)..DisplayRow(6)), + Some(DisplayRow(3)), + ) }) .unwrap(); - assert_eq!(relative_rows[&0], 3); - assert_eq!(relative_rows[&1], 2); - assert_eq!(relative_rows[&2], 1); + assert_eq!(relative_rows[&DisplayRow(0)], 3); + assert_eq!(relative_rows[&DisplayRow(1)], 2); + assert_eq!(relative_rows[&DisplayRow(2)], 1); // current line has no relative number - assert_eq!(relative_rows[&4], 1); - assert_eq!(relative_rows[&5], 2); + assert_eq!(relative_rows[&DisplayRow(4)], 1); + assert_eq!(relative_rows[&DisplayRow(5)], 2); // works if cursor is before screen let relative_rows = window .update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); - element.calculate_relative_line_numbers(&snapshot, &(3..6), Some(1)) + element.calculate_relative_line_numbers( + &snapshot, + &(DisplayRow(3)..DisplayRow(6)), + Some(DisplayRow(1)), + ) }) .unwrap(); assert_eq!(relative_rows.len(), 3); - assert_eq!(relative_rows[&3], 2); - assert_eq!(relative_rows[&4], 3); - assert_eq!(relative_rows[&5], 4); + assert_eq!(relative_rows[&DisplayRow(3)], 2); + assert_eq!(relative_rows[&DisplayRow(4)], 3); + assert_eq!(relative_rows[&DisplayRow(5)], 4); // works if cursor is after screen let relative_rows = window .update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); - element.calculate_relative_line_numbers(&snapshot, &(0..3), Some(6)) + element.calculate_relative_line_numbers( + &snapshot, + &(DisplayRow(0)..DisplayRow(3)), + Some(DisplayRow(6)), + ) }) .unwrap(); assert_eq!(relative_rows.len(), 3); - assert_eq!(relative_rows[&0], 5); - assert_eq!(relative_rows[&1], 4); - assert_eq!(relative_rows[&2], 3); + assert_eq!(relative_rows[&DisplayRow(0)], 5); + assert_eq!(relative_rows[&DisplayRow(1)], 4); + assert_eq!(relative_rows[&DisplayRow(2)], 3); } #[gpui::test] @@ -4918,30 +4955,39 @@ mod tests { let local_selections = &state.selections[0].1; assert_eq!(local_selections.len(), 3); // moves cursor back one line - assert_eq!(local_selections[0].head, DisplayPoint::new(0, 6)); + assert_eq!( + local_selections[0].head, + DisplayPoint::new(DisplayRow(0), 6) + ); assert_eq!( local_selections[0].range, - DisplayPoint::new(0, 0)..DisplayPoint::new(1, 0) + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(1), 0) ); // moves cursor back one column assert_eq!( local_selections[1].range, - DisplayPoint::new(3, 2)..DisplayPoint::new(3, 3) + DisplayPoint::new(DisplayRow(3), 2)..DisplayPoint::new(DisplayRow(3), 3) + ); + assert_eq!( + local_selections[1].head, + DisplayPoint::new(DisplayRow(3), 2) ); - assert_eq!(local_selections[1].head, DisplayPoint::new(3, 2)); // leaves cursor on the max point assert_eq!( local_selections[2].range, - DisplayPoint::new(5, 6)..DisplayPoint::new(6, 0) + DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(6), 0) + ); + assert_eq!( + local_selections[2].head, + DisplayPoint::new(DisplayRow(6), 0) ); - assert_eq!(local_selections[2].head, DisplayPoint::new(6, 0)); // active lines does not include 1 (even though the range of the selection does) assert_eq!( - state.active_rows.keys().cloned().collect::>(), - vec![0, 3, 5, 6] + state.active_rows.keys().cloned().collect::>(), + vec![DisplayRow(0), DisplayRow(3), DisplayRow(5), DisplayRow(6)] ); // multi-buffer support @@ -4987,8 +5033,8 @@ mod tests { editor.cursor_shape = CursorShape::Block; editor.change_selections(None, cx, |s| { s.select_display_ranges([ - DisplayPoint::new(4, 0)..DisplayPoint::new(7, 0), - DisplayPoint::new(10, 0)..DisplayPoint::new(13, 0), + DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(7), 0), + DisplayPoint::new(DisplayRow(10), 0)..DisplayPoint::new(DisplayRow(13), 0), ]); }); }); @@ -5004,16 +5050,22 @@ mod tests { // and doesn't allow selection to bleed through assert_eq!( local_selections[0].range, - DisplayPoint::new(4, 0)..DisplayPoint::new(6, 0) + DisplayPoint::new(DisplayRow(4), 0)..DisplayPoint::new(DisplayRow(6), 0) + ); + assert_eq!( + local_selections[0].head, + DisplayPoint::new(DisplayRow(5), 0) ); - assert_eq!(local_selections[0].head, DisplayPoint::new(5, 0)); // moves cursor on buffer boundary back two lines // and doesn't allow selection to bleed through assert_eq!( local_selections[1].range, - DisplayPoint::new(10, 0)..DisplayPoint::new(11, 0) + DisplayPoint::new(DisplayRow(10), 0)..DisplayPoint::new(DisplayRow(11), 0) + ); + assert_eq!( + local_selections[1].head, + DisplayPoint::new(DisplayRow(10), 0) ); - assert_eq!(local_selections[1].head, DisplayPoint::new(10, 0)); } #[gpui::test] @@ -5303,7 +5355,7 @@ fn compute_auto_height_layout( snapshot = editor.snapshot(cx); } - let scroll_height = Pixels::from(snapshot.max_point().row() + 1) * line_height; + let scroll_height = Pixels::from(snapshot.max_point().row().next_row().0) * line_height; let height = scroll_height .max(line_height) .min(line_height * max_lines as f32); diff --git a/crates/editor/src/git.rs b/crates/editor/src/git.rs index 7b43b4c230..665c649e6e 100644 --- a/crates/editor/src/git.rs +++ b/crates/editor/src/git.rs @@ -4,29 +4,29 @@ use std::ops::Range; use git::diff::{DiffHunk, DiffHunkStatus}; use language::Point; -use multi_buffer::Anchor; +use multi_buffer::{Anchor, MultiBufferRow}; use crate::{ display_map::{DisplaySnapshot, ToDisplayPoint}, - AnchorRangeExt, + hunk_status, AnchorRangeExt, DisplayRow, }; #[derive(Debug, Clone, PartialEq, Eq)] pub enum DisplayDiffHunk { Folded { - display_row: u32, + display_row: DisplayRow, }, Unfolded { diff_base_byte_range: Range, - display_row_range: Range, + display_row_range: Range, multi_buffer_range: Range, status: DiffHunkStatus, }, } impl DisplayDiffHunk { - pub fn start_display_row(&self) -> u32 { + pub fn start_display_row(&self) -> DisplayRow { match self { &DisplayDiffHunk::Folded { display_row } => display_row, DisplayDiffHunk::Unfolded { @@ -35,7 +35,7 @@ impl DisplayDiffHunk { } } - pub fn contains_display_row(&self, display_row: u32) -> bool { + pub fn contains_display_row(&self, display_row: DisplayRow) -> bool { let range = match self { &DisplayDiffHunk::Folded { display_row } => display_row..=display_row, @@ -48,21 +48,26 @@ impl DisplayDiffHunk { } } -pub fn diff_hunk_to_display(hunk: &DiffHunk, snapshot: &DisplaySnapshot) -> DisplayDiffHunk { - let hunk_start_point = Point::new(hunk.associated_range.start, 0); - let hunk_start_point_sub = Point::new(hunk.associated_range.start.saturating_sub(1), 0); +pub fn diff_hunk_to_display( + hunk: &DiffHunk, + snapshot: &DisplaySnapshot, +) -> DisplayDiffHunk { + let hunk_start_point = Point::new(hunk.associated_range.start.0, 0); + let hunk_start_point_sub = Point::new(hunk.associated_range.start.0.saturating_sub(1), 0); let hunk_end_point_sub = Point::new( hunk.associated_range .end + .0 .saturating_sub(1) - .max(hunk.associated_range.start), + .max(hunk.associated_range.start.0), 0, ); - let is_removal = hunk.status() == DiffHunkStatus::Removed; + let status = hunk_status(hunk); + let is_removal = status == DiffHunkStatus::Removed; - let folds_start = Point::new(hunk.associated_range.start.saturating_sub(2), 0); - let folds_end = Point::new(hunk.associated_range.end + 2, 0); + let folds_start = Point::new(hunk.associated_range.start.0.saturating_sub(2), 0); + let folds_end = Point::new(hunk.associated_range.end.0 + 2, 0); let folds_range = folds_start..folds_end; let containing_fold = snapshot.folds_in_range(folds_range).find(|fold| { @@ -83,7 +88,7 @@ pub fn diff_hunk_to_display(hunk: &DiffHunk, snapshot: &DisplaySnapshot) -> let start = hunk_start_point.to_display_point(snapshot).row(); let hunk_end_row = hunk.associated_range.end.max(hunk.associated_range.start); - let hunk_end_point = Point::new(hunk_end_row, 0); + let hunk_end_point = Point::new(hunk_end_row.0, 0); let multi_buffer_start = snapshot.buffer_snapshot.anchor_after(hunk_start_point); let multi_buffer_end = snapshot.buffer_snapshot.anchor_before(hunk_end_point); @@ -92,7 +97,7 @@ pub fn diff_hunk_to_display(hunk: &DiffHunk, snapshot: &DisplaySnapshot) -> DisplayDiffHunk::Unfolded { display_row_range: start..end, multi_buffer_range: multi_buffer_start..multi_buffer_end, - status: hunk.status(), + status, diff_base_byte_range: hunk.diff_base_byte_range.clone(), } } @@ -100,11 +105,11 @@ pub fn diff_hunk_to_display(hunk: &DiffHunk, snapshot: &DisplaySnapshot) -> #[cfg(test)] mod tests { - use crate::editor_tests::init_test; use crate::Point; + use crate::{editor_tests::init_test, hunk_status}; use gpui::{Context, TestAppContext}; use language::Capability::ReadWrite; - use multi_buffer::{ExcerptRange, MultiBuffer}; + use multi_buffer::{ExcerptRange, MultiBuffer, MultiBufferRow}; use project::{FakeFs, Project}; use unindent::Unindent; #[gpui::test] @@ -257,26 +262,41 @@ mod tests { ); let expected = [ - (DiffHunkStatus::Modified, 1..2), - (DiffHunkStatus::Modified, 2..3), + ( + DiffHunkStatus::Modified, + MultiBufferRow(1)..MultiBufferRow(2), + ), + ( + DiffHunkStatus::Modified, + MultiBufferRow(2)..MultiBufferRow(3), + ), //TODO: Define better when and where removed hunks show up at range extremities - (DiffHunkStatus::Removed, 6..6), - (DiffHunkStatus::Removed, 8..8), - (DiffHunkStatus::Added, 10..11), + ( + DiffHunkStatus::Removed, + MultiBufferRow(6)..MultiBufferRow(6), + ), + ( + DiffHunkStatus::Removed, + MultiBufferRow(8)..MultiBufferRow(8), + ), + ( + DiffHunkStatus::Added, + MultiBufferRow(10)..MultiBufferRow(11), + ), ]; assert_eq!( snapshot - .git_diff_hunks_in_range(0..12) - .map(|hunk| (hunk.status(), hunk.associated_range)) + .git_diff_hunks_in_range(MultiBufferRow(0)..MultiBufferRow(12)) + .map(|hunk| (hunk_status(&hunk), hunk.associated_range)) .collect::>(), &expected, ); assert_eq!( snapshot - .git_diff_hunks_in_range_rev(0..12) - .map(|hunk| (hunk.status(), hunk.associated_range)) + .git_diff_hunks_in_range_rev(MultiBufferRow(0)..MultiBufferRow(12)) + .map(|hunk| (hunk_status(&hunk), hunk.associated_range)) .collect::>(), expected .iter() diff --git a/crates/editor/src/git/blame.rs b/crates/editor/src/git/blame.rs index 83c2b727f5..14f4c8418c 100644 --- a/crates/editor/src/git/blame.rs +++ b/crates/editor/src/git/blame.rs @@ -8,6 +8,7 @@ use git::{ }; use gpui::{Model, ModelContext, Subscription, Task}; use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown}; +use multi_buffer::MultiBufferRow; use project::{Item, Project}; use smallvec::SmallVec; use sum_tree::SumTree; @@ -185,7 +186,7 @@ impl GitBlame { pub fn blame_for_rows<'a>( &'a mut self, - rows: impl 'a + IntoIterator>, + rows: impl 'a + IntoIterator>, cx: &mut ModelContext, ) -> impl 'a + Iterator> { self.sync(cx); @@ -193,7 +194,7 @@ impl GitBlame { let mut cursor = self.entries.cursor::(); rows.into_iter().map(move |row| { let row = row?; - cursor.seek_forward(&row, Bias::Right, &()); + cursor.seek_forward(&row.0, Bias::Right, &()); cursor.item()?.blame.clone() }) } @@ -532,7 +533,7 @@ mod tests { ($blame:expr, $rows:expr, $expected:expr, $cx:expr) => { assert_eq!( $blame - .blame_for_rows($rows.map(Some), $cx) + .blame_for_rows($rows.map(MultiBufferRow).map(Some), $cx) .collect::>(), $expected ); @@ -597,7 +598,7 @@ mod tests { blame.update(cx, |blame, cx| { assert_eq!( blame - .blame_for_rows((0..1).map(Some), cx) + .blame_for_rows((0..1).map(MultiBufferRow).map(Some), cx) .collect::>(), vec![None] ); @@ -661,7 +662,7 @@ mod tests { // All lines assert_eq!( blame - .blame_for_rows((0..8).map(Some), cx) + .blame_for_rows((0..8).map(MultiBufferRow).map(Some), cx) .collect::>(), vec![ Some(blame_entry("1b1b1b", 0..1)), @@ -677,7 +678,7 @@ mod tests { // Subset of lines assert_eq!( blame - .blame_for_rows((1..4).map(Some), cx) + .blame_for_rows((1..4).map(MultiBufferRow).map(Some), cx) .collect::>(), vec![ Some(blame_entry("0d0d0d", 1..2)), @@ -688,7 +689,7 @@ mod tests { // Subset of lines, with some not displayed assert_eq!( blame - .blame_for_rows(vec![Some(1), None, None], cx) + .blame_for_rows(vec![Some(MultiBufferRow(1)), None, None], cx) .collect::>(), vec![Some(blame_entry("0d0d0d", 1..2)), None, None] ); diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 3444f72bbc..143d5e359f 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -1,8 +1,8 @@ use crate::{ display_map::{InlayOffset, ToDisplayPoint}, hover_links::{InlayHighlight, RangeInEditor}, - Anchor, AnchorRangeExt, DisplayPoint, Editor, EditorSettings, EditorSnapshot, EditorStyle, - ExcerptId, Hover, RangeToAnchorExt, + Anchor, AnchorRangeExt, DisplayPoint, DisplayRow, Editor, EditorSettings, EditorSnapshot, + EditorStyle, ExcerptId, Hover, RangeToAnchorExt, }; use futures::{stream::FuturesUnordered, FutureExt}; use gpui::{ @@ -440,7 +440,7 @@ impl HoverState { &mut self, snapshot: &EditorSnapshot, style: &EditorStyle, - visible_rows: Range, + visible_rows: Range, max_size: Size, workspace: Option>, cx: &mut ViewContext, diff --git a/crates/editor/src/hunk_diff.rs b/crates/editor/src/hunk_diff.rs index 671da1f9cb..73c71f4dca 100644 --- a/crates/editor/src/hunk_diff.rs +++ b/crates/editor/src/hunk_diff.rs @@ -7,7 +7,9 @@ use collections::{hash_map, HashMap, HashSet}; use git::diff::{DiffHunk, DiffHunkStatus}; use gpui::{AppContext, Hsla, Model, Task, View}; use language::Buffer; -use multi_buffer::{Anchor, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToPoint}; +use multi_buffer::{ + Anchor, ExcerptRange, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, ToPoint, +}; use text::{BufferId, Point}; use ui::{ div, ActiveTheme, Context as _, IntoElement, ParentElement, Styled, ViewContext, VisualContext, @@ -16,9 +18,9 @@ use util::{debug_panic, RangeExt}; use crate::{ git::{diff_hunk_to_display, DisplayDiffHunk}, - hunks_for_selections, BlockDisposition, BlockId, BlockProperties, BlockStyle, DiffRowHighlight, - Editor, EditorSnapshot, ExpandAllHunkDiffs, RangeToAnchorExt, RevertSelectedHunks, - ToDisplayPoint, ToggleHunkDiff, + hunk_status, hunks_for_selections, BlockDisposition, BlockId, BlockProperties, BlockStyle, + DiffRowHighlight, Editor, EditorSnapshot, ExpandAllHunkDiffs, RangeToAnchorExt, + RevertSelectedHunks, ToDisplayPoint, ToggleHunkDiff, }; #[derive(Debug, Clone)] @@ -90,11 +92,11 @@ impl Editor { let hunks = snapshot .display_snapshot .buffer_snapshot - .git_diff_hunks_in_range(0..u32::MAX) + .git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX) .filter(|hunk| { - let hunk_display_row_range = Point::new(hunk.associated_range.start, 0) + let hunk_display_row_range = Point::new(hunk.associated_range.start.0, 0) .to_display_point(&snapshot.display_snapshot) - ..Point::new(hunk.associated_range.end, 0) + ..Point::new(hunk.associated_range.end.0, 0) .to_display_point(&snapshot.display_snapshot); let row_range_end = display_rows_with_expanded_hunks.get(&hunk_display_row_range.start.row()); @@ -105,7 +107,7 @@ impl Editor { fn toggle_hunks_expanded( &mut self, - hunks_to_toggle: Vec>, + hunks_to_toggle: Vec>, cx: &mut ViewContext, ) { let previous_toggle_task = self.expanded_hunks.hunk_update_tasks.remove(&None); @@ -176,10 +178,10 @@ impl Editor { }); for remaining_hunk in hunks_to_toggle { let remaining_hunk_point_range = - Point::new(remaining_hunk.associated_range.start, 0) - ..Point::new(remaining_hunk.associated_range.end, 0); + Point::new(remaining_hunk.associated_range.start.0, 0) + ..Point::new(remaining_hunk.associated_range.end.0, 0); hunks_to_expand.push(HunkToExpand { - status: remaining_hunk.status(), + status: hunk_status(&remaining_hunk), multi_buffer_range: remaining_hunk_point_range .to_anchors(&snapshot.buffer_snapshot), diff_base_byte_range: remaining_hunk.diff_base_byte_range.clone(), @@ -374,9 +376,10 @@ impl Editor { } let snapshot = editor.snapshot(cx); - let buffer_snapshot = buffer.read(cx).snapshot(); - let mut recalculated_hunks = buffer_snapshot - .git_diff_hunks_in_row_range(0..u32::MAX) + let mut recalculated_hunks = snapshot + .buffer_snapshot + .git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX) + .filter(|hunk| hunk.buffer_id == buffer_id) .fuse() .peekable(); let mut highlights_to_remove = @@ -402,7 +405,7 @@ impl Editor { .to_display_point(&snapshot) .row(); while let Some(buffer_hunk) = recalculated_hunks.peek() { - match diff_hunk_to_display(buffer_hunk, &snapshot) { + match diff_hunk_to_display(&buffer_hunk, &snapshot) { DisplayDiffHunk::Folded { display_row } => { recalculated_hunks.next(); if !expanded_hunk.folded @@ -441,7 +444,7 @@ impl Editor { } else { if !expanded_hunk.folded && expanded_hunk_display_range == hunk_display_range - && expanded_hunk.status == buffer_hunk.status() + && expanded_hunk.status == hunk_status(buffer_hunk) && expanded_hunk.diff_base_byte_range == buffer_hunk.diff_base_byte_range { @@ -614,15 +617,17 @@ fn editor_with_deleted_text( editor }); - let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row() as u8); + let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row().0 as u8); (editor_height, editor) } fn buffer_diff_hunk( buffer_snapshot: &MultiBufferSnapshot, row_range: Range, -) -> Option> { - let mut hunks = buffer_snapshot.git_diff_hunks_in_range(row_range.start.row..row_range.end.row); +) -> Option> { + let mut hunks = buffer_snapshot.git_diff_hunks_in_range( + MultiBufferRow(row_range.start.row)..MultiBufferRow(row_range.end.row), + ); let hunk = hunks.next()?; let second_hunk = hunks.next(); if second_hunk.is_none() { diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 397b33705f..d750b70267 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -2,10 +2,12 @@ //! in editor given a given motion (e.g. it handles converting a "move left" command into coordinates in editor). It is exposed mostly for use by vim crate. use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint}; -use crate::{char_kind, scroll::ScrollAnchor, CharKind, EditorStyle, ToOffset, ToPoint}; +use crate::{ + char_kind, scroll::ScrollAnchor, CharKind, DisplayRow, EditorStyle, RowExt, ToOffset, ToPoint, +}; use gpui::{px, Pixels, WindowTextSystem}; use language::Point; -use multi_buffer::MultiBufferSnapshot; +use multi_buffer::{MultiBufferRow, MultiBufferSnapshot}; use serde::Deserialize; use std::{ops::Range, sync::Arc}; @@ -35,7 +37,7 @@ pub struct TextLayoutDetails { pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint { if point.column() > 0 { *point.column_mut() -= 1; - } else if point.row() > 0 { + } else if point.row().0 > 0 { *point.row_mut() -= 1; *point.column_mut() = map.line_len(point.row()); } @@ -127,7 +129,7 @@ pub(crate) fn up_by_rows( _ => map.x_for_display_point(start, text_layout_details), }; - let prev_row = start.row().saturating_sub(row_count); + let prev_row = DisplayRow(start.row().0.saturating_sub(row_count)); let mut point = map.clip_point( DisplayPoint::new(prev_row, map.line_len(prev_row)), Bias::Left, @@ -137,7 +139,7 @@ pub(crate) fn up_by_rows( } else if preserve_column_at_start { return (start, goal); } else { - point = DisplayPoint::new(0, 0); + point = DisplayPoint::new(DisplayRow(0), 0); goal_x = px(0.); } @@ -166,7 +168,7 @@ pub(crate) fn down_by_rows( _ => map.x_for_display_point(start, text_layout_details), }; - let new_row = start.row() + row_count; + let new_row = DisplayRow(start.row().0 + row_count); let mut point = map.clip_point(DisplayPoint::new(new_row, 0), Bias::Right); if point.row() > start.row() { *point.column_mut() = map.display_column_for_x(point.row(), goal_x, text_layout_details) @@ -220,7 +222,9 @@ pub fn indented_line_beginning( let soft_line_start = map.clip_point(DisplayPoint::new(display_point.row(), 0), Bias::Right); let indent_start = Point::new( point.row, - map.buffer_snapshot.indent_size_for_line(point.row).len, + map.buffer_snapshot + .indent_size_for_line(MultiBufferRow(point.row)) + .len, ) .to_display_point(map); let line_start = map.prev_line_boundary(point).1; @@ -326,7 +330,7 @@ pub fn start_of_paragraph( let mut found_non_blank_line = false; for row in (0..point.row + 1).rev() { - let blank = map.buffer_snapshot.is_line_blank(row); + let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row)); if found_non_blank_line && blank { if count <= 1 { return Point::new(row, 0).to_display_point(map); @@ -349,13 +353,13 @@ pub fn end_of_paragraph( mut count: usize, ) -> DisplayPoint { let point = display_point.to_point(map); - if point.row == map.max_buffer_row() { + if point.row == map.max_buffer_row().0 { return map.max_point(); } let mut found_non_blank_line = false; - for row in point.row..map.max_buffer_row() + 1 { - let blank = map.buffer_snapshot.is_line_blank(row); + for row in point.row..map.max_buffer_row().next_row().0 { + let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row)); if found_non_blank_line && blank { if count <= 1 { return Point::new(row, 0).to_display_point(map); @@ -549,13 +553,16 @@ pub fn split_display_range_by_lines( let mut start = range.start; // Loop over all the covered rows until the one containing the range end - for row in range.start.row()..range.end.row() { - let row_end_column = map.line_len(row); - let end = map.clip_point(DisplayPoint::new(row, row_end_column), Bias::Left); + for row in range.start.row().0..range.end.row().0 { + let row_end_column = map.line_len(DisplayRow(row)); + let end = map.clip_point( + DisplayPoint::new(DisplayRow(row), row_end_column), + Bias::Left, + ); if start != end { result.push(start..end); } - start = map.clip_point(DisplayPoint::new(row + 1, 0), Bias::Left); + start = map.clip_point(DisplayPoint::new(DisplayRow(row + 1), 0), Bias::Left); } // Add the final range from the start of the last end to the original range end. @@ -570,7 +577,7 @@ mod tests { use crate::{ display_map::Inlay, test::{editor_test_context::EditorTestContext, marked_display_snapshot}, - Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer, + Buffer, DisplayMap, DisplayRow, ExcerptRange, InlayId, MultiBuffer, }; use gpui::{font, Context as _}; use language::Capability; @@ -900,126 +907,126 @@ mod tests { assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn"); - let col_2_x = - snapshot.x_for_display_point(DisplayPoint::new(2, 2), &text_layout_details); + let col_2_x = snapshot + .x_for_display_point(DisplayPoint::new(DisplayRow(2), 2), &text_layout_details); // Can't move up into the first excerpt's header assert_eq!( up( &snapshot, - DisplayPoint::new(2, 2), + DisplayPoint::new(DisplayRow(2), 2), SelectionGoal::HorizontalPosition(col_2_x.0), false, &text_layout_details ), ( - DisplayPoint::new(2, 0), + DisplayPoint::new(DisplayRow(2), 0), SelectionGoal::HorizontalPosition(0.0) ), ); assert_eq!( up( &snapshot, - DisplayPoint::new(2, 0), + DisplayPoint::new(DisplayRow(2), 0), SelectionGoal::None, false, &text_layout_details ), ( - DisplayPoint::new(2, 0), + DisplayPoint::new(DisplayRow(2), 0), SelectionGoal::HorizontalPosition(0.0) ), ); - let col_4_x = - snapshot.x_for_display_point(DisplayPoint::new(3, 4), &text_layout_details); + let col_4_x = snapshot + .x_for_display_point(DisplayPoint::new(DisplayRow(3), 4), &text_layout_details); // Move up and down within first excerpt assert_eq!( up( &snapshot, - DisplayPoint::new(3, 4), + DisplayPoint::new(DisplayRow(3), 4), SelectionGoal::HorizontalPosition(col_4_x.0), false, &text_layout_details ), ( - DisplayPoint::new(2, 3), + DisplayPoint::new(DisplayRow(2), 3), SelectionGoal::HorizontalPosition(col_4_x.0) ), ); assert_eq!( down( &snapshot, - DisplayPoint::new(2, 3), + DisplayPoint::new(DisplayRow(2), 3), SelectionGoal::HorizontalPosition(col_4_x.0), false, &text_layout_details ), ( - DisplayPoint::new(3, 4), + DisplayPoint::new(DisplayRow(3), 4), SelectionGoal::HorizontalPosition(col_4_x.0) ), ); - let col_5_x = - snapshot.x_for_display_point(DisplayPoint::new(6, 5), &text_layout_details); + let col_5_x = snapshot + .x_for_display_point(DisplayPoint::new(DisplayRow(6), 5), &text_layout_details); // Move up and down across second excerpt's header assert_eq!( up( &snapshot, - DisplayPoint::new(6, 5), + DisplayPoint::new(DisplayRow(6), 5), SelectionGoal::HorizontalPosition(col_5_x.0), false, &text_layout_details ), ( - DisplayPoint::new(3, 4), + DisplayPoint::new(DisplayRow(3), 4), SelectionGoal::HorizontalPosition(col_5_x.0) ), ); assert_eq!( down( &snapshot, - DisplayPoint::new(3, 4), + DisplayPoint::new(DisplayRow(3), 4), SelectionGoal::HorizontalPosition(col_5_x.0), false, &text_layout_details ), ( - DisplayPoint::new(6, 5), + DisplayPoint::new(DisplayRow(6), 5), SelectionGoal::HorizontalPosition(col_5_x.0) ), ); - let max_point_x = - snapshot.x_for_display_point(DisplayPoint::new(7, 2), &text_layout_details); + let max_point_x = snapshot + .x_for_display_point(DisplayPoint::new(DisplayRow(7), 2), &text_layout_details); // Can't move down off the end assert_eq!( down( &snapshot, - DisplayPoint::new(7, 0), + DisplayPoint::new(DisplayRow(7), 0), SelectionGoal::HorizontalPosition(0.0), false, &text_layout_details ), ( - DisplayPoint::new(7, 2), + DisplayPoint::new(DisplayRow(7), 2), SelectionGoal::HorizontalPosition(max_point_x.0) ), ); assert_eq!( down( &snapshot, - DisplayPoint::new(7, 2), + DisplayPoint::new(DisplayRow(7), 2), SelectionGoal::HorizontalPosition(max_point_x.0), false, &text_layout_details ), ( - DisplayPoint::new(7, 2), + DisplayPoint::new(DisplayRow(7), 2), SelectionGoal::HorizontalPosition(max_point_x.0) ), ); diff --git a/crates/editor/src/scroll.rs b/crates/editor/src/scroll.rs index 97d5a6538a..1107c97022 100644 --- a/crates/editor/src/scroll.rs +++ b/crates/editor/src/scroll.rs @@ -6,8 +6,8 @@ use crate::{ display_map::{DisplaySnapshot, ToDisplayPoint}, hover_popover::hide_hover, persistence::DB, - Anchor, DisplayPoint, Editor, EditorEvent, EditorMode, EditorSettings, InlayHintRefreshReason, - MultiBufferSnapshot, ToPoint, + Anchor, DisplayPoint, DisplayRow, Editor, EditorEvent, EditorMode, EditorSettings, + InlayHintRefreshReason, MultiBufferSnapshot, RowExt, ToPoint, }; pub use autoscroll::{Autoscroll, AutoscrollStrategy}; use gpui::{point, px, AppContext, Entity, Global, Pixels, Task, ViewContext, WindowContext}; @@ -48,7 +48,7 @@ impl ScrollAnchor { if self.anchor == Anchor::min() { scroll_position.y = 0.; } else { - let scroll_top = self.anchor.to_display_point(snapshot).row() as f32; + let scroll_top = self.anchor.to_display_point(snapshot).row().as_f32(); scroll_position.y = scroll_top + scroll_position.y; } scroll_position @@ -200,7 +200,7 @@ impl ScrollManager { ) } else { let scroll_top_buffer_point = - DisplayPoint::new(scroll_position.y as u32, 0).to_point(&map); + DisplayPoint::new(DisplayRow(scroll_position.y as u32), 0).to_point(&map); let top_anchor = map .buffer_snapshot .anchor_at(scroll_top_buffer_point, Bias::Right); @@ -210,7 +210,7 @@ impl ScrollManager { anchor: top_anchor, offset: point( scroll_position.x.max(0.), - scroll_position.y - top_anchor.to_display_point(&map).row() as f32, + scroll_position.y - top_anchor.to_display_point(&map).row().as_f32(), ), }, scroll_top_buffer_point.row, @@ -472,7 +472,7 @@ impl Editor { } if let Some(visible_lines) = self.visible_line_count() { - if newest_head.row() < screen_top.row() + visible_lines as u32 { + if newest_head.row() < DisplayRow(screen_top.row().0 + visible_lines as u32) { return Ordering::Equal; } } diff --git a/crates/editor/src/scroll/actions.rs b/crates/editor/src/scroll/actions.rs index 436a0291d0..c43191e57c 100644 --- a/crates/editor/src/scroll/actions.rs +++ b/crates/editor/src/scroll/actions.rs @@ -37,7 +37,7 @@ impl Editor { let scroll_margin_rows = self.vertical_scroll_margin() as u32; let mut new_screen_top = self.selections.newest_display(cx).head(); - *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows); + *new_screen_top.row_mut() = new_screen_top.row().0.saturating_sub(scroll_margin_rows); *new_screen_top.column_mut() = 0; let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left); let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top); @@ -60,7 +60,7 @@ impl Editor { }; let mut new_screen_top = self.selections.newest_display(cx).head(); - *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2); + *new_screen_top.row_mut() = new_screen_top.row().0.saturating_sub(visible_rows / 2); *new_screen_top.column_mut() = 0; let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left); let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top); @@ -86,6 +86,7 @@ impl Editor { let mut new_screen_top = self.selections.newest_display(cx).head(); *new_screen_top.row_mut() = new_screen_top .row() + .0 .saturating_sub(visible_rows.saturating_sub(scroll_margin_rows)); *new_screen_top.column_mut() = 0; let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left); diff --git a/crates/editor/src/scroll/autoscroll.rs b/crates/editor/src/scroll/autoscroll.rs index d197d01046..b24be19ad6 100644 --- a/crates/editor/src/scroll/autoscroll.rs +++ b/crates/editor/src/scroll/autoscroll.rs @@ -5,7 +5,8 @@ use gpui::{px, Bounds, Pixels, ViewContext}; use language::Point; use crate::{ - display_map::ToDisplayPoint, DiffRowHighlight, Editor, EditorMode, LineWithInvisibles, + display_map::ToDisplayPoint, DiffRowHighlight, DisplayRow, Editor, EditorMode, + LineWithInvisibles, RowExt, }; #[derive(PartialEq, Eq, Clone, Copy)] @@ -88,9 +89,9 @@ impl Editor { } } let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) { - (display_map.max_point().row() as f32 - visible_lines + 1.).max(0.) + (display_map.max_point().row().as_f32() - visible_lines + 1.).max(0.) } else { - display_map.max_point().row() as f32 + display_map.max_point().row().as_f32() }; if scroll_position.y > max_scroll_top { scroll_position.y = max_scroll_top; @@ -113,7 +114,7 @@ impl Editor { ) .first_entry() { - target_top = *first_highlighted_row.key() as f32; + target_top = first_highlighted_row.key().as_f32(); target_bottom = target_top + 1.; } else { let selections = self.selections.all::(cx); @@ -122,14 +123,16 @@ impl Editor { .unwrap() .head() .to_display_point(&display_map) - .row() as f32; + .row() + .as_f32(); target_bottom = selections .last() .unwrap() .head() .to_display_point(&display_map) - .row() as f32 - + 1.0; + .row() + .next_row() + .as_f32(); // If the selections can't all fit on screen, scroll to the newest. if autoscroll == Autoscroll::newest() @@ -141,7 +144,8 @@ impl Editor { .unwrap() .head() .to_display_point(&display_map) - .row() as f32; + .row() + .as_f32(); target_top = newest_selection_top; target_bottom = newest_selection_top + 1.; } @@ -227,7 +231,7 @@ impl Editor { pub(crate) fn autoscroll_horizontally( &mut self, - start_row: u32, + start_row: DisplayRow, viewport_width: Pixels, scroll_width: Pixels, max_glyph_width: Pixels, @@ -245,16 +249,18 @@ impl Editor { target_right = px(0.); for selection in selections { let head = selection.head().to_display_point(&display_map); - if head.row() >= start_row && head.row() < start_row + layouts.len() as u32 { + if head.row() >= start_row + && head.row() < DisplayRow(start_row.0 + layouts.len() as u32) + { let start_column = head.column().saturating_sub(3); let end_column = cmp::min(display_map.line_len(head.row()), head.column() + 3); target_left = target_left.min( - layouts[(head.row() - start_row) as usize] + layouts[head.row().minus(start_row) as usize] .line .x_for_index(start_column as usize), ); target_right = target_right.max( - layouts[(head.row() - start_row) as usize] + layouts[head.row().minus(start_row) as usize] .line .x_for_index(end_column as usize) + max_glyph_width, diff --git a/crates/editor/src/selections_collection.rs b/crates/editor/src/selections_collection.rs index 137cff4827..03859ddf2a 100644 --- a/crates/editor/src/selections_collection.rs +++ b/crates/editor/src/selections_collection.rs @@ -14,7 +14,8 @@ use util::post_inc; use crate::{ display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint}, movement::TextLayoutDetails, - Anchor, DisplayPoint, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode, ToOffset, + Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode, + ToOffset, }; #[derive(Debug, Clone)] @@ -308,7 +309,7 @@ impl SelectionsCollection { pub fn build_columnar_selection( &mut self, display_map: &DisplaySnapshot, - row: u32, + row: DisplayRow, positions: &Range, reversed: bool, text_layout_details: &TextLayoutDetails, diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index bc0c0afb11..65fec2ab8f 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -81,23 +81,30 @@ pub fn editor_hunks( editor: &Editor, snapshot: &DisplaySnapshot, cx: &mut ViewContext<'_, Editor>, -) -> Vec<(String, git::diff::DiffHunkStatus, core::ops::Range)> { +) -> Vec<( + String, + git::diff::DiffHunkStatus, + std::ops::Range, +)> { + use multi_buffer::MultiBufferRow; use text::Point; + use crate::hunk_status; + snapshot .buffer_snapshot - .git_diff_hunks_in_range(0..u32::MAX) + .git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX) .map(|hunk| { - let display_range = Point::new(hunk.associated_range.start, 0) + let display_range = Point::new(hunk.associated_range.start.0, 0) .to_display_point(snapshot) .row() - ..Point::new(hunk.associated_range.end, 0) + ..Point::new(hunk.associated_range.end.0, 0) .to_display_point(snapshot) .row(); let (_, buffer, _) = editor .buffer() .read(cx) - .excerpt_containing(Point::new(hunk.associated_range.start, 0), cx) + .excerpt_containing(Point::new(hunk.associated_range.start.0, 0), cx) .expect("no excerpt for expanded buffer's hunk start"); let diff_base = buffer .read(cx) @@ -105,7 +112,7 @@ pub fn editor_hunks( .expect("should have a diff base for expanded hunk") .slice(hunk.diff_base_byte_range.clone()) .to_string(); - (diff_base, hunk.status(), display_range) + (diff_base, hunk_status(&hunk), display_range) }) .collect() } @@ -115,7 +122,11 @@ pub fn expanded_hunks( editor: &Editor, snapshot: &DisplaySnapshot, cx: &mut ViewContext<'_, Editor>, -) -> Vec<(String, git::diff::DiffHunkStatus, core::ops::Range)> { +) -> Vec<( + String, + git::diff::DiffHunkStatus, + std::ops::Range, +)> { editor .expanded_hunks .hunks(false) @@ -150,7 +161,9 @@ pub fn expanded_hunks( pub fn expanded_hunks_background_highlights( editor: &mut Editor, cx: &mut gpui::WindowContext, -) -> Vec> { +) -> Vec> { + use crate::DisplayRow; + let mut highlights = Vec::new(); let mut range_start = 0; @@ -159,19 +172,19 @@ pub fn expanded_hunks_background_highlights( { match previous_highlighted_row { Some(previous_row) => { - if previous_row + 1 != highlighted_row { - highlights.push(range_start..=previous_row); - range_start = highlighted_row; + if previous_row + 1 != highlighted_row.0 { + highlights.push(DisplayRow(range_start)..=DisplayRow(previous_row)); + range_start = highlighted_row.0; } } None => { - range_start = highlighted_row; + range_start = highlighted_row.0; } } - previous_highlighted_row = Some(highlighted_row); + previous_highlighted_row = Some(highlighted_row.0); } if let Some(previous_row) = previous_highlighted_row { - highlights.push(range_start..=previous_row); + highlights.push(DisplayRow(range_start)..=DisplayRow(previous_row)); } highlights diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index 8d6ddc0011..8947a9a557 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -1,5 +1,6 @@ use crate::{ display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer, + RowExt, }; use collections::BTreeMap; use futures::Future; @@ -256,7 +257,7 @@ impl EditorTestContext { let details = editor.text_layout_details(cx); let y = pixel_position.y - + line_height * (display_point.row() as f32 - newest_point.row() as f32); + + line_height * (display_point.row().as_f32() - newest_point.row().as_f32()); let x = pixel_position.x + snapshot.x_for_display_point(display_point, &details) - snapshot.x_for_display_point(newest_point, &details); Point::new(x, y) diff --git a/crates/git/src/diff.rs b/crates/git/src/diff.rs index 29806bcd56..083527a1de 100644 --- a/crates/git/src/diff.rs +++ b/crates/git/src/diff.rs @@ -30,18 +30,6 @@ pub struct DiffHunk { pub diff_base_byte_range: Range, } -impl DiffHunk { - pub fn status(&self) -> DiffHunkStatus { - if self.diff_base_byte_range.is_empty() { - DiffHunkStatus::Added - } else if self.associated_range.is_empty() { - DiffHunkStatus::Removed - } else { - DiffHunkStatus::Modified - } - } -} - impl sum_tree::Item for DiffHunk { type Summary = DiffHunkSummary; diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index 5e6e51612f..67cbe6c767 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -352,6 +352,7 @@ mod tests { editor .highlighted_display_rows(HashSet::default(), cx) .into_keys() + .map(|r| r.0) .collect() }) } diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 540fbaa20b..8303c63b34 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -75,6 +75,8 @@ pub enum Capability { ReadOnly, } +pub type BufferRow = u32; + /// An in-memory representation of a source code file, including its text, /// syntax trees, git status, and diagnostics. pub struct Buffer { @@ -3104,7 +3106,7 @@ impl BufferSnapshot { /// row range. pub fn git_diff_hunks_in_row_range( &self, - range: Range, + range: Range, ) -> impl '_ + Iterator> { self.git_diff.hunks_in_row_range(range, self) } diff --git a/crates/multi_buffer/Cargo.toml b/crates/multi_buffer/Cargo.toml index 611cec57e0..acd0c89f8e 100644 --- a/crates/multi_buffer/Cargo.toml +++ b/crates/multi_buffer/Cargo.toml @@ -35,6 +35,7 @@ log.workspace = true parking_lot.workspace = true rand.workspace = true settings.workspace = true +serde.workspace = true smallvec.workspace = true sum_tree.workspace = true text.workspace = true diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index ab2ff89141..20bfc37537 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -11,9 +11,9 @@ use itertools::Itertools; use language::{ char_kind, language_settings::{language_settings, LanguageSettings}, - AutoindentMode, Buffer, BufferChunks, BufferSnapshot, Capability, CharKind, Chunk, CursorShape, - DiagnosticEntry, File, IndentSize, Language, LanguageScope, OffsetRangeExt, OffsetUtf16, - Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _, + AutoindentMode, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability, CharKind, Chunk, + CursorShape, DiagnosticEntry, File, IndentSize, Language, LanguageScope, OffsetRangeExt, + OffsetUtf16, Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _, ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped, }; use smallvec::SmallVec; @@ -100,6 +100,16 @@ pub enum Event { DiagnosticsUpdated, } +pub type MultiBufferPoint = Point; + +#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, serde::Deserialize)] +#[serde(transparent)] +pub struct MultiBufferRow(pub u32); + +impl MultiBufferRow { + pub const MIN: Self = Self(0); + pub const MAX: Self = Self(u32::MAX); +} #[derive(Clone)] struct History { next_transaction_id: TransactionId, @@ -165,8 +175,7 @@ pub struct MultiBufferSnapshot { /// A boundary between [`Excerpt`]s in a [`MultiBuffer`] pub struct ExcerptBoundary { pub id: ExcerptId, - /// The row in the `MultiBuffer` where the boundary is located - pub row: u32, + pub row: MultiBufferRow, pub buffer: BufferSnapshot, pub range: ExcerptRange, /// It's possible to have multiple excerpts in the same buffer, @@ -190,7 +199,7 @@ struct Excerpt { /// The range of the buffer to be shown in the excerpt range: ExcerptRange, /// The last row in the excerpted slice of the buffer - max_buffer_row: u32, + max_buffer_row: BufferRow, /// A summary of the text in the excerpt text_summary: TextSummary, has_trailing_newline: bool, @@ -229,7 +238,7 @@ struct ExcerptSummary { /// The location of the last [`Excerpt`] being summarized excerpt_locator: Locator, /// The maximum row of the [`Excerpt`]s being summarized - max_buffer_row: u32, + max_buffer_row: MultiBufferRow, text: TextSummary, } @@ -2111,8 +2120,8 @@ impl MultiBufferSnapshot { self.chunks(range, false).map(|chunk| chunk.text) } - pub fn is_line_blank(&self, row: u32) -> bool { - self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row))) + pub fn is_line_blank(&self, row: MultiBufferRow) -> bool { + self.text_for_range(Point::new(row.0, 0)..Point::new(row.0, self.line_len(row))) .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none()) } @@ -2181,7 +2190,7 @@ impl MultiBufferSnapshot { self.excerpts.summary().text.len == 0 } - pub fn max_buffer_row(&self) -> u32 { + pub fn max_buffer_row(&self) -> MultiBufferRow { self.excerpts.summary().max_buffer_row } @@ -2312,7 +2321,7 @@ impl MultiBufferSnapshot { } } - pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows { + pub fn buffer_rows(&self, start_row: MultiBufferRow) -> MultiBufferRows { let mut result = MultiBufferRows { buffer_row_range: 0..0, excerpts: self.excerpts.cursor(), @@ -2509,7 +2518,7 @@ impl MultiBufferSnapshot { &self, rows: impl IntoIterator, cx: &AppContext, - ) -> BTreeMap { + ) -> BTreeMap { let mut result = BTreeMap::new(); let mut rows_for_excerpt = Vec::new(); @@ -2555,16 +2564,19 @@ impl MultiBufferSnapshot { let buffer_indents = excerpt .buffer .suggested_indents(buffer_rows, single_indent_size); - let multibuffer_indents = buffer_indents - .into_iter() - .map(|(row, indent)| (start_multibuffer_row + row - start_buffer_row, indent)); + let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| { + ( + MultiBufferRow(start_multibuffer_row + row - start_buffer_row), + indent, + ) + }); result.extend(multibuffer_indents); } result } - pub fn indent_size_for_line(&self, row: u32) -> IndentSize { + pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize { if let Some((buffer, range)) = self.buffer_line_for_row(row) { let mut size = buffer.indent_size_for_line(range.start.row); size.len = size @@ -2577,9 +2589,9 @@ impl MultiBufferSnapshot { } } - pub fn prev_non_blank_row(&self, mut row: u32) -> Option { - while row > 0 { - row -= 1; + pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option { + while row.0 > 0 { + row.0 -= 1; if !self.is_line_blank(row) { return Some(row); } @@ -2587,7 +2599,7 @@ impl MultiBufferSnapshot { None } - pub fn line_len(&self, row: u32) -> u32 { + pub fn line_len(&self, row: MultiBufferRow) -> u32 { if let Some((_, range)) = self.buffer_line_for_row(row) { range.end.column - range.start.column } else { @@ -2595,15 +2607,18 @@ impl MultiBufferSnapshot { } } - pub fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range)> { + pub fn buffer_line_for_row( + &self, + row: MultiBufferRow, + ) -> Option<(&BufferSnapshot, Range)> { let mut cursor = self.excerpts.cursor::(); - let point = Point::new(row, 0); + let point = Point::new(row.0, 0); cursor.seek(&point, Bias::Right, &()); if cursor.item().is_none() && *cursor.start() == point { cursor.prev(&()); } if let Some(excerpt) = cursor.item() { - let overshoot = row - cursor.start().row; + let overshoot = row.0 - cursor.start().row; let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer); let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer); let buffer_row = excerpt_start.row + overshoot; @@ -3028,7 +3043,7 @@ impl MultiBufferSnapshot { let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id; let boundary = ExcerptBoundary { id: excerpt.id, - row: cursor.start().1.row, + row: MultiBufferRow(cursor.start().1.row), buffer: excerpt.buffer.clone(), range: excerpt.range.clone(), starts_new_buffer, @@ -3312,11 +3327,11 @@ impl MultiBufferSnapshot { pub fn git_diff_hunks_in_range_rev( &self, - row_range: Range, - ) -> impl Iterator> + '_ { + row_range: Range, + ) -> impl Iterator> + '_ { let mut cursor = self.excerpts.cursor::(); - cursor.seek(&Point::new(row_range.end, 0), Bias::Left, &()); + cursor.seek(&Point::new(row_range.end.0, 0), Bias::Left, &()); if cursor.item().is_none() { cursor.prev(&()); } @@ -3325,7 +3340,7 @@ impl MultiBufferSnapshot { let excerpt = cursor.item()?; let multibuffer_start = *cursor.start(); let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; - if multibuffer_start.row >= row_range.end { + if multibuffer_start.row >= row_range.end.0 { return None; } @@ -3334,15 +3349,15 @@ impl MultiBufferSnapshot { let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; - if row_range.start > multibuffer_start.row { + if row_range.start.0 > multibuffer_start.row { let buffer_start_point = - excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0); + excerpt_start_point + Point::new(row_range.start.0 - multibuffer_start.row, 0); buffer_start = excerpt.buffer.anchor_before(buffer_start_point); } - if row_range.end < multibuffer_end.row { + if row_range.end.0 < multibuffer_end.row { let buffer_end_point = - excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0); + excerpt_start_point + Point::new(row_range.end.0 - multibuffer_start.row, 0); buffer_end = excerpt.buffer.anchor_before(buffer_end_point); } @@ -3363,7 +3378,7 @@ impl MultiBufferSnapshot { .saturating_sub(excerpt_start_point.row); DiffHunk { - associated_range: start..end, + associated_range: MultiBufferRow(start)..MultiBufferRow(end), diff_base_byte_range: hunk.diff_base_byte_range.clone(), buffer_range: hunk.buffer_range.clone(), buffer_id: hunk.buffer_id, @@ -3379,11 +3394,11 @@ impl MultiBufferSnapshot { pub fn git_diff_hunks_in_range( &self, - row_range: Range, - ) -> impl Iterator> + '_ { + row_range: Range, + ) -> impl Iterator> + '_ { let mut cursor = self.excerpts.cursor::(); - cursor.seek(&Point::new(row_range.start, 0), Bias::Left, &()); + cursor.seek(&Point::new(row_range.start.0, 0), Bias::Left, &()); std::iter::from_fn(move || { let excerpt = cursor.item()?; @@ -3392,25 +3407,25 @@ impl MultiBufferSnapshot { let mut buffer_start = excerpt.range.context.start; let mut buffer_end = excerpt.range.context.end; - let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end) { + let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end.0) { cmp::Ordering::Less => { let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; - if row_range.start > multibuffer_start.row { + if row_range.start.0 > multibuffer_start.row { let buffer_start_point = excerpt_start_point - + Point::new(row_range.start - multibuffer_start.row, 0); + + Point::new(row_range.start.0 - multibuffer_start.row, 0); buffer_start = excerpt.buffer.anchor_before(buffer_start_point); } - if row_range.end < multibuffer_end.row { + if row_range.end.0 < multibuffer_end.row { let buffer_end_point = excerpt_start_point - + Point::new(row_range.end - multibuffer_start.row, 0); + + Point::new(row_range.end.0 - multibuffer_start.row, 0); buffer_end = excerpt.buffer.anchor_before(buffer_end_point); } excerpt_start_point.row..excerpt_end_point.row } - cmp::Ordering::Equal if row_range.end == 0 => { + cmp::Ordering::Equal if row_range.end.0 == 0 => { buffer_end = buffer_start; 0..0 } @@ -3422,7 +3437,7 @@ impl MultiBufferSnapshot { .git_diff_hunks_intersecting_range(buffer_start..buffer_end) .map(move |hunk| { let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 { - 0..1 + MultiBufferRow(0)..MultiBufferRow(1) } else { let start = multibuffer_start.row + hunk @@ -3435,7 +3450,7 @@ impl MultiBufferSnapshot { .end .min(excerpt_rows.end + 1) .saturating_sub(excerpt_rows.start); - start..end + MultiBufferRow(start)..MultiBufferRow(end) }; DiffHunk { associated_range: buffer_range, @@ -4096,7 +4111,7 @@ impl sum_tree::Item for Excerpt { ExcerptSummary { excerpt_id: self.id, excerpt_locator: self.locator.clone(), - max_buffer_row: self.max_buffer_row, + max_buffer_row: MultiBufferRow(self.max_buffer_row), text, } } @@ -4198,22 +4213,22 @@ impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option { } impl<'a> MultiBufferRows<'a> { - pub fn seek(&mut self, row: u32) { + pub fn seek(&mut self, row: MultiBufferRow) { self.buffer_row_range = 0..0; self.excerpts - .seek_forward(&Point::new(row, 0), Bias::Right, &()); + .seek_forward(&Point::new(row.0, 0), Bias::Right, &()); if self.excerpts.item().is_none() { self.excerpts.prev(&()); - if self.excerpts.item().is_none() && row == 0 { + if self.excerpts.item().is_none() && row.0 == 0 { self.buffer_row_range = 0..1; return; } } if let Some(excerpt) = self.excerpts.item() { - let overshoot = row - self.excerpts.start().row; + let overshoot = row.0 - self.excerpts.start().row; let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row; self.buffer_row_range.start = excerpt_start + overshoot; self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1; @@ -4546,7 +4561,7 @@ mod tests { assert_eq!(snapshot.text(), buffer.read(cx).text()); assert_eq!( - snapshot.buffer_rows(0).collect::>(), + snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), (0..buffer.read(cx).row_count()) .map(Some) .collect::>() @@ -4557,7 +4572,7 @@ mod tests { assert_eq!(snapshot.text(), buffer.read(cx).text()); assert_eq!( - snapshot.buffer_rows(0).collect::>(), + snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), (0..buffer.read(cx).row_count()) .map(Some) .collect::>() @@ -4685,27 +4700,33 @@ mod tests { ) ); assert_eq!( - snapshot.buffer_rows(0).collect::>(), + snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), [Some(1), Some(2), Some(3), Some(4), Some(3)] ); assert_eq!( - snapshot.buffer_rows(2).collect::>(), + snapshot.buffer_rows(MultiBufferRow(2)).collect::>(), [Some(3), Some(4), Some(3)] ); - assert_eq!(snapshot.buffer_rows(4).collect::>(), [Some(3)]); - assert_eq!(snapshot.buffer_rows(5).collect::>(), []); + assert_eq!( + snapshot.buffer_rows(MultiBufferRow(4)).collect::>(), + [Some(3)] + ); + assert_eq!( + snapshot.buffer_rows(MultiBufferRow(5)).collect::>(), + [] + ); assert_eq!( boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot), &[ - (0, "bbbb\nccccc".to_string(), true), - (2, "ddd\neeee".to_string(), false), - (4, "jj".to_string(), true), + (MultiBufferRow(0), "bbbb\nccccc".to_string(), true), + (MultiBufferRow(2), "ddd\neeee".to_string(), false), + (MultiBufferRow(4), "jj".to_string(), true), ] ); assert_eq!( boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot), - &[(0, "bbbb\nccccc".to_string(), true)] + &[(MultiBufferRow(0), "bbbb\nccccc".to_string(), true)] ); assert_eq!( boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot), @@ -4717,19 +4738,19 @@ mod tests { ); assert_eq!( boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), - &[(2, "ddd\neeee".to_string(), false)] + &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] ); assert_eq!( boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), - &[(2, "ddd\neeee".to_string(), false)] + &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] ); assert_eq!( boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot), - &[(2, "ddd\neeee".to_string(), false)] + &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] ); assert_eq!( boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot), - &[(4, "jj".to_string(), true)] + &[(MultiBufferRow(4), "jj".to_string(), true)] ); assert_eq!( boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot), @@ -4812,7 +4833,7 @@ mod tests { fn boundaries_in_range( range: Range, snapshot: &MultiBufferSnapshot, - ) -> Vec<(u32, String, bool)> { + ) -> Vec<(MultiBufferRow, String, bool)> { snapshot .excerpt_boundaries_in_range(range) .map(|boundary| { @@ -5100,8 +5121,14 @@ mod tests { let snapshot = multibuffer.read(cx).snapshot(cx); assert_eq!(snapshot.text(), ""); - assert_eq!(snapshot.buffer_rows(0).collect::>(), &[Some(0)]); - assert_eq!(snapshot.buffer_rows(1).collect::>(), &[]); + assert_eq!( + snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), + &[Some(0)] + ); + assert_eq!( + snapshot.buffer_rows(MultiBufferRow(1)).collect::>(), + &[] + ); } #[gpui::test] @@ -5518,14 +5545,16 @@ mod tests { log::info!("MultiBuffer text: {:?}", expected_text); assert_eq!( - snapshot.buffer_rows(0).collect::>(), + snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), expected_buffer_rows, ); for _ in 0..5 { let start_row = rng.gen_range(0..=expected_buffer_rows.len()); assert_eq!( - snapshot.buffer_rows(start_row as u32).collect::>(), + snapshot + .buffer_rows(MultiBufferRow(start_row as u32)) + .collect::>(), &expected_buffer_rows[start_row..], "buffer_rows({})", start_row @@ -5533,7 +5562,7 @@ mod tests { } assert_eq!( - snapshot.max_buffer_row(), + snapshot.max_buffer_row().0, expected_buffer_rows.into_iter().flatten().max().unwrap() ); @@ -5666,7 +5695,7 @@ mod tests { for (row, line) in expected_text.split('\n').enumerate() { assert_eq!( - snapshot.line_len(row as u32), + snapshot.line_len(MultiBufferRow(row as u32)), line.len() as u32, "line_len({}).", row diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index cdaf5fcf20..b90e931876 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -486,6 +486,7 @@ mod tests { editor .highlighted_display_rows(HashSet::default(), cx) .into_keys() + .map(|r| r.0) .collect() }) } diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 7eb7296fa1..1c1f1e974a 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -1090,7 +1090,7 @@ mod tests { use std::ops::Range; use super::*; - use editor::{DisplayPoint, Editor}; + use editor::{display_map::DisplayRow, DisplayPoint, Editor}; use gpui::{Context, Hsla, TestAppContext, VisualTestContext}; use language::Buffer; use project::Project; @@ -1157,8 +1157,8 @@ mod tests { assert_eq!( display_points_of(editor.all_text_background_highlights(cx)), &[ - DisplayPoint::new(2, 17)..DisplayPoint::new(2, 19), - DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45), + DisplayPoint::new(DisplayRow(2), 17)..DisplayPoint::new(DisplayRow(2), 19), + DisplayPoint::new(DisplayRow(2), 43)..DisplayPoint::new(DisplayRow(2), 45), ] ); }); @@ -1172,7 +1172,7 @@ mod tests { editor.update(cx, |editor, cx| { assert_eq!( display_points_of(editor.all_text_background_highlights(cx)), - &[DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45),] + &[DisplayPoint::new(DisplayRow(2), 43)..DisplayPoint::new(DisplayRow(2), 45),] ); }); @@ -1186,13 +1186,13 @@ mod tests { assert_eq!( display_points_of(editor.all_text_background_highlights(cx)), &[ - DisplayPoint::new(0, 24)..DisplayPoint::new(0, 26), - DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43), - DisplayPoint::new(2, 71)..DisplayPoint::new(2, 73), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 3), - DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13), - DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58), - DisplayPoint::new(3, 60)..DisplayPoint::new(3, 62), + DisplayPoint::new(DisplayRow(0), 24)..DisplayPoint::new(DisplayRow(0), 26), + DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43), + DisplayPoint::new(DisplayRow(2), 71)..DisplayPoint::new(DisplayRow(2), 73), + DisplayPoint::new(DisplayRow(3), 1)..DisplayPoint::new(DisplayRow(3), 3), + DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13), + DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58), + DisplayPoint::new(DisplayRow(3), 60)..DisplayPoint::new(DisplayRow(3), 62), ] ); }); @@ -1207,16 +1207,18 @@ mod tests { assert_eq!( display_points_of(editor.all_text_background_highlights(cx)), &[ - DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43), - DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13), - DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58), + DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43), + DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13), + DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58), ] ); }); editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0) + ]) }); }); search_bar.update(cx, |search_bar, cx| { @@ -1224,7 +1226,7 @@ mod tests { search_bar.select_next_match(&SelectNextMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)] + [DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1235,7 +1237,7 @@ mod tests { search_bar.select_next_match(&SelectNextMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)] + [DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1246,7 +1248,7 @@ mod tests { search_bar.select_next_match(&SelectNextMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)] + [DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1257,7 +1259,7 @@ mod tests { search_bar.select_next_match(&SelectNextMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)] + [DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1268,7 +1270,7 @@ mod tests { search_bar.select_prev_match(&SelectPrevMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)] + [DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1279,7 +1281,7 @@ mod tests { search_bar.select_prev_match(&SelectPrevMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)] + [DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1290,7 +1292,7 @@ mod tests { search_bar.select_prev_match(&SelectPrevMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)] + [DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1301,7 +1303,9 @@ mod tests { // the closest match to the left. editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0) + ]) }); }); search_bar.update(cx, |search_bar, cx| { @@ -1309,7 +1313,7 @@ mod tests { search_bar.select_prev_match(&SelectPrevMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)] + [DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1320,7 +1324,9 @@ mod tests { // closest match to the right. editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0) + ]) }); }); search_bar.update(cx, |search_bar, cx| { @@ -1328,7 +1334,7 @@ mod tests { search_bar.select_next_match(&SelectNextMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)] + [DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1339,7 +1345,9 @@ mod tests { // the last match. editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(3, 60)..DisplayPoint::new(3, 60)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(3), 60)..DisplayPoint::new(DisplayRow(3), 60) + ]) }); }); search_bar.update(cx, |search_bar, cx| { @@ -1347,7 +1355,7 @@ mod tests { search_bar.select_prev_match(&SelectPrevMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)] + [DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1358,7 +1366,9 @@ mod tests { // first match. editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(3, 60)..DisplayPoint::new(3, 60)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(3), 60)..DisplayPoint::new(DisplayRow(3), 60) + ]) }); }); search_bar.update(cx, |search_bar, cx| { @@ -1366,7 +1376,7 @@ mod tests { search_bar.select_next_match(&SelectNextMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)] + [DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1377,7 +1387,9 @@ mod tests { // selects the last match. editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]) + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0) + ]) }); }); search_bar.update(cx, |search_bar, cx| { @@ -1385,7 +1397,7 @@ mod tests { search_bar.select_prev_match(&SelectPrevMatch, cx); assert_eq!( editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)] + [DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)] ); }); search_bar.update(cx, |search_bar, _| { @@ -1414,7 +1426,7 @@ mod tests { editor.update(cx, |editor, cx| { assert_eq!( display_points_of(editor.all_text_background_highlights(cx)), - &[DisplayPoint::new(2, 43)..DisplayPoint::new(2, 45),] + &[DisplayPoint::new(DisplayRow(2), 43)..DisplayPoint::new(DisplayRow(2), 45),] ); }); @@ -1439,7 +1451,7 @@ mod tests { editor.update(cx, |editor, cx| { assert_eq!( display_points_of(editor.all_text_background_highlights(cx)), - &[DisplayPoint::new(0, 35)..DisplayPoint::new(0, 40),] + &[DisplayPoint::new(DisplayRow(0), 35)..DisplayPoint::new(DisplayRow(0), 40),] ); }); @@ -2041,8 +2053,8 @@ mod tests { assert_eq!( display_points_of(editor.all_text_background_highlights(cx)), &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 20), - DisplayPoint::new(1, 9)..DisplayPoint::new(1, 19), + DisplayPoint::new(DisplayRow(0), 10)..DisplayPoint::new(DisplayRow(0), 20), + DisplayPoint::new(DisplayRow(1), 9)..DisplayPoint::new(DisplayRow(1), 19), ], ); }); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index dd814f9973..5658ba28de 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1688,7 +1688,7 @@ fn register_workspace_action_for_present_search( #[cfg(test)] pub mod tests { use super::*; - use editor::DisplayPoint; + use editor::{display_map::DisplayRow, DisplayPoint}; use gpui::{Action, TestAppContext, WindowHandle}; use project::FakeFs; use serde_json::json; @@ -1730,15 +1730,15 @@ pub mod tests { .update(cx, |editor, cx| editor.all_text_background_highlights(cx)), &[ ( - DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35), + DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35), match_background_color ), ( - DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40), + DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40), match_background_color ), ( - DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9), + DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9), match_background_color ) ] @@ -1748,7 +1748,7 @@ pub mod tests { search_view .results_editor .update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35)] + [DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35)] ); search_view.select_match(Direction::Next, cx); @@ -1761,7 +1761,7 @@ pub mod tests { search_view .results_editor .update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40)] + [DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40)] ); search_view.select_match(Direction::Next, cx); }) @@ -1774,7 +1774,7 @@ pub mod tests { search_view .results_editor .update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9)] + [DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9)] ); search_view.select_match(Direction::Next, cx); }) @@ -1787,7 +1787,7 @@ pub mod tests { search_view .results_editor .update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35)] + [DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35)] ); search_view.select_match(Direction::Prev, cx); }) @@ -1800,7 +1800,7 @@ pub mod tests { search_view .results_editor .update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9)] + [DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9)] ); search_view.select_match(Direction::Prev, cx); }) @@ -1813,7 +1813,7 @@ pub mod tests { search_view .results_editor .update(cx, |editor, cx| editor.selections.display_ranges(cx)), - [DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40)] + [DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40)] ); }) .unwrap(); diff --git a/crates/vim/Cargo.toml b/crates/vim/Cargo.toml index 3efd05259e..d75b637a63 100644 --- a/crates/vim/Cargo.toml +++ b/crates/vim/Cargo.toml @@ -26,6 +26,7 @@ gpui.workspace = true itertools.workspace = true language.workspace = true log.workspace = true +multi_buffer.workspace = true nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", features = [ "use_tokio", ], optional = true } diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index 99cc880a56..411c412533 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -1,13 +1,14 @@ use editor::{ - display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint}, + display_map::{DisplayRow, DisplaySnapshot, FoldPoint, ToDisplayPoint}, movement::{ self, find_boundary, find_preceding_boundary_display_point, FindRange, TextLayoutDetails, }, scroll::Autoscroll, - Anchor, Bias, DisplayPoint, ToOffset, + Anchor, Bias, DisplayPoint, RowExt, ToOffset, }; use gpui::{actions, impl_actions, px, ViewContext, WindowContext}; use language::{char_kind, CharKind, Point, Selection, SelectionGoal}; +use multi_buffer::MultiBufferRow; use serde::Deserialize; use std::ops::Range; use workspace::Workspace; @@ -843,7 +844,7 @@ impl Motion { selection.end = map.clip_point(selection.end, Bias::Right); // Don't reset the end here return Some(selection.start..selection.end); - } else if selection.start.row() > 0 { + } else if selection.start.row().0 > 0 { *selection.start.row_mut() -= 1; *selection.start.column_mut() = map.line_len(selection.start.row()); selection.start = map.clip_point(selection.start, Bias::Left); @@ -860,10 +861,10 @@ impl Motion { ignore_punctuation: _, } = self { - let start_row = selection.start.to_point(&map).row; - if selection.end.to_point(&map).row > start_row { + let start_row = MultiBufferRow(selection.start.to_point(&map).row); + if selection.end.to_point(&map).row > start_row.0 { selection.end = - Point::new(start_row, map.buffer_snapshot.line_len(start_row)) + Point::new(start_row.0, map.buffer_snapshot.line_len(start_row)) .to_display_point(&map) } } @@ -997,7 +998,7 @@ fn up_down_buffer_rows( map.fold_snapshot .clip_point(FoldPoint::new(start.row(), 0), Bias::Left), ); - let select_nth_wrapped_row = point.row() - begin_folded_line.row(); + let select_nth_wrapped_row = point.row().0 - begin_folded_line.row().0; let (goal_wrap, goal_x) = match goal { SelectionGoal::WrappedHorizontalPosition((row, x)) => (row, x), @@ -1020,7 +1021,7 @@ fn up_down_buffer_rows( let mut i = 0; while i < goal_wrap && begin_folded_line.row() < map.max_point().row() { - let next_folded_line = DisplayPoint::new(begin_folded_line.row() + 1, 0); + let next_folded_line = DisplayPoint::new(begin_folded_line.row().next_row(), 0); if map .display_point_to_fold_point(next_folded_line, Bias::Right) .row() @@ -1215,7 +1216,7 @@ fn previous_word_end( let scope = map.buffer_snapshot.language_scope_at(point.to_point(map)); let mut point = point.to_point(map); - if point.column < map.buffer_snapshot.line_len(point.row) { + if point.column < map.buffer_snapshot.line_len(MultiBufferRow(point.row)) { point.column += 1; } for _ in 0..times { @@ -1375,7 +1376,7 @@ fn previous_subword_end( let scope = map.buffer_snapshot.language_scope_at(point.to_point(map)); let mut point = point.to_point(map); - if point.column < map.buffer_snapshot.line_len(point.row) { + if point.column < map.buffer_snapshot.line_len(MultiBufferRow(point.row)) { point.column += 1; } for _ in 0..times { @@ -1497,7 +1498,7 @@ fn end_of_document( let new_row = if let Some(line) = line { (line - 1) as u32 } else { - map.max_buffer_row() + map.max_buffer_row().0 }; let new_point = Point::new(new_row, point.column()); @@ -1672,22 +1673,24 @@ fn window_top( .anchor .to_display_point(map); - if first_visible_line.row() != 0 && text_layout_details.vertical_scroll_margin as usize > times + if first_visible_line.row() != DisplayRow(0) + && text_layout_details.vertical_scroll_margin as usize > times { times = text_layout_details.vertical_scroll_margin.ceil() as usize; } if let Some(visible_rows) = text_layout_details.visible_rows { - let bottom_row = first_visible_line.row() + visible_rows as u32; - let new_row = (first_visible_line.row() + (times as u32)) + let bottom_row = first_visible_line.row().0 + visible_rows as u32; + let new_row = (first_visible_line.row().0 + (times as u32)) .min(bottom_row) - .min(map.max_point().row()); + .min(map.max_point().row().0); let new_col = point.column().min(map.line_len(first_visible_line.row())); - let new_point = DisplayPoint::new(new_row, new_col); + let new_point = DisplayPoint::new(DisplayRow(new_row), new_col); (map.clip_point(new_point, Bias::Left), SelectionGoal::None) } else { - let new_row = (first_visible_line.row() + (times as u32)).min(map.max_point().row()); + let new_row = + DisplayRow((first_visible_line.row().0 + (times as u32)).min(map.max_point().row().0)); let new_col = point.column().min(map.line_len(first_visible_line.row())); let new_point = DisplayPoint::new(new_row, new_col); @@ -1707,10 +1710,11 @@ fn window_middle( .to_display_point(map); let max_visible_rows = - (visible_rows as u32).min(map.max_point().row() - first_visible_line.row()); + (visible_rows as u32).min(map.max_point().row().0 - first_visible_line.row().0); let new_row = - (first_visible_line.row() + (max_visible_rows / 2)).min(map.max_point().row()); + (first_visible_line.row().0 + (max_visible_rows / 2)).min(map.max_point().row().0); + let new_row = DisplayRow(new_row); let new_col = point.column().min(map.line_len(new_row)); let new_point = DisplayPoint::new(new_row, new_col); (map.clip_point(new_point, Bias::Left), SelectionGoal::None) @@ -1730,18 +1734,19 @@ fn window_bottom( .scroll_anchor .anchor .to_display_point(map); - let bottom_row = first_visible_line.row() + let bottom_row = first_visible_line.row().0 + (visible_rows + text_layout_details.scroll_anchor.offset.y - 1.).floor() as u32; - if bottom_row < map.max_point().row() + if bottom_row < map.max_point().row().0 && text_layout_details.vertical_scroll_margin as usize > times { times = text_layout_details.vertical_scroll_margin.ceil() as usize; } - let bottom_row_capped = bottom_row.min(map.max_point().row()); - let new_row = if bottom_row_capped.saturating_sub(times as u32) < first_visible_line.row() { + let bottom_row_capped = bottom_row.min(map.max_point().row().0); + let new_row = if bottom_row_capped.saturating_sub(times as u32) < first_visible_line.row().0 + { first_visible_line.row() } else { - bottom_row_capped.saturating_sub(times as u32) + DisplayRow(bottom_row_capped.saturating_sub(times as u32)) }; let new_col = point.column().min(map.line_len(new_row)); let new_point = DisplayPoint::new(new_row, new_col); diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index 9510e4f050..5604145ba6 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -25,6 +25,7 @@ use editor::Bias; use gpui::{actions, ViewContext, WindowContext}; use language::{Point, SelectionGoal}; use log::error; +use multi_buffer::MultiBufferRow; use workspace::Workspace; use self::{ @@ -314,7 +315,7 @@ fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContex .collect(); let edits = selection_start_rows.into_iter().map(|row| { let indent = snapshot - .indent_size_for_line(row) + .indent_size_for_line(MultiBufferRow(row)) .chars() .collect::(); let start_of_line = Point::new(row, 0); @@ -349,10 +350,10 @@ fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContex .collect(); let edits = selection_end_rows.into_iter().map(|row| { let indent = snapshot - .indent_size_for_line(row) + .indent_size_for_line(MultiBufferRow(row)) .chars() .collect::(); - let end_of_line = Point::new(row, snapshot.line_len(row)); + let end_of_line = Point::new(row, snapshot.line_len(MultiBufferRow(row))); (end_of_line..end_of_line, "\n".to_string() + &indent) }); editor.change_selections(Some(Autoscroll::fit()), cx, |s| { diff --git a/crates/vim/src/normal/case.rs b/crates/vim/src/normal/case.rs index 85a416d9a9..1d8447bea8 100644 --- a/crates/vim/src/normal/case.rs +++ b/crates/vim/src/normal/case.rs @@ -1,6 +1,7 @@ use editor::scroll::Autoscroll; use gpui::ViewContext; use language::{Bias, Point}; +use multi_buffer::MultiBufferRow; use workspace::Workspace; use crate::{ @@ -48,8 +49,10 @@ where match vim.state().mode { Mode::VisualLine => { let start = Point::new(selection.start.row, 0); - let end = - Point::new(selection.end.row, snapshot.line_len(selection.end.row)); + let end = Point::new( + selection.end.row, + snapshot.line_len(MultiBufferRow(selection.end.row)), + ); ranges.push(start..end); cursor_positions.push(start..start); } @@ -71,7 +74,7 @@ where } ranges.push(start..end); - if end.column == snapshot.line_len(end.row) { + if end.column == snapshot.line_len(MultiBufferRow(end.row)) { end = snapshot.clip_point(end - Point::new(0, 1), Bias::Left); } cursor_positions.push(end..end) diff --git a/crates/vim/src/normal/delete.rs b/crates/vim/src/normal/delete.rs index 9c539ca490..a32de3373c 100644 --- a/crates/vim/src/normal/delete.rs +++ b/crates/vim/src/normal/delete.rs @@ -7,6 +7,7 @@ use editor::{ }; use gpui::WindowContext; use language::{Point, Selection}; +use multi_buffer::MultiBufferRow; pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option, cx: &mut WindowContext) { vim.stop_recording(); @@ -29,7 +30,7 @@ pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option, cx: &m if selection.is_empty() && map .buffer_snapshot - .line_len(selection.start.to_point(&map).row) + .line_len(MultiBufferRow(selection.start.to_point(&map).row)) == 0 { selection.end = map @@ -79,7 +80,7 @@ pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut Windo let mut move_selection_start_to_previous_line = |map: &DisplaySnapshot, selection: &mut Selection| { let start = selection.start.to_offset(map, Bias::Left); - if selection.start.row() > 0 { + if selection.start.row().0 > 0 { should_move_to_start.insert(selection.id); selection.start = (start - '\n'.len_utf8()).to_display_point(map); } diff --git a/crates/vim/src/normal/paste.rs b/crates/vim/src/normal/paste.rs index 803365cd43..8902c5baaf 100644 --- a/crates/vim/src/normal/paste.rs +++ b/crates/vim/src/normal/paste.rs @@ -2,6 +2,7 @@ use std::cmp; use editor::{ display_map::ToDisplayPoint, movement, scroll::Autoscroll, ClipboardSelection, DisplayPoint, + RowExt, }; use gpui::{impl_actions, AppContext, ViewContext}; use language::{Bias, SelectionGoal}; @@ -99,13 +100,13 @@ fn paste(_: &mut Workspace, action: &Paste, cx: &mut ViewContext) { .map(|selection| cmp::min(selection.start.column(), selection.end.column())) .min() .unwrap(); - let mut row = current_selections.last().unwrap().end.row() + 1; + let mut row = current_selections.last().unwrap().end.row().next_row(); while i < clipboard_selections.len() { let cursor = display_map.clip_point(DisplayPoint::new(row, left), Bias::Left); selections_to_process.push((cursor..cursor, false)); i += 1; - row += 1; + row.0 += 1; } } diff --git a/crates/vim/src/normal/scroll.rs b/crates/vim/src/normal/scroll.rs index 2b8b192225..56731af30e 100644 --- a/crates/vim/src/normal/scroll.rs +++ b/crates/vim/src/normal/scroll.rs @@ -1,6 +1,8 @@ use crate::Vim; use editor::{ - display_map::ToDisplayPoint, scroll::ScrollAmount, DisplayPoint, Editor, EditorSettings, + display_map::{DisplayRow, ToDisplayPoint}, + scroll::ScrollAmount, + DisplayPoint, Editor, EditorSettings, }; use gpui::{actions, ViewContext}; use language::Bias; @@ -85,11 +87,13 @@ fn scroll_editor( if preserve_cursor_position { let old_top = old_top_anchor.to_display_point(map); - let new_row = top.row() + selection.head().row() - old_top.row(); + let new_row = + DisplayRow(top.row().0 + selection.head().row().0 - old_top.row().0); head = map.clip_point(DisplayPoint::new(new_row, head.column()), Bias::Left) } - let min_row = top.row() + vertical_scroll_margin as u32; - let max_row = top.row() + visible_rows - vertical_scroll_margin as u32 - 1; + let min_row = DisplayRow(top.row().0 + vertical_scroll_margin as u32); + let max_row = + DisplayRow(top.row().0 + visible_rows - vertical_scroll_margin as u32 - 1); let new_head = if head.row() < min_row { map.clip_point(DisplayPoint::new(min_row, head.column()), Bias::Left) diff --git a/crates/vim/src/normal/search.rs b/crates/vim/src/normal/search.rs index c819cf4265..72d7e637d3 100644 --- a/crates/vim/src/normal/search.rs +++ b/crates/vim/src/normal/search.rs @@ -509,7 +509,7 @@ fn parse_replace_all(query: &str) -> Replacement { #[cfg(test)] mod test { - use editor::DisplayPoint; + use editor::{display_map::DisplayRow, DisplayPoint}; use indoc::indoc; use search::BufferSearchBar; @@ -582,7 +582,7 @@ mod test { let highlights = editor.all_text_background_highlights(cx); assert_eq!(3, highlights.len()); assert_eq!( - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 2), highlights[0].0 ) }); diff --git a/crates/vim/src/object.rs b/crates/vim/src/object.rs index a3cd89fbe3..199c0b7422 100644 --- a/crates/vim/src/object.rs +++ b/crates/vim/src/object.rs @@ -14,6 +14,7 @@ use itertools::Itertools; use gpui::{actions, impl_actions, ViewContext, WindowContext}; use language::{char_kind, BufferSnapshot, CharKind, Point, Selection}; +use multi_buffer::MultiBufferRow; use serde::Deserialize; use workspace::Workspace; @@ -724,7 +725,7 @@ fn paragraph( let paragraph_end_row = paragraph_end.row(); let paragraph_ends_with_eof = paragraph_end_row == map.max_point().row(); let point = relative_to.to_point(map); - let current_line_is_empty = map.buffer_snapshot.is_line_blank(point.row); + let current_line_is_empty = map.buffer_snapshot.is_line_blank(MultiBufferRow(point.row)); if around { if paragraph_ends_with_eof { @@ -733,13 +734,13 @@ fn paragraph( } let paragraph_start_row = paragraph_start.row(); - if paragraph_start_row != 0 { + if paragraph_start_row.0 != 0 { let previous_paragraph_last_line_start = - Point::new(paragraph_start_row - 1, 0).to_display_point(map); + Point::new(paragraph_start_row.0 - 1, 0).to_display_point(map); paragraph_start = start_of_paragraph(map, previous_paragraph_last_line_start); } } else { - let next_paragraph_start = Point::new(paragraph_end_row + 1, 0).to_display_point(map); + let next_paragraph_start = Point::new(paragraph_end_row.0 + 1, 0).to_display_point(map); paragraph_end = end_of_paragraph(map, next_paragraph_start); } } @@ -756,10 +757,10 @@ pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> return DisplayPoint::zero(); } - let is_current_line_blank = map.buffer_snapshot.is_line_blank(point.row); + let is_current_line_blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(point.row)); for row in (0..point.row).rev() { - let blank = map.buffer_snapshot.is_line_blank(row); + let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row)); if blank != is_current_line_blank { return Point::new(row + 1, 0).to_display_point(map); } @@ -773,18 +774,21 @@ pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> /// The trailing newline is excluded from the paragraph. pub fn end_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint { let point = display_point.to_point(map); - if point.row == map.max_buffer_row() { + if point.row == map.max_buffer_row().0 { return map.max_point(); } - let is_current_line_blank = map.buffer_snapshot.is_line_blank(point.row); + let is_current_line_blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(point.row)); - for row in point.row + 1..map.max_buffer_row() + 1 { - let blank = map.buffer_snapshot.is_line_blank(row); + for row in point.row + 1..map.max_buffer_row().0 + 1 { + let blank = map.buffer_snapshot.is_line_blank(MultiBufferRow(row)); if blank != is_current_line_blank { let previous_row = row - 1; - return Point::new(previous_row, map.buffer_snapshot.line_len(previous_row)) - .to_display_point(map); + return Point::new( + previous_row, + map.buffer_snapshot.line_len(MultiBufferRow(previous_row)), + ) + .to_display_point(map); } } diff --git a/crates/vim/src/test.rs b/crates/vim/src/test.rs index 2d3946e9fb..bcf48ebdef 100644 --- a/crates/vim/src/test.rs +++ b/crates/vim/src/test.rs @@ -6,7 +6,7 @@ mod vim_test_context; use std::time::Duration; use command_palette::CommandPalette; -use editor::DisplayPoint; +use editor::{display_map::DisplayRow, DisplayPoint}; use futures::StreamExt; use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext}; pub use neovim_backed_binding_test_context::*; @@ -235,7 +235,7 @@ async fn test_selection_on_search(cx: &mut gpui::TestAppContext) { let highlights = editor.all_text_background_highlights(cx); assert_eq!(3, highlights.len()); assert_eq!( - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 2), highlights[0].0 ) }); diff --git a/crates/vim/src/utils.rs b/crates/vim/src/utils.rs index 1888b303eb..e8fb1d2e24 100644 --- a/crates/vim/src/utils.rs +++ b/crates/vim/src/utils.rs @@ -3,6 +3,7 @@ use std::time::Duration; use editor::{ClipboardSelection, Editor}; use gpui::{ClipboardItem, ViewContext}; use language::{CharKind, Point}; +use multi_buffer::MultiBufferRow; use settings::Settings; use crate::{state::Mode, UseSystemClipboard, Vim, VimSettings}; @@ -74,10 +75,10 @@ fn copy_selections_content_internal( // contains a newline (so that delete works as expected). We undo that change // here. let is_last_line = linewise - && end.row == buffer.max_buffer_row() + && end.row == buffer.max_buffer_row().0 && buffer.max_point().column > 0 - && start.row < buffer.max_buffer_row() - && start == Point::new(start.row, buffer.line_len(start.row)); + && start.row < buffer.max_buffer_row().0 + && start == Point::new(start.row, buffer.line_len(MultiBufferRow(start.row))); if is_last_line { start = Point::new(start.row + 1, 0); @@ -96,7 +97,7 @@ fn copy_selections_content_internal( clipboard_selections.push(ClipboardSelection { len: text.len() - initial_len, is_entire_line: linewise, - first_line_indent: buffer.indent_size_for_line(start.row).len, + first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len, }); } } diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index f46ccc08a2..2301d524ec 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -9,6 +9,7 @@ use editor::{ }; use gpui::{actions, ViewContext, WindowContext}; use language::{Point, Selection, SelectionGoal}; +use multi_buffer::MultiBufferRow; use search::BufferSearchBar; use util::ResultExt; use workspace::{searchable::Direction, Workspace}; @@ -251,9 +252,9 @@ pub fn visual_block_motion( break; } if tail.row() > head.row() { - row -= 1 + row.0 -= 1 } else { - row += 1 + row.0 += 1 } } @@ -313,13 +314,15 @@ pub fn visual_object(object: Object, cx: &mut WindowContext) { // trailing newline is included in its selection from the beginning. if object == Object::Paragraph && range.start != range.end { let row_of_selection_end_line = selection.end.to_point(map).row; - let new_selection_end = - if map.buffer_snapshot.line_len(row_of_selection_end_line) == 0 - { - Point::new(row_of_selection_end_line + 1, 0) - } else { - Point::new(row_of_selection_end_line, 1) - }; + let new_selection_end = if map + .buffer_snapshot + .line_len(MultiBufferRow(row_of_selection_end_line)) + == 0 + { + Point::new(row_of_selection_end_line + 1, 0) + } else { + Point::new(row_of_selection_end_line, 1) + }; selection.end = new_selection_end.to_display_point(map); } } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index fe3845bd22..60662b9495 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -910,7 +910,7 @@ mod tests { use super::*; use assets::Assets; use collections::HashSet; - use editor::{scroll::Autoscroll, DisplayPoint, Editor}; + use editor::{display_map::DisplayRow, scroll::Autoscroll, DisplayPoint, Editor}; use gpui::{ actions, Action, AnyWindowHandle, AppContext, AssetSource, BorrowAppContext, Entity, TestAppContext, VisualTestContext, WindowHandle, @@ -2229,9 +2229,8 @@ mod tests { .update(cx, |_, cx| { editor1.update(cx, |editor, cx| { editor.change_selections(Some(Autoscroll::fit()), cx, |s| { - s.select_display_ranges( - [DisplayPoint::new(10, 0)..DisplayPoint::new(10, 0)], - ) + s.select_display_ranges([DisplayPoint::new(DisplayRow(10), 0) + ..DisplayPoint::new(DisplayRow(10), 0)]) }); }); }) @@ -2256,9 +2255,8 @@ mod tests { .update(cx, |_, cx| { editor3.update(cx, |editor, cx| { editor.change_selections(Some(Autoscroll::fit()), cx, |s| { - s.select_display_ranges( - [DisplayPoint::new(12, 0)..DisplayPoint::new(12, 0)], - ) + s.select_display_ranges([DisplayPoint::new(DisplayRow(12), 0) + ..DisplayPoint::new(DisplayRow(12), 0)]) }); editor.newline(&Default::default(), cx); editor.newline(&Default::default(), cx); @@ -2279,7 +2277,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file3.clone(), DisplayPoint::new(16, 0), 12.5) + (file3.clone(), DisplayPoint::new(DisplayRow(16), 0), 12.5) ); workspace @@ -2289,7 +2287,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file3.clone(), DisplayPoint::new(0, 0), 0.) + (file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); workspace @@ -2299,7 +2297,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file2.clone(), DisplayPoint::new(0, 0), 0.) + (file2.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); workspace @@ -2309,7 +2307,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file1.clone(), DisplayPoint::new(10, 0), 0.) + (file1.clone(), DisplayPoint::new(DisplayRow(10), 0), 0.) ); workspace @@ -2319,7 +2317,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file1.clone(), DisplayPoint::new(0, 0), 0.) + (file1.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); // Go back one more time and ensure we don't navigate past the first item in the history. @@ -2330,7 +2328,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file1.clone(), DisplayPoint::new(0, 0), 0.) + (file1.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); workspace @@ -2340,7 +2338,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file1.clone(), DisplayPoint::new(10, 0), 0.) + (file1.clone(), DisplayPoint::new(DisplayRow(10), 0), 0.) ); workspace @@ -2350,7 +2348,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file2.clone(), DisplayPoint::new(0, 0), 0.) + (file2.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); // Go forward to an item that has been closed, ensuring it gets re-opened at the same @@ -2373,7 +2371,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file3.clone(), DisplayPoint::new(0, 0), 0.) + (file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); workspace @@ -2383,7 +2381,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file3.clone(), DisplayPoint::new(16, 0), 12.5) + (file3.clone(), DisplayPoint::new(DisplayRow(16), 0), 12.5) ); workspace @@ -2393,7 +2391,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file3.clone(), DisplayPoint::new(0, 0), 0.) + (file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); // Go back to an item that has been closed and removed from disk @@ -2422,7 +2420,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file2.clone(), DisplayPoint::new(0, 0), 0.) + (file2.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); workspace .update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx)) @@ -2431,7 +2429,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file3.clone(), DisplayPoint::new(0, 0), 0.) + (file3.clone(), DisplayPoint::new(DisplayRow(0), 0), 0.) ); // Modify file to collapse multiple nav history entries into the same location. @@ -2440,9 +2438,8 @@ mod tests { .update(cx, |_, cx| { editor1.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges( - [DisplayPoint::new(15, 0)..DisplayPoint::new(15, 0)], - ) + s.select_display_ranges([DisplayPoint::new(DisplayRow(15), 0) + ..DisplayPoint::new(DisplayRow(15), 0)]) }) }); }) @@ -2452,9 +2449,8 @@ mod tests { .update(cx, |_, cx| { editor1.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([ - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0) - ]) + s.select_display_ranges([DisplayPoint::new(DisplayRow(3), 0) + ..DisplayPoint::new(DisplayRow(3), 0)]) }); }); }) @@ -2464,9 +2460,8 @@ mod tests { .update(cx, |_, cx| { editor1.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([ - DisplayPoint::new(13, 0)..DisplayPoint::new(13, 0) - ]) + s.select_display_ranges([DisplayPoint::new(DisplayRow(13), 0) + ..DisplayPoint::new(DisplayRow(13), 0)]) }) }); }) @@ -2477,9 +2472,8 @@ mod tests { editor1.update(cx, |editor, cx| { editor.transact(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([ - DisplayPoint::new(2, 0)..DisplayPoint::new(14, 0) - ]) + s.select_display_ranges([DisplayPoint::new(DisplayRow(2), 0) + ..DisplayPoint::new(DisplayRow(14), 0)]) }); editor.insert("", cx); }) @@ -2491,7 +2485,8 @@ mod tests { .update(cx, |_, cx| { editor1.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { - s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]) + s.select_display_ranges([DisplayPoint::new(DisplayRow(1), 0) + ..DisplayPoint::new(DisplayRow(1), 0)]) }) }); }) @@ -2503,7 +2498,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file1.clone(), DisplayPoint::new(2, 0), 0.) + (file1.clone(), DisplayPoint::new(DisplayRow(2), 0), 0.) ); workspace .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx)) @@ -2512,7 +2507,7 @@ mod tests { .unwrap(); assert_eq!( active_location(&workspace, cx), - (file1.clone(), DisplayPoint::new(3, 0), 0.) + (file1.clone(), DisplayPoint::new(DisplayRow(3), 0), 0.) ); fn active_location(