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 = anstyle_git::parse(input)
25            .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)
37            .ok_or_else(|| anyhow::anyhow!("Failed to parse LS_COLORS '{}'", input))?;
38
39        self.ls_colors_cache.insert(input.to_string(), result);
40        Ok(result)
41    }
42
43    pub fn parse_flexible(&self, input: &str) -> Result<AnsiStyle> {
44        match self.parse_git_style(input) {
45            Ok(style) => Ok(style),
46            Err(_) => self
47                .parse_ls_colors(input)
48                .with_context(|| format!("Could not parse style string: '{}'", input)),
49        }
50    }
51}
52
53impl Default for CachedStyleParser {
54    fn default() -> Self {
55        Self::new()
56    }
57}