Skip to main content

todo_tree/printer/
utils.rs

1use super::options::PrintOptions;
2use crate::utils::display::priority_to_color;
3use colored::Colorize;
4use std::path::Path;
5use todo_tree_core::Priority;
6
7pub fn format_path(path: &Path, options: &PrintOptions) -> String {
8    if options.full_paths {
9        path.display().to_string()
10    } else if let Some(base) = &options.base_path {
11        path.strip_prefix(base)
12            .map(|p| p.display().to_string())
13            .unwrap_or_else(|_| path.display().to_string())
14    } else {
15        path.display().to_string()
16    }
17}
18
19pub fn make_clickable_link(path: &Path, line: usize, options: &PrintOptions) -> Option<String> {
20    if !options.clickable_links || !supports_hyperlinks() {
21        return None;
22    }
23
24    let display_path = format_path(path, options);
25    let abs_path = path.canonicalize().ok()?;
26    let file_url = format!("file://{}:{}", abs_path.display(), line);
27
28    let link = format!(
29        "\x1b]8;;{}\x1b\\{}\x1b]8;;\x1b\\",
30        file_url,
31        if options.colored {
32            display_path.bold().to_string()
33        } else {
34            display_path
35        }
36    );
37
38    Some(link)
39}
40
41pub fn make_line_link(path: &Path, line: usize, options: &PrintOptions) -> Option<String> {
42    if !options.clickable_links || !supports_hyperlinks() {
43        return None;
44    }
45
46    let abs_path = path.canonicalize().ok()?;
47    let file_url = format!("file://{}:{}", abs_path.display(), line);
48    let display = format!("L{}", line);
49
50    let link = format!(
51        "\x1b]8;;{}\x1b\\{}\x1b]8;;\x1b\\",
52        file_url,
53        if options.colored {
54            display.cyan().to_string()
55        } else {
56            display
57        }
58    );
59
60    Some(link)
61}
62
63pub fn colorize_tag(tag: &str, options: &PrintOptions) -> String {
64    if !options.colored {
65        return tag.to_string();
66    }
67
68    let color = priority_to_color(Priority::from_tag(tag));
69    tag.color(color).bold().to_string()
70}
71
72fn supports_hyperlinks() -> bool {
73    if let Ok(term_program) = std::env::var("TERM_PROGRAM") {
74        let supported_terminals = [
75            "iTerm.app",
76            "WezTerm",
77            "Hyper",
78            "Tabby",
79            "Alacritty",
80            "vscode",
81            "VSCodium",
82            "Ghostty",
83        ];
84        if supported_terminals.iter().any(|t| term_program.contains(t)) {
85            return true;
86        }
87    }
88
89    if let Ok(colorterm) = std::env::var("COLORTERM")
90        && (colorterm == "truecolor" || colorterm == "24bit")
91    {
92        return true;
93    }
94
95    if std::env::var("VTE_VERSION").is_ok() {
96        return true;
97    }
98
99    if std::env::var("KONSOLE_VERSION").is_ok() {
100        return true;
101    }
102
103    false
104}