Skip to main content

show_highlight/
show_highlight.rs

1use std::env;
2use std::error::Error;
3use std::fs;
4
5use highlight_spans::Grammar;
6use render_ansi::{highlight_to_ansi_with_mode_and_background, ColorMode};
7use theme_engine::load_theme;
8
9/// Parses a grammar argument and returns a human-friendly error on failure.
10fn parse_grammar(input: &str) -> Result<Grammar, String> {
11    Grammar::from_name(input).ok_or_else(|| {
12        format!(
13            "unknown grammar '{}'; use one of: {}",
14            input,
15            Grammar::supported_names().join(", ")
16        )
17    })
18}
19
20/// Prints CLI usage for the `show_highlight` example.
21fn print_usage() {
22    eprintln!("Usage:");
23    eprintln!(
24        "  cargo run -p render-ansi --example show_highlight -- <source-file> [theme] [grammar] [--color-mode truecolor|ansi256|ansi16] [--theme-bg]"
25    );
26    eprintln!();
27    eprintln!("Examples:");
28    eprintln!("  cargo run -p render-ansi --example show_highlight -- sample.cls");
29    eprintln!(
30        "  cargo run -p render-ansi --example show_highlight -- sample.cls solarized-dark objectscript"
31    );
32    eprintln!(
33        "  cargo run -p render-ansi --example show_highlight -- sample.sql tokyonight-dark sql"
34    );
35    eprintln!(
36        "  cargo run -p render-ansi --example show_highlight -- sample.sql tokyonight-dark sql --color-mode ansi256"
37    );
38    eprintln!(
39        "  cargo run -p render-ansi --example show_highlight -- sample.sql tokyonight-dark sql --color-mode ansi16"
40    );
41    eprintln!(
42        "  cargo run -p render-ansi --example show_highlight -- sample.sql tokyonight-dark sql --theme-bg"
43    );
44}
45
46/// Parses a color mode argument and returns a human-friendly error on failure.
47fn parse_color_mode(input: &str) -> Result<ColorMode, String> {
48    ColorMode::from_name(input).ok_or_else(|| {
49        format!(
50            "unknown color mode '{}'; use one of: {}",
51            input,
52            ColorMode::supported_names().join(", ")
53        )
54    })
55}
56
57/// Loads a file, highlights it, and prints full-frame ANSI output.
58///
59/// # Errors
60///
61/// Returns an error when argument parsing, file IO, theme loading, or
62/// highlight/render execution fails.
63fn main() -> Result<(), Box<dyn Error>> {
64    let args: Vec<String> = env::args().collect();
65    if args.len() < 2 {
66        print_usage();
67        return Ok(());
68    }
69
70    let source_path = &args[1];
71    let theme_name = args.get(2).map(String::as_str).unwrap_or("tokyonight-dark");
72    let grammar_name = args.get(3).map(String::as_str).unwrap_or("objectscript");
73    let mut color_mode = ColorMode::TrueColor;
74    let mut preserve_terminal_background = true;
75
76    let mut i = 4usize;
77    while i < args.len() {
78        match args[i].as_str() {
79            "--color-mode" => {
80                i += 1;
81                let Some(value) = args.get(i) else {
82                    return Err("expected value after --color-mode".into());
83                };
84                color_mode =
85                    parse_color_mode(value).map_err(|msg| format!("invalid color mode: {msg}"))?;
86            }
87            "--theme-bg" => {
88                preserve_terminal_background = false;
89            }
90            "--terminal-bg" => {
91                preserve_terminal_background = true;
92            }
93            flag => {
94                return Err(format!("unknown option '{flag}'").into());
95            }
96        }
97        i += 1;
98    }
99
100    let grammar = parse_grammar(grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
101    let source = fs::read(source_path)?;
102    let theme = load_theme(theme_name)?;
103
104    let rendered = highlight_to_ansi_with_mode_and_background(
105        &source,
106        grammar,
107        &theme,
108        color_mode,
109        preserve_terminal_background,
110    )?;
111    println!("{rendered}");
112
113    Ok(())
114}