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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::path::PathBuf;

use once_cell::sync::Lazy;

// enum Preview Mode
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
pub enum PreviewMode {
    /// Preview mode for regular document
    #[cfg_attr(feature = "clap", clap(name = "document"))]
    Document,

    /// Preview mode for slide
    #[cfg_attr(feature = "clap", clap(name = "slide"))]
    Slide,
}

#[cfg(feature = "clap")]
const ENV_PATH_SEP: char = if cfg!(windows) { ';' } else { ':' };

#[derive(Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
pub struct PreviewArgs {
    /// Data plane server will bind to this address
    #[cfg_attr(
        feature = "clap",
        clap(
            long = "data-plane-host",
            default_value = "127.0.0.1:23625",
            value_name = "HOST",
            hide(true)
        )
    )]
    pub data_plane_host: String,

    /// Control plane server will bind to this address
    #[cfg_attr(
        feature = "clap",
        clap(
            long = "control-plane-host",
            default_value = "127.0.0.1:23626",
            value_name = "HOST",
            hide(true)
        )
    )]
    pub control_plane_host: String,

    /// Only render visible part of the document. This can improve performance
    /// but still being experimental.
    #[cfg_attr(feature = "clap", clap(long = "partial-rendering"))]
    pub enable_partial_rendering: bool,

    /// Invert colors of the preview (useful for dark themes without cost).
    /// Please note you could see the origin colors when you hover elements in
    /// the preview.
    #[clap(long, default_value = "never")]
    pub invert_colors: String,
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "clap", clap(name = "typst-preview", author, version, about, long_version(LONG_VERSION.as_str())))]
pub struct CliArguments {
    #[cfg_attr(feature = "clap", clap(flatten))]
    pub preview: PreviewArgs,

    /// Preview mode
    #[cfg_attr(
        feature = "clap",
        clap(long = "preview-mode", default_value = "document", value_name = "MODE")
    )]
    pub preview_mode: PreviewMode,

    /// Host for the preview server
    #[cfg_attr(
        feature = "clap",
        clap(
            long = "host",
            value_name = "HOST",
            default_value = "127.0.0.1:23627",
            alias = "static-file-host"
        )
    )]
    pub static_file_host: String,

    /// Don't open the preview in the browser after compilation.
    #[cfg_attr(feature = "clap", clap(long = "no-open"))]
    pub dont_open_in_browser: bool,

    /// Add a string key-value pair visible through `sys.inputs`
    #[clap(
        long = "input",
        value_name = "key=value",
        action = clap::ArgAction::Append,
        value_parser = clap::builder::ValueParser::new(parse_input_pair),
    )]
    pub inputs: Vec<(String, String)>,

    /// Ensures system fonts won't be searched, unless explicitly included via
    /// `--font-path`
    #[arg(long)]
    pub ignore_system_fonts: bool,

    /// Add additional directories to search for fonts
    #[cfg_attr(
        feature = "clap",
        clap(
            long = "font-path",
            value_name = "DIR",
            action = clap::ArgAction::Append,
            env = "TYPST_FONT_PATHS",
            value_delimiter = ENV_PATH_SEP,
        )
    )]
    pub font_paths: Vec<PathBuf>,

    /// Root directory for your project
    #[cfg_attr(feature = "clap", clap(long = "root", value_name = "DIR"))]
    pub root: Option<PathBuf>,

    pub input: PathBuf,
}

// This parse function comes from typst-cli
/// Parses key/value pairs split by the first equal sign.
///
/// This function will return an error if the argument contains no equals sign
/// or contains the key (before the equals sign) is empty.
fn parse_input_pair(raw: &str) -> Result<(String, String), String> {
    let (key, val) = raw
        .split_once('=')
        .ok_or("input must be a key and a value separated by an equal sign")?;
    let key = key.trim().to_owned();
    if key.is_empty() {
        return Err("the key was missing or empty".to_owned());
    }
    let val = val.trim().to_owned();
    Ok((key, val))
}

pub static LONG_VERSION: Lazy<String> = Lazy::new(|| {
    format!(
        "
Version:             {}
Build Timestamp:     {}
Build Git Describe:  {}
Commit SHA:          {}
Commit Date:         {}
Commit Branch:       {}
Cargo Target Triple: {}
",
        env!("CARGO_PKG_VERSION"),
        env!("VERGEN_BUILD_TIMESTAMP"),
        env!("VERGEN_GIT_DESCRIBE"),
        option_env!("VERGEN_GIT_SHA").unwrap_or("None"),
        option_env!("VERGEN_GIT_COMMIT_TIMESTAMP").unwrap_or("None"),
        option_env!("VERGEN_GIT_BRANCH").unwrap_or("None"),
        env!("VERGEN_CARGO_TARGET_TRIPLE"),
    )
});