diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index f2d50bd13f..59c5dd9aa8 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -184,6 +184,8 @@ "z f": "editor::FoldSelectedRanges", "z shift-m": "editor::FoldAll", "z shift-r": "editor::UnfoldAll", + "z l": "vim::ColumnRight", + "z h": "vim::ColumnLeft", "shift-z shift-q": ["pane::CloseActiveItem", { "save_intent": "skip" }], "shift-z shift-z": ["pane::CloseActiveItem", { "save_intent": "save_all" }], // Count support diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index fae6654af5..48ec6c885e 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -7739,8 +7739,7 @@ impl Element for EditorElement { let line_height = style.text.line_height_in_pixels(window.rem_size()); let em_width = window.text_system().em_width(font_id, font_size).unwrap(); let em_advance = window.text_system().em_advance(font_id, font_size).unwrap(); - - let glyph_grid_cell = size(em_width, line_height); + let glyph_grid_cell = size(em_advance, line_height); let gutter_dimensions = snapshot .gutter_dimensions( @@ -8299,7 +8298,7 @@ impl Element for EditorElement { MultiBufferRow(end_anchor.to_point(&snapshot.buffer_snapshot).row); let scroll_max = point( - ((scroll_width - editor_content_width) / em_width).max(0.0), + ((scroll_width - editor_content_width) / em_advance).max(0.0), max_scroll_top, ); @@ -8311,7 +8310,7 @@ impl Element for EditorElement { start_row, editor_content_width, scroll_width, - em_width, + em_advance, &line_layouts, cx, ) @@ -8326,10 +8325,9 @@ impl Element for EditorElement { }); let scroll_pixel_position = point( - scroll_position.x * em_width, + scroll_position.x * em_advance, scroll_position.y * line_height, ); - let indent_guides = self.layout_indent_guides( content_origin, text_hitbox.origin, @@ -9454,7 +9452,7 @@ impl PositionMap { let scroll_position = self.snapshot.scroll_position(); let position = position - text_bounds.origin; let y = position.y.max(px(0.)).min(self.size.height); - let x = position.x + (scroll_position.x * self.em_width); + let x = position.x + (scroll_position.x * self.em_advance); let row = ((y / self.line_height) + scroll_position.y) as u32; let (column, x_overshoot_after_line_end) = if let Some(line) = self diff --git a/crates/editor/src/scroll.rs b/crates/editor/src/scroll.rs index a8081b95bd..6cc483cb65 100644 --- a/crates/editor/src/scroll.rs +++ b/crates/editor/src/scroll.rs @@ -669,12 +669,23 @@ impl Editor { return; } - let cur_position = self.scroll_position(cx); + let mut current_position = self.scroll_position(cx); let Some(visible_line_count) = self.visible_line_count() else { return; }; - let new_pos = cur_position + point(0., amount.lines(visible_line_count)); - self.set_scroll_position(new_pos, window, cx); + + // If the scroll position is currently at the left edge of the document + // (x == 0.0) and the intent is to scroll right, the gutter's margin + // should first be added to the current position, otherwise the cursor + // will end at the column position minus the margin, which looks off. + if current_position.x == 0.0 && amount.columns() > 0. { + if let Some(last_position_map) = &self.last_position_map { + current_position.x += self.gutter_dimensions.margin / last_position_map.em_advance; + } + } + let new_position = + current_position + point(amount.columns(), amount.lines(visible_line_count)); + self.set_scroll_position(new_position, window, cx); } /// Returns an ordering. The newest selection is: diff --git a/crates/editor/src/scroll/scroll_amount.rs b/crates/editor/src/scroll/scroll_amount.rs index 0c0319b821..bc9d4757f1 100644 --- a/crates/editor/src/scroll/scroll_amount.rs +++ b/crates/editor/src/scroll/scroll_amount.rs @@ -5,6 +5,8 @@ use ui::{Pixels, px}; pub enum ScrollDirection { Upwards, Downwards, + Rightwards, + Leftwards, } impl ScrollDirection { @@ -19,6 +21,8 @@ pub enum ScrollAmount { Line(f32), // Scroll N pages (positive is towards the end of the document) Page(f32), + // Scroll N columns (positive is towards the right of the document) + Column(f32), } impl ScrollAmount { @@ -32,6 +36,15 @@ impl ScrollAmount { } (visible_line_count * count).trunc() } + Self::Column(_count) => 0.0, + } + } + + pub fn columns(&self) -> f32 { + match self { + Self::Line(_count) => 0.0, + Self::Page(_count) => 0.0, + Self::Column(count) => *count, } } @@ -39,6 +52,12 @@ impl ScrollAmount { match self { ScrollAmount::Line(x) => px(line_height.0 * x), ScrollAmount::Page(x) => px(height.0 * x), + // This function seems to only be leveraged by the popover that is + // displayed by the editor when, for example, viewing a function's + // documentation. Right now that only supports vertical scrolling, + // so I'm leaving this at 0.0 for now to try and make it clear that + // this should not have an impact on that? + ScrollAmount::Column(_) => px(0.0), } } @@ -53,6 +72,8 @@ impl ScrollAmount { match self { Self::Line(amount) if amount.is_sign_positive() => ScrollDirection::Downwards, Self::Page(amount) if amount.is_sign_positive() => ScrollDirection::Downwards, + Self::Column(amount) if amount.is_sign_positive() => ScrollDirection::Rightwards, + Self::Column(amount) if amount.is_sign_negative() => ScrollDirection::Leftwards, _ => ScrollDirection::Upwards, } } diff --git a/crates/vim/src/normal/scroll.rs b/crates/vim/src/normal/scroll.rs index 5f3c6073be..f227f982cb 100644 --- a/crates/vim/src/normal/scroll.rs +++ b/crates/vim/src/normal/scroll.rs @@ -10,7 +10,16 @@ use settings::Settings; actions!( vim, - [LineUp, LineDown, ScrollUp, ScrollDown, PageUp, PageDown] + [ + LineUp, + LineDown, + ColumnRight, + ColumnLeft, + ScrollUp, + ScrollDown, + PageUp, + PageDown + ] ); pub fn register(editor: &mut Editor, cx: &mut Context) { @@ -20,6 +29,14 @@ pub fn register(editor: &mut Editor, cx: &mut Context) { Vim::action(editor, cx, |vim, _: &LineUp, window, cx| { vim.scroll(false, window, cx, |c| ScrollAmount::Line(-c.unwrap_or(1.))) }); + Vim::action(editor, cx, |vim, _: &ColumnRight, window, cx| { + vim.scroll(false, window, cx, |c| ScrollAmount::Column(c.unwrap_or(1.))) + }); + Vim::action(editor, cx, |vim, _: &ColumnLeft, window, cx| { + vim.scroll(false, window, cx, |c| { + ScrollAmount::Column(-c.unwrap_or(1.)) + }) + }); Vim::action(editor, cx, |vim, _: &PageDown, window, cx| { vim.scroll(false, window, cx, |c| ScrollAmount::Page(c.unwrap_or(1.))) });