summaryrefslogtreecommitdiff
path: root/crates/typst-cli/src/main.rs
blob: 62f1456695d9d9449ce99bb796b301adbb0c76b6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
mod args;
mod compile;
mod fonts;
mod package;
mod query;
mod tracing;
mod watch;
mod world;

use std::cell::Cell;
use std::env;
use std::io::{self, IsTerminal, Write};
use std::process::ExitCode;

use clap::Parser;
use codespan_reporting::term::{self, termcolor};
use termcolor::{ColorChoice, WriteColor};

use crate::args::{CliArguments, Command};

thread_local! {
    /// The CLI's exit code.
    static EXIT: Cell<ExitCode> = Cell::new(ExitCode::SUCCESS);
}

/// Entry point.
fn main() -> ExitCode {
    let arguments = CliArguments::parse();
    let _guard = match crate::tracing::setup_tracing(&arguments) {
        Ok(guard) => guard,
        Err(err) => {
            eprintln!("failed to initialize tracing {}", err);
            None
        }
    };

    let res = match arguments.command {
        Command::Compile(command) => crate::compile::compile(command),
        Command::Watch(command) => crate::watch::watch(command),
        Command::Query(command) => crate::query::query(command),
        Command::Fonts(command) => crate::fonts::fonts(command),
    };

    if let Err(msg) = res {
        set_failed();
        print_error(&msg).expect("failed to print error");
    }

    EXIT.with(|cell| cell.get())
}

/// Ensure a failure exit code.
fn set_failed() {
    EXIT.with(|cell| cell.set(ExitCode::FAILURE));
}

/// Print an application-level error (independent from a source file).
fn print_error(msg: &str) -> io::Result<()> {
    let mut w = color_stream();
    let styles = term::Styles::default();

    w.set_color(&styles.header_error)?;
    write!(w, "error")?;

    w.reset()?;
    writeln!(w, ": {msg}.")
}

/// Get stderr with color support if desirable.
fn color_stream() -> termcolor::StandardStream {
    termcolor::StandardStream::stderr(if std::io::stderr().is_terminal() {
        ColorChoice::Auto
    } else {
        ColorChoice::Never
    })
}

/// Used by `args.rs`.
fn typst_version() -> &'static str {
    env!("TYPST_VERSION")
}