aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/ui/editor.rs
diff options
context:
space:
mode:
authorJJ2023-11-01 01:00:19 +0000
committerJJ2023-11-01 04:08:32 +0000
commiteaf8d6d30da5014a3c475c4187b9dccfe621afd5 (patch)
treedd1d64f6b72b27256caa988120ab3075d08a9c69 /helix-term/src/ui/editor.rs
parent5c371208692df2727d02a37646b7829f011680a8 (diff)
Add rainbow tree-sitter highlights
ref: https://github.com/helix-editor/helix/issues/695 ref: https://github.com/helix-editor/helix/pull/2857 Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
Diffstat (limited to 'helix-term/src/ui/editor.rs')
-rw-r--r--helix-term/src/ui/editor.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index a305907b..9e30cea4 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -97,6 +97,11 @@ impl EditorView {
let theme = &editor.theme;
let config = editor.config();
+ let should_render_rainbow_brackets = doc
+ .language_config()
+ .and_then(|lang_config| lang_config.rainbow_brackets)
+ .unwrap_or(config.rainbow_brackets);
+
let text_annotations = view.text_annotations(doc, Some(theme));
let mut line_decorations: Vec<Box<dyn LineDecoration>> = Vec::new();
let mut translated_positions: Vec<TranslatedPosition> = Vec::new();
@@ -128,6 +133,12 @@ impl EditorView {
let mut highlights =
Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme);
+ if should_render_rainbow_brackets {
+ highlights = Box::new(syntax::merge(
+ highlights,
+ Self::doc_rainbow_highlights(doc, view.offset.anchor, inner.height, theme),
+ ));
+ }
let overlay_highlights = Self::overlay_syntax_highlights(
doc,
view.offset.anchor,
@@ -336,6 +347,48 @@ impl EditorView {
}
}
+ pub fn doc_rainbow_highlights(
+ doc: &Document,
+ anchor: usize,
+ height: u16,
+ theme: &Theme,
+ ) -> Vec<(usize, std::ops::Range<usize>)> {
+ let syntax = match doc.syntax() {
+ Some(syntax) => syntax,
+ None => return Vec::new(),
+ };
+
+ let text = doc.text().slice(..);
+ let row = text.char_to_line(anchor.min(text.len_chars()));
+
+ // calculate viewport byte ranges
+ let last_line = doc.text().len_lines().saturating_sub(1);
+ let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
+ let visible_start = text.line_to_byte(row.min(last_line));
+ let visible_end = text.line_to_byte(last_visible_line + 1);
+
+ // The calculation for the current nesting level for rainbow highlights
+ // depends on where we start the iterator from. For accuracy, we start
+ // the iterator further back than the viewport: at the start of the containing
+ // non-root syntax-tree node. Any spans that are off-screen are truncated when
+ // the spans are merged via [syntax::merge].
+ let syntax_node_start =
+ syntax::child_for_byte_range(syntax.tree().root_node(), visible_start..visible_start)
+ .map_or(visible_start, |node| node.byte_range().start);
+ let syntax_node_range = syntax_node_start..visible_end;
+
+ let mut spans = syntax.rainbow_spans(text, Some(syntax_node_range), theme.rainbow_length());
+
+ for (_highlight, range) in spans.iter_mut() {
+ let start = text.byte_to_char(ensure_grapheme_boundary_next_byte(text, range.start));
+ let end = text.byte_to_char(ensure_grapheme_boundary_next_byte(text, range.end));
+
+ *range = start..end;
+ }
+
+ spans
+ }
+
/// Get highlight spans for document diagnostics
pub fn doc_diagnostics_highlights(
doc: &Document,