diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 013de1e7df..63c7e0c69a 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1643,12 +1643,12 @@ impl PaintState { } else { 0 }; - let column_overshoot = (0f32.max(x - line.width()) / layout.em_advance) as u32; - ( - DisplayPoint::new(row, column), - DisplayPoint::new(row_overshoot, column_overshoot), - ) + let point = snapshot.clip_point(DisplayPoint::new(row, column), Bias::Left); + let mut column_overshoot = (0f32.max(x - line.width()) / layout.em_advance) as u32; + column_overshoot = column_overshoot + column - point.column(); + + (point, DisplayPoint::new(row_overshoot, column_overshoot)) } } diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index 50f16cb995..5a256d271a 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -238,6 +238,8 @@ impl Line { None } + // If round_to_closest, find the closest index to the given x position + // If !round_to_closest, find the largest index before the given x position pub fn index_for_x(&self, x: f32) -> Option { if x >= self.layout.width { None diff --git a/crates/vim/src/editor_events.rs b/crates/vim/src/editor_events.rs index c68e5182b0..7b777a50ed 100644 --- a/crates/vim/src/editor_events.rs +++ b/crates/vim/src/editor_events.rs @@ -34,12 +34,13 @@ fn editor_focused(EditorFocused(editor): &EditorFocused, cx: &mut MutableAppCont } let editor = editor.read(cx); - if editor.selections.newest::(cx).is_empty() { - if editor.mode() != EditorMode::Full { - vim.switch_mode(Mode::Insert, cx); - } - } else { - vim.switch_mode(Mode::Visual { line: false }, cx); + let editor_mode = editor.mode(); + let newest_selection_empty = editor.selections.newest::(cx).is_empty(); + + if editor_mode != EditorMode::Full { + vim.switch_mode(Mode::Insert, true, cx); + } else if !newest_selection_empty { + vim.switch_mode(Mode::Visual { line: false }, true, cx); } }); } @@ -69,7 +70,7 @@ fn editor_released(EditorReleased(editor): &EditorReleased, cx: &mut MutableAppC fn editor_local_selections_changed(newest_empty: bool, cx: &mut MutableAppContext) { Vim::update(cx, |vim, cx| { if vim.enabled && vim.state.mode == Mode::Normal && !newest_empty { - vim.switch_mode(Mode::Visual { line: false }, cx) + vim.switch_mode(Mode::Visual { line: false }, false, cx) } }) } diff --git a/crates/vim/src/insert.rs b/crates/vim/src/insert.rs index 1e19b7d918..b8387e7165 100644 --- a/crates/vim/src/insert.rs +++ b/crates/vim/src/insert.rs @@ -20,7 +20,7 @@ fn normal_before(_: &mut Workspace, _: &NormalBefore, cx: &mut ViewContext) { Vim::update(cx, |vim, cx| { - vim.switch_mode(Mode::Insert, cx); + vim.switch_mode(Mode::Insert, false, cx); vim.update_active_editor(cx, |editor, cx| { editor.change_selections(Some(Autoscroll::Fit), cx, |s| { s.move_cursors_with(|map, cursor, goal| { @@ -108,7 +108,7 @@ fn insert_first_non_whitespace( cx: &mut ViewContext, ) { Vim::update(cx, |vim, cx| { - vim.switch_mode(Mode::Insert, cx); + vim.switch_mode(Mode::Insert, false, cx); vim.update_active_editor(cx, |editor, cx| { editor.change_selections(Some(Autoscroll::Fit), cx, |s| { s.move_cursors_with(|map, cursor, goal| { @@ -121,7 +121,7 @@ fn insert_first_non_whitespace( fn insert_end_of_line(_: &mut Workspace, _: &InsertEndOfLine, cx: &mut ViewContext) { Vim::update(cx, |vim, cx| { - vim.switch_mode(Mode::Insert, cx); + vim.switch_mode(Mode::Insert, false, cx); vim.update_active_editor(cx, |editor, cx| { editor.change_selections(Some(Autoscroll::Fit), cx, |s| { s.move_cursors_with(|map, cursor, goal| { @@ -134,7 +134,7 @@ fn insert_end_of_line(_: &mut Workspace, _: &InsertEndOfLine, cx: &mut ViewConte fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContext) { Vim::update(cx, |vim, cx| { - vim.switch_mode(Mode::Insert, cx); + vim.switch_mode(Mode::Insert, false, cx); vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { let (map, old_selections) = editor.selections.all_display(cx); @@ -166,7 +166,7 @@ fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContex fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContext) { Vim::update(cx, |vim, cx| { - vim.switch_mode(Mode::Insert, cx); + vim.switch_mode(Mode::Insert, false, cx); vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { let (map, old_selections) = editor.selections.all_display(cx); diff --git a/crates/vim/src/normal/change.rs b/crates/vim/src/normal/change.rs index 9f526744d0..55445c930e 100644 --- a/crates/vim/src/normal/change.rs +++ b/crates/vim/src/normal/change.rs @@ -31,7 +31,7 @@ pub fn change_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) { editor.insert(&"", cx); }); }); - vim.switch_mode(Mode::Insert, cx) + vim.switch_mode(Mode::Insert, false, cx) } // From the docs https://vimhelp.org/change.txt.html#cw @@ -70,7 +70,7 @@ fn change_word( editor.insert(&"", cx); }); }); - vim.switch_mode(Mode::Insert, cx); + vim.switch_mode(Mode::Insert, false, cx); }); } diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 5655e51e29..b90dd4fcec 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -36,7 +36,7 @@ pub fn init(cx: &mut MutableAppContext) { // Vim Actions cx.add_action(|_: &mut Workspace, &SwitchMode(mode): &SwitchMode, cx| { - Vim::update(cx, |vim, cx| vim.switch_mode(mode, cx)) + Vim::update(cx, |vim, cx| vim.switch_mode(mode, false, cx)) }); cx.add_action( |_: &mut Workspace, &PushOperator(operator): &PushOperator, cx| { @@ -62,7 +62,7 @@ pub fn init(cx: &mut MutableAppContext) { if vim.state.mode != Mode::Normal || vim.active_operator().is_some() { MutableAppContext::defer(cx, |cx| { Vim::update(cx, |state, cx| { - state.switch_mode(Mode::Normal, cx); + state.switch_mode(Mode::Normal, false, cx); }); }); } else { @@ -115,37 +115,27 @@ impl Vim { .map(|ae| ae.update(cx, update)) } - fn switch_mode(&mut self, mode: Mode, cx: &mut MutableAppContext) { - let previous_mode = self.state.mode; + fn switch_mode(&mut self, mode: Mode, leave_selections: bool, cx: &mut MutableAppContext) { self.state.mode = mode; self.state.operator_stack.clear(); // Sync editor settings like clip mode self.sync_vim_settings(cx); + if leave_selections { + return; + } + // Adjust selections for editor in self.editors.values() { if let Some(editor) = editor.upgrade(cx) { editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| { s.move_with(|map, selection| { - // If empty selections if self.state.empty_selections_only() { let new_head = map.clip_point(selection.head(), Bias::Left); selection.collapse_to(new_head, selection.goal) } else { - if matches!(mode, Mode::Visual { line: false }) - && !matches!(previous_mode, Mode::Visual { .. }) - && !selection.reversed - && !selection.is_empty() - { - // Mode wasn't visual mode before, but is now. We need to move the end - // back by one character so that the region to be modifed stays the same - *selection.end.column_mut() = - selection.end.column().saturating_sub(1); - selection.end = map.clip_point(selection.end, Bias::Left); - } - selection.set_head( map.clip_point(selection.head(), Bias::Left), selection.goal, @@ -183,7 +173,7 @@ impl Vim { self.enabled = enabled; self.state = Default::default(); if enabled { - self.switch_mode(Mode::Normal, cx); + self.switch_mode(Mode::Normal, false, cx); } self.sync_vim_settings(cx); } diff --git a/crates/vim/src/vim_test_context.rs b/crates/vim/src/vim_test_context.rs index e13f9fda51..dff0aaf375 100644 --- a/crates/vim/src/vim_test_context.rs +++ b/crates/vim/src/vim_test_context.rs @@ -119,7 +119,7 @@ impl<'a> VimTestContext<'a> { pub fn set_state(&mut self, text: &str, mode: Mode) { self.cx.update(|cx| { Vim::update(cx, |vim, cx| { - vim.switch_mode(mode, cx); + vim.switch_mode(mode, false, cx); }) }); self.cx.set_state(text); diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index 7028f00e92..fedb999cad 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -89,7 +89,7 @@ pub fn change(_: &mut Workspace, _: &VisualChange, cx: &mut ViewContext) }); }); }); - vim.switch_mode(Mode::Normal, cx); + vim.switch_mode(Mode::Normal, false, cx); }); } @@ -266,7 +266,7 @@ pub fn paste(_: &mut Workspace, _: &VisualPaste, cx: &mut ViewContext } }); }); - vim.switch_mode(Mode::Normal, cx); + vim.switch_mode(Mode::Normal, false, cx); }); }