From 60dde3a40928e010e518b225b948c413f995a383 Mon Sep 17 00:00:00 2001 From: Stephen Broadley Date: Fri, 2 Aug 2024 18:53:23 +0100 Subject: [PATCH] added 'nullspace' option --- helix-term/src/ui/editor.rs | 56 ++++++++++++++++++++++++++++++++++--- helix-view/src/editor.rs | 19 +++++++++++++ helix-view/src/view.rs | 20 ++++++++++++- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index f7541fe25..61a8f392f 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -93,7 +93,51 @@ impl EditorView { let theme = &editor.theme; let config = editor.config(); - let view_offset = doc.view_offset(view.id); + if config.nullspace.enable { + let gutter_width = view.gutter_offset(doc); + let text_width = config.text_width as u16; + + let view_width = text_width + gutter_width; + + if view_width < view.area.width { + let null_width = (area.width - view_width) / 2; + + let null_l = area.with_width(null_width).clip_bottom(1); + let null_r = Rect::new( + area.x + view_width + null_width, + area.y, + area.width - view_width - null_width, + area.height, + ) + .clip_bottom(1); + + let null_style = theme + .try_get("ui.null") + .or_else(|| Some(theme.get("ui.linenr"))) + .unwrap(); + + fn fill_area(s: &mut Surface, r: Rect, c: char) { + for y in r.top()..r.bottom() { + for x in r.left()..r.right() { + let cell = s.get_mut(x, y).unwrap(); + cell.symbol.clear(); + cell.symbol.push(c); + } + } + } + + // We currently on use the first char in the 'pattern' + // but in future I would like to use the whole string + // to render nicer patterns. + let c = config.nullspace.pattern.chars().nth(0).unwrap(); + + fill_area(surface, null_l, c); + fill_area(surface, null_r, c); + + surface.set_style(null_l, null_style); + surface.set_style(null_r, null_style); + } + } let text_annotations = view.text_annotations(doc, Some(theme)); let mut decorations = DecorationManager::default(); @@ -165,13 +209,16 @@ impl EditorView { } } - let gutter_overflow = view.gutter_offset(doc) == 0; - if !gutter_overflow { + let gutter_width = view.gutter_offset(doc); + if gutter_width > 0 { + let mut gutter_area = inner.with_width(gutter_width); + gutter_area.x -= gutter_width; + Self::render_gutter( editor, doc, view, - view.area, + gutter_area, theme, is_focused & self.terminal_focused, &mut decorations, @@ -201,6 +248,7 @@ impl EditorView { inline_diagnostic_config, config.end_of_line_diagnostics, )); + render_document( surface, inner, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1708b3b4e..5054e79d5 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -315,6 +315,8 @@ pub struct Config { /// Column numbers at which to draw the rulers. Defaults to `[]`, meaning no rulers. pub rulers: Vec, #[serde(default)] + pub nullspace: NullspaceConfig, + #[serde(default)] pub whitespace: WhitespaceConfig, /// Persistently display open buffers along the top pub bufferline: BufferLine, @@ -698,6 +700,22 @@ impl std::str::FromStr for GutterType { } } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] +pub struct NullspaceConfig { + pub enable: bool, + pub pattern: String, +} + +impl Default for NullspaceConfig { + fn default() -> Self { + Self { + enable: true, + pattern: String::from("╲"), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(default)] pub struct WhitespaceConfig { @@ -960,6 +978,7 @@ impl Default for Config { lsp: LspConfig::default(), terminal: get_terminal_provider(), rulers: Vec::new(), + nullspace: NullspaceConfig::default(), whitespace: WhitespaceConfig::default(), bufferline: BufferLine::default(), indent_guides: IndentGuidesConfig::default(), diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index a229f01ea..2c3130c22 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -191,7 +191,25 @@ impl View { } pub fn inner_area(&self, doc: &Document) -> Rect { - self.area.clip_left(self.gutter_offset(doc)).clip_bottom(1) // -1 for statusline + let config = doc.config.load(); + let gutter_width = self.gutter_offset(doc); + + if config.nullspace.enable { + let text_width = config.text_width as u16; + let view_width = gutter_width + text_width; + + if self.area.width > view_width { + let null_width = (self.area.width - view_width) / 2; + + return self + .area + .clip_left(gutter_width + null_width) + .clip_bottom(1) + .with_width(text_width.min(self.area.width)); + } + } + + self.area.clip_left(gutter_width).clip_bottom(1) // -1 for statusline } pub fn inner_height(&self) -> usize {