From e34e2ef75f0976e8d09e26fcd89e4b0d4e5f65f7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 22 Feb 2025 15:44:45 -0500 Subject: [PATCH] Implement the highlighted src intermediate format. I am going to remove the enum because I realized plain src blocks can just be highlighted src blocks with only RawText entries. --- src/intermediate/src_block.rs | 61 +++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/src/intermediate/src_block.rs b/src/intermediate/src_block.rs index 5566cbf..ca88164 100644 --- a/src/intermediate/src_block.rs +++ b/src/intermediate/src_block.rs @@ -24,11 +24,23 @@ pub(crate) struct PlainSrcBlock { #[derive(Debug, Clone)] pub(crate) struct HighlightedSrcBlock { - pub(crate) lines: Vec, + pub(crate) lines: Vec, pub(crate) language: Option, pub(crate) post_blank: organic::types::PostBlank, } +#[derive(Debug, Clone)] +pub(crate) struct HighlightedSrcLine { + pub(crate) children: Vec, +} + +#[derive(Debug, Clone)] +pub(crate) enum HighlightedSrcSegment { + RawText(String), + HighlightStart { name: String }, + HighlightEnd, +} + intermediate!( ISrcBlock, &'orig organic::types::SrcBlock<'parse>, @@ -97,6 +109,14 @@ intermediate!( } ); +impl HighlightedSrcLine { + pub(crate) fn new() -> HighlightedSrcLine { + HighlightedSrcLine { + children: Vec::new(), + } + } +} + fn ascii_whitespace_value(c: char) -> usize { match c { ' ' => 1, @@ -107,7 +127,7 @@ fn ascii_whitespace_value(c: char) -> usize { } } -fn highlight_nix(lines: &[L]) -> Result, CustomError> +fn highlight_nix(lines: &[L]) -> Result, CustomError> where L: Borrow, { @@ -126,28 +146,43 @@ where .highlight(&config, combined_text.as_bytes(), None, |_| None) .unwrap(); - let mut highlighted_text = Vec::new(); + let mut highlighted_text: Vec = Vec::with_capacity(lines.len()); + let mut current_line = HighlightedSrcLine::new(); for event in highlights { match event.unwrap() { HighlightEvent::Source { start, end } => { - highlighted_text.push(Cow::Borrowed(&combined_text[start..end])); + let mut span = &combined_text[start..end]; + while let Some(line_break_index) = span.find('\n') { + let first_line = &span[..(line_break_index + 1)]; + current_line + .children + .push(HighlightedSrcSegment::RawText(first_line.to_owned())); + highlighted_text.push(current_line); + current_line = HighlightedSrcLine::new(); + span = &span[(line_break_index + 1)..]; + } + if !span.is_empty() { + current_line + .children + .push(HighlightedSrcSegment::RawText(span.to_owned())); + } } HighlightEvent::HighlightStart(s) => { - let class_name = format!("srchl_{}", highlight_names[s.0]); - highlighted_text.push(Cow::Owned(format!(r#""#, class_name))); + current_line + .children + .push(HighlightedSrcSegment::HighlightStart { + name: highlight_names[s.0].to_owned(), + }); } HighlightEvent::HighlightEnd => { - highlighted_text.push(Cow::Borrowed(r#""#)); + current_line + .children + .push(HighlightedSrcSegment::HighlightEnd); } } } - let highlighted_text = highlighted_text.join(""); - let lines = highlighted_text - .split_inclusive('\n') - .map(str::to_owned) - .collect(); - Ok(lines) + Ok(highlighted_text) } // use tree_sitter::Parser;