Skip to main content

ck_tui/
utils.rs

1use ck_core::heatmap::{self, HeatmapBucket};
2use ratatui::style::Color;
3use std::path::{Path, PathBuf};
4use std::sync::OnceLock;
5use syntect::highlighting::ThemeSet;
6use syntect::parsing::SyntaxSet;
7
8pub fn syntax_set() -> &'static SyntaxSet {
9    static SYNTAX_SET: OnceLock<SyntaxSet> = OnceLock::new();
10    SYNTAX_SET.get_or_init(SyntaxSet::load_defaults_newlines)
11}
12
13pub fn theme_set() -> &'static ThemeSet {
14    static THEME_SET: OnceLock<ThemeSet> = OnceLock::new();
15    THEME_SET.get_or_init(ThemeSet::load_defaults)
16}
17
18pub use heatmap::{calculate_token_similarity, split_into_tokens};
19
20pub fn score_to_color(score: f32) -> Color {
21    match HeatmapBucket::from_score(score) {
22        HeatmapBucket::Step8 => Color::Rgb(0, 255, 100),
23        HeatmapBucket::Step7 => Color::Rgb(0, 200, 80),
24        HeatmapBucket::Step6 => Color::Rgb(0, 160, 70),
25        HeatmapBucket::Step5 => Color::Rgb(100, 140, 60),
26        _ => Color::Rgb(140, 140, 140),
27    }
28}
29
30pub fn apply_heatmap_color_to_token(token: &str, score: f32) -> Color {
31    // Skip coloring whitespace and punctuation
32    if token.trim().is_empty() || token.chars().all(|c| !c.is_alphanumeric()) {
33        return Color::Reset;
34    }
35
36    // 8-step linear gradient: grey to green with bright final step
37    let bucket = HeatmapBucket::from_score(score);
38
39    bucket
40        .rgb()
41        .map(|(r, g, b)| Color::Rgb(r, g, b))
42        .unwrap_or(Color::Reset)
43}
44
45pub fn find_repo_root(path: &Path) -> Option<PathBuf> {
46    let mut current = if path.is_file() {
47        path.parent().unwrap_or(path)
48    } else {
49        path
50    };
51
52    loop {
53        if current.join(".ck").exists() {
54            return Some(current.to_path_buf());
55        }
56        match current.parent() {
57            Some(parent) => current = parent,
58            None => return None,
59        }
60    }
61}