feat: implement basic highlighting (does not handle newlines yet)

pull/12706/head
Nikita Revenco 2025-01-27 21:55:35 +00:00
parent f4827c8abf
commit fa2de3222f
3 changed files with 93 additions and 33 deletions

View File

@ -1,3 +1,11 @@
/// ```helix
/// #(|hello world)#
/// #(|hello world)#
/// #[hello world|]#
/// #(|hello world)#
/// ```
fn a() {}
use crate::{ use crate::{
commands::{self, OnKeyCallback, OnKeyCallbackKind}, commands::{self, OnKeyCallback, OnKeyCallbackKind},
compositor::{Component, Context, Event, EventResult}, compositor::{Component, Context, Event, EventResult},

View File

@ -5,13 +5,14 @@ use tui::{
text::{Span, Spans, Text}, text::{Span, Spans, Text},
}; };
use std::sync::Arc; use std::{cmp::Ordering, collections::HashSet, sync::Arc};
use pulldown_cmark::{CodeBlockKind, Event, HeadingLevel, Options, Parser, Tag, TagEnd}; use pulldown_cmark::{CodeBlockKind, Event, HeadingLevel, Options, Parser, Tag, TagEnd};
use helix_core::{ use helix_core::{
syntax::{self, HighlightEvent, InjectionLanguageMarker, Syntax}, syntax::{self, HighlightEvent, InjectionLanguageMarker, Syntax},
RopeSlice, test::print,
Rope, RopeSlice,
}; };
use helix_view::{ use helix_view::{
graphics::{Margin, Rect, Style}, graphics::{Margin, Rect, Style},
@ -71,42 +72,89 @@ pub fn highlighted_code_block<'a>(
Box::new(highlight_iter) Box::new(highlight_iter)
}; };
let mut highlights = Vec::new(); if language == "helix" {
for event in highlight_iter { let (text, selections) = print(text);
match event { // let text = Rope::from(text).slice(..);
HighlightEvent::HighlightStart(span) => {
highlights.push(span);
}
HighlightEvent::HighlightEnd => {
highlights.pop();
}
HighlightEvent::Source { start, end } => {
let style = highlights
.iter()
.fold(text_style, |acc, span| acc.patch(theme.highlight(span.0)));
let mut slice = &text[start..end]; let style_cursor = get_theme("ui.cursor");
// TODO: do we need to handle all unicode line endings let style_cursor_primary = get_theme("ui.cursor.primary");
// here, or is just '\n' okay? let style_selection = get_theme("ui.selection");
while let Some(end) = slice.find('\n') { let style_selection_primary = get_theme("ui.selection.primary");
// emit span up to newline let style_text = get_theme("ui.text");
let text = &slice[..end];
let text = text.replace('\t', " "); // replace tabs
let span = Span::styled(text, style);
spans.push(span);
// truncate slice to after newline let mut ranges2 = HashSet::new();
slice = &slice[end + 1..]; let mut cursors = HashSet::new();
let primary_idx = selections.primary_index();
// make a new line for range in selections.iter() {
let spans = std::mem::take(&mut spans); ranges2.extend(range.from()..range.to());
lines.push(Spans::from(spans)); cursors.insert(if range.head > range.anchor {
range.head.saturating_sub(1)
} else {
range.head
});
}
for (idx, ch) in text.chars().enumerate() {
let is_cursor = cursors.contains(&idx);
let is_selection = ranges2.contains(&idx);
let style = if is_cursor {
if idx == primary_idx {
style_cursor_primary
} else {
style_cursor
} }
} else if is_selection {
if idx == primary_idx {
style_selection_primary
} else {
style_selection
}
} else {
style_text
};
// if there's anything left, emit it too spans.push(Span::styled(ch.to_string(), style));
if !slice.is_empty() { }
let span = Span::styled(slice.replace('\t', " "), style); } else {
spans.push(span); let mut highlights = Vec::new();
for event in highlight_iter {
match event {
HighlightEvent::HighlightStart(span) => {
highlights.push(span);
}
HighlightEvent::HighlightEnd => {
highlights.pop();
}
HighlightEvent::Source { start, end } => {
let style = highlights
.iter()
.fold(text_style, |acc, span| acc.patch(theme.highlight(span.0)));
let mut slice = &text[start..end];
// TODO: do we need to handle all unicode line endings
// here, or is just '\n' okay?
while let Some(end) = slice.find('\n') {
// emit span up to newline
let text = &slice[..end];
let text = text.replace('\t', " "); // replace tabs
let span = Span::styled(text, style);
spans.push(span);
// truncate slice to after newline
slice = &slice[end + 1..];
// make a new line
let spans = std::mem::take(&mut spans);
lines.push(Spans::from(spans));
}
// if there's anything left, emit it too
if !slice.is_empty() {
let span = Span::styled(slice.replace('\t', " "), style);
spans.push(span);
}
} }
} }
} }

4
lol.helix 100644
View File

@ -0,0 +1,4 @@
hello world #[|lol]#
hello world #[lol|]#
hello wor#(| hello world )#
#(lol|)#