hac_core/syntax/
highlighter.rs1use std::collections::{HashMap, VecDeque};
2use std::fmt::Debug;
3use std::sync::RwLock;
4
5use lazy_static::lazy_static;
6use ratatui::style::Style;
7use tree_sitter::{Parser, Query, QueryCursor, Tree};
8
9lazy_static! {
10 pub static ref HIGHLIGHTER: RwLock<Highlighter> = RwLock::new(Highlighter::default());
11}
12
13pub struct Highlighter {
14 parser: Parser,
15 query: Query,
16}
17
18impl Debug for Highlighter {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 f.debug_struct("Highlighter").finish()
21 }
22}
23
24#[derive(Debug, PartialEq)]
25pub struct ColorInfo {
26 pub start: usize,
27 pub end: usize,
28 pub style: Style,
29}
30
31impl Default for Highlighter {
32 fn default() -> Self {
33 let mut parser = Parser::new();
34 let json_language = include_str!("queries/json/highlights.scm");
35 let query = Query::new(&tree_sitter_json::language(), json_language)
36 .expect("failed to load json query");
37
38 parser
39 .set_language(&tree_sitter_json::language())
40 .expect("error loading json grammar");
41
42 Highlighter { parser, query }
43 }
44}
45
46impl Highlighter {
47 pub fn parse(&mut self, buffer: &str) -> Option<Tree> {
48 self.parser.parse(buffer, None)
49 }
50
51 pub fn apply(
52 &self,
53 buffer: &str,
54 tree: Option<&Tree>,
55 tokens: &HashMap<String, Style>,
56 ) -> VecDeque<ColorInfo> {
57 let mut colors = VecDeque::new();
58
59 if let Some(tree) = tree {
60 let mut cursor = QueryCursor::new();
61 let matches = cursor.matches(&self.query, tree.root_node(), buffer.as_bytes());
62
63 for m in matches {
64 for cap in m.captures {
65 let node = cap.node;
66 let start = node.start_byte();
67 let end = node.end_byte();
68 let capture_name = self.query.capture_names()[cap.index as usize];
69 if let Some(style) = tokens.get(capture_name) {
70 colors.push_back(ColorInfo {
71 start,
72 end,
73 style: *style,
74 });
75 }
76 }
77 }
78 }
79
80 colors
81 }
82
83 pub fn find_indentation_level(tree: &Tree, cursor_byte_idx: usize) -> usize {
84 let root_node = tree.root_node();
85 let current_node = root_node
86 .descendant_for_byte_range(cursor_byte_idx, cursor_byte_idx)
87 .unwrap();
88 let mut indent_level: usize = 0;
89 let mut current_node = current_node;
90 while let Some(parent) = current_node.parent() {
91 if parent.kind().eq("pair") {
92 current_node = parent;
93 continue;
94 }
95 current_node = parent;
96 indent_level += 1;
97 }
98 indent_level.saturating_sub(1)
99 }
100}