tectonic/
unstable_opts.rs1use std::default::Default;
12use std::path::PathBuf;
13use std::str::FromStr;
14
15const HELPMSG: &str = r#"Available unstable options:
16
17 -Z help List all unstable options
18 -Z continue-on-errors Keep compiling even when severe errors occur
19 -Z min-crossrefs=<num> Equivalent to bibtex's -min-crossrefs flag - "include after <num>
20 crossrefs" [default: 2]
21 -Z paper-size=<spec> Change the initial paper size [default: letter]
22 -Z search-path=<path> Also look in <path> for files (unless --untrusted has been specified),
23 like TEXINPUTS. Can be specified multiple times.
24 -Z shell-escape Enable \write18 (unless --untrusted has been specified)
25 -Z shell-escape-cwd=<path> Working directory to use for \write18. Use $(pwd) for same behaviour as
26 most other engines (e.g. for relative paths in \inputminted).
27 Implies -Z shell-escape
28 -Z deterministic-mode Force a deterministic build environment. Note that setting
29 `SOURCE_DATE_EPOCH` is usually sufficient for reproducible builds,
30 and this option makes some extra functionality trade-offs.
31 Specifically, deterministic mode breaks SyncTeX's auxiliary files
32 as they include and rely on absolute file paths
33"#;
34
35#[doc(hidden)]
37#[derive(Debug, Clone)]
38pub enum UnstableArg {
39 ContinueOnErrors,
40 Help,
41 MinCrossrefs(u32),
42 PaperSize(String),
43 SearchPath(PathBuf),
44 ShellEscapeEnabled,
45 ShellEscapeCwd(String),
46 DeterministicModeEnabled,
47}
48
49impl FromStr for UnstableArg {
50 type Err = Box<dyn std::error::Error + Send + Sync + 'static>;
51
52 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
54 let mut splitter = s.splitn(2, '=');
55 let arg = splitter.next().unwrap(); let value = splitter.next();
57
58 let require_value = |value_name| {
62 value.ok_or_else(|| {
63 format!("'-Z {arg}=<{value_name}>' requires a value but none was supplied",).into()
64 })
65 };
66
67 let require_no_value = |unwanted_value: Option<&str>, builtin_value: UnstableArg| {
68 if let Some(value) = unwanted_value {
69 Err(format!(
70 "'-Z {arg}={value}', was supplied but '-Z {arg}' does not take a value."
71 )
72 .into())
73 } else {
74 Ok(builtin_value)
75 }
76 };
77
78 match arg {
79 "help" => Ok(UnstableArg::Help),
80
81 "continue-on-errors" => Ok(UnstableArg::ContinueOnErrors),
82
83 "min-crossrefs" => require_value("num")
84 .and_then(|s| {
85 FromStr::from_str(s).map_err(|e| format!("-Z min-crossrefs: {e}").into())
86 })
87 .map(UnstableArg::MinCrossrefs),
88
89 "paper-size" => require_value("spec").map(|s| UnstableArg::PaperSize(s.to_string())),
90
91 "search-path" => require_value("path").map(|s| UnstableArg::SearchPath(s.into())),
92
93 "shell-escape" => require_no_value(value, UnstableArg::ShellEscapeEnabled),
94
95 "shell-escape-cwd" => {
96 require_value("path").map(|s| UnstableArg::ShellEscapeCwd(s.to_string()))
97 }
98
99 "deterministic-mode" => require_no_value(value, UnstableArg::DeterministicModeEnabled),
100
101 _ => Err(format!("Unknown unstable option '{arg}'").into()),
102 }
103 }
104}
105
106#[derive(Debug, Default)]
111pub struct UnstableOptions {
112 pub continue_on_errors: bool,
115
116 pub paper_size: Option<String>,
118
119 pub shell_escape: bool,
123
124 pub min_crossrefs: Option<u32>,
126
127 pub extra_search_paths: Vec<PathBuf>,
129
130 pub shell_escape_cwd: Option<String>,
133
134 pub deterministic_mode: bool,
145}
146
147impl UnstableOptions {
148 #[doc(hidden)]
149 pub fn from_unstable_args<I>(uargs: I) -> Self
150 where
151 I: Iterator<Item = UnstableArg>,
152 {
153 let mut opts = UnstableOptions::default();
154
155 for u in uargs {
156 use UnstableArg::*;
157 match u {
158 Help => print_unstable_help_and_exit(),
159 ContinueOnErrors => opts.continue_on_errors = true,
160 MinCrossrefs(num) => opts.min_crossrefs = Some(num),
161 PaperSize(size) => opts.paper_size = Some(size),
162 ShellEscapeEnabled => opts.shell_escape = true,
163 SearchPath(p) => opts.extra_search_paths.push(p),
164 ShellEscapeCwd(p) => {
165 opts.shell_escape_cwd = Some(p);
166 opts.shell_escape = true;
167 }
168 DeterministicModeEnabled => opts.deterministic_mode = true,
169 }
170 }
171
172 opts
173 }
174}
175
176#[doc(hidden)]
177pub fn print_unstable_help_and_exit() {
178 print!("{HELPMSG}");
179 std::process::exit(0);
180}