From e8214fb1e6009d44a4b7094c6e5297a19f18f549 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 18 Jul 2022 09:13:47 +0800 Subject: [PATCH] Make gutters padding optional (#2996) If all gutters are removed, there are still an extra one padding, would be nice to remove that to save some space. --- book/src/configuration.md | 2 +- helix-term/src/ui/editor.rs | 2 +- helix-view/src/editor.rs | 8 ++++- helix-view/src/gutter.rs | 11 +++++++ helix-view/src/view.rs | 63 +++++++++++++++++++++++++++---------- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 4c849f2625b1..b8b939e79a83 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -38,7 +38,7 @@ hidden = false | `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`
Windows: `["cmd", "/C"]` | | `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers. | `absolute` | | `cursorline` | Highlight all lines with a cursor. | `false` | -| `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers`, note that `diagnostics` also includes other features like breakpoints | `["diagnostics", "line-numbers"]` | +| `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers` and `padding`, note that `diagnostics` also includes other features like breakpoints | `["diagnostics", "line-numbers", "padding"]` | | `auto-completion` | Enable automatic pop up of auto-completion. | `true` | | `auto-format` | Enable automatic formatting on save. | `true` | | `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` | diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 9b8bf8eb593d..911ee0f09d4a 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -615,7 +615,7 @@ impl EditorView { // avoid lots of small allocations by reusing a text buffer for each line let mut text = String::with_capacity(8); - for (constructor, width) in &view.gutters { + for (constructor, width) in view.gutters() { let gutter = constructor(editor, doc, view, theme, is_focused, *width); text.reserve(*width); // ensure there's enough space for the gutter for (i, line) in (view.offset.row..(last_line + 1)).enumerate() { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 51c0eee0f4eb..babb5c438848 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -314,6 +314,8 @@ pub enum GutterType { Diagnostics, /// Show line numbers LineNumbers, + /// Show one blank space + Padding, } impl std::str::FromStr for GutterType { @@ -450,7 +452,11 @@ impl Default for Config { }, line_number: LineNumber::Absolute, cursorline: false, - gutters: vec![GutterType::Diagnostics, GutterType::LineNumbers], + gutters: vec![ + GutterType::Diagnostics, + GutterType::LineNumbers, + GutterType::Padding, + ], middle_click_paste: true, auto_pairs: AutoPairConfig::default(), auto_completion: true, diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 05fec75894fd..8f7c306266a9 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -102,6 +102,17 @@ pub fn line_numbers<'doc>( }) } +pub fn padding<'doc>( + _editor: &'doc Editor, + _doc: &'doc Document, + _view: &View, + _theme: &Theme, + _is_focused: bool, + _width: usize, +) -> GutterFn<'doc> { + Box::new(|_line: usize, _selected: bool, _out: &mut String| None) +} + #[inline(always)] const fn abs_diff(a: usize, b: usize) -> usize { if a > b { diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index bfae12a4465e..8bf3611f6d20 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -75,7 +75,11 @@ pub struct View { pub last_modified_docs: [Option; 2], /// used to store previous selections of tree-sitter objects pub object_selections: Vec, - pub gutters: Vec<(Gutter, usize)>, + /// Gutter (constructor) and width of gutter, used to calculate + /// `gutter_offset` + gutters: Vec<(Gutter, usize)>, + /// cached total width of gutter + gutter_offset: u16, } impl fmt::Debug for View { @@ -91,12 +95,23 @@ impl fmt::Debug for View { impl View { pub fn new(doc: DocumentId, gutter_types: Vec) -> Self { let mut gutters: Vec<(Gutter, usize)> = vec![]; + let mut gutter_offset = 0; use crate::editor::GutterType; for gutter_type in &gutter_types { - match gutter_type { - GutterType::Diagnostics => gutters.push((gutter::diagnostics_or_breakpoints, 1)), - GutterType::LineNumbers => gutters.push((gutter::line_numbers, 5)), - } + let width = match gutter_type { + GutterType::Diagnostics => 1, + GutterType::LineNumbers => 5, + GutterType::Padding => 1, + }; + gutter_offset += width; + gutters.push(( + match gutter_type { + GutterType::Diagnostics => gutter::diagnostics_or_breakpoints, + GutterType::LineNumbers => gutter::line_numbers, + GutterType::Padding => gutter::padding, + }, + width as usize, + )); } Self { id: ViewId::default(), @@ -108,6 +123,7 @@ impl View { last_modified_docs: [None, None], object_selections: Vec::new(), gutters, + gutter_offset, } } @@ -119,14 +135,12 @@ impl View { } pub fn inner_area(&self) -> Rect { - // TODO: cache this - let offset = self - .gutters - .iter() - .map(|(_, width)| *width as u16) - .sum::() - + 1; // +1 for some space between gutters and line - self.area.clip_left(offset).clip_bottom(1) // -1 for statusline + // TODO add abilty to not use cached offset for runtime configurable gutter + self.area.clip_left(self.gutter_offset).clip_bottom(1) // -1 for statusline + } + + pub fn gutters(&self) -> &[(Gutter, usize)] { + &self.gutters } // @@ -327,7 +341,11 @@ mod tests { fn test_text_pos_at_screen_coords() { let mut view = View::new( DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], + vec![ + GutterType::Diagnostics, + GutterType::LineNumbers, + GutterType::Padding, + ], ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); @@ -374,7 +392,10 @@ mod tests { #[test] fn test_text_pos_at_screen_coords_without_line_numbers_gutter() { - let mut view = View::new(DocumentId::default(), vec![GutterType::Diagnostics]); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::Padding], + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); let text = rope.slice(..); @@ -400,7 +421,11 @@ mod tests { fn test_text_pos_at_screen_coords_cjk() { let mut view = View::new( DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], + vec![ + GutterType::Diagnostics, + GutterType::LineNumbers, + GutterType::Padding, + ], ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hi! こんにちは皆さん"); @@ -440,7 +465,11 @@ mod tests { fn test_text_pos_at_screen_coords_graphemes() { let mut view = View::new( DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], + vec![ + GutterType::Diagnostics, + GutterType::LineNumbers, + GutterType::Padding, + ], ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hèl̀l̀ò world!");