From e6b865ed0b1b77934733d86b59d60870e9f5881f Mon Sep 17 00:00:00 2001 From: Omnikar Date: Wed, 1 Dec 2021 17:59:23 -0500 Subject: allow whitespace to be rendered Co-authored-by: Michael Davis --- helix-term/Cargo.toml | 1 + helix-term/src/application.rs | 2 +- helix-term/src/ui/editor.rs | 55 ++++++++++++++++++++++++++++++++++++++----- helix-term/src/ui/picker.rs | 1 + 4 files changed, 52 insertions(+), 7 deletions(-) (limited to 'helix-term') diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 2e0b774b..4b2611ed 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -33,6 +33,7 @@ anyhow = "1" once_cell = "1.10" which = "4.2" +ropey = { version = "1.4", default-features = false } tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } num_cpus = "1" diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 7733c2c6..91caade7 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -283,7 +283,7 @@ impl Application { // the Application can apply it. ConfigEvent::Update(editor_config) => { let mut app_config = (*self.config.load().clone()).clone(); - app_config.editor = editor_config; + app_config.editor = *editor_config; self.config.store(Arc::new(app_config)); } } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 318180d7..798b8ac8 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -124,7 +124,15 @@ impl EditorView { Box::new(highlights) }; - Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights); + Self::render_text_highlights( + doc, + view.offset, + inner, + surface, + theme, + highlights, + &editor.config().whitespace, + ); Self::render_gutter(editor, doc, view, view.area, surface, theme, is_focused); Self::render_rulers(editor, doc, view, inner, surface, theme); @@ -344,7 +352,10 @@ impl EditorView { surface: &mut Surface, theme: &Theme, highlights: H, + whitespace: &helix_view::editor::WhitespaceConfig, ) { + use helix_view::editor::WhitespaceRenderValue; + // It's slightly more efficient to produce a full RopeSlice from the Rope, then slice that a bunch // of times than it is to always call Rope::slice/get_slice (it will internally always hit RSEnum::Light). let text = doc.text().slice(..); @@ -353,9 +364,20 @@ impl EditorView { let mut visual_x = 0u16; let mut line = 0u16; let tab_width = doc.tab_width(); - let tab = " ".repeat(tab_width); + let tab = if whitespace.render.tab() == WhitespaceRenderValue::All { + (1..tab_width).fold(whitespace.characters.tab.to_string(), |s, _| s + " ") + } else { + " ".repeat(tab_width) + }; + let space = whitespace.characters.space.to_string(); + let newline = if whitespace.render.newline() == WhitespaceRenderValue::All { + whitespace.characters.newline.to_string() + } else { + " ".to_string() + }; let text_style = theme.get("ui.text"); + let whitespace_style = theme.get("ui.virtual.whitespace"); 'outer: for event in highlights { match event { @@ -374,6 +396,14 @@ impl EditorView { .iter() .fold(text_style, |acc, span| acc.patch(theme.highlight(span.0))); + let space = if whitespace.render.space() == WhitespaceRenderValue::All + && text.len_chars() < end + { + &space + } else { + " " + }; + use helix_core::graphemes::{grapheme_width, RopeGraphemes}; for grapheme in RopeGraphemes::new(text) { @@ -386,8 +416,8 @@ impl EditorView { surface.set_string( viewport.x + visual_x - offset.col as u16, viewport.y + line, - " ", - style, + &newline, + style.patch(whitespace_style), ); } @@ -400,12 +430,21 @@ impl EditorView { } } else { let grapheme = Cow::from(grapheme); + let is_whitespace; let (grapheme, width) = if grapheme == "\t" { + is_whitespace = true; // make sure we display tab as appropriate amount of spaces let visual_tab_width = tab_width - (visual_x as usize % tab_width); - (&tab[..visual_tab_width], visual_tab_width) + let grapheme_tab_width = + ropey::str_utils::char_to_byte_idx(&tab, visual_tab_width); + + (&tab[..grapheme_tab_width], visual_tab_width) + } else if grapheme == " " { + is_whitespace = true; + (space, 1) } else { + is_whitespace = false; // Cow will prevent allocations if span contained in a single slice // which should really be the majority case let width = grapheme_width(&grapheme); @@ -418,7 +457,11 @@ impl EditorView { viewport.x + visual_x - offset.col as u16, viewport.y + line, grapheme, - style, + if is_whitespace { + style.patch(whitespace_style) + } else { + style + }, ); } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index dec59c89..3ca6965c 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -240,6 +240,7 @@ impl Component for FilePicker { surface, &cx.editor.theme, highlights, + &cx.editor.config().whitespace, ); // highlight the line -- cgit v1.2.3-70-g09d2