From 7e97fcaacb1dd83eaf666f52d5a88bf4c6c29127 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Fri, 17 Oct 2025 21:56:57 +0200 Subject: [PATCH] Reduce `display_map` snapshot creation (#39354) Re-applies https://github.com/zed-industries/zed/pull/30840 This PR re-applies the initial [PR](https://github.com/zed-industries/zed/pull/30840). As it was closed because it was hard to land, because of the many conflicts. This PR re-applies the changes for it. In several cases we were creating multiple display_map snapshots within the same root-level function call. Creating a display_map snapshot is quite slow, and in some cases we were creating the snapshot multiple times. Release Notes: - N/A --- .../agent_ui/src/acp/completion_provider.rs | 4 +- crates/agent_ui/src/agent_diff.rs | 41 ++- crates/agent_ui/src/context_picker.rs | 8 +- crates/agent_ui/src/inline_assistant.rs | 17 +- crates/agent_ui/src/text_thread_editor.rs | 45 ++- .../src/selection_command.rs | 2 +- crates/collab/src/tests/editor_tests.rs | 4 +- crates/collab/src/tests/following_tests.rs | 59 +++- crates/collab_ui/src/channel_view.rs | 9 +- crates/command_palette/src/command_palette.rs | 6 +- crates/debugger_ui/src/debugger_ui.rs | 11 +- .../src/session/running/console.rs | 8 +- crates/debugger_ui/src/stack_trace_view.rs | 5 +- .../src/tests/new_process_modal.rs | 5 +- crates/diagnostics/src/items.rs | 5 +- crates/editor/src/editor.rs | 289 +++++++++++------- crates/editor/src/editor_tests.rs | 263 +++++++++++----- crates/editor/src/element.rs | 19 +- crates/editor/src/indent_guides.rs | 2 +- crates/editor/src/items.rs | 14 +- crates/editor/src/linked_editing_ranges.rs | 2 +- crates/editor/src/mouse_context_menu.rs | 6 +- crates/editor/src/scroll/actions.rs | 21 +- crates/editor/src/scroll/autoscroll.rs | 4 +- crates/editor/src/selections_collection.rs | 115 ++++--- crates/editor/src/signature_help.rs | 2 +- crates/editor/src/tasks.rs | 2 +- crates/editor/src/test.rs | 2 +- crates/editor/src/test/editor_test_context.rs | 14 +- crates/file_finder/src/file_finder_tests.rs | 4 +- crates/git_ui/src/text_diff_view.rs | 2 +- crates/go_to_line/src/go_to_line.rs | 6 +- crates/language_tools/src/lsp_log_view.rs | 7 +- crates/language_tools/src/syntax_tree_view.rs | 5 +- .../src/markdown_preview_view.rs | 8 +- crates/outline/src/outline.rs | 7 +- crates/outline_panel/src/outline_panel.rs | 19 +- .../project_panel/src/project_panel_tests.rs | 6 +- crates/repl/src/repl_editor.rs | 10 +- crates/vim/src/change_list.rs | 9 +- crates/vim/src/command.rs | 22 +- crates/vim/src/helix.rs | 28 +- crates/vim/src/helix/duplicate.rs | 3 +- crates/vim/src/helix/paste.rs | 3 +- crates/vim/src/insert.rs | 2 +- crates/vim/src/normal.rs | 28 +- crates/vim/src/normal/convert.rs | 2 +- crates/vim/src/normal/increment.rs | 2 +- crates/vim/src/normal/mark.rs | 31 +- crates/vim/src/normal/paste.rs | 5 +- crates/vim/src/normal/scroll.rs | 10 +- crates/vim/src/normal/substitute.rs | 5 +- crates/vim/src/normal/yank.rs | 4 +- crates/vim/src/replace.rs | 12 +- crates/vim/src/state.rs | 4 +- crates/vim/src/surrounds.rs | 15 +- crates/vim/src/test.rs | 5 +- crates/vim/src/vim.rs | 17 +- crates/vim/src/visual.rs | 11 +- .../zed/src/zed/quick_action_bar/repl_menu.rs | 3 +- 60 files changed, 853 insertions(+), 426 deletions(-) diff --git a/crates/agent_ui/src/acp/completion_provider.rs b/crates/agent_ui/src/acp/completion_provider.rs index 73f0622df878c2abc1d2feef945ef2e771dceaf9..c5ab47fe18970791c047ef157f6664188c95e346 100644 --- a/crates/agent_ui/src/acp/completion_provider.rs +++ b/crates/agent_ui/src/acp/completion_provider.rs @@ -652,7 +652,9 @@ impl ContextPickerCompletionProvider { .active_item(cx) .and_then(|item| item.downcast::()) .is_some_and(|editor| { - editor.update(cx, |editor, cx| editor.has_non_empty_selection(cx)) + editor.update(cx, |editor, cx| { + editor.has_non_empty_selection(&editor.display_snapshot(cx)) + }) }); if has_selection { entries.push(ContextPickerEntry::Action( diff --git a/crates/agent_ui/src/agent_diff.rs b/crates/agent_ui/src/agent_diff.rs index 67014e3c3a4c8bd9b43f34d9cad3c23832efdc13..c2b624ecfca2bed4c9480bf681fe17b43b569685 100644 --- a/crates/agent_ui/src/agent_diff.rs +++ b/crates/agent_ui/src/agent_diff.rs @@ -452,7 +452,10 @@ fn update_editor_selection( window: &mut Window, cx: &mut Context, ) { - let newest_cursor = editor.selections.newest::(cx).head(); + let newest_cursor = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head(); if !diff_hunks.iter().any(|hunk| { hunk.row_range @@ -1895,7 +1898,9 @@ mod tests { ); assert_eq!( editor - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(1, 0)..Point::new(1, 0) ); @@ -1909,7 +1914,9 @@ mod tests { ); assert_eq!( editor - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(3, 0)..Point::new(3, 0) ); @@ -1930,7 +1937,9 @@ mod tests { ); assert_eq!( editor - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(3, 0)..Point::new(3, 0) ); @@ -1962,7 +1971,9 @@ mod tests { ); assert_eq!( editor - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(3, 0)..Point::new(3, 0) ); @@ -2119,7 +2130,9 @@ mod tests { ); assert_eq!( editor1 - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(1, 0)..Point::new(1, 0) ); @@ -2160,7 +2173,9 @@ mod tests { ); assert_eq!( editor1 - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(3, 0)..Point::new(3, 0) ); @@ -2181,7 +2196,9 @@ mod tests { ); assert_eq!( editor1 - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(3, 0)..Point::new(3, 0) ); @@ -2207,7 +2224,9 @@ mod tests { ); assert_eq!( editor1 - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(3, 0)..Point::new(3, 0) ); @@ -2240,7 +2259,9 @@ mod tests { ); assert_eq!( editor2 - .update(cx, |editor, cx| editor.selections.newest::(cx)) + .update(cx, |editor, cx| editor + .selections + .newest::(&editor.display_snapshot(cx))) .range(), Point::new(0, 0)..Point::new(0, 0) ); diff --git a/crates/agent_ui/src/context_picker.rs b/crates/agent_ui/src/context_picker.rs index cfb2ce0a60441c18d62965dddf6a626c4b4a4243..caffb31521e397ca7cd6b1fa0c8f4ae73d5ab9ff 100644 --- a/crates/agent_ui/src/context_picker.rs +++ b/crates/agent_ui/src/context_picker.rs @@ -606,7 +606,11 @@ pub(crate) fn available_context_picker_entries( .read(cx) .active_item(cx) .and_then(|item| item.downcast::()) - .is_some_and(|editor| editor.update(cx, |editor, cx| editor.has_non_empty_selection(cx))); + .is_some_and(|editor| { + editor.update(cx, |editor, cx| { + editor.has_non_empty_selection(&editor.display_snapshot(cx)) + }) + }); if has_selection { entries.push(ContextPickerEntry::Action( ContextPickerAction::AddSelections, @@ -725,7 +729,7 @@ pub(crate) fn selection_ranges( }; editor.update(cx, |editor, cx| { - let selections = editor.selections.all_adjusted(cx); + let selections = editor.selections.all_adjusted(&editor.display_snapshot(cx)); let buffer = editor.buffer().clone().read(cx); let snapshot = buffer.snapshot(cx); diff --git a/crates/agent_ui/src/inline_assistant.rs b/crates/agent_ui/src/inline_assistant.rs index 4c09e475b10881ab9bc2327b5b18b1c66e2ba4ad..0f7f1f1d78056553f758796c7e6b2f14781fce0f 100644 --- a/crates/agent_ui/src/inline_assistant.rs +++ b/crates/agent_ui/src/inline_assistant.rs @@ -363,9 +363,12 @@ impl InlineAssistant { cx: &mut App, ) { let (snapshot, initial_selections, newest_selection) = editor.update(cx, |editor, cx| { - let selections = editor.selections.all::(cx); - let newest_selection = editor.selections.newest::(cx); - (editor.snapshot(window, cx), selections, newest_selection) + let snapshot = editor.snapshot(window, cx); + let selections = editor.selections.all::(&snapshot.display_snapshot); + let newest_selection = editor + .selections + .newest::(&snapshot.display_snapshot); + (snapshot, selections, newest_selection) }); // Check if there is already an inline assistant that contains the @@ -798,7 +801,9 @@ impl InlineAssistant { if editor.read(cx).selections.count() == 1 { let (selection, buffer) = editor.update(cx, |editor, cx| { ( - editor.selections.newest::(cx), + editor + .selections + .newest::(&editor.display_snapshot(cx)), editor.buffer().read(cx).snapshot(cx), ) }); @@ -829,7 +834,9 @@ impl InlineAssistant { if editor.read(cx).selections.count() == 1 { let (selection, buffer) = editor.update(cx, |editor, cx| { ( - editor.selections.newest::(cx), + editor + .selections + .newest::(&editor.display_snapshot(cx)), editor.buffer().read(cx).snapshot(cx), ) }); diff --git a/crates/agent_ui/src/text_thread_editor.rs b/crates/agent_ui/src/text_thread_editor.rs index 1b19ef1aa4046b1159d849e56a9e959d13dc53ce..2d28d95450726554787f6a9cb211e852ceaccddf 100644 --- a/crates/agent_ui/src/text_thread_editor.rs +++ b/crates/agent_ui/src/text_thread_editor.rs @@ -431,9 +431,9 @@ impl TextThreadEditor { } fn cursors(&self, cx: &mut App) -> Vec { - let selections = self - .editor - .update(cx, |editor, cx| editor.selections.all::(cx)); + let selections = self.editor.update(cx, |editor, cx| { + editor.selections.all::(&editor.display_snapshot(cx)) + }); selections .into_iter() .map(|selection| selection.head()) @@ -446,7 +446,10 @@ impl TextThreadEditor { editor.transact(window, cx, |editor, window, cx| { editor.change_selections(Default::default(), window, cx, |s| s.try_cancel()); let snapshot = editor.buffer().read(cx).snapshot(cx); - let newest_cursor = editor.selections.newest::(cx).head(); + let newest_cursor = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head(); if newest_cursor.column > 0 || snapshot .chars_at(newest_cursor) @@ -1248,11 +1251,19 @@ impl TextThreadEditor { let context_editor = context_editor_view.read(cx).editor.clone(); context_editor.update(cx, |context_editor, cx| { - if context_editor.selections.newest::(cx).is_empty() { + let display_map = context_editor.display_snapshot(cx); + if context_editor + .selections + .newest::(&display_map) + .is_empty() + { let snapshot = context_editor.buffer().read(cx).snapshot(cx); let (_, _, snapshot) = snapshot.as_singleton()?; - let head = context_editor.selections.newest::(cx).head(); + let head = context_editor + .selections + .newest::(&display_map) + .head(); let offset = snapshot.point_to_offset(head); let surrounding_code_block_range = find_surrounding_code_block(snapshot, offset)?; @@ -1269,7 +1280,7 @@ impl TextThreadEditor { (!text.is_empty()).then_some((text, true)) } else { - let selection = context_editor.selections.newest_adjusted(cx); + let selection = context_editor.selections.newest_adjusted(&display_map); let buffer = context_editor.buffer().read(cx).snapshot(cx); let selected_text = buffer.text_for_range(selection.range()).collect::(); @@ -1457,7 +1468,7 @@ impl TextThreadEditor { let selections = editor.update(cx, |editor, cx| { editor .selections - .all_adjusted(cx) + .all_adjusted(&editor.display_snapshot(cx)) .into_iter() .filter_map(|s| { (!s.is_empty()) @@ -1489,7 +1500,10 @@ impl TextThreadEditor { self.editor.update(cx, |editor, cx| { editor.insert("\n", window, cx); for (text, crease_title) in creases { - let point = editor.selections.newest::(cx).head(); + let point = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head(); let start_row = MultiBufferRow(point.row); editor.insert(&text, window, cx); @@ -1561,7 +1575,9 @@ impl TextThreadEditor { cx: &mut Context, ) -> (String, CopyMetadata, Vec>) { let (mut selection, creases) = self.editor.update(cx, |editor, cx| { - let mut selection = editor.selections.newest_adjusted(cx); + let mut selection = editor + .selections + .newest_adjusted(&editor.display_snapshot(cx)); let snapshot = editor.buffer().read(cx).snapshot(cx); selection.goal = SelectionGoal::None; @@ -1680,7 +1696,10 @@ impl TextThreadEditor { if images.is_empty() { self.editor.update(cx, |editor, cx| { - let paste_position = editor.selections.newest::(cx).head(); + let paste_position = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head(); editor.paste(action, window, cx); if let Some(metadata) = metadata { @@ -1727,13 +1746,13 @@ impl TextThreadEditor { editor.transact(window, cx, |editor, _window, cx| { let edits = editor .selections - .all::(cx) + .all::(&editor.display_snapshot(cx)) .into_iter() .map(|selection| (selection.start..selection.end, "\n")); editor.edit(edits, cx); let snapshot = editor.buffer().read(cx).snapshot(cx); - for selection in editor.selections.all::(cx) { + for selection in editor.selections.all::(&editor.display_snapshot(cx)) { image_positions.push(snapshot.anchor_before(selection.end)); } }); diff --git a/crates/assistant_slash_commands/src/selection_command.rs b/crates/assistant_slash_commands/src/selection_command.rs index c8692dec718a03af777753f35ae646f245878ed9..ce6c0b931411d8073ffd6c97b648bb044ad857e7 100644 --- a/crates/assistant_slash_commands/src/selection_command.rs +++ b/crates/assistant_slash_commands/src/selection_command.rs @@ -79,7 +79,7 @@ impl SlashCommand for SelectionCommand { editor.update(cx, |editor, cx| { let selection_ranges = editor .selections - .all_adjusted(cx) + .all_adjusted(&editor.display_snapshot(cx)) .iter() .map(|selection| selection.range()) .collect::>(); diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs index 9a923c3fb3a11e0ecd01706c19c0087de6475a09..6e6a815a0b4c0fc8e8e2f367738a60aea604b5e1 100644 --- a/crates/collab/src/tests/editor_tests.rs +++ b/crates/collab/src/tests/editor_tests.rs @@ -877,7 +877,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T 6..9 ); rename.editor.update(cx, |rename_editor, cx| { - let rename_selection = rename_editor.selections.newest::(cx); + let rename_selection = rename_editor.selections.newest::(&rename_editor.display_snapshot(cx)); assert_eq!( rename_selection.range(), 0..3, @@ -924,7 +924,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T let lsp_rename_end = rename.range.end.to_offset(&buffer); assert_eq!(lsp_rename_start..lsp_rename_end, 6..9); rename.editor.update(cx, |rename_editor, cx| { - let rename_selection = rename_editor.selections.newest::(cx); + let rename_selection = rename_editor.selections.newest::(&rename_editor.display_snapshot(cx)); assert_eq!( rename_selection.range(), 1..2, diff --git a/crates/collab/src/tests/following_tests.rs b/crates/collab/src/tests/following_tests.rs index 6f4a819f440929a9cc004cc018169420f758d264..ab72ce3605b7c93bac05dc6321b44b7abb964d93 100644 --- a/crates/collab/src/tests/following_tests.rs +++ b/crates/collab/src/tests/following_tests.rs @@ -122,13 +122,19 @@ async fn test_basic_following( editor.handle_input("b", window, cx); editor.handle_input("c", window, cx); editor.select_left(&Default::default(), window, cx); - assert_eq!(editor.selections.ranges(cx), vec![3..2]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![3..2] + ); }); editor_a2.update_in(cx_a, |editor, window, cx| { editor.handle_input("d", window, cx); editor.handle_input("e", window, cx); editor.select_left(&Default::default(), window, cx); - assert_eq!(editor.selections.ranges(cx), vec![2..1]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![2..1] + ); }); // When client B starts following client A, only the active view state is replicated to client B. @@ -149,11 +155,15 @@ async fn test_basic_following( Some((worktree_id, rel_path("2.txt")).into()) ); assert_eq!( - editor_b2.update(cx_b, |editor, cx| editor.selections.ranges(cx)), + editor_b2.update(cx_b, |editor, cx| editor + .selections + .ranges(&editor.display_snapshot(cx))), vec![2..1] ); assert_eq!( - editor_b1.update(cx_b, |editor, cx| editor.selections.ranges(cx)), + editor_b1.update(cx_b, |editor, cx| editor + .selections + .ranges(&editor.display_snapshot(cx))), vec![3..3] ); @@ -384,7 +394,10 @@ async fn test_basic_following( cx_b.background_executor.run_until_parked(); editor_b1.update(cx_b, |editor, cx| { - assert_eq!(editor.selections.ranges(cx), &[1..1, 2..2]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + &[1..1, 2..2] + ); }); editor_a1.update_in(cx_a, |editor, window, cx| { @@ -402,7 +415,10 @@ async fn test_basic_following( executor.advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); executor.run_until_parked(); editor_b1.update(cx_b, |editor, cx| { - assert_eq!(editor.selections.ranges(cx), &[3..3]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + &[3..3] + ); }); // After unfollowing, client B stops receiving updates from client A. @@ -1679,7 +1695,10 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T .advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); cx_a.run_until_parked(); editor_b.update(cx_b, |editor, cx| { - assert_eq!(editor.selections.ranges(cx), vec![1..1]) + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![1..1] + ) }); // a unshares the project @@ -1701,7 +1720,10 @@ async fn test_following_stops_on_unshare(cx_a: &mut TestAppContext, cx_b: &mut T .advance_clock(workspace::item::LEADER_UPDATE_THROTTLE); cx_a.run_until_parked(); editor_b.update(cx_b, |editor, cx| { - assert_eq!(editor.selections.ranges(cx), vec![1..1]) + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![1..1] + ) }); cx_b.update(|_, cx| { let room = ActiveCall::global(cx).read(cx).room().unwrap().read(cx); @@ -1799,13 +1821,19 @@ async fn test_following_into_excluded_file( editor.handle_input("b", window, cx); editor.handle_input("c", window, cx); editor.select_left(&Default::default(), window, cx); - assert_eq!(editor.selections.ranges(cx), vec![3..2]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![3..2] + ); }); editor_for_excluded_a.update_in(cx_a, |editor, window, cx| { editor.select_all(&Default::default(), window, cx); editor.handle_input("new commit message", window, cx); editor.select_left(&Default::default(), window, cx); - assert_eq!(editor.selections.ranges(cx), vec![18..17]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![18..17] + ); }); // When client B starts following client A, currently visible file is replicated @@ -1827,7 +1855,9 @@ async fn test_following_into_excluded_file( Some((worktree_id, rel_path(".git/COMMIT_EDITMSG")).into()) ); assert_eq!( - editor_for_excluded_b.update(cx_b, |editor, cx| editor.selections.ranges(cx)), + editor_for_excluded_b.update(cx_b, |editor, cx| editor + .selections + .ranges(&editor.display_snapshot(cx))), vec![18..17] ); @@ -2037,7 +2067,12 @@ async fn test_following_to_channel_notes_without_a_shared_project( assert_eq!(notes.channel(cx).unwrap().name, "channel-1"); notes.editor.update(cx, |editor, cx| { assert_eq!(editor.text(cx), "Hello from A."); - assert_eq!(editor.selections.ranges::(cx), &[3..4]); + assert_eq!( + editor + .selections + .ranges::(&editor.display_snapshot(cx)), + &[3..4] + ); }) }); diff --git a/crates/collab_ui/src/channel_view.rs b/crates/collab_ui/src/channel_view.rs index e37abbbccdbcdb7335b45b3fbe01d8797541e336..4e4bd2ca958d20225a7188b1f7f601e879e22835 100644 --- a/crates/collab_ui/src/channel_view.rs +++ b/crates/collab_ui/src/channel_view.rs @@ -287,9 +287,12 @@ impl ChannelView { } fn copy_link(&mut self, _: &CopyLink, window: &mut Window, cx: &mut Context) { - let position = self - .editor - .update(cx, |editor, cx| editor.selections.newest_display(cx).start); + let position = self.editor.update(cx, |editor, cx| { + editor + .selections + .newest_display(&editor.display_snapshot(cx)) + .start + }); self.copy_link_for_position(position, window, cx) } diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index e718fe99297802ea90d425aef5063f3b55a86579..f9ed9ec6faf6b1cefbd9159a06e145b32c752c1f 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -698,7 +698,11 @@ mod tests { editor.update_in(cx, |editor, window, cx| { assert!(editor.focus_handle(cx).is_focused(window)); assert_eq!( - editor.selections.last::(cx).range().start, + editor + .selections + .last::(&editor.display_snapshot(cx)) + .range() + .start, Point::new(2, 0) ); }); diff --git a/crates/debugger_ui/src/debugger_ui.rs b/crates/debugger_ui/src/debugger_ui.rs index 689e3cd878b574d31963231df9bcff317ea6d64c..78cc9e9bd28beb31474c12662d7e118eae6f066e 100644 --- a/crates/debugger_ui/src/debugger_ui.rs +++ b/crates/debugger_ui/src/debugger_ui.rs @@ -341,8 +341,10 @@ pub fn init(cx: &mut App) { maybe!({ let (buffer, position, _) = editor .update(cx, |editor, cx| { - let cursor_point: language::Point = - editor.selections.newest(cx).head(); + let cursor_point: language::Point = editor + .selections + .newest(&editor.display_snapshot(cx)) + .head(); editor .buffer() @@ -392,7 +394,10 @@ pub fn init(cx: &mut App) { let text = editor .update(cx, |editor, cx| { editor.text_for_range( - editor.selections.newest(cx).range(), + editor + .selections + .newest(&editor.display_snapshot(cx)) + .range(), &mut None, window, cx, diff --git a/crates/debugger_ui/src/session/running/console.rs b/crates/debugger_ui/src/session/running/console.rs index 635955dda9c1c26d7e501c7991d2afc9fa1c9bb1..29cdf9a8067c099a8454ad21b459853cf3982f1a 100644 --- a/crates/debugger_ui/src/session/running/console.rs +++ b/crates/debugger_ui/src/session/running/console.rs @@ -963,8 +963,12 @@ mod tests { ) { cx.set_state(input); - let buffer_position = - cx.editor(|editor, _, cx| editor.selections.newest::(cx).start); + let buffer_position = cx.editor(|editor, _, cx| { + editor + .selections + .newest::(&editor.display_snapshot(cx)) + .start + }); let snapshot = &cx.buffer_snapshot(); diff --git a/crates/debugger_ui/src/stack_trace_view.rs b/crates/debugger_ui/src/stack_trace_view.rs index 3806e77b6e932b90f4dec143ddacd40a02e6e421..07caabaacaf00d2752a04c5ba68be07a5678c40a 100644 --- a/crates/debugger_ui/src/stack_trace_view.rs +++ b/crates/debugger_ui/src/stack_trace_view.rs @@ -55,7 +55,10 @@ impl StackTraceView { cx.subscribe_in(&editor, window, |this, editor, event, window, cx| { if let EditorEvent::SelectionsChanged { local: true } = event { let excerpt_id = editor.update(cx, |editor, cx| { - let position: Point = editor.selections.newest(cx).head(); + let position: Point = editor + .selections + .newest(&editor.display_snapshot(cx)) + .head(); editor .snapshot(window, cx) diff --git a/crates/debugger_ui/src/tests/new_process_modal.rs b/crates/debugger_ui/src/tests/new_process_modal.rs index 80e27ee6bdeb1d1a2627ad7aa46bf68c38464510..2f470560d5a58a1ed9e56ebe89257572d195689e 100644 --- a/crates/debugger_ui/src/tests/new_process_modal.rs +++ b/crates/debugger_ui/src/tests/new_process_modal.rs @@ -231,7 +231,10 @@ async fn test_save_debug_scenario_to_file(executor: BackgroundExecutor, cx: &mut editor.update(cx, |editor, cx| { assert_eq!( - editor.selections.newest::(cx).head(), + editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head(), Point::new(5, 2) ) }); diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index b03b686c996ea85310bd446100255896870549f1..d3947b9b5d56b3ae71c3af7c8bf829676041123b 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -170,7 +170,10 @@ impl DiagnosticIndicator { fn update(&mut self, editor: Entity, window: &mut Window, cx: &mut Context) { let (buffer, cursor_position) = editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); - let cursor_position = editor.selections.newest::(cx).head(); + let cursor_position = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head(); (buffer, cursor_position) }); let new_diagnostic = buffer diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 5d881f221b238c35224f804c1b95094a2db957e8..66e5b4df9d035e85114d177ba0456fba9d2f3d10 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2323,21 +2323,22 @@ impl Editor { } EditorEvent::Edited { .. } => { if !vim_enabled(cx) { - let (map, selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_adjusted_display(&display_map); let pop_state = editor .change_list .last() .map(|previous| { previous.len() == selections.len() && previous.iter().enumerate().all(|(ix, p)| { - p.to_display_point(&map).row() + p.to_display_point(&display_map).row() == selections[ix].head().row() }) }) .unwrap_or(false); let new_positions = selections .into_iter() - .map(|s| map.display_point_to_anchor(s.head(), Bias::Left)) + .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left)) .collect(); editor .change_list @@ -2408,6 +2409,10 @@ impl Editor { editor } + pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot { + self.selections.display_map(cx) + } + pub fn deploy_mouse_context_menu( &mut self, position: gpui::Point, @@ -2443,7 +2448,7 @@ impl Editor { } self.selections - .disjoint_in_range::(range.clone(), cx) + .disjoint_in_range::(range.clone(), &self.display_snapshot(cx)) .into_iter() .any(|selection| { // This is needed to cover a corner case, if we just check for an existing @@ -3039,7 +3044,7 @@ impl Editor { // Copy selections to primary selection buffer #[cfg(any(target_os = "linux", target_os = "freebsd"))] if local { - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); let buffer_handle = self.buffer.read(cx).read(cx); let mut text = String::new(); @@ -3491,7 +3496,7 @@ impl Editor { cx: &mut Context, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let tail = self.selections.newest::(cx).tail(); + let tail = self.selections.newest::(&display_map).tail(); let click_count = click_count.max(match self.selections.select_mode() { SelectMode::Character => 1, SelectMode::Word(_) => 2, @@ -3610,7 +3615,7 @@ impl Editor { let point_to_delete: Option = { let selected_points: Vec> = - self.selections.disjoint_in_range(start..end, cx); + self.selections.disjoint_in_range(start..end, &display_map); if !add || click_count > 1 { None @@ -3686,7 +3691,7 @@ impl Editor { ); }; - let tail = self.selections.newest::(cx).tail(); + let tail = self.selections.newest::(&display_map).tail(); let selection_anchor = display_map.buffer_snapshot().anchor_before(tail); self.columnar_selection_state = match mode { ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse { @@ -3813,7 +3818,7 @@ impl Editor { fn end_selection(&mut self, window: &mut Window, cx: &mut Context) { self.columnar_selection_state.take(); if let Some(pending_mode) = self.selections.pending_mode() { - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.select(selections); s.clear_pending(); @@ -3902,9 +3907,9 @@ impl Editor { cx.notify(); } - pub fn has_non_empty_selection(&self, cx: &mut App) -> bool { + pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool { self.selections - .all_adjusted(cx) + .all_adjusted(snapshot) .iter() .any(|selection| !selection.is_empty()) } @@ -4053,7 +4058,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); - let selections = self.selections.all_adjusted(cx); + let selections = self.selections.all_adjusted(&self.display_snapshot(cx)); let mut bracket_inserted = false; let mut edits = Vec::new(); let mut linked_edits = HashMap::<_, Vec<_>>::default(); @@ -4403,7 +4408,7 @@ impl Editor { let trigger_in_words = this.show_edit_predictions_in_menu() || !had_active_edit_prediction; if this.hard_wrap.is_some() { - let latest: Range = this.selections.newest(cx).range(); + let latest: Range = this.selections.newest(&map).range(); if latest.is_empty() && this .buffer() @@ -4479,7 +4484,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); self.transact(window, cx, |this, window, cx| { let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = { - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&this.display_snapshot(cx)); let multi_buffer = this.buffer.read(cx); let buffer = multi_buffer.snapshot(cx); selections @@ -4771,7 +4776,12 @@ impl Editor { let mut edits = Vec::new(); let mut rows = Vec::new(); - for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() { + for (rows_inserted, selection) in self + .selections + .all_adjusted(&self.display_snapshot(cx)) + .into_iter() + .enumerate() + { let cursor = selection.head(); let row = cursor.row; @@ -4831,7 +4841,7 @@ impl Editor { let mut rows = Vec::new(); let mut rows_inserted = 0; - for selection in self.selections.all_adjusted(cx) { + for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) { let cursor = selection.head(); let row = cursor.row; @@ -4903,7 +4913,7 @@ impl Editor { let text: Arc = text.into(); self.transact(window, cx, |this, window, cx| { - let old_selections = this.selections.all_adjusted(cx); + let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx)); let selection_anchors = this.buffer.update(cx, |buffer, cx| { let anchors = { let snapshot = buffer.read(cx); @@ -5013,7 +5023,7 @@ impl Editor { /// If any empty selections is touching the start of its innermost containing autoclose /// region, expand it to select the brackets. fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context) { - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); let buffer = self.buffer.read(cx).read(cx); let new_selections = self .selections_with_autoclose_regions(selections, &buffer) @@ -6010,7 +6020,7 @@ impl Editor { let prefix = &old_text[..old_text.len().saturating_sub(lookahead)]; let suffix = &old_text[lookbehind.min(old_text.len())..]; - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); let mut ranges = Vec::new(); let mut linked_edits = HashMap::<_, Vec<_>>::default(); @@ -6162,7 +6172,10 @@ impl Editor { Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => { DisplayPoint::new(*row, 0).to_point(&snapshot) } - _ => self.selections.newest::(cx).head(), + _ => self + .selections + .newest::(&snapshot.display_snapshot) + .head(), }; let Some((buffer, buffer_row)) = snapshot .buffer_snapshot() @@ -6624,7 +6637,9 @@ impl Editor { if newest_selection.head().diff_base_anchor.is_some() { return None; } - let newest_selection_adjusted = this.selections.newest_adjusted(cx); + let display_snapshot = this.display_snapshot(cx); + let newest_selection_adjusted = + this.selections.newest_adjusted(&display_snapshot); let buffer = this.buffer.read(cx); let (start_buffer, start) = @@ -6699,7 +6714,10 @@ impl Editor { pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context) { let snapshot = self.snapshot(window, cx); - let cursor = self.selections.newest::(cx).head(); + let cursor = self + .selections + .newest::(&snapshot.display_snapshot) + .head(); let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor) else { return; @@ -7572,7 +7590,10 @@ impl Editor { // Find an insertion that starts at the cursor position. let snapshot = self.buffer.read(cx).snapshot(cx); - let cursor_offset = self.selections.newest::(cx).head(); + let cursor_offset = self + .selections + .newest::(&self.display_snapshot(cx)) + .head(); let insertion = edits.iter().find_map(|(range, text)| { let range = range.to_offset(&snapshot); if range.is_empty() && range.start == cursor_offset { @@ -8528,7 +8549,11 @@ impl Editor { &mut self, cx: &mut Context, ) -> Option<(Entity, u32, Arc)> { - let cursor_row = self.selections.newest_adjusted(cx).head().row; + let cursor_row = self + .selections + .newest_adjusted(&self.display_snapshot(cx)) + .head() + .row; let ((buffer_id, row), tasks) = self .tasks @@ -8545,7 +8570,10 @@ impl Editor { cx: &mut Context, ) -> Option<(Entity, u32, Arc)> { let snapshot = self.buffer.read(cx).snapshot(cx); - let offset = self.selections.newest::(cx).head(); + let offset = self + .selections + .newest::(&self.display_snapshot(cx)) + .head(); let excerpt = snapshot.excerpt_containing(offset..offset)?; let buffer_id = excerpt.buffer().remote_id(); @@ -9862,8 +9890,7 @@ impl Editor { // Check whether the just-entered snippet ends with an auto-closable bracket. if self.autoclose_regions.is_empty() { let snapshot = self.buffer.read(cx).snapshot(cx); - let mut all_selections = self.selections.all::(cx); - for selection in &mut all_selections { + for selection in &mut self.selections.all::(&self.display_snapshot(cx)) { let selection_head = selection.head(); let Some(scope) = snapshot.language_scope_at(selection_head) else { continue; @@ -10001,9 +10028,12 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); self.transact(window, cx, |this, window, cx| { this.select_autoclose_pair(window, cx); + + let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx)); + let mut linked_ranges = HashMap::<_, Vec<_>>::default(); if !this.linked_edit_ranges.is_empty() { - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&display_map); let snapshot = this.buffer.read(cx).snapshot(cx); for selection in selections.iter() { @@ -10022,8 +10052,7 @@ impl Editor { } } - let mut selections = this.selections.all::(cx); - let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx)); + let mut selections = this.selections.all::(&display_map); for selection in &mut selections { if selection.is_empty() { let old_head = selection.head(); @@ -10138,7 +10167,7 @@ impl Editor { return; } self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); - let mut selections = self.selections.all_adjusted(cx); + let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx)); let buffer = self.buffer.read(cx); let snapshot = buffer.snapshot(cx); let rows_iter = selections.iter().map(|s| s.head().row); @@ -10254,7 +10283,7 @@ impl Editor { } self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); - let mut selections = self.selections.all::(cx); + let mut selections = self.selections.all::(&self.display_snapshot(cx)); let mut prev_edited_row = 0; let mut row_delta = 0; let mut edits = Vec::new(); @@ -10363,7 +10392,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let mut deletion_ranges = Vec::new(); let mut last_outdent = None; { @@ -10424,7 +10453,7 @@ impl Editor { cx, ); }); - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&this.display_snapshot(cx)); this.change_selections(Default::default(), window, cx, |s| s.select(selections)); }); } @@ -10441,7 +10470,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); let selections = self .selections - .all::(cx) + .all::(&self.display_snapshot(cx)) .into_iter() .map(|s| s.range()); @@ -10449,7 +10478,7 @@ impl Editor { this.buffer.update(cx, |buffer, cx| { buffer.autoindent_ranges(selections, cx); }); - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&this.display_snapshot(cx)); this.change_selections(Default::default(), window, cx, |s| s.select(selections)); }); } @@ -10457,7 +10486,7 @@ impl Editor { pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context) { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let mut new_cursors = Vec::new(); let mut edit_ranges = Vec::new(); @@ -10551,7 +10580,7 @@ impl Editor { return; } let mut row_ranges = Vec::>::new(); - for selection in self.selections.all::(cx) { + for selection in self.selections.all::(&self.display_snapshot(cx)) { let start = MultiBufferRow(selection.start.row); // Treat single line selections as if they include the next line. Otherwise this action // would do nothing for single line selections individual cursors. @@ -10694,7 +10723,11 @@ impl Editor { let mut edits = Vec::new(); let mut boundaries = Vec::new(); - for selection in self.selections.all::(cx).iter() { + for selection in self + .selections + .all::(&self.display_snapshot(cx)) + .iter() + { let Some(wrap_config) = snapshot .language_at(selection.start) .and_then(|lang| lang.config().wrap_characters.clone()) @@ -10764,7 +10797,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); let mut buffer_ids = HashSet::default(); let snapshot = self.buffer().read(cx).snapshot(cx); - for selection in self.selections.all::(cx) { + for selection in self.selections.all::(&self.display_snapshot(cx)) { buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range())) } @@ -10781,7 +10814,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); let selections = self .selections - .all(cx) + .all(&self.display_snapshot(cx)) .into_iter() .map(|s| s.range()) .collect(); @@ -11189,7 +11222,7 @@ impl Editor { let mut edits = Vec::new(); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let mut selections = selections.iter().peekable(); let mut contiguous_row_selections = Vec::new(); let mut new_selections = Vec::new(); @@ -11591,7 +11624,7 @@ impl Editor { let mut edits = Vec::new(); let mut selection_adjustment = 0i32; - for selection in self.selections.all_adjusted(cx) { + for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) { let selection_is_empty = selection.is_empty(); let (start, end) = if selection_is_empty { @@ -11683,7 +11716,7 @@ impl Editor { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = display_map.buffer_snapshot(); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let mut edits = Vec::new(); let mut selections_iter = selections.iter().peekable(); @@ -11791,7 +11824,7 @@ impl Editor { let mut unfold_ranges = Vec::new(); let mut refold_creases = Vec::new(); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let mut selections = selections.iter().peekable(); let mut contiguous_row_selections = Vec::new(); let mut new_selections = Vec::new(); @@ -11902,7 +11935,7 @@ impl Editor { let mut unfold_ranges = Vec::new(); let mut refold_creases = Vec::new(); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let mut selections = selections.iter().peekable(); let mut contiguous_row_selections = Vec::new(); let mut new_selections = Vec::new(); @@ -12035,7 +12068,7 @@ impl Editor { }); this.buffer .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&this.display_snapshot(cx)); this.change_selections(Default::default(), window, cx, |s| { s.select(selections); }); @@ -12054,7 +12087,7 @@ impl Editor { pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context) { let buffer = self.buffer.read(cx).snapshot(cx); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); #[derive(Clone, Debug, PartialEq)] enum CommentFormat { @@ -12430,7 +12463,7 @@ impl Editor { ) -> ClipboardItem { let mut text = String::new(); let buffer = self.buffer.read(cx).snapshot(cx); - let mut selections = self.selections.all::(cx); + let mut selections = self.selections.all::(&self.display_snapshot(cx)); let mut clipboard_selections = Vec::with_capacity(selections.len()); { let max_point = buffer.max_point(); @@ -12526,7 +12559,7 @@ impl Editor { } fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context) { - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); let buffer = self.buffer.read(cx).read(cx); let mut text = String::new(); @@ -12637,8 +12670,9 @@ impl Editor { self.transact(window, cx, |this, window, cx| { let had_active_edit_prediction = this.has_active_edit_prediction(); - let old_selections = this.selections.all::(cx); - let cursor_offset = this.selections.last::(cx).head(); + let display_map = this.display_snapshot(cx); + let old_selections = this.selections.all::(&display_map); + let cursor_offset = this.selections.last::(&display_map).head(); if let Some(mut clipboard_selections) = clipboard_selections { let all_selections_were_entire_line = @@ -12719,7 +12753,7 @@ impl Editor { ); }); - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&this.display_snapshot(cx)); this.change_selections(Default::default(), window, cx, |s| s.select(selections)); } else { let url = url::Url::parse(&clipboard_text).ok(); @@ -12784,7 +12818,7 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); if selections.is_empty() { log::warn!("There should always be at least one selection in Zed. This is a bug."); @@ -14047,7 +14081,7 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let mut selection = self.selections.last::(cx); + let mut selection = self.selections.last::(&self.display_snapshot(cx)); selection.set_head(Point::zero(), SelectionGoal::None); self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); self.change_selections(Default::default(), window, cx, |s| { @@ -14126,7 +14160,7 @@ impl Editor { pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context) { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let buffer = self.buffer.read(cx).snapshot(cx); - let mut selection = self.selections.first::(cx); + let mut selection = self.selections.first::(&self.display_snapshot(cx)); selection.set_head(buffer.len(), SelectionGoal::None); self.change_selections(Default::default(), window, cx, |s| { s.select(vec![selection]); @@ -14144,7 +14178,7 @@ impl Editor { pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context) { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections.all::(cx); + let mut selections = self.selections.all::(&display_map); let max_point = display_map.buffer_snapshot().max_point(); for selection in &mut selections { let rows = selection.spanned_rows(true, &display_map); @@ -14165,7 +14199,7 @@ impl Editor { ) { let selections = self .selections - .all::(cx) + .all::(&self.display_snapshot(cx)) .into_iter() .map(|selection| selection.start..selection.end) .collect::>(); @@ -14244,7 +14278,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let all_selections = self.selections.all::(cx); + let all_selections = self.selections.all::(&display_map); let text_layout_details = self.text_layout_details(window); let (mut columnar_selections, new_selections_to_columnarize) = { @@ -14378,7 +14412,7 @@ impl Editor { let final_selection_ids: HashSet<_> = self .selections - .all::(cx) + .all::(&display_map) .iter() .map(|s| s.id) .collect(); @@ -14436,7 +14470,7 @@ impl Editor { cx: &mut Context, ) -> Result<()> { let buffer = display_map.buffer_snapshot(); - let mut selections = self.selections.all::(cx); + let mut selections = self.selections.all::(&display_map); if let Some(mut select_next_state) = self.select_next_state.take() { let query = &select_next_state.query; if !select_next_state.done { @@ -14610,7 +14644,7 @@ impl Editor { let mut new_selections = Vec::new(); - let reversed = self.selections.oldest::(cx).reversed; + let reversed = self.selections.oldest::(&display_map).reversed; let buffer = display_map.buffer_snapshot(); let query_matches = select_next_state .query @@ -14674,7 +14708,7 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = display_map.buffer_snapshot(); - let mut selections = self.selections.all::(cx); + let mut selections = self.selections.all::(&display_map); if let Some(mut select_prev_state) = self.select_prev_state.take() { let query = &select_prev_state.query; if !select_prev_state.done { @@ -14862,7 +14896,9 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx); let text_layout_details = &self.text_layout_details(window); self.transact(window, cx, |this, window, cx| { - let mut selections = this.selections.all::(cx); + let mut selections = this + .selections + .all::(&this.display_snapshot(cx)); let mut edits = Vec::new(); let mut selection_edit_ranges = Vec::new(); let mut last_toggled_row = None; @@ -15093,7 +15129,7 @@ impl Editor { // Adjust selections so that they end before any comment suffixes that // were inserted. let mut suffixes_inserted = suffixes_inserted.into_iter().peekable(); - let mut selections = this.selections.all::(cx); + let mut selections = this.selections.all::(&this.display_snapshot(cx)); let snapshot = this.buffer.read(cx).read(cx); for selection in &mut selections { while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() { @@ -15119,7 +15155,7 @@ impl Editor { drop(snapshot); this.change_selections(Default::default(), window, cx, |s| s.select(selections)); - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&this.display_snapshot(cx)); let selections_on_single_row = selections.windows(2).all(|selections| { selections[0].start.row == selections[1].start.row && selections[0].end.row == selections[1].end.row @@ -15163,7 +15199,10 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let buffer = self.buffer.read(cx).snapshot(cx); - let old_selections = self.selections.all::(cx).into_boxed_slice(); + let old_selections = self + .selections + .all::(&self.display_snapshot(cx)) + .into_boxed_slice(); fn update_selection( selection: &Selection, @@ -15218,7 +15257,10 @@ impl Editor { let Some(visible_row_count) = self.visible_row_count() else { return; }; - let old_selections: Box<[_]> = self.selections.all::(cx).into(); + let old_selections: Box<[_]> = self + .selections + .all::(&self.display_snapshot(cx)) + .into(); if old_selections.is_empty() { return; } @@ -15376,7 +15418,7 @@ impl Editor { let buffer = self.buffer.read(cx).snapshot(cx); let selections = self .selections - .all::(cx) + .all::(&self.display_snapshot(cx)) .into_iter() // subtracting the offset requires sorting .sorted_by_key(|i| i.start); @@ -15448,7 +15490,10 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let old_selections: Box<[_]> = self.selections.all::(cx).into(); + let old_selections: Box<[_]> = self + .selections + .all::(&self.display_snapshot(cx)) + .into(); if old_selections.is_empty() { return; } @@ -15497,7 +15542,10 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let old_selections: Box<[_]> = self.selections.all::(cx).into(); + let old_selections: Box<[_]> = self + .selections + .all::(&self.display_snapshot(cx)) + .into(); if old_selections.is_empty() { return; } @@ -16046,7 +16094,7 @@ impl Editor { cx: &mut Context, ) { let buffer = self.buffer.read(cx).snapshot(cx); - let selection = self.selections.newest::(cx); + let selection = self.selections.newest::(&self.display_snapshot(cx)); let mut active_group_id = None; if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics @@ -16127,7 +16175,7 @@ impl Editor { pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context) { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let snapshot = self.snapshot(window, cx); - let selection = self.selections.newest::(cx); + let selection = self.selections.newest::(&self.display_snapshot(cx)); self.go_to_hunk_before_or_after_position( &snapshot, selection.head(), @@ -16188,7 +16236,7 @@ impl Editor { ) { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let snapshot = self.snapshot(window, cx); - let selection = self.selections.newest::(cx); + let selection = self.selections.newest::(&snapshot.display_snapshot); self.go_to_hunk_before_or_after_position( &snapshot, selection.head(), @@ -16278,7 +16326,10 @@ impl Editor { self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let snapshot = self.snapshot(window, cx); let buffer = &snapshot.buffer_snapshot(); - let position = self.selections.newest::(cx).head(); + let position = self + .selections + .newest::(&snapshot.display_snapshot) + .head(); let anchor_position = buffer.anchor_after(position); // Get all document highlights (both read and write) @@ -16461,7 +16512,10 @@ impl Editor { let Some(provider) = self.semantics_provider.clone() else { return Task::ready(Ok(Navigated::No)); }; - let head = self.selections.newest::(cx).head(); + let head = self + .selections + .newest::(&self.display_snapshot(cx)) + .head(); let buffer = self.buffer.read(cx); let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else { return Task::ready(Ok(Navigated::No)); @@ -16792,7 +16846,7 @@ impl Editor { window: &mut Window, cx: &mut Context, ) -> Option>> { - let selection = self.selections.newest::(cx); + let selection = self.selections.newest::(&self.display_snapshot(cx)); let multi_buffer = self.buffer.read(cx); let head = selection.head(); @@ -17267,7 +17321,10 @@ impl Editor { if moving_cursor { let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| { - editor.selections.newest::(cx).head() + editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head() }); // Update the selection to match the position of the selection inside @@ -17330,7 +17387,7 @@ impl Editor { let ranges = self .selections - .all_adjusted(cx) + .all_adjusted(&self.display_snapshot(cx)) .into_iter() .map(|selection| selection.range()) .collect_vec(); @@ -18029,9 +18086,9 @@ impl Editor { cx: &mut Context, ) { if self.buffer_kind(cx) == ItemBufferKind::Singleton { - let selection = self.selections.newest::(cx); - let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + let selection = self.selections.newest::(&display_map); + let range = if selection.is_empty() { let point = selection.head().to_display_point(&display_map); let start = DisplayPoint::new(point.row(), 0).to_point(&display_map); @@ -18074,7 +18131,7 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let selection = self.selections.newest::(cx); + let selection = self.selections.newest::(&self.display_snapshot(cx)); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let range = if selection.is_empty() { @@ -18097,7 +18154,7 @@ impl Editor { if self.buffer_kind(cx) == ItemBufferKind::Singleton { let mut to_fold = Vec::new(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let selections = self.selections.all_adjusted(cx); + let selections = self.selections.all_adjusted(&display_map); for selection in selections { let range = selection.range().sorted(); @@ -18204,7 +18261,7 @@ impl Editor { let row_ranges_to_keep: Vec> = self .selections - .all::(cx) + .all::(&self.display_snapshot(cx)) .into_iter() .map(|sel| sel.start.row..sel.end.row) .collect(); @@ -18379,7 +18436,7 @@ impl Editor { ) { let mut to_fold = Vec::new(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let selections = self.selections.all_adjusted(cx); + let selections = self.selections.all_adjusted(&display_map); for selection in selections { let range = selection.range().sorted(); @@ -18423,7 +18480,7 @@ impl Editor { if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) { let autoscroll = self .selections - .all::(cx) + .all::(&display_map) .iter() .any(|selection| crease.range().overlaps(&selection.range())); @@ -18435,7 +18492,7 @@ impl Editor { if self.buffer_kind(cx) == ItemBufferKind::Singleton { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = display_map.buffer_snapshot(); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let ranges = selections .iter() .map(|s| { @@ -18469,7 +18526,7 @@ impl Editor { cx: &mut Context, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let ranges = selections .iter() .map(|s| { @@ -18501,7 +18558,7 @@ impl Editor { let autoscroll = self .selections - .all::(cx) + .all::(&display_map) .iter() .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range)); @@ -18536,8 +18593,8 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let selections = self.selections.all_adjusted(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + let selections = self.selections.all_adjusted(&display_map); let ranges = selections .into_iter() .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone())) @@ -18870,7 +18927,10 @@ impl Editor { self.stage_or_unstage_diff_hunks(stage, ranges, cx); let snapshot = self.snapshot(window, cx); - let position = self.selections.newest::(cx).head(); + let position = self + .selections + .newest::(&snapshot.display_snapshot) + .head(); let mut row = snapshot .buffer_snapshot() .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point()) @@ -19018,7 +19078,7 @@ impl Editor { let snapshot = self.snapshot(window, cx); let hunks = snapshot.hunks_for_ranges( self.selections - .all(cx) + .all(&snapshot.display_snapshot) .into_iter() .map(|selection| selection.range()), ); @@ -19754,7 +19814,10 @@ impl Editor { ) -> Option<()> { let blame = self.blame.as_ref()?; let snapshot = self.snapshot(window, cx); - let cursor = self.selections.newest::(cx).head(); + let cursor = self + .selections + .newest::(&snapshot.display_snapshot) + .head(); let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?; let (_, blame_entry) = blame .update(cx, |blame, cx| { @@ -19896,7 +19959,7 @@ impl Editor { fn get_permalink_to_line(&self, cx: &mut Context) -> Task> { let buffer_and_selection = maybe!({ - let selection = self.selections.newest::(cx); + let selection = self.selections.newest::(&self.display_snapshot(cx)); let selection_range = selection.range(); let multi_buffer = self.buffer().read(cx); @@ -19974,7 +20037,12 @@ impl Editor { _: &mut Window, cx: &mut Context, ) { - let selection = self.selections.newest::(cx).start.row + 1; + let selection = self + .selections + .newest::(&self.display_snapshot(cx)) + .start + .row + + 1; if let Some(file) = self.target_file(cx) { let path = file.path().display(file.path_style(cx)); cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}"))); @@ -20045,7 +20113,7 @@ impl Editor { self.transact(window, cx, |this, window, cx| { let edits = this .selections - .all::(cx) + .all::(&this.display_snapshot(cx)) .into_iter() .map(|selection| { let uuid = match version { @@ -21131,7 +21199,7 @@ impl Editor { return; }; - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); let multi_buffer = self.buffer.read(cx); let multi_buffer_snapshot = multi_buffer.snapshot(cx); let mut new_selections_by_buffer = HashMap::default(); @@ -21255,7 +21323,7 @@ impl Editor { } } None => { - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&self.display_snapshot(cx)); let multi_buffer = self.buffer.read(cx); for selection in selections { for (snapshot, range, _, anchor) in multi_buffer @@ -21393,7 +21461,9 @@ impl Editor { range: Range, cx: &mut App, ) -> Vec> { - let selections = self.selections.all::(cx); + let selections = self + .selections + .all::(&self.display_snapshot(cx)); let newest_selection = selections .iter() .max_by_key(|selection| selection.id) @@ -21556,7 +21626,10 @@ impl Editor { cx: &mut Context, ) { self.request_autoscroll(Autoscroll::newest(), cx); - let position = self.selections.newest_display(cx).start; + let position = self + .selections + .newest_display(&self.display_snapshot(cx)) + .start; mouse_context_menu::deploy_context_menu(self, None, position, window, cx); } @@ -21576,7 +21649,9 @@ impl Editor { return; } if let Some(relative_utf16_range) = relative_utf16_range { - let selections = self.selections.all::(cx); + let selections = self + .selections + .all::(&self.display_snapshot(cx)); self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { let new_ranges = selections.into_iter().map(|range| { let start = OffsetUtf16( @@ -21716,7 +21791,7 @@ impl Editor { } let transaction = self.transact(window, cx, |this, window, cx| { - let selections = this.selections.all::(cx); + let selections = this.selections.all::(&this.display_snapshot(cx)); let edits = selections .iter() .map(|selection| (selection.end..selection.end, pending.clone())); @@ -21735,7 +21810,7 @@ impl Editor { let snapshot = self.snapshot(window, cx); let ranges = self .selections - .all::(cx) + .all::(&snapshot.display_snapshot) .into_iter() .map(|selection| { snapshot.buffer_snapshot().anchor_after(selection.end) @@ -23867,7 +23942,9 @@ impl EntityInputHandler for Editor { return None; } - let selection = self.selections.newest::(cx); + let selection = self + .selections + .newest::(&self.display_snapshot(cx)); let range = selection.range(); Some(UTF16Selection { @@ -23910,7 +23987,7 @@ impl EntityInputHandler for Editor { let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| { let newest_selection_id = this.selections.newest_anchor().id; this.selections - .all::(cx) + .all::(&this.display_snapshot(cx)) .iter() .zip(ranges_to_replace.iter()) .find_map(|(selection, range)| { @@ -23985,7 +24062,7 @@ impl EntityInputHandler for Editor { let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| { let newest_selection_id = this.selections.newest_anchor().id; this.selections - .all::(cx) + .all::(&this.display_snapshot(cx)) .iter() .zip(ranges_to_replace.iter()) .find_map(|(selection, range)| { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 2c8dc9e3548fa5edd2cc3020f1a314e961bd71a3..239dc2969196d400a84824eabc0ca7e300851a35 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -219,7 +219,10 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { editor.insert("cd", window, cx); editor.end_transaction_at(now, cx); assert_eq!(editor.text(cx), "12cd56"); - assert_eq!(editor.selections.ranges(cx), vec![4..4]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![4..4] + ); editor.start_transaction_at(now, window, cx); editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { @@ -228,7 +231,10 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { editor.insert("e", window, cx); editor.end_transaction_at(now, cx); assert_eq!(editor.text(cx), "12cde6"); - assert_eq!(editor.selections.ranges(cx), vec![5..5]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![5..5] + ); now += group_interval + Duration::from_millis(1); editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { @@ -244,30 +250,45 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { }); assert_eq!(editor.text(cx), "ab2cde6"); - assert_eq!(editor.selections.ranges(cx), vec![3..3]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![3..3] + ); // Last transaction happened past the group interval in a different editor. // Undo it individually and don't restore selections. editor.undo(&Undo, window, cx); assert_eq!(editor.text(cx), "12cde6"); - assert_eq!(editor.selections.ranges(cx), vec![2..2]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![2..2] + ); // First two transactions happened within the group interval in this editor. // Undo them together and restore selections. editor.undo(&Undo, window, cx); editor.undo(&Undo, window, cx); // Undo stack is empty here, so this is a no-op. assert_eq!(editor.text(cx), "123456"); - assert_eq!(editor.selections.ranges(cx), vec![0..0]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![0..0] + ); // Redo the first two transactions together. editor.redo(&Redo, window, cx); assert_eq!(editor.text(cx), "12cde6"); - assert_eq!(editor.selections.ranges(cx), vec![5..5]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![5..5] + ); // Redo the last transaction on its own. editor.redo(&Redo, window, cx); assert_eq!(editor.text(cx), "ab2cde6"); - assert_eq!(editor.selections.ranges(cx), vec![6..6]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + vec![6..6] + ); // Test empty transactions. editor.start_transaction_at(now, window, cx); @@ -770,10 +791,14 @@ fn test_clone(cx: &mut TestAppContext) { ); assert_set_eq!( cloned_editor - .update(cx, |editor, _, cx| editor.selections.ranges::(cx)) + .update(cx, |editor, _, cx| editor + .selections + .ranges::(&editor.display_snapshot(cx))) .unwrap(), editor - .update(cx, |editor, _, cx| editor.selections.ranges(cx)) + .update(cx, |editor, _, cx| editor + .selections + .ranges(&editor.display_snapshot(cx))) .unwrap() ); assert_set_eq!( @@ -3161,7 +3186,7 @@ fn test_newline_with_old_selections(cx: &mut TestAppContext) { ); }); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), &[ Point::new(1, 2)..Point::new(1, 2), Point::new(2, 2)..Point::new(2, 2), @@ -3183,7 +3208,7 @@ fn test_newline_with_old_selections(cx: &mut TestAppContext) { // The selections are moved after the inserted newlines assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), &[ Point::new(2, 0)..Point::new(2, 0), Point::new(4, 0)..Point::new(4, 0), @@ -3673,13 +3698,19 @@ fn test_insert_with_old_selections(cx: &mut TestAppContext) { buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], None, cx); assert_eq!(buffer.read(cx).text(), "a(), b(), c()".unindent()); }); - assert_eq!(editor.selections.ranges(cx), &[2..2, 7..7, 12..12],); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + &[2..2, 7..7, 12..12], + ); editor.insert("Z", window, cx); assert_eq!(editor.text(cx), "a(Z), b(Z), c(Z)"); // The selections are moved after the inserted characters - assert_eq!(editor.selections.ranges(cx), &[3..3, 9..9, 15..15],); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + &[3..3, 9..9, 15..15], + ); }); } @@ -4439,7 +4470,9 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { let buffer = buffer.read(cx).as_singleton().unwrap(); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), &[Point::new(0, 0)..Point::new(0, 0)] ); @@ -4447,7 +4480,9 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd\n\n"); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), &[Point::new(0, 3)..Point::new(0, 3)] ); @@ -4458,7 +4493,9 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb ccc ddd\n\n"); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), &[Point::new(0, 11)..Point::new(0, 11)] ); @@ -4466,7 +4503,9 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { editor.undo(&Undo, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd\n\n"); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), &[Point::new(0, 5)..Point::new(2, 2)] ); @@ -4477,7 +4516,9 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd\n"); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), [Point::new(2, 3)..Point::new(2, 3)] ); @@ -4485,7 +4526,9 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd"); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), [Point::new(2, 3)..Point::new(2, 3)] ); @@ -4493,7 +4536,9 @@ fn test_join_lines_with_single_selection(cx: &mut TestAppContext) { editor.join_lines(&JoinLines, window, cx); assert_eq!(buffer.read(cx).text(), "aaa bbb\nccc\nddd"); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), [Point::new(2, 3)..Point::new(2, 3)] ); @@ -4550,7 +4595,9 @@ fn test_join_lines_with_multi_selection(cx: &mut TestAppContext) { assert_eq!(buffer.read(cx).text(), "aaa bbb ccc\nddd\n"); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), [ Point::new(0, 7)..Point::new(0, 7), Point::new(1, 3)..Point::new(1, 3) @@ -5908,15 +5955,24 @@ fn test_transpose(cx: &mut TestAppContext) { }); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bac"); - assert_eq!(editor.selections.ranges(cx), [2..2]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [2..2] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bca"); - assert_eq!(editor.selections.ranges(cx), [3..3]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [3..3] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bac"); - assert_eq!(editor.selections.ranges(cx), [3..3]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [3..3] + ); editor }); @@ -5929,22 +5985,34 @@ fn test_transpose(cx: &mut TestAppContext) { }); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acb\nde"); - assert_eq!(editor.selections.ranges(cx), [3..3]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [3..3] + ); editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.select_ranges([4..4]) }); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acbd\ne"); - assert_eq!(editor.selections.ranges(cx), [5..5]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [5..5] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acbde\n"); - assert_eq!(editor.selections.ranges(cx), [6..6]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [6..6] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "acbd\ne"); - assert_eq!(editor.selections.ranges(cx), [6..6]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [6..6] + ); editor }); @@ -5957,23 +6025,38 @@ fn test_transpose(cx: &mut TestAppContext) { }); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bacd\ne"); - assert_eq!(editor.selections.ranges(cx), [2..2, 3..3, 5..5]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [2..2, 3..3, 5..5] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcade\n"); - assert_eq!(editor.selections.ranges(cx), [3..3, 4..4, 6..6]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [3..3, 4..4, 6..6] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcda\ne"); - assert_eq!(editor.selections.ranges(cx), [4..4, 6..6]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [4..4, 6..6] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcade\n"); - assert_eq!(editor.selections.ranges(cx), [4..4, 6..6]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [4..4, 6..6] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "bcaed\n"); - assert_eq!(editor.selections.ranges(cx), [5..5, 6..6]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [5..5, 6..6] + ); editor }); @@ -5986,15 +6069,24 @@ fn test_transpose(cx: &mut TestAppContext) { }); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "🏀🍐✋"); - assert_eq!(editor.selections.ranges(cx), [8..8]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [8..8] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "🏀✋🍐"); - assert_eq!(editor.selections.ranges(cx), [11..11]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [11..11] + ); editor.transpose(&Default::default(), window, cx); assert_eq!(editor.text(cx), "🏀🍐✋"); - assert_eq!(editor.selections.ranges(cx), [11..11]); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + [11..11] + ); editor }); @@ -9540,7 +9632,7 @@ async fn test_autoindent(cx: &mut TestAppContext) { editor.newline(&Newline, window, cx); assert_eq!(editor.text(cx), "fn a(\n \n) {\n \n}\n"); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), &[ Point::new(1, 4)..Point::new(1, 4), Point::new(3, 4)..Point::new(3, 4), @@ -9616,7 +9708,7 @@ async fn test_autoindent_disabled(cx: &mut TestAppContext) { ) ); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), &[ Point::new(1, 0)..Point::new(1, 0), Point::new(3, 0)..Point::new(3, 0), @@ -10255,7 +10347,9 @@ async fn test_autoclose_with_embedded_language(cx: &mut TestAppContext) { // Precondition: different languages are active at different locations. cx.update_editor(|editor, window, cx| { let snapshot = editor.snapshot(window, cx); - let cursors = editor.selections.ranges::(cx); + let cursors = editor + .selections + .ranges::(&editor.display_snapshot(cx)); let languages = cursors .iter() .map(|c| snapshot.language_at(c.start).unwrap().name()) @@ -10700,7 +10794,9 @@ async fn test_delete_autoclose_pair(cx: &mut TestAppContext) { .unindent() ); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), [ Point::new(0, 4)..Point::new(0, 4), Point::new(1, 4)..Point::new(1, 4), @@ -10720,7 +10816,9 @@ async fn test_delete_autoclose_pair(cx: &mut TestAppContext) { .unindent() ); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), [ Point::new(0, 2)..Point::new(0, 2), Point::new(1, 2)..Point::new(1, 2), @@ -10739,7 +10837,9 @@ async fn test_delete_autoclose_pair(cx: &mut TestAppContext) { .unindent() ); assert_eq!( - editor.selections.ranges::(cx), + editor + .selections + .ranges::(&editor.display_snapshot(cx)), [ Point::new(0, 1)..Point::new(0, 1), Point::new(1, 1)..Point::new(1, 1), @@ -10945,7 +11045,12 @@ async fn test_snippet_placeholder_choices(cx: &mut TestAppContext) { fn assert(editor: &mut Editor, cx: &mut Context, marked_text: &str) { let (expected_text, selection_ranges) = marked_text_ranges(marked_text, false); assert_eq!(editor.text(cx), expected_text); - assert_eq!(editor.selections.ranges::(cx), selection_ranges); + assert_eq!( + editor + .selections + .ranges::(&editor.display_snapshot(cx)), + selection_ranges + ); } assert( @@ -10976,7 +11081,7 @@ async fn test_snippets(cx: &mut TestAppContext) { let snippet = Snippet::parse("f(${1:one}, ${2:two}, ${1:three})$0").unwrap(); let insertion_ranges = editor .selections - .all(cx) + .all(&editor.display_snapshot(cx)) .iter() .map(|s| s.range()) .collect::>(); @@ -11056,7 +11161,7 @@ async fn test_snippet_indentation(cx: &mut TestAppContext) { .unwrap(); let insertion_ranges = editor .selections - .all(cx) + .all(&editor.display_snapshot(cx)) .iter() .map(|s| s.range()) .collect::>(); @@ -15945,7 +16050,7 @@ fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) { editor.handle_input("X", window, cx); assert_eq!(editor.text(cx), "Xaaaa\nXbbbb"); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [ Point::new(0, 1)..Point::new(0, 1), Point::new(1, 1)..Point::new(1, 1), @@ -15959,7 +16064,7 @@ fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) { editor.backspace(&Default::default(), window, cx); assert_eq!(editor.text(cx), "Xa\nbbb"); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [Point::new(1, 0)..Point::new(1, 0)] ); @@ -15969,7 +16074,7 @@ fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) { editor.backspace(&Default::default(), window, cx); assert_eq!(editor.text(cx), "X\nbb"); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [Point::new(0, 1)..Point::new(0, 1)] ); }); @@ -16027,7 +16132,10 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) { false, ); assert_eq!(editor.text(cx), expected_text); - assert_eq!(editor.selections.ranges(cx), expected_selections); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + expected_selections + ); editor.newline(&Newline, window, cx); let (expected_text, expected_selections) = marked_text_ranges( @@ -16044,7 +16152,10 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) { false, ); assert_eq!(editor.text(cx), expected_text); - assert_eq!(editor.selections.ranges(cx), expected_selections); + assert_eq!( + editor.selections.ranges(&editor.display_snapshot(cx)), + expected_selections + ); }); } @@ -16085,7 +16196,7 @@ fn test_refresh_selections(cx: &mut TestAppContext) { cx, ); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [ Point::new(1, 3)..Point::new(1, 3), Point::new(2, 1)..Point::new(2, 1), @@ -16098,7 +16209,7 @@ fn test_refresh_selections(cx: &mut TestAppContext) { _ = editor.update(cx, |editor, window, cx| { editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| s.refresh()); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [ Point::new(1, 3)..Point::new(1, 3), Point::new(2, 1)..Point::new(2, 1), @@ -16112,7 +16223,7 @@ fn test_refresh_selections(cx: &mut TestAppContext) { _ = editor.update(cx, |editor, window, cx| { // Removing an excerpt causes the first selection to become degenerate. assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [ Point::new(0, 0)..Point::new(0, 0), Point::new(0, 1)..Point::new(0, 1) @@ -16123,7 +16234,7 @@ fn test_refresh_selections(cx: &mut TestAppContext) { // location. editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| s.refresh()); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [ Point::new(0, 1)..Point::new(0, 1), Point::new(0, 3)..Point::new(0, 3) @@ -16167,7 +16278,7 @@ fn test_refresh_selections_while_selecting_with_mouse(cx: &mut TestAppContext) { cx, ); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [Point::new(1, 3)..Point::new(1, 3)] ); editor @@ -16178,14 +16289,14 @@ fn test_refresh_selections_while_selecting_with_mouse(cx: &mut TestAppContext) { }); _ = editor.update(cx, |editor, window, cx| { assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [Point::new(0, 0)..Point::new(0, 0)] ); // Ensure we don't panic when selections are refreshed and that the pending selection is finalized. editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| s.refresh()); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), [Point::new(0, 3)..Point::new(0, 3)] ); assert!(editor.selections.pending_anchor().is_some()); @@ -16435,7 +16546,10 @@ async fn test_following(cx: &mut TestAppContext) { .await .unwrap(); _ = follower.update(cx, |follower, _, cx| { - assert_eq!(follower.selections.ranges(cx), vec![1..1]); + assert_eq!( + follower.selections.ranges(&follower.display_snapshot(cx)), + vec![1..1] + ); }); assert!(*is_still_following.borrow()); assert_eq!(*follower_edit_event_count.borrow(), 0); @@ -16488,7 +16602,10 @@ async fn test_following(cx: &mut TestAppContext) { .unwrap(); _ = follower.update(cx, |follower, _, cx| { assert_eq!(follower.scroll_position(cx), gpui::Point::new(1.5, 0.0)); - assert_eq!(follower.selections.ranges(cx), vec![0..0]); + assert_eq!( + follower.selections.ranges(&follower.display_snapshot(cx)), + vec![0..0] + ); }); assert!(*is_still_following.borrow()); @@ -16512,7 +16629,10 @@ async fn test_following(cx: &mut TestAppContext) { .await .unwrap(); _ = follower.update(cx, |follower, _, cx| { - assert_eq!(follower.selections.ranges(cx), vec![0..0, 1..1]); + assert_eq!( + follower.selections.ranges(&follower.display_snapshot(cx)), + vec![0..0, 1..1] + ); }); assert!(*is_still_following.borrow()); @@ -16533,7 +16653,10 @@ async fn test_following(cx: &mut TestAppContext) { .await .unwrap(); _ = follower.update(cx, |follower, _, cx| { - assert_eq!(follower.selections.ranges(cx), vec![0..2]); + assert_eq!( + follower.selections.ranges(&follower.display_snapshot(cx)), + vec![0..2] + ); }); // Scrolling locally breaks the follow @@ -22668,11 +22791,11 @@ fn add_log_breakpoint_at_cursor( .first() .and_then(|(anchor, bp)| bp.as_ref().map(|bp| (*anchor, bp.clone()))) .unwrap_or_else(|| { - let cursor_position: Point = editor.selections.newest(cx).head(); + let snapshot = editor.snapshot(window, cx); + let cursor_position: Point = + editor.selections.newest(&snapshot.display_snapshot).head(); - let breakpoint_position = editor - .snapshot(window, cx) - .display_snapshot + let breakpoint_position = snapshot .buffer_snapshot() .anchor_before(Point::new(cursor_position.row, 0)); @@ -23619,7 +23742,7 @@ println!("5"); assert_eq!( editor .selections - .all::(cx) + .all::(&editor.display_snapshot(cx)) .into_iter() .map(|s| s.range()) .collect::>(), @@ -23662,7 +23785,7 @@ println!("5"); assert_eq!( editor .selections - .all::(cx) + .all::(&editor.display_snapshot(cx)) .into_iter() .map(|s| s.range()) .collect::>(), @@ -23788,7 +23911,7 @@ println!("5"); assert_eq!( editor .selections - .all::(cx) + .all::(&editor.display_snapshot(cx)) .into_iter() .map(|s| s.range()) .collect::>(), @@ -23814,7 +23937,7 @@ println!("5"); assert_eq!( editor .selections - .all::(cx) + .all::(&editor.display_snapshot(cx)) .into_iter() .map(|s| s.range()) .collect::>(), @@ -25211,7 +25334,7 @@ fn assert_selection_ranges(marked_text: &str, editor: &mut Editor, cx: &mut Cont let (text, ranges) = marked_text_ranges(marked_text, true); assert_eq!(editor.text(cx), text); assert_eq!( - editor.selections.ranges(cx), + editor.selections.ranges(&editor.display_snapshot(cx)), ranges, "Assert selections are {}", marked_text diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index f71110ed95d13eba4577e53cf148e8d7efbc20c1..2dcb9996c37d54ad352795b39a0b28ece2827759 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1377,7 +1377,7 @@ impl EditorElement { editor_with_selections.update(cx, |editor, cx| { if editor.show_local_selections { let mut layouts = Vec::new(); - let newest = editor.selections.newest(cx); + let newest = editor.selections.newest(&editor.display_snapshot(cx)); for selection in local_selections.iter().cloned() { let is_empty = selection.start == selection.end; let is_newest = selection == newest; @@ -3195,7 +3195,9 @@ impl EditorElement { let (newest_selection_head, is_relative) = self.editor.update(cx, |editor, cx| { let newest_selection_head = newest_selection_head.unwrap_or_else(|| { - let newest = editor.selections.newest::(cx); + let newest = editor + .selections + .newest::(&editor.display_snapshot(cx)); SelectionLayout::new( newest, editor.selections.line_mode(), @@ -8793,7 +8795,8 @@ impl Element for EditorElement { .editor_with_selections(cx) .map(|editor| { editor.update(cx, |editor, cx| { - let all_selections = editor.selections.all::(cx); + let all_selections = + editor.selections.all::(&snapshot.display_snapshot); let selected_buffer_ids = if editor.buffer_kind(cx) == ItemBufferKind::Singleton { Vec::new() @@ -8815,10 +8818,12 @@ impl Element for EditorElement { selected_buffer_ids }; - let mut selections = editor - .selections - .disjoint_in_range(start_anchor..end_anchor, cx); - selections.extend(editor.selections.pending(cx)); + let mut selections = editor.selections.disjoint_in_range( + start_anchor..end_anchor, + &snapshot.display_snapshot, + ); + selections + .extend(editor.selections.pending(&snapshot.display_snapshot)); (selections, selected_buffer_ids) }) diff --git a/crates/editor/src/indent_guides.rs b/crates/editor/src/indent_guides.rs index 22b57bd80579c61405cf46b5e84d1fa128a38ffb..7c392d27531472a413ce4d32d09cce4eb722e462 100644 --- a/crates/editor/src/indent_guides.rs +++ b/crates/editor/src/indent_guides.rs @@ -69,7 +69,7 @@ impl Editor { window: &mut Window, cx: &mut Context, ) -> Option> { - let selection = self.selections.newest::(cx); + let selection = self.selections.newest::(&self.display_snapshot(cx)); let cursor_row = MultiBufferRow(selection.head().row); let state = &mut self.active_indent_guides_state; diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index de47f66183ee972e77a54e436bf25b94cef66e36..708efbbe979dd153dbafde265e56bc2ddd725f76 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -594,7 +594,7 @@ impl Item for Editor { cx: &mut Context, ) -> bool { if let Ok(data) = data.downcast::() { - let newest_selection = self.selections.newest::(cx); + let newest_selection = self.selections.newest::(&self.display_snapshot(cx)); let buffer = self.buffer.read(cx).read(cx); let offset = if buffer.can_resolve(&data.cursor_anchor) { data.cursor_anchor.to_point(&buffer) @@ -1539,13 +1539,13 @@ impl SearchableItem for Editor { fn query_suggestion(&mut self, window: &mut Window, cx: &mut Context) -> String { let setting = EditorSettings::get_global(cx).seed_search_query_from_cursor; let snapshot = self.snapshot(window, cx); - let snapshot = snapshot.buffer_snapshot(); - let selection = self.selections.newest_adjusted(cx); + let selection = self.selections.newest_adjusted(&snapshot.display_snapshot); + let buffer_snapshot = snapshot.buffer_snapshot(); match setting { SeedQuerySetting::Never => String::new(), SeedQuerySetting::Selection | SeedQuerySetting::Always if !selection.is_empty() => { - let text: String = snapshot + let text: String = buffer_snapshot .text_for_range(selection.start..selection.end) .collect(); if text.contains('\n') { @@ -1556,10 +1556,10 @@ impl SearchableItem for Editor { } SeedQuerySetting::Selection => String::new(), SeedQuerySetting::Always => { - let (range, kind) = - snapshot.surrounding_word(selection.start, Some(CharScopeContext::Completion)); + let (range, kind) = buffer_snapshot + .surrounding_word(selection.start, Some(CharScopeContext::Completion)); if kind == Some(CharKind::Word) { - let text: String = snapshot.text_for_range(range).collect(); + let text: String = buffer_snapshot.text_for_range(range).collect(); if !text.trim().is_empty() { return text; } diff --git a/crates/editor/src/linked_editing_ranges.rs b/crates/editor/src/linked_editing_ranges.rs index a26e24e1cbca4f06e94cde4898e7f9d2a80da8e1..c883ec14fb4c50a11fb4dfba1031baebf4637f11 100644 --- a/crates/editor/src/linked_editing_ranges.rs +++ b/crates/editor/src/linked_editing_ranges.rs @@ -59,7 +59,7 @@ pub(super) fn refresh_linked_ranges( let mut applicable_selections = Vec::new(); editor .update(cx, |editor, cx| { - let selections = editor.selections.all::(cx); + let selections = editor.selections.all::(&editor.display_snapshot(cx)); let snapshot = editor.buffer.read(cx).snapshot(cx); let buffer = editor.buffer.read(cx); for selection in selections { diff --git a/crates/editor/src/mouse_context_menu.rs b/crates/editor/src/mouse_context_menu.rs index 3d8bbb36103f2e82ce421c9ba83dea0bd6396780..cef691dec483c8a9ae978499689db69b14c5dffe 100644 --- a/crates/editor/src/mouse_context_menu.rs +++ b/crates/editor/src/mouse_context_menu.rs @@ -154,7 +154,7 @@ pub fn deploy_context_menu( return; } - let display_map = editor.selections.display_map(cx); + let display_map = editor.display_snapshot(cx); let source_anchor = display_map.display_point_to_anchor(point, text::Bias::Right); let context_menu = if let Some(custom) = editor.custom_context_menu.take() { let menu = custom(editor, point, window, cx); @@ -169,8 +169,8 @@ pub fn deploy_context_menu( return; }; - let display_map = editor.selections.display_map(cx); let snapshot = editor.snapshot(window, cx); + let display_map = editor.display_snapshot(cx); let buffer = snapshot.buffer_snapshot(); let anchor = buffer.anchor_before(point.to_point(&display_map)); if !display_ranges(&display_map, &editor.selections).any(|r| r.contains(&point)) { @@ -185,7 +185,7 @@ pub fn deploy_context_menu( let has_reveal_target = editor.target_file(cx).is_some(); let has_selections = editor .selections - .all::(cx) + .all::(&display_map) .into_iter() .any(|s| !s.is_empty()); let has_git_repo = buffer diff --git a/crates/editor/src/scroll/actions.rs b/crates/editor/src/scroll/actions.rs index 1d98cb537ab8cc9dcf7aac23e6c43f6c1a26ff0a..3b2ed55df724485ee72e6afbc02c7111817869fb 100644 --- a/crates/editor/src/scroll/actions.rs +++ b/crates/editor/src/scroll/actions.rs @@ -72,7 +72,12 @@ impl Editor { cx: &mut Context, ) { let scroll_margin_rows = self.vertical_scroll_margin() as u32; - let new_screen_top = self.selections.newest_display(cx).head().row().0; + let new_screen_top = self + .selections + .newest_display(&self.display_snapshot(cx)) + .head() + .row() + .0; let new_screen_top = new_screen_top.saturating_sub(scroll_margin_rows); self.set_scroll_top_row(DisplayRow(new_screen_top), window, cx); } @@ -86,7 +91,12 @@ impl Editor { let Some(visible_rows) = self.visible_line_count().map(|count| count as u32) else { return; }; - let new_screen_top = self.selections.newest_display(cx).head().row().0; + let new_screen_top = self + .selections + .newest_display(&self.display_snapshot(cx)) + .head() + .row() + .0; let new_screen_top = new_screen_top.saturating_sub(visible_rows / 2); self.set_scroll_top_row(DisplayRow(new_screen_top), window, cx); } @@ -101,7 +111,12 @@ impl Editor { let Some(visible_rows) = self.visible_line_count().map(|count| count as u32) else { return; }; - let new_screen_top = self.selections.newest_display(cx).head().row().0; + let new_screen_top = self + .selections + .newest_display(&self.display_snapshot(cx)) + .head() + .row() + .0; let new_screen_top = new_screen_top.saturating_sub(visible_rows.saturating_sub(scroll_margin_rows)); self.set_scroll_top_row(DisplayRow(new_screen_top), window, cx); diff --git a/crates/editor/src/scroll/autoscroll.rs b/crates/editor/src/scroll/autoscroll.rs index 9130e3cbf879d1b38461a34470b79cc5a50a3cac..28fd9442193bbec663d3f72eaa805214375dd8ca 100644 --- a/crates/editor/src/scroll/autoscroll.rs +++ b/crates/editor/src/scroll/autoscroll.rs @@ -148,7 +148,7 @@ impl Editor { target_top = first_highlighted_row.as_f64(); target_bottom = target_top + 1.; } else { - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); target_top = selections .first() @@ -293,7 +293,7 @@ impl Editor { let scroll_width = ScrollOffset::from(scroll_width); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let selections = self.selections.all::(cx); + let selections = self.selections.all::(&display_map); let mut scroll_position = self.scroll_manager.scroll_position(&display_map); let mut target_left; diff --git a/crates/editor/src/selections_collection.rs b/crates/editor/src/selections_collection.rs index 9ca2d1cb4ee116fb77bcae41fcb9d6a435629cff..ab0e78595310da43b803cd53b9177dec53a37d81 100644 --- a/crates/editor/src/selections_collection.rs +++ b/crates/editor/src/selections_collection.rs @@ -110,7 +110,7 @@ impl SelectionsCollection { if self.pending.is_none() { self.disjoint_anchors_arc() } else { - let all_offset_selections = self.all::(cx); + let all_offset_selections = self.all::(&self.display_map(cx)); let buffer = self.buffer(cx); all_offset_selections .into_iter() @@ -129,25 +129,23 @@ impl SelectionsCollection { pub fn pending>( &self, - cx: &mut App, + snapshot: &DisplaySnapshot, ) -> Option> { - let map = self.display_map(cx); - - resolve_selections(self.pending_anchor(), &map).next() + resolve_selections(self.pending_anchor(), &snapshot).next() } pub(crate) fn pending_mode(&self) -> Option { self.pending.as_ref().map(|pending| pending.mode.clone()) } - pub fn all<'a, D>(&self, cx: &mut App) -> Vec> + pub fn all<'a, D>(&self, snapshot: &DisplaySnapshot) -> Vec> where D: 'a + TextDimension + Ord + Sub, { - let map = self.display_map(cx); let disjoint_anchors = &self.disjoint; - let mut disjoint = resolve_selections::(disjoint_anchors.iter(), &map).peekable(); - let mut pending_opt = self.pending::(cx); + let mut disjoint = + resolve_selections::(disjoint_anchors.iter(), &snapshot).peekable(); + let mut pending_opt = self.pending::(&snapshot); iter::from_fn(move || { if let Some(pending) = pending_opt.as_mut() { while let Some(next_selection) = disjoint.peek() { @@ -175,12 +173,11 @@ impl SelectionsCollection { } /// Returns all of the selections, adjusted to take into account the selection line_mode - pub fn all_adjusted(&self, cx: &mut App) -> Vec> { - let mut selections = self.all::(cx); + pub fn all_adjusted(&self, snapshot: &DisplaySnapshot) -> Vec> { + let mut selections = self.all::(&snapshot); if self.line_mode { - let map = self.display_map(cx); for selection in &mut selections { - let new_range = map.expand_to_line(selection.range()); + let new_range = snapshot.expand_to_line(selection.range()); selection.start = new_range.start; selection.end = new_range.end; } @@ -210,11 +207,10 @@ impl SelectionsCollection { } /// Returns the newest selection, adjusted to take into account the selection line_mode - pub fn newest_adjusted(&self, cx: &mut App) -> Selection { - let mut selection = self.newest::(cx); + pub fn newest_adjusted(&self, snapshot: &DisplaySnapshot) -> Selection { + let mut selection = self.newest::(&snapshot); if self.line_mode { - let map = self.display_map(cx); - let new_range = map.expand_to_line(selection.range()); + let new_range = snapshot.expand_to_line(selection.range()); selection.start = new_range.start; selection.end = new_range.end; } @@ -223,53 +219,55 @@ impl SelectionsCollection { pub fn all_adjusted_display( &self, - cx: &mut App, - ) -> (DisplaySnapshot, Vec>) { + display_map: &DisplaySnapshot, + ) -> Vec> { if self.line_mode { - let selections = self.all::(cx); - let map = self.display_map(cx); + let selections = self.all::(&display_map); let result = selections .into_iter() .map(|mut selection| { - let new_range = map.expand_to_line(selection.range()); + let new_range = display_map.expand_to_line(selection.range()); selection.start = new_range.start; selection.end = new_range.end; - selection.map(|point| point.to_display_point(&map)) + selection.map(|point| point.to_display_point(&display_map)) }) .collect(); - (map, result) + result } else { - self.all_display(cx) + self.all_display(display_map) } } - pub fn disjoint_in_range<'a, D>(&self, range: Range, cx: &mut App) -> Vec> + pub fn disjoint_in_range<'a, D>( + &self, + range: Range, + snapshot: &DisplaySnapshot, + ) -> Vec> where D: 'a + TextDimension + Ord + Sub + std::fmt::Debug, { - let map = self.display_map(cx); let start_ix = match self .disjoint - .binary_search_by(|probe| probe.end.cmp(&range.start, map.buffer_snapshot())) + .binary_search_by(|probe| probe.end.cmp(&range.start, snapshot.buffer_snapshot())) { Ok(ix) | Err(ix) => ix, }; let end_ix = match self .disjoint - .binary_search_by(|probe| probe.start.cmp(&range.end, map.buffer_snapshot())) + .binary_search_by(|probe| probe.start.cmp(&range.end, snapshot.buffer_snapshot())) { Ok(ix) => ix + 1, Err(ix) => ix, }; - resolve_selections(&self.disjoint[start_ix..end_ix], &map).collect() + resolve_selections(&self.disjoint[start_ix..end_ix], snapshot).collect() } - pub fn all_display(&self, cx: &mut App) -> (DisplaySnapshot, Vec>) { - let map = self.display_map(cx); + pub fn all_display(&self, snapshot: &DisplaySnapshot) -> Vec> { let disjoint_anchors = &self.disjoint; - let mut disjoint = resolve_selections_display(disjoint_anchors.iter(), &map).peekable(); - let mut pending_opt = resolve_selections_display(self.pending_anchor(), &map).next(); - let selections = iter::from_fn(move || { + let mut disjoint = + resolve_selections_display(disjoint_anchors.iter(), &snapshot).peekable(); + let mut pending_opt = resolve_selections_display(self.pending_anchor(), &snapshot).next(); + iter::from_fn(move || { if let Some(pending) = pending_opt.as_mut() { while let Some(next_selection) = disjoint.peek() { if pending.start <= next_selection.end && pending.end >= next_selection.start { @@ -292,8 +290,7 @@ impl SelectionsCollection { disjoint.next() } }) - .collect(); - (map, selections) + .collect() } pub fn newest_anchor(&self) -> &Selection { @@ -306,19 +303,15 @@ impl SelectionsCollection { pub fn newest>( &self, - cx: &mut App, + snapshot: &DisplaySnapshot, ) -> Selection { - let map = self.display_map(cx); - - resolve_selections([self.newest_anchor()], &map) + resolve_selections([self.newest_anchor()], &snapshot) .next() .unwrap() } - pub fn newest_display(&self, cx: &mut App) -> Selection { - let map = self.display_map(cx); - - resolve_selections_display([self.newest_anchor()], &map) + pub fn newest_display(&self, snapshot: &DisplaySnapshot) -> Selection { + resolve_selections_display([self.newest_anchor()], &snapshot) .next() .unwrap() } @@ -333,11 +326,9 @@ impl SelectionsCollection { pub fn oldest>( &self, - cx: &mut App, + snapshot: &DisplaySnapshot, ) -> Selection { - let map = self.display_map(cx); - - resolve_selections([self.oldest_anchor()], &map) + resolve_selections([self.oldest_anchor()], &snapshot) .next() .unwrap() } @@ -349,12 +340,18 @@ impl SelectionsCollection { .unwrap_or_else(|| self.disjoint.first().cloned().unwrap()) } - pub fn first>(&self, cx: &mut App) -> Selection { - self.all(cx).first().unwrap().clone() + pub fn first>( + &self, + snapshot: &DisplaySnapshot, + ) -> Selection { + self.all(snapshot).first().unwrap().clone() } - pub fn last>(&self, cx: &mut App) -> Selection { - self.all(cx).last().unwrap().clone() + pub fn last>( + &self, + snapshot: &DisplaySnapshot, + ) -> Selection { + self.all(snapshot).last().unwrap().clone() } /// Returns a list of (potentially backwards!) ranges representing the selections. @@ -362,9 +359,9 @@ impl SelectionsCollection { #[cfg(any(test, feature = "test-support"))] pub fn ranges>( &self, - cx: &mut App, + snapshot: &DisplaySnapshot, ) -> Vec> { - self.all::(cx) + self.all::(snapshot) .iter() .map(|s| { if s.reversed { @@ -596,7 +593,8 @@ impl<'a> MutableSelectionsCollection<'a> { where T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub + std::marker::Copy, { - let mut selections = self.collection.all(self.cx); + let display_map = self.display_map(); + let mut selections = self.collection.all(&display_map); let mut start = range.start.to_offset(&self.buffer()); let mut end = range.end.to_offset(&self.buffer()); let reversed = if start > end { @@ -790,7 +788,7 @@ impl<'a> MutableSelectionsCollection<'a> { ) { let mut changed = false; let display_map = self.display_map(); - let (_, selections) = self.collection.all_display(self.cx); + let selections = self.collection.all_display(&display_map); let selections = selections .into_iter() .map(|selection| { @@ -814,9 +812,10 @@ impl<'a> MutableSelectionsCollection<'a> { ) { let mut changed = false; let snapshot = self.buffer().clone(); + let display_map = self.display_map(); let selections = self .collection - .all::(self.cx) + .all::(&display_map) .into_iter() .map(|selection| { let mut moved_selection = selection.clone(); diff --git a/crates/editor/src/signature_help.rs b/crates/editor/src/signature_help.rs index 150044391a397cc2c35ffc8a85311c1470668ab1..6abd3e48880a59f3ce74511013bcd048ad5a2a51 100644 --- a/crates/editor/src/signature_help.rs +++ b/crates/editor/src/signature_help.rs @@ -82,7 +82,7 @@ impl Editor { if !(self.signature_help_state.is_shown() || self.auto_signature_help_enabled(cx)) { return false; } - let newest_selection = self.selections.newest::(cx); + let newest_selection = self.selections.newest::(&self.display_snapshot(cx)); let head = newest_selection.head(); if !newest_selection.is_empty() && head != newest_selection.tail() { diff --git a/crates/editor/src/tasks.rs b/crates/editor/src/tasks.rs index d27e4564057ae9b0827ddec98bb3cfaeaf455211..e39880ddc1f575a7b12f40c5496c75c1f473c6e9 100644 --- a/crates/editor/src/tasks.rs +++ b/crates/editor/src/tasks.rs @@ -14,7 +14,7 @@ impl Editor { return Task::ready(None); }; let (selection, buffer, editor_snapshot) = { - let selection = self.selections.newest_adjusted(cx); + let selection = self.selections.newest_adjusted(&self.display_snapshot(cx)); let Some((buffer, _)) = self .buffer() .read(cx) diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index a3a8d81c64a709b65d8d7a894e338800cdeb71c5..9d1003e8c08b3d725ffa13b90eb0ee405520d8cd 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -108,7 +108,7 @@ pub fn assert_text_with_selections( assert_eq!(editor.text(cx), unmarked_text, "text doesn't match"); let actual = generate_marked_text( &editor.text(cx), - &editor.selections.ranges(cx), + &editor.selections.ranges(&editor.display_snapshot(cx)), marked_text.contains("«"), ); assert_eq!(actual, marked_text, "Selections don't match"); diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index 601eb9512cdef472ce0a5d660309d671c339ebe9..c6779d1e564deb57233dd9e4719ca87f8d6a2da1 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -265,7 +265,10 @@ impl EditorTestContext { pub fn pixel_position_for(&mut self, display_point: DisplayPoint) -> Point { self.update_editor(|editor, window, cx| { - let newest_point = editor.selections.newest_display(cx).head(); + let newest_point = editor + .selections + .newest_display(&editor.display_snapshot(cx)) + .head(); let pixel_position = editor.pixel_position_of_newest_cursor.unwrap(); let line_height = editor .style() @@ -590,7 +593,7 @@ impl EditorTestContext { fn editor_selections(&mut self) -> Vec> { self.editor .update(&mut self.cx, |editor, cx| { - editor.selections.all::(cx) + editor.selections.all::(&editor.display_snapshot(cx)) }) .into_iter() .map(|s| { @@ -688,9 +691,12 @@ pub fn assert_state_with_diff( expected_diff_text: &str, ) { let (snapshot, selections) = editor.update_in(cx, |editor, window, cx| { + let snapshot = editor.snapshot(window, cx); ( - editor.snapshot(window, cx).buffer_snapshot().clone(), - editor.selections.ranges::(cx), + snapshot.buffer_snapshot().clone(), + editor + .selections + .ranges::(&snapshot.display_snapshot), ) }); diff --git a/crates/file_finder/src/file_finder_tests.rs b/crates/file_finder/src/file_finder_tests.rs index b59d59e23953bb71af8909eb149943e8ff607357..50cba6ce5fd8c6af0fcbbc10855ff92caa532f22 100644 --- a/crates/file_finder/src/file_finder_tests.rs +++ b/crates/file_finder/src/file_finder_tests.rs @@ -490,7 +490,7 @@ async fn test_row_column_numbers_query_inside_file(cx: &mut TestAppContext) { cx.executor().advance_clock(Duration::from_secs(2)); editor.update(cx, |editor, cx| { - let all_selections = editor.selections.all_adjusted(cx); + let all_selections = editor.selections.all_adjusted(&editor.display_snapshot(cx)); assert_eq!( all_selections.len(), 1, @@ -565,7 +565,7 @@ async fn test_row_column_numbers_query_outside_file(cx: &mut TestAppContext) { cx.executor().advance_clock(Duration::from_secs(2)); editor.update(cx, |editor, cx| { - let all_selections = editor.selections.all_adjusted(cx); + let all_selections = editor.selections.all_adjusted(&editor.display_snapshot(cx)); assert_eq!( all_selections.len(), 1, diff --git a/crates/git_ui/src/text_diff_view.rs b/crates/git_ui/src/text_diff_view.rs index 8f7dac4e4049a65dbd630966cea249664d22ba61..fd8cd3597377a6de78b3153ccc430afe81b1127e 100644 --- a/crates/git_ui/src/text_diff_view.rs +++ b/crates/git_ui/src/text_diff_view.rs @@ -49,7 +49,7 @@ impl TextDiffView { let selection_data = source_editor.update(cx, |editor, cx| { let multibuffer = editor.buffer().read(cx); let source_buffer = multibuffer.as_singleton()?; - let selections = editor.selections.all::(cx); + let selections = editor.selections.all::(&editor.display_snapshot(cx)); let buffer_snapshot = source_buffer.read(cx); let first_selection = selections.first()?; let max_point = buffer_snapshot.max_point(); diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index f9dd0178922b1a479caade3953d2eb0c0e75c83d..9b0fb6d8c16b0e44b1bbfd1464f44bb7e88b0cde 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -74,7 +74,9 @@ impl GoToLine { ) -> Self { let (user_caret, last_line, scroll_position) = active_editor.update(cx, |editor, cx| { let user_caret = UserCaretPosition::at_selection_end( - &editor.selections.last::(cx), + &editor + .selections + .last::(&editor.display_snapshot(cx)), &editor.buffer().read(cx).snapshot(cx), ); @@ -739,7 +741,7 @@ mod tests { let selections = editor.update(cx, |editor, cx| { editor .selections - .all::(cx) + .all::(&editor.display_snapshot(cx)) .into_iter() .map(|s| s.start..s.end) .collect::>() diff --git a/crates/language_tools/src/lsp_log_view.rs b/crates/language_tools/src/lsp_log_view.rs index 1c24bfdcf44c09a1729065835debd4ef5fbb2252..e834dd6aec003930d68ed745f67aff50b2c8f66b 100644 --- a/crates/language_tools/src/lsp_log_view.rs +++ b/crates/language_tools/src/lsp_log_view.rs @@ -229,8 +229,11 @@ impl LspLogView { log_view.editor.update(cx, |editor, cx| { editor.set_read_only(false); let last_offset = editor.buffer().read(cx).len(cx); - let newest_cursor_is_at_end = - editor.selections.newest::(cx).start >= last_offset; + let newest_cursor_is_at_end = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .start + >= last_offset; editor.edit( vec![ (last_offset..last_offset, text.as_str()), diff --git a/crates/language_tools/src/syntax_tree_view.rs b/crates/language_tools/src/syntax_tree_view.rs index c1c4b604269ae8d731e39b541e05fbed139692cc..464d518c2e9c697d292d7bffda7ee7bae68dd254 100644 --- a/crates/language_tools/src/syntax_tree_view.rs +++ b/crates/language_tools/src/syntax_tree_view.rs @@ -252,7 +252,10 @@ impl SyntaxTreeView { .editor .update(cx, |editor, cx| editor.snapshot(window, cx)); let (buffer, range, excerpt_id) = editor_state.editor.update(cx, |editor, cx| { - let selection_range = editor.selections.last::(cx).range(); + let selection_range = editor + .selections + .last::(&editor.display_snapshot(cx)) + .range(); let multi_buffer = editor.buffer().read(cx); let (buffer, range, excerpt_id) = snapshot .buffer_snapshot() diff --git a/crates/markdown_preview/src/markdown_preview_view.rs b/crates/markdown_preview/src/markdown_preview_view.rs index d20ed40b7928186e2caf564be5ff66b0bd04f0d1..f62ff0874df8079f44868dfeaa1ad2fd0348e474 100644 --- a/crates/markdown_preview/src/markdown_preview_view.rs +++ b/crates/markdown_preview/src/markdown_preview_view.rs @@ -278,8 +278,12 @@ impl MarkdownPreviewView { this.parse_markdown_from_active_editor(true, window, cx); } EditorEvent::SelectionsChanged { .. } => { - let selection_range = editor - .update(cx, |editor, cx| editor.selections.last::(cx).range()); + let selection_range = editor.update(cx, |editor, cx| { + editor + .selections + .last::(&editor.display_snapshot(cx)) + .range() + }); this.selected_block = this.get_block_index_under_cursor(selection_range); this.list_state.scroll_to_reveal_item(this.selected_block); cx.notify(); diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index ac74d6284f4fe2fe62bcad7be447b142255056b4..9e49fabb474d765aa79703ef55c1c98842bee209 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -245,7 +245,10 @@ impl PickerDelegate for OutlineViewDelegate { let (buffer, cursor_offset) = self.active_editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); - let cursor_offset = editor.selections.newest::(cx).head(); + let cursor_offset = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head(); (buffer, cursor_offset) }); selected_index = self @@ -673,7 +676,7 @@ mod tests { let selections = editor.update(cx, |editor, cx| { editor .selections - .all::(cx) + .all::(&editor.display_snapshot(cx)) .into_iter() .map(|s| s.start..s.end) .collect::>() diff --git a/crates/outline_panel/src/outline_panel.rs b/crates/outline_panel/src/outline_panel.rs index 847edef1c697e8e008ec8f1010e99fb87362284e..4a4990b40a5f3f7ad2f182e007593e62a8bcd015 100644 --- a/crates/outline_panel/src/outline_panel.rs +++ b/crates/outline_panel/src/outline_panel.rs @@ -3099,7 +3099,10 @@ impl OutlinePanel { cx: &mut Context, ) -> Option { let selection = editor.update(cx, |editor, cx| { - editor.selections.newest::(cx).head() + editor + .selections + .newest::(&editor.display_snapshot(cx)) + .head() }); let editor_snapshot = editor.update(cx, |editor, cx| editor.snapshot(window, cx)); let multi_buffer = editor.read(cx).buffer(); @@ -6957,13 +6960,13 @@ outline: struct OutlineEntryExcerpt fn selected_row_text(editor: &Entity, cx: &mut App) -> String { editor.update(cx, |editor, cx| { - let selections = editor.selections.all::(cx); - assert_eq!(selections.len(), 1, "Active editor should have exactly one selection after any outline panel interactions"); - let selection = selections.first().unwrap(); - let multi_buffer_snapshot = editor.buffer().read(cx).snapshot(cx); - let line_start = language::Point::new(selection.start.row, 0); - let line_end = multi_buffer_snapshot.clip_point(language::Point::new(selection.end.row, u32::MAX), language::Bias::Right); - multi_buffer_snapshot.text_for_range(line_start..line_end).collect::().trim().to_owned() + let selections = editor.selections.all::(&editor.display_snapshot(cx)); + assert_eq!(selections.len(), 1, "Active editor should have exactly one selection after any outline panel interactions"); + let selection = selections.first().unwrap(); + let multi_buffer_snapshot = editor.buffer().read(cx).snapshot(cx); + let line_start = language::Point::new(selection.start.row, 0); + let line_end = multi_buffer_snapshot.clip_point(language::Point::new(selection.end.row, u32::MAX), language::Bias::Right); + multi_buffer_snapshot.text_for_range(line_start..line_end).collect::().trim().to_owned() }) } diff --git a/crates/project_panel/src/project_panel_tests.rs b/crates/project_panel/src/project_panel_tests.rs index 3f1e1e1b3c3fd909f667ebf9dc8e717b0d116c78..890041728988bab2914ad7f00ae11637cd9291eb 100644 --- a/crates/project_panel/src/project_panel_tests.rs +++ b/crates/project_panel/src/project_panel_tests.rs @@ -657,7 +657,7 @@ async fn test_editing_files(cx: &mut gpui::TestAppContext) { let confirm = panel.update_in(cx, |panel, window, cx| { panel.filename_editor.update(cx, |editor, cx| { - let file_name_selections = editor.selections.all::(cx); + let file_name_selections = editor.selections.all::(&editor.display_snapshot(cx)); assert_eq!( file_name_selections.len(), 1, @@ -731,7 +731,7 @@ async fn test_editing_files(cx: &mut gpui::TestAppContext) { panel.update_in(cx, |panel, window, cx| { panel.filename_editor.update(cx, |editor, cx| { - let file_name_selections = editor.selections.all::(cx); + let file_name_selections = editor.selections.all::(&editor.display_snapshot(cx)); assert_eq!(file_name_selections.len(), 1, "File editing should have a single selection, but got: {file_name_selections:?}"); let file_name_selection = &file_name_selections[0]; assert_eq!(file_name_selection.start, 0, "Should select the file name from the start"); @@ -1214,7 +1214,7 @@ async fn test_copy_paste(cx: &mut gpui::TestAppContext) { panel.update_in(cx, |panel, window, cx| { panel.filename_editor.update(cx, |editor, cx| { - let file_name_selections = editor.selections.all::(cx); + let file_name_selections = editor.selections.all::(&editor.display_snapshot(cx)); assert_eq!( file_name_selections.len(), 1, diff --git a/crates/repl/src/repl_editor.rs b/crates/repl/src/repl_editor.rs index b4c928c33e021229caaa68e11b7cdd7228ed934d..a47d680e9bfe7a82cee25db360a59223e89df93e 100644 --- a/crates/repl/src/repl_editor.rs +++ b/crates/repl/src/repl_editor.rs @@ -85,7 +85,11 @@ pub fn run( let editor = editor.upgrade().context("editor was dropped")?; let selected_range = editor - .update(cx, |editor, cx| editor.selections.newest_adjusted(cx)) + .update(cx, |editor, cx| { + editor + .selections + .newest_adjusted(&editor.display_snapshot(cx)) + }) .range(); let multibuffer = editor.read(cx).buffer().clone(); let Some(buffer) = multibuffer.read(cx).as_singleton() else { @@ -473,7 +477,9 @@ fn language_supported(language: &Arc, cx: &mut App) -> bool { fn get_language(editor: WeakEntity, cx: &mut App) -> Option> { editor .update(cx, |editor, cx| { - let selection = editor.selections.newest::(cx); + let selection = editor + .selections + .newest::(&editor.display_snapshot(cx)); let buffer = editor.buffer().read(cx).snapshot(cx); buffer.language_at(selection.head()).cloned() }) diff --git a/crates/vim/src/change_list.rs b/crates/vim/src/change_list.rs index c92ce4720e8ccd0454a83409d76789334192745f..a921d182e6ebd0ef96ef0b8d1cce75ed6d532d96 100644 --- a/crates/vim/src/change_list.rs +++ b/crates/vim/src/change_list.rs @@ -50,7 +50,8 @@ impl Vim { pub(crate) fn push_to_change_list(&mut self, window: &mut Window, cx: &mut Context) { let Some((new_positions, buffer)) = self.update_editor(cx, |vim, editor, cx| { - let (map, selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_adjusted_display(&display_map); let buffer = editor.buffer().clone(); let pop_state = editor @@ -59,7 +60,7 @@ impl Vim { .map(|previous| { previous.len() == selections.len() && previous.iter().enumerate().all(|(ix, p)| { - p.to_display_point(&map).row() == selections[ix].head().row() + p.to_display_point(&display_map).row() == selections[ix].head().row() }) }) .unwrap_or(false); @@ -68,11 +69,11 @@ impl Vim { .into_iter() .map(|s| { let point = if vim.mode == Mode::Insert { - movement::saturating_left(&map, s.head()) + movement::saturating_left(&display_map, s.head()) } else { s.head() }; - map.display_point_to_anchor(point, Bias::Left) + display_map.display_point_to_anchor(point, Bias::Left) }) .collect::>(); diff --git a/crates/vim/src/command.rs b/crates/vim/src/command.rs index f5a170055d3604f023c4c31fa5a413a8e52cbc66..9dc4ec999a47e6a0e8ab802761cab474ef81499b 100644 --- a/crates/vim/src/command.rs +++ b/crates/vim/src/command.rs @@ -606,7 +606,9 @@ pub fn register(editor: &mut Editor, cx: &mut Context) { let result = vim.update_editor(cx, |vim, editor, cx| { let snapshot = editor.snapshot(window, cx); let buffer_row = action.range.head().buffer_row(vim, editor, window, cx)?; - let current = editor.selections.newest::(cx); + let current = editor + .selections + .newest::(&editor.display_snapshot(cx)); let target = snapshot .buffer_snapshot() .clip_point(Point::new(buffer_row.0, current.head().column), Bias::Left); @@ -1903,7 +1905,9 @@ impl OnMatchingLines { }); window.dispatch_action(action, cx); cx.defer_in(window, move |editor, window, cx| { - let newest = editor.selections.newest::(cx); + let newest = editor + .selections + .newest::(&editor.display_snapshot(cx)); editor.change_selections( SelectionEffects::no_scroll(), window, @@ -2000,7 +2004,9 @@ impl Vim { }; let command = self.update_editor(cx, |_, editor, cx| { let snapshot = editor.snapshot(window, cx); - let start = editor.selections.newest_display(cx); + let start = editor + .selections + .newest_display(&editor.display_snapshot(cx)); let text_layout_details = editor.text_layout_details(window); let (mut range, _) = motion .range( @@ -2047,7 +2053,9 @@ impl Vim { }; let command = self.update_editor(cx, |_, editor, cx| { let snapshot = editor.snapshot(window, cx); - let start = editor.selections.newest_display(cx); + let start = editor + .selections + .newest_display(&editor.display_snapshot(cx)); let range = object .range(&snapshot, start.clone(), around, None) .unwrap_or(start.range()); @@ -2156,7 +2164,11 @@ impl ShellExec { Point::new(range.start.0, 0) ..snapshot.clip_point(Point::new(range.end.0 + 1, 0), Bias::Right) } else { - let mut end = editor.selections.newest::(cx).range().end; + let mut end = editor + .selections + .newest::(&editor.display_snapshot(cx)) + .range() + .end; end = snapshot.clip_point(Point::new(end.row + 1, 0), Bias::Right); needs_newline_prefix = end == snapshot.max_point(); end..end diff --git a/crates/vim/src/helix.rs b/crates/vim/src/helix.rs index ed7abaa11c1a6b95e436b019de1605792c82fc9d..6788a186fb45222f7b09fe756862e6cb337c6d90 100644 --- a/crates/vim/src/helix.rs +++ b/crates/vim/src/helix.rs @@ -345,7 +345,7 @@ impl Vim { self.update_editor(cx, |vim, editor, cx| { let has_selection = editor .selections - .all_adjusted(cx) + .all_adjusted(&editor.display_snapshot(cx)) .iter() .any(|selection| !selection.is_empty()); @@ -478,19 +478,20 @@ impl Vim { pub fn helix_replace(&mut self, text: &str, window: &mut Window, cx: &mut Context) { self.update_editor(cx, |_, editor, cx| { editor.transact(window, cx, |editor, window, cx| { - let (map, selections) = editor.selections.all_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_display(&display_map); // Store selection info for positioning after edit let selection_info: Vec<_> = selections .iter() .map(|selection| { let range = selection.range(); - let start_offset = range.start.to_offset(&map, Bias::Left); - let end_offset = range.end.to_offset(&map, Bias::Left); + let start_offset = range.start.to_offset(&display_map, Bias::Left); + let end_offset = range.end.to_offset(&display_map, Bias::Left); let was_empty = range.is_empty(); let was_reversed = selection.reversed; ( - map.buffer_snapshot().anchor_before(start_offset), + display_map.buffer_snapshot().anchor_before(start_offset), end_offset - start_offset, was_empty, was_reversed, @@ -504,11 +505,11 @@ impl Vim { // For empty selections, extend to replace one character if range.is_empty() { - range.end = movement::saturating_right(&map, range.start); + range.end = movement::saturating_right(&display_map, range.start); } - let byte_range = range.start.to_offset(&map, Bias::Left) - ..range.end.to_offset(&map, Bias::Left); + let byte_range = range.start.to_offset(&display_map, Bias::Left) + ..range.end.to_offset(&display_map, Bias::Left); if !byte_range.is_empty() { let replacement_text = text.repeat(byte_range.len()); @@ -568,7 +569,7 @@ impl Vim { self.update_editor(cx, |_, editor, cx| { editor.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx); let display_map = editor.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = editor.selections.all::(cx); + let mut selections = editor.selections.all::(&display_map); let max_point = display_map.buffer_snapshot().max_point(); let buffer_snapshot = &display_map.buffer_snapshot(); @@ -606,7 +607,9 @@ impl Vim { cx: &mut Context, ) { self.update_editor(cx, |_, editor, cx| { - let newest = editor.selections.newest::(cx); + let newest = editor + .selections + .newest::(&editor.display_snapshot(cx)); editor.change_selections(Default::default(), window, cx, |s| s.select(vec![newest])); }); } @@ -633,7 +636,10 @@ impl Vim { if yank { vim.copy_selections_content(editor, MotionKind::Exclusive, window, cx); } - let selections = editor.selections.all::(cx).into_iter(); + let selections = editor + .selections + .all::(&editor.display_snapshot(cx)) + .into_iter(); let edits = selections.map(|selection| (selection.start..selection.end, "")); editor.edit(edits, cx); }); diff --git a/crates/vim/src/helix/duplicate.rs b/crates/vim/src/helix/duplicate.rs index 91e53f13e9962db30ad34b91a3c29e2a530626d8..1b1f10b00b6a7381f22c6ec3be674dc2c085eff6 100644 --- a/crates/vim/src/helix/duplicate.rs +++ b/crates/vim/src/helix/duplicate.rs @@ -56,7 +56,8 @@ impl Vim { let times = times.unwrap_or(1); self.update_editor(cx, |_, editor, cx| { let mut selections = Vec::new(); - let (map, mut original_selections) = editor.selections.all_display(cx); + let map = editor.display_snapshot(cx); + let mut original_selections = editor.selections.all_display(&map); // The order matters, because it is recorded when the selections are added. if above { original_selections.reverse(); diff --git a/crates/vim/src/helix/paste.rs b/crates/vim/src/helix/paste.rs index 9b6b6e454ac1e8d3a47009fcd85db0d2da00261e..62d8c6caef99050cffa17a2e608a924aa97c3e99 100644 --- a/crates/vim/src/helix/paste.rs +++ b/crates/vim/src/helix/paste.rs @@ -44,7 +44,8 @@ impl Vim { return; }; - let (display_map, current_selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let current_selections = editor.selections.all_adjusted_display(&display_map); // The clipboard can have multiple selections, and there can // be multiple selections. Helix zips them together, so the first diff --git a/crates/vim/src/insert.rs b/crates/vim/src/insert.rs index 5b9fef402a7b4fee9ae1d8722cb2cf22f3c2fdb9..98d542dbc4d3651b5307959fba01bf7320983cc9 100644 --- a/crates/vim/src/insert.rs +++ b/crates/vim/src/insert.rs @@ -84,7 +84,7 @@ impl Vim { self.update_editor(cx, |_, editor, cx| { let snapshot = editor.buffer().read(cx).snapshot(cx); let mut edits = Vec::new(); - for selection in editor.selections.all::(cx) { + for selection in editor.selections.all::(&editor.display_snapshot(cx)) { let point = selection.head(); let new_row = match direction { Direction::Next => point.row + 1, diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index 2757a927aaa8ad7d565e56ccbda4042e5f3c56b3..f80f9be38edbb7fafb0864437c8de2bda4740154 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -657,7 +657,7 @@ impl Vim { self.switch_mode(Mode::Insert, false, window, cx); self.update_editor(cx, |_, editor, cx| { editor.transact(window, cx, |editor, window, cx| { - let selections = editor.selections.all::(cx); + let selections = editor.selections.all::(&editor.display_snapshot(cx)); let snapshot = editor.buffer().read(cx).snapshot(cx); let selection_start_rows: BTreeSet = selections @@ -699,7 +699,7 @@ impl Vim { self.update_editor(cx, |_, editor, cx| { let text_layout_details = editor.text_layout_details(window); editor.transact(window, cx, |editor, window, cx| { - let selections = editor.selections.all::(cx); + let selections = editor.selections.all::(&editor.display_snapshot(cx)); let snapshot = editor.buffer().read(cx).snapshot(cx); let selection_end_rows: BTreeSet = selections @@ -745,7 +745,7 @@ impl Vim { Vim::take_forced_motion(cx); self.update_editor(cx, |_, editor, cx| { editor.transact(window, cx, |editor, _, cx| { - let selections = editor.selections.all::(cx); + let selections = editor.selections.all::(&editor.display_snapshot(cx)); let selection_start_rows: BTreeSet = selections .into_iter() @@ -774,9 +774,10 @@ impl Vim { Vim::take_forced_motion(cx); self.update_editor(cx, |_, editor, cx| { editor.transact(window, cx, |editor, window, cx| { - let selections = editor.selections.all::(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all::(&display_map); let snapshot = editor.buffer().read(cx).snapshot(cx); - let (_map, display_selections) = editor.selections.all_display(cx); + let display_selections = editor.selections.all_display(&display_map); let original_positions = display_selections .iter() .map(|s| (s.id, s.head())) @@ -937,13 +938,14 @@ impl Vim { self.update_editor(cx, |_, editor, cx| { editor.transact(window, cx, |editor, window, cx| { editor.set_clip_at_line_ends(false, cx); - let (map, display_selections) = editor.selections.all_display(cx); + let display_map = editor.display_snapshot(cx); + let display_selections = editor.selections.all_display(&display_map); - let mut edits = Vec::new(); + let mut edits = Vec::with_capacity(display_selections.len()); for selection in &display_selections { let mut range = selection.range(); for _ in 0..count { - let new_point = movement::saturating_right(&map, range.end); + let new_point = movement::saturating_right(&display_map, range.end); if range.end == new_point { return; } @@ -951,8 +953,8 @@ impl Vim { } edits.push(( - range.start.to_offset(&map, Bias::Left) - ..range.end.to_offset(&map, Bias::Left), + range.start.to_offset(&display_map, Bias::Left) + ..range.end.to_offset(&display_map, Bias::Left), text.repeat(if is_return_char { 0 } else { count }), )); } @@ -976,16 +978,16 @@ impl Vim { pub fn save_selection_starts( &self, editor: &Editor, - cx: &mut Context, ) -> HashMap { - let (map, selections) = editor.selections.all_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_display(&display_map); selections .iter() .map(|selection| { ( selection.id, - map.display_point_to_anchor(selection.start, Bias::Right), + display_map.display_point_to_anchor(selection.start, Bias::Right), ) }) .collect::>() diff --git a/crates/vim/src/normal/convert.rs b/crates/vim/src/normal/convert.rs index 11d040850d341155bf428ebc337cc9e3f4cc42c3..0ee132a44d20723970fecbbef4cef13ff31e310c 100644 --- a/crates/vim/src/normal/convert.rs +++ b/crates/vim/src/normal/convert.rs @@ -199,7 +199,7 @@ impl Vim { let mut ranges = Vec::new(); let mut cursor_positions = Vec::new(); let snapshot = editor.buffer().read(cx).snapshot(cx); - for selection in editor.selections.all_adjusted(cx) { + for selection in editor.selections.all_adjusted(&editor.display_snapshot(cx)) { match vim.mode { Mode::Visual | Mode::VisualLine => { ranges.push(selection.start..selection.end); diff --git a/crates/vim/src/normal/increment.rs b/crates/vim/src/normal/increment.rs index 34ac4aab1f11c547ed1335e1a9da12fe52be9b08..4b27b4dfaf911c72458c9f412d5d0d2ba4cd70b8 100644 --- a/crates/vim/src/normal/increment.rs +++ b/crates/vim/src/normal/increment.rs @@ -58,7 +58,7 @@ impl Vim { let mut new_anchors = Vec::new(); let snapshot = editor.buffer().read(cx).snapshot(cx); - for selection in editor.selections.all_adjusted(cx) { + for selection in editor.selections.all_adjusted(&editor.display_snapshot(cx)) { if !selection.is_empty() && (vim.mode != Mode::VisualBlock || new_anchors.is_empty()) { diff --git a/crates/vim/src/normal/mark.rs b/crates/vim/src/normal/mark.rs index ea9aafe1315d3d89afe9d258f4e736717ffe789f..3bb040511fdd7fa53dd97198ae02b492b0e7359d 100644 --- a/crates/vim/src/normal/mark.rs +++ b/crates/vim/src/normal/mark.rs @@ -50,16 +50,19 @@ impl Vim { let mut reversed = vec![]; self.update_editor(cx, |vim, editor, cx| { - let (map, selections) = editor.selections.all_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_display(&display_map); for selection in selections { - let end = movement::saturating_left(&map, selection.end); + let end = movement::saturating_left(&display_map, selection.end); ends.push( - map.buffer_snapshot() - .anchor_before(end.to_offset(&map, Bias::Left)), + display_map + .buffer_snapshot() + .anchor_before(end.to_offset(&display_map, Bias::Left)), ); starts.push( - map.buffer_snapshot() - .anchor_before(selection.start.to_offset(&map, Bias::Left)), + display_map + .buffer_snapshot() + .anchor_before(selection.start.to_offset(&display_map, Bias::Left)), ); reversed.push(selection.reversed) } @@ -301,19 +304,21 @@ impl Vim { name = "'"; } if matches!(name, "{" | "}" | "(" | ")") { - let (map, selections) = editor.selections.all_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_display(&display_map); let anchors = selections .into_iter() .map(|selection| { let point = match name { - "{" => movement::start_of_paragraph(&map, selection.head(), 1), - "}" => movement::end_of_paragraph(&map, selection.head(), 1), - "(" => motion::sentence_backwards(&map, selection.head(), 1), - ")" => motion::sentence_forwards(&map, selection.head(), 1), + "{" => movement::start_of_paragraph(&display_map, selection.head(), 1), + "}" => movement::end_of_paragraph(&display_map, selection.head(), 1), + "(" => motion::sentence_backwards(&display_map, selection.head(), 1), + ")" => motion::sentence_forwards(&display_map, selection.head(), 1), _ => unreachable!(), }; - map.buffer_snapshot() - .anchor_before(point.to_offset(&map, Bias::Left)) + display_map + .buffer_snapshot() + .anchor_before(point.to_offset(&display_map, Bias::Left)) }) .collect::>(); return Some(Mark::Local(anchors)); diff --git a/crates/vim/src/normal/paste.rs b/crates/vim/src/normal/paste.rs index 2a45695928ec3fe87a8f26c5161bb1f095186c53..74a28322d13b6ab0f563e6953f6b1edbfea66740 100644 --- a/crates/vim/src/normal/paste.rs +++ b/crates/vim/src/normal/paste.rs @@ -56,7 +56,8 @@ impl Vim { vim.copy_selections_content(editor, MotionKind::for_mode(vim.mode), window, cx); } - let (display_map, current_selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let current_selections = editor.selections.all_adjusted_display(&display_map); // unlike zed, if you have a multi-cursor selection from vim block mode, // pasting it will paste it on subsequent lines, even if you don't yet @@ -173,7 +174,7 @@ impl Vim { original_indent_columns.push(original_indent_column); } - let cursor_offset = editor.selections.last::(cx).head(); + let cursor_offset = editor.selections.last::(&display_map).head(); if editor .buffer() .read(cx) diff --git a/crates/vim/src/normal/scroll.rs b/crates/vim/src/normal/scroll.rs index edb3d7f2157aec8d23faee5fa1a069a10974360f..ff884e3b7393b39b86114338fe2af11e384e1fa0 100644 --- a/crates/vim/src/normal/scroll.rs +++ b/crates/vim/src/normal/scroll.rs @@ -363,7 +363,10 @@ mod test { point(0., 3.0) ); assert_eq!( - editor.selections.newest(cx).range(), + editor + .selections + .newest(&editor.display_snapshot(cx)) + .range(), Point::new(6, 0)..Point::new(6, 0) ) }); @@ -380,7 +383,10 @@ mod test { point(0., 3.0) ); assert_eq!( - editor.selections.newest(cx).range(), + editor + .selections + .newest(&editor.display_snapshot(cx)) + .range(), Point::new(0, 0)..Point::new(6, 1) ) }); diff --git a/crates/vim/src/normal/substitute.rs b/crates/vim/src/normal/substitute.rs index 889d48717068b0561fd21614dc9fb5d0581754dc..df8d7b4879e21491ed808de1dad78cfebc5b12ec 100644 --- a/crates/vim/src/normal/substitute.rs +++ b/crates/vim/src/normal/substitute.rs @@ -94,7 +94,10 @@ impl Vim { MotionKind::Exclusive }; vim.copy_selections_content(editor, kind, window, cx); - let selections = editor.selections.all::(cx).into_iter(); + let selections = editor + .selections + .all::(&editor.display_snapshot(cx)) + .into_iter(); let edits = selections.map(|selection| (selection.start..selection.end, "")); editor.edit(edits, cx); }); diff --git a/crates/vim/src/normal/yank.rs b/crates/vim/src/normal/yank.rs index fe8180ffff37de51a019b394fd5742278b9355e2..d5a45fca544d61735f62a8f46e849db2c009847f 100644 --- a/crates/vim/src/normal/yank.rs +++ b/crates/vim/src/normal/yank.rs @@ -106,7 +106,7 @@ impl Vim { true, editor .selections - .all_adjusted(cx) + .all_adjusted(&editor.display_snapshot(cx)) .iter() .map(|s| s.range()) .collect(), @@ -128,7 +128,7 @@ impl Vim { false, editor .selections - .all_adjusted(cx) + .all_adjusted(&editor.display_snapshot(cx)) .iter() .map(|s| s.range()) .collect(), diff --git a/crates/vim/src/replace.rs b/crates/vim/src/replace.rs index 40fe4f213e205569129775a2e495ec2b3bee14b6..c9a9fbdb9ee3428ce80c934a686a73a63ddee714 100644 --- a/crates/vim/src/replace.rs +++ b/crates/vim/src/replace.rs @@ -53,7 +53,7 @@ impl Vim { editor.transact(window, cx, |editor, window, cx| { editor.set_clip_at_line_ends(false, cx); let map = editor.snapshot(window, cx); - let display_selections = editor.selections.all::(cx); + let display_selections = editor.selections.all::(&map.display_snapshot); // Handles all string that require manipulation, including inserts and replaces let edits = display_selections @@ -98,7 +98,7 @@ impl Vim { editor.transact(window, cx, |editor, window, cx| { editor.set_clip_at_line_ends(false, cx); let map = editor.snapshot(window, cx); - let selections = editor.selections.all::(cx); + let selections = editor.selections.all::(&map.display_snapshot); let mut new_selections = vec![]; let edits: Vec<(Range, String)> = selections .into_iter() @@ -150,7 +150,9 @@ impl Vim { self.stop_recording(cx); self.update_editor(cx, |vim, editor, cx| { editor.set_clip_at_line_ends(false, cx); - let mut selection = editor.selections.newest_display(cx); + let mut selection = editor + .selections + .newest_display(&editor.display_snapshot(cx)); let snapshot = editor.snapshot(window, cx); object.expand_selection(&snapshot, &mut selection, around, None); let start = snapshot @@ -196,7 +198,9 @@ impl Vim { self.update_editor(cx, |vim, editor, cx| { editor.set_clip_at_line_ends(false, cx); let text_layout_details = editor.text_layout_details(window); - let mut selection = editor.selections.newest_display(cx); + let mut selection = editor + .selections + .newest_display(&editor.display_snapshot(cx)); let snapshot = editor.snapshot(window, cx); motion.expand_selection( &snapshot, diff --git a/crates/vim/src/state.rs b/crates/vim/src/state.rs index 98a2fe0b17fb27bc7201fb82a904b0d6c4ade1cc..959edff63dd50fa549edcbae1bea213224b923af 100644 --- a/crates/vim/src/state.rs +++ b/crates/vim/src/state.rs @@ -863,7 +863,9 @@ impl VimGlobals { } } '%' => editor.and_then(|editor| { - let selection = editor.selections.newest::(cx); + let selection = editor + .selections + .newest::(&editor.display_snapshot(cx)); if let Some((_, buffer, _)) = editor .buffer() .read(cx) diff --git a/crates/vim/src/surrounds.rs b/crates/vim/src/surrounds.rs index e1b46f56a9e8b934e8c8e55d144b8eb325352375..bc817e2d4871a0be07e8c100b332f5630dcec711 100644 --- a/crates/vim/src/surrounds.rs +++ b/crates/vim/src/surrounds.rs @@ -45,7 +45,8 @@ impl Vim { }, }; let surround = pair.end != surround_alias((*text).as_ref()); - let (display_map, display_selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let display_selections = editor.selections.all_adjusted_display(&display_map); let mut edits = Vec::new(); let mut anchors = Vec::new(); @@ -144,7 +145,8 @@ impl Vim { editor.transact(window, cx, |editor, window, cx| { editor.set_clip_at_line_ends(false, cx); - let (display_map, display_selections) = editor.selections.all_display(cx); + let display_map = editor.display_snapshot(cx); + let display_selections = editor.selections.all_display(&display_map); let mut edits = Vec::new(); let mut anchors = Vec::new(); @@ -256,7 +258,8 @@ impl Vim { let preserve_space = will_replace_pair.start == will_replace_pair.end || !opening; - let (display_map, selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_adjusted_display(&display_map); let mut edits = Vec::new(); let mut anchors = Vec::new(); @@ -382,7 +385,8 @@ impl Vim { self.update_editor(cx, |_, editor, cx| { editor.transact(window, cx, |editor, window, cx| { editor.set_clip_at_line_ends(false, cx); - let (display_map, selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_adjusted_display(&display_map); let mut anchors = Vec::new(); for selection in &selections { @@ -500,7 +504,8 @@ impl Vim { let mut min_range_size = usize::MAX; let _ = self.editor.update(cx, |editor, cx| { - let (display_map, selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_adjusted_display(&display_map); // Even if there's multiple cursors, we'll simply rely on // the first one to understand what bracket pair to map to. // I believe we could, if worth it, go one step above and diff --git a/crates/vim/src/test.rs b/crates/vim/src/test.rs index 297ef6447368bdc35ed3935b25dcd687f0e9f252..93b610877a163ba0f3035e8a0483f531a3246e6c 100644 --- a/crates/vim/src/test.rs +++ b/crates/vim/src/test.rs @@ -2295,7 +2295,10 @@ async fn test_clipping_on_mode_change(cx: &mut gpui::TestAppContext) { let mut pixel_position = cx.update_editor(|editor, window, cx| { let snapshot = editor.snapshot(window, cx); - let current_head = editor.selections.newest_display(cx).end; + let current_head = editor + .selections + .newest_display(&snapshot.display_snapshot) + .end; editor.last_bounds().unwrap().origin + editor .display_to_pixel_point(current_head, &snapshot, window) diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 1d8aed62936711cdd048ee1817d2d2aad475f628..7481d176109907baccf6e742d0b3f3614014dcac 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -1359,7 +1359,10 @@ impl Vim { return; }; let newest_selection_empty = editor.update(cx, |editor, cx| { - editor.selections.newest::(cx).is_empty() + editor + .selections + .newest::(&editor.display_snapshot(cx)) + .is_empty() }); let editor = editor.read(cx); let editor_mode = editor.mode(); @@ -1455,9 +1458,11 @@ impl Vim { cx: &mut Context, ) -> Option { self.update_editor(cx, |_, editor, cx| { - let selection = editor.selections.newest::(cx); + let snapshot = &editor.snapshot(window, cx); + let selection = editor + .selections + .newest::(&snapshot.display_snapshot); - let snapshot = editor.snapshot(window, cx); let snapshot = snapshot.buffer_snapshot(); let (range, kind) = snapshot.surrounding_word(selection.start, Some(CharScopeContext::Completion)); @@ -1484,9 +1489,11 @@ impl Vim { let selections = self.editor().map(|editor| { editor.update(cx, |editor, cx| { + let snapshot = editor.display_snapshot(cx); + ( - editor.selections.oldest::(cx), - editor.selections.newest::(cx), + editor.selections.oldest::(&snapshot), + editor.selections.newest::(&snapshot), ) }) }); diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index fcbfd11bb62b9c6cf1e4df54f7521b4ba4810f69..bce49eb7d4a3c21b00a8076f0474d9da591cc993 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -747,7 +747,8 @@ impl Vim { self.stop_recording(cx); self.update_editor(cx, |_, editor, cx| { editor.transact(window, cx, |editor, window, cx| { - let (display_map, selections) = editor.selections.all_adjusted_display(cx); + let display_map = editor.display_snapshot(cx); + let selections = editor.selections.all_adjusted_display(&display_map); // Selections are biased right at the start. So we need to store // anchors that are biased left so that we can restore the selections @@ -858,7 +859,9 @@ impl Vim { }); } self.update_editor(cx, |_, editor, cx| { - let latest = editor.selections.newest::(cx); + let latest = editor + .selections + .newest::(&editor.display_snapshot(cx)); start_selection = latest.start; end_selection = latest.end; }); @@ -879,7 +882,9 @@ impl Vim { return; } self.update_editor(cx, |_, editor, cx| { - let latest = editor.selections.newest::(cx); + let latest = editor + .selections + .newest::(&editor.display_snapshot(cx)); if vim_is_normal { start_selection = latest.start; end_selection = latest.end; diff --git a/crates/zed/src/zed/quick_action_bar/repl_menu.rs b/crates/zed/src/zed/quick_action_bar/repl_menu.rs index 82eb82de1e2807346eb3ade2ced8a7946413f0a4..5210bb718c0663d2c256f865f0fcabf41bd5708f 100644 --- a/crates/zed/src/zed/quick_action_bar/repl_menu.rs +++ b/crates/zed/src/zed/quick_action_bar/repl_menu.rs @@ -54,7 +54,8 @@ impl QuickActionBar { .count() .ne(&0) .then(|| { - let latest = this.selections.newest_display(cx); + let snapshot = this.display_snapshot(cx); + let latest = this.selections.newest_display(&snapshot); !latest.is_empty() }) .unwrap_or_default()