aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/ui/editor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src/ui/editor.rs')
-rw-r--r--helix-term/src/ui/editor.rs52
1 files changed, 41 insertions, 11 deletions
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index a8027d1b..dc6362c6 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -13,7 +13,6 @@ use helix_core::{
},
movement::Direction,
syntax::{self, HighlightEvent},
- unicode::segmentation::UnicodeSegmentation,
unicode::width::UnicodeWidthStr,
LineEnding, Position, Range, Selection, Transaction,
};
@@ -131,7 +130,7 @@ impl EditorView {
surface,
theme,
highlights,
- &editor.config().whitespace,
+ &editor.config(),
);
Self::render_gutter(editor, doc, view, view.area, surface, theme, is_focused);
Self::render_rulers(editor, doc, view, inner, surface, theme);
@@ -373,8 +372,9 @@ impl EditorView {
surface: &mut Surface,
theme: &Theme,
highlights: H,
- whitespace: &helix_view::editor::WhitespaceConfig,
+ config: &helix_view::editor::Config,
) {
+ let whitespace = &config.whitespace;
use helix_view::editor::WhitespaceRenderValue;
// It's slightly more efficient to produce a full RopeSlice from the Rope, then slice that a bunch
@@ -397,10 +397,30 @@ impl EditorView {
} else {
" ".to_string()
};
+ let indent_guide_char = config.indent_guides.character.to_string();
let text_style = theme.get("ui.text");
let whitespace_style = theme.get("ui.virtual.whitespace");
+ let mut is_in_indent_area = true;
+ let mut last_line_indent_level = 0;
+ let indent_style = theme.get("ui.virtual.indent-guide");
+
+ let draw_indent_guides = |indent_level, line, surface: &mut Surface| {
+ if !config.indent_guides.render {
+ return;
+ }
+
+ for i in 0..(indent_level / tab_width as u16) {
+ surface.set_string(
+ viewport.x + (i * tab_width as u16) - offset.col as u16,
+ viewport.y + line,
+ &indent_guide_char,
+ indent_style,
+ );
+ }
+ };
+
'outer: for event in highlights {
match event {
HighlightEvent::HighlightStart(span) => {
@@ -453,8 +473,18 @@ impl EditorView {
);
}
+ // This is an empty line; draw indent guides at previous line's
+ // indent level to avoid breaking the guides on blank lines.
+ if visual_x == 0 {
+ draw_indent_guides(last_line_indent_level, line, surface);
+ } else if is_in_indent_area {
+ // A line with whitespace only
+ draw_indent_guides(visual_x, line, surface);
+ }
+
visual_x = 0;
line += 1;
+ is_in_indent_area = true;
// TODO: with proper iter this shouldn't be necessary
if line >= viewport.height {
@@ -464,7 +494,7 @@ impl EditorView {
let grapheme = Cow::from(grapheme);
let is_whitespace;
- let (grapheme, width) = if grapheme == "\t" {
+ let (display_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);
@@ -491,7 +521,7 @@ impl EditorView {
surface.set_string(
viewport.x + visual_x - offset.col as u16,
viewport.y + line,
- grapheme,
+ display_grapheme,
if is_whitespace {
style.patch(whitespace_style)
} else {
@@ -499,6 +529,11 @@ impl EditorView {
},
);
}
+ if is_in_indent_area && !(grapheme == " " || grapheme == "\t") {
+ draw_indent_guides(visual_x, line, surface);
+ is_in_indent_area = false;
+ last_line_indent_level = visual_x;
+ }
visual_x = visual_x.saturating_add(width as u16);
}
@@ -1355,12 +1390,7 @@ impl Component for EditorView {
disp.push_str(&count.to_string())
}
for key in self.keymaps.pending() {
- let s = key.to_string();
- if s.graphemes(true).count() > 1 {
- disp.push_str(&format!("<{}>", s));
- } else {
- disp.push_str(&s);
- }
+ disp.push_str(&key.key_sequence_format());
}
if let Some(pseudo_pending) = &cx.editor.pseudo_pending {
disp.push_str(pseudo_pending.as_str())