100 lines
2.7 KiB
Rust
100 lines
2.7 KiB
Rust
use relm4::gtk::{prelude::*, TextBuffer};
|
|
use tree_sitter::Language;
|
|
use tree_sitter_highlight::{Highlight, HighlightConfiguration, HighlightEvent};
|
|
|
|
const HIGHLIGHT_NAMES: &[&str] = &[
|
|
"attribute",
|
|
"comment",
|
|
"conditional",
|
|
"constant",
|
|
"function",
|
|
"function.builtin",
|
|
"keyword",
|
|
"label",
|
|
"number",
|
|
"operator",
|
|
"punctuation",
|
|
"repeat",
|
|
"string",
|
|
"type",
|
|
"variable",
|
|
];
|
|
|
|
pub const JSON_HL_QUERY: &str = include_str!("../ts/json_highlights.scm");
|
|
pub const LUA_HL_QUERY: &str = include_str!("../ts/lua_highlights.scm");
|
|
|
|
pub fn highlight_text_buffer(buf: &TextBuffer, lang: Language, highlight_query: &str) {
|
|
buf.remove_all_tags(&buf.start_iter(), &buf.end_iter());
|
|
|
|
let mut conf = HighlightConfiguration::new(lang, highlight_query, "", "").unwrap();
|
|
conf.configure(HIGHLIGHT_NAMES);
|
|
|
|
let table = buf.tag_table();
|
|
let tag = |name: &str| table.lookup(name).expect("missing text tag!");
|
|
|
|
let txt = buf.text(&buf.start_iter(), &buf.end_iter(), false);
|
|
crate::HIGHLIGHTER.with(|hl| {
|
|
let mut hl = hl.borrow_mut();
|
|
let hls = hl.highlight(&conf, txt.as_bytes(), None, |_| None);
|
|
|
|
if let Ok(hls) = hls.and_then(|hls| hls.collect::<Result<Vec<_>, _>>()) {
|
|
let mut acc = HighlightAcc::default();
|
|
|
|
for hl in hls {
|
|
acc.push(hl);
|
|
}
|
|
|
|
for Span {
|
|
start,
|
|
end,
|
|
hl: Highlight(hl),
|
|
} in acc.spans
|
|
{
|
|
buf.apply_tag(
|
|
&tag(HIGHLIGHT_NAMES[hl]),
|
|
&buf.iter_at_offset(start as i32),
|
|
&buf.iter_at_offset(end as i32),
|
|
);
|
|
}
|
|
} else {
|
|
buf.apply_tag(&tag("error"), &buf.start_iter(), &buf.end_iter());
|
|
}
|
|
});
|
|
}
|
|
|
|
#[derive(Debug, Default)]
|
|
struct HighlightAcc {
|
|
prev_pos: usize,
|
|
pos: usize,
|
|
cur_hl: Option<Highlight>,
|
|
pub spans: Vec<Span>,
|
|
}
|
|
|
|
impl HighlightAcc {
|
|
pub fn push(&mut self, ev: HighlightEvent) {
|
|
match ev {
|
|
HighlightEvent::Source { end, .. } => {
|
|
self.prev_pos = self.pos;
|
|
self.pos = end;
|
|
},
|
|
HighlightEvent::HighlightStart(hl) => self.cur_hl = Some(hl),
|
|
HighlightEvent::HighlightEnd => {
|
|
if let Some(hl) = self.cur_hl.take() {
|
|
self.spans.push(Span {
|
|
start: self.prev_pos,
|
|
end: self.pos,
|
|
hl,
|
|
});
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Span {
|
|
start: usize,
|
|
end: usize,
|
|
hl: Highlight,
|
|
}
|