atomcode_core/semantic/
cache.rs1use std::collections::HashMap;
2use std::path::{Path, PathBuf};
3use std::time::SystemTime;
4
5use tree_sitter::{Parser, Tree};
6
7use super::language::{Lang, LanguageRegistry};
8
9struct CacheEntry {
11 tree: Tree,
12 modified: SystemTime,
13 lang: Lang,
14}
15
16pub struct ASTCache {
19 entries: HashMap<PathBuf, CacheEntry>,
20 parser: Parser,
21}
22
23impl ASTCache {
24 pub fn new() -> Self {
25 Self {
26 entries: HashMap::new(),
27 parser: Parser::new(),
28 }
29 }
30
31 pub fn get_tree(&mut self, path: &Path) -> Option<(Tree, Lang)> {
36 let modified = std::fs::metadata(path).ok()?.modified().ok()?;
37 let abs = std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());
38
39 if let Some(entry) = self.entries.get(&abs) {
41 if entry.modified == modified {
42 return Some((entry.tree.clone(), entry.lang));
43 }
44 }
45
46 let lang = LanguageRegistry::detect(path)?;
48 self.parser.set_language(&lang.grammar()).ok()?;
49 let source = std::fs::read_to_string(path).ok()?;
50 let tree = self.parser.parse(&source, None)?;
51
52 self.entries.insert(
53 abs,
54 CacheEntry {
55 tree: tree.clone(),
56 modified,
57 lang,
58 },
59 );
60
61 Some((tree, lang))
62 }
63
64 pub fn parse_source(&mut self, source: &str, lang: Lang) -> Option<Tree> {
66 self.parser.set_language(&lang.grammar()).ok()?;
67 self.parser.parse(source, None)
68 }
69
70 pub fn invalidate(&mut self, path: &Path) {
72 let abs = std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());
73 self.entries.remove(&abs);
74 }
75
76 pub fn clear(&mut self) {
78 self.entries.clear();
79 }
80}