// The `info` command (upstream `typst-cli/src/info.rs`).
///|
/// The environment variables that are of interest to Typst.
fn env_var_names() -> Array[String] {
let names = [
"TYPST_CERT", "TYPST_FEATURES", "TYPST_FONT_PATHS", "TYPST_IGNORE_SYSTEM_FONTS",
"TYPST_IGNORE_EMBEDDED_FONTS", "TYPST_PACKAGE_CACHE_PATH", "TYPST_PACKAGE_PATH",
"TYPST_ROOT", "TYPST_UPDATE_BACKUP_PATH", "SOURCE_DATE_EPOCH",
]
if @platform.os() == Linux {
names.append([
"XDG_CACHE_HOME", "XDG_DATA_HOME", "FONTCONFIG_FILE", "OPENSSL_CONF",
])
}
names.append([
"NO_COLOR", "NO_PROXY", "HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY",
])
names
}
///|
/// The operating system name (`std::env::consts::OS`).
fn os_name() -> String {
match @platform.os() {
Linux => "linux"
MacOs => "macos"
Windows => "windows"
}
}
///|
/// Execute an info command.
fn info(command : InfoCommand) -> Unit raise HintedFailure {
let env = env_var_names().map(key => (key, @platform.env_var(key)))
let get = (key : String) => {
match env.iter().find_first(e => e.0 == key) {
Some((_, value)) => value
None => None
}
}
// Turns a comma separated list of feature names into feature flags.
let mut html = false
let mut bundle = false
let mut a11y_extras = false
for feature in get("TYPST_FEATURES").unwrap_or("").split(",") {
match feature.to_owned() {
"" => ()
"html" => html = true
"bundle" => bundle = true
"a11y-extras" => a11y_extras = true
other => print_error("unknown runtime feature: `\{other}`")
}
}
let font_paths = get("TYPST_FONT_PATHS")
.unwrap_or("")
.split(":")
.filter(s => s != "")
.map(s => s.to_owned())
.to_array()
let parse_env_bool = (key : String) => {
match get(key) {
None => false
Some("true") => true
Some("false") => false
Some(val) => {
print_error(
"invalid value `\{val}` for `\{key}`, expected `true` or `false`.",
)
false
}
}
}
let system = !parse_env_bool("TYPST_IGNORE_SYSTEM_FONTS")
let embedded = !parse_env_bool("TYPST_IGNORE_EMBEDDED_FONTS")
let package_path = match get("TYPST_PACKAGE_PATH") {
Some(path) => Some(path)
None => @kit.FsPackages::system_data().map(fs => fs.path())
}
let package_cache_path = match get("TYPST_PACKAGE_CACHE_PATH") {
Some(path) => Some(path)
None => @kit.FsPackages::system_cache().map(fs => fs.path())
}
let arch = if @platform.supports_binary_stdout() {
@platform.arch()
} else {
"wasm32"
}
match command.format {
Some(format) => {
let opt = (v : String?) => {
match v {
Some(s) => @serde.Data::Str(s)
None => @serde.Data::None
}
}
let value : @serde.Data = Map([
("version", Str(typst_version)),
(
"build",
Map([
("commit", Str(upstream_commit)),
("platform", Map([("os", Str(os_name())), ("arch", Str(arch))])),
(
"settings",
Map([("self-update", Bool(false)), ("http-server", Bool(false))]),
),
]),
),
(
"features",
Map([
("html", Bool(html)),
("bundle", Bool(bundle)),
("a11y-extras", Bool(a11y_extras)),
]),
),
(
"fonts",
Map([
("paths", Seq(font_paths.map(p => @serde.Data::Str(p)))),
("system", Bool(system)),
("embedded", Bool(embedded)),
]),
),
(
"packages",
Map([
("package-path", opt(package_path)),
("package-cache-path", opt(package_cache_path)),
]),
),
("env", Map(env.map(e => (e.0, opt(e.1))))),
])
let serialized = match format {
Json => @tjson.to_string(value, pretty=command.pretty)
Yaml =>
@yaml.to_string(value) catch {
@yaml.YamlError(message~, ..) => raise bail(message)
}
}
print_out(serialized + "\n")
}
None => {
let out = terminal_out()
let key = (k : String, pad : Int32?) => {
out.set_color(@kit.ColorSpec::new().with_fg(Cyan))
out.write(pad_right(k, pad))
out.reset()
}
let simple = (v : String, pad : Int32?) => {
out.set_color(@kit.ColorSpec::new().with_fg(Green))
out.write(pad_right(v, pad))
out.reset()
}
let special = (v : String, pad : Int32?) => {
out.set_color(@kit.ColorSpec::new().with_fg(Blue))
out.write(pad_right(v, pad))
out.reset()
}
let bool_value = (b : Bool, pad : Int32?) => {
special(if b { "on" } else { "off" }, pad)
}
let opt_value = (v : String?) => {
match v {
Some(v) => simple(v, None)
None => special("", None)
}
}
key("Version", None)
out.write(" ")
simple(typst_version, None)
out.write(" (")
simple(upstream_commit[:8].to_owned(), None)
out.write(", ")
simple(os_name(), None)
out.write(" on ")
simple(arch, None)
out.writeln(")\n")
out.writeln("Build settings")
for
entry in [
("self-update", false, "Update Typst via `typst update`"),
("http-server", false, "Serve HTML via `typst watch`"),
] {
out.write(" ")
key(entry.0, Some(11))
out.write(" ")
bool_value(entry.1, Some(3))
out.writeln(" (\{entry.2})")
}
out.writeln("")
out.writeln("Features")
for
entry in [
("html", html, "Experimental HTML export"),
("bundle", bundle, "Experimental bundle export"),
("a11y-extras", a11y_extras, "Experimental accessibility additions"),
] {
out.write(" ")
key(entry.0, Some(11))
out.write(" ")
bool_value(entry.1, Some(3))
out.writeln(" (\{entry.2})")
}
out.writeln("")
out.writeln("Fonts")
out.write(" ")
key("Custom font paths", None)
if font_paths.is_empty() {
out.write(" ")
special("", None)
out.writeln("")
} else {
out.writeln("")
for path in font_paths {
out.write(" - ")
simple(path, None)
out.writeln("")
}
}
for entry in [("System fonts", system), ("Embedded fonts", embedded)] {
out.write(" ")
key(entry.0, Some(14))
out.write(" ")
bool_value(entry.1, None)
out.writeln("")
}
out.writeln("")
out.writeln("Packages")
for
entry in [
("Package path", package_path),
("Package cache path", package_cache_path),
] {
out.write(" ")
key(entry.0, Some(18))
out.write(" ")
opt_value(entry.1)
out.writeln("")
}
out.writeln("")
out.writeln("Environment variables")
let mut key_pad = 0
for e in env {
if e.0.length() > key_pad {
key_pad = e.0.length()
}
}
for e in env {
out.write(" ")
key(e.0, Some(key_pad))
out.write(" ")
opt_value(e.1)
out.writeln("")
}
flush_terminal(out)
}
}
}
///|
/// Pads a string with spaces to the right (`{: String {
match pad {
Some(pad) => {
let len = s.iter().count()
if len < pad {
s + " ".repeat(pad - len)
} else {
s
}
}
None => s
}
}