draft highlight tag implementation

This commit is contained in:
yggverse 2024-12-03 01:23:23 +02:00
parent ac1b896fc0
commit 70dfac115f
2 changed files with 115 additions and 28 deletions

View File

@ -69,14 +69,22 @@ impl Reader {
// Is inline code
if let Some(code) = Code::inline_from(line) {
// Append value to buffer
match syntax.highlight(&code.value, &tag.code.text_tag, None) {
Ok(highlight) => {
for (text_tag, entity) in highlight {
buffer.insert_with_tags(&mut buffer.end_iter(), &entity, &[&text_tag]);
}
}
Err(_) => {
buffer.insert_with_tags(
&mut buffer.end_iter(),
&match syntax.auto_highlight(&code.value, None) {
Ok(highlight) => highlight,
Err(_) => code.value.to_string(), // @TODO handle
},
&code.value,
&[&tag.code.text_tag],
);
} // @TODO handle
}
// Append new line
buffer.insert(&mut buffer.end_iter(), NEW_LINE);
// Skip other actions for this line
@ -119,15 +127,25 @@ impl Reader {
None => None,
};
// Insert multiline code buffer into main buffer
// Insert multiline code into main buffer
match syntax.highlight(&this.value, &tag.code.text_tag, alt) {
Ok(highlight) => {
for (text_tag, entity) in highlight {
buffer.insert_with_tags(
&mut buffer.end_iter(),
&match syntax.auto_highlight(&this.value, alt) {
Ok(highlight) => highlight,
Err(_) => this.value.to_string(), // @TODO handle
},
&entity,
&[&text_tag],
);
}
}
Err(_) => {
buffer.insert_with_tags(
&mut buffer.end_iter(),
&this.value,
&[&tag.code.text_tag],
);
} // @TODO handle
}
// Reset
multiline = None;

View File

@ -1,8 +1,13 @@
use gtk::{
gdk::RGBA,
pango::{Style, Underline},
prelude::TextTagExt,
TextTag,
};
use syntect::{
easy::HighlightLines,
highlighting::ThemeSet,
highlighting::{Color, FontStyle, ThemeSet},
parsing::{SyntaxReference, SyntaxSet},
util::as_24_bit_terminal_escaped,
Error,
};
@ -21,28 +26,92 @@ impl Syntax {
}
}
pub fn auto_highlight(&self, source: &str, alt: Option<&String>) -> Result<String, Error> {
if let Some(name) = alt {
if let Some(syntax_reference) = self.syntax_set.find_syntax_by_name(name) {
return self.highlight(source, syntax_reference);
}
}
if let Some(syntax_reference) = self.syntax_set.find_syntax_by_first_line(source) {
return self.highlight(source, syntax_reference);
}
Ok(source.to_string())
}
pub fn highlight(
&self,
source_code: &str,
source_tag: &TextTag,
alt: Option<&String>,
) -> Result<Vec<(TextTag, String)>, Error> {
if let Some(name) = alt {
if let Some(reference) = self.syntax_set.find_syntax_by_extension(name) {
return self.syntect_buffer(source_code, source_tag, reference);
}
}
if let Some(reference) = self.syntax_set.find_syntax_by_first_line(source_code) {
return self.syntect_buffer(source_code, source_tag, reference);
}
Ok(self.default_buffer(source_code, source_tag))
}
fn default_buffer(&self, source: &str, source_tag: &TextTag) -> Vec<(TextTag, String)> {
// Init new line buffer
let mut buffer = Vec::new();
// Create new tag from source preset
let mut tag = TextTag::new(None);
tag.clone_from(source_tag);
// Append
buffer.push((tag, source.to_string()));
buffer
}
fn syntect_buffer(
&self,
source: &str,
source_tag: &TextTag,
syntax_reference: &SyntaxReference,
) -> Result<String, Error> {
) -> Result<Vec<(TextTag, String)>, Error> {
// Init new line buffer
let mut buffer = Vec::new();
// Apply syntect decorator
let ranges = HighlightLines::new(syntax_reference, &self.theme_set.themes[DEFAULT_THEME])
.highlight_line(&source, &self.syntax_set)?;
Ok(as_24_bit_terminal_escaped(&ranges[..], true))
// Build tags
for (style, entity) in ranges {
// Create new tag from source preset
let mut tag = TextTag::new(None);
tag.clone_from(source_tag);
// Tuneup using syntect conversion
tag.set_background_rgba(Some(&color_to_rgba(style.background)));
tag.set_foreground_rgba(Some(&color_to_rgba(style.foreground)));
tag.set_style(font_style_to_style(style.font_style));
tag.set_underline(font_style_to_underline(style.font_style));
// Append
buffer.push((tag, entity.to_string()));
}
Ok(buffer)
}
}
// Tools
fn color_to_rgba(color: Color) -> RGBA {
RGBA::new(
color.r.into(),
color.g.into(),
color.b.into(),
color.a.into(),
)
}
fn font_style_to_style(font_style: FontStyle) -> Style {
match font_style {
FontStyle::ITALIC => Style::Italic,
_ => Style::Normal,
}
}
fn font_style_to_underline(font_style: FontStyle) -> Underline {
match font_style {
FontStyle::UNDERLINE => Underline::Single,
_ => Underline::None,
}
}