Skip to main content

vtcode_core/utils/
cached_style_parser.rs

1use anstyle::Style as AnsiStyle;
2use anyhow::{Context, Result};
3use vtcode_commons::lr_map::LrMap;
4
5/// Thread-safe cached parser for Git and LS_COLORS style strings.
6pub struct CachedStyleParser {
7    git_cache: LrMap<String, AnsiStyle>,
8    ls_colors_cache: LrMap<String, AnsiStyle>,
9}
10
11impl CachedStyleParser {
12    pub fn new() -> Self {
13        Self {
14            git_cache: LrMap::new(),
15            ls_colors_cache: LrMap::new(),
16        }
17    }
18
19    pub fn parse_git_style(&self, input: &str) -> Result<AnsiStyle> {
20        if let Some(cached) = self.git_cache.get(input) {
21            return Ok(cached);
22        }
23
24        let result =
25            anstyle_git::parse(input).map_err(|e| anyhow::anyhow!("Failed to parse Git style '{input}': {e:?}"))?;
26
27        self.git_cache.insert(input.to_string(), result);
28        Ok(result)
29    }
30
31    pub fn parse_ls_colors(&self, input: &str) -> Result<AnsiStyle> {
32        if let Some(cached) = self.ls_colors_cache.get(input) {
33            return Ok(cached);
34        }
35
36        let result = anstyle_ls::parse(input).ok_or_else(|| anyhow::anyhow!("Failed to parse LS_COLORS '{input}'"))?;
37
38        self.ls_colors_cache.insert(input.to_string(), result);
39        Ok(result)
40    }
41
42    pub fn parse_flexible(&self, input: &str) -> Result<AnsiStyle> {
43        match self.parse_git_style(input) {
44            Ok(style) => Ok(style),
45            Err(_) => self
46                .parse_ls_colors(input)
47                .with_context(|| format!("Could not parse style string: '{input}'")),
48        }
49    }
50}
51
52impl Default for CachedStyleParser {
53    fn default() -> Self {
54        Self::new()
55    }
56}