Simplify CLI

This commit is contained in:
Laurenz 2022-01-24 16:38:34 +01:00
parent 36cae88799
commit db158719d6
5 changed files with 144 additions and 146 deletions

77
Cargo.lock generated
View File

@ -14,12 +14,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "anyhow"
version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
[[package]]
name = "arrayref"
version = "0.3.6"
@ -92,9 +86,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "crc32fast"
version = "1.3.0"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836"
checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3"
dependencies = [
"cfg-if",
]
@ -219,9 +213,9 @@ checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
[[package]]
name = "filedescriptor"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed3d8a5e20435ff00469e51a0d82049bae66504b5c429920dadf9bb54d47b3f"
checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e"
dependencies = [
"libc",
"thiserror",
@ -246,16 +240,6 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
[[package]]
name = "fontdb"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01b07f5c05414a0d8caba4c17eef8dc8b5c8955fc7c68d324191c7a56d3f3449"
dependencies = [
"log",
"ttf-parser",
]
[[package]]
name = "fxhash"
version = "0.2.1"
@ -279,7 +263,7 @@ dependencies = [
[[package]]
name = "iai"
version = "0.1.1"
source = "git+https://github.com/reknih/iai#f57a4452e7ac3b118e695e1feddb6ea02c4015be"
source = "git+https://github.com/reknih/iai#3f0f92736408ebce6545808b98e0cb2aea89b7dd"
dependencies = [
"cfg-if",
]
@ -332,9 +316,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.112"
version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
[[package]]
name = "log"
@ -485,9 +469,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.14"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
@ -559,15 +543,16 @@ dependencies = [
[[package]]
name = "resvg"
version = "0.19.0"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "256cc9203115db152290219f35f3362e729301b59e2a391fb2721fe3fa155352"
checksum = "d94a32ca845cdda27237a40beba9bd3d3858ac8fc5356eb9442bdeecfe34d9e0"
dependencies = [
"jpeg-decoder",
"log",
"pico-args",
"png 0.17.2",
"rgb",
"svgtypes",
"tiny-skia",
"usvg",
]
@ -632,18 +617,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.133"
version = "1.0.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
checksum = "2cf9235533494ea2ddcdb794665461814781c53f19d87b76e571a1c35acbad2b"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.133"
version = "1.0.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
checksum = "8dcde03d87d4c973c04be249e7d8f0b35db1c848c487bd43032808e59dd8328d"
dependencies = [
"proc-macro2",
"quote",
@ -661,9 +646,9 @@ dependencies = [
[[package]]
name = "siphasher"
version = "0.3.8"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba1eead9e94aa5a2e02de9e7839f96a007f686ae7a1d57c7797774810d24908a"
checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
[[package]]
name = "smallvec"
@ -673,9 +658,9 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]]
name = "svg2pdf"
version = "0.1.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8af8eebab963c97dc4ae380c0adb6063fdaaf586dd961b55205c6a9d646430"
checksum = "b7feae49dae1a460ecd13b50e4389204672daac9c7133fd830132f44486ab84d"
dependencies = [
"image",
"miniz_oxide 0.4.4",
@ -694,9 +679,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.85"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
@ -756,7 +741,7 @@ checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6"
name = "typst"
version = "0.1.0"
dependencies = [
"anyhow",
"bytemuck",
"codespan-reporting",
"dirs",
"filedescriptor",
@ -831,12 +816,6 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-vo"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
[[package]]
name = "unicode-width"
version = "0.1.9"
@ -851,28 +830,22 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "usvg"
version = "0.19.0"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f472f6f5d41d3eaef059bc893dcd2382eefcdda3e04ebe0b2860c56b538e491e"
checksum = "00f064d38f79ff69e3160e2fba884e4ede897061c15178041a3976371c68cab1"
dependencies = [
"base64",
"data-url",
"flate2",
"float-cmp",
"fontdb",
"kurbo",
"log",
"pico-args",
"rctree",
"roxmltree",
"rustybuzz",
"simplecss",
"siphasher",
"svgtypes",
"ttf-parser",
"unicode-bidi",
"unicode-script",
"unicode-vo",
]
[[package]]

View File

@ -5,10 +5,63 @@ authors = ["The Typst Project Developers"]
edition = "2021"
[features]
default = ["cli", "fs", "layout-cache"]
cli = ["anyhow", "codespan-reporting", "fs", "pico-args", "same-file"]
default = ["fs", "layout-cache"]
cli = ["fs", "pico-args", "codespan-reporting", "same-file"]
fs = ["dirs", "memmap2", "same-file", "walkdir"]
layout-cache = ["rand"]
layout-cache = []
# Dependency updates:
# - Bump ttf-parser when rustybuzz is updated
# - Bump usvg and resvg in conjunction with svg2pdf
[dependencies]
# Workspace
typst-macros = { path = "./macros" }
# Utilities
bytemuck = "1"
fxhash = "0.2"
itertools = "0.10"
once_cell = "1"
serde = { version = "1", features = ["derive", "rc"] }
# Text and font handling
ttf-parser = "0.12"
rustybuzz = "0.4"
unicode-bidi = "0.3.5"
unicode-segmentation = "1"
unicode-xid = "0.2"
xi-unicode = "0.3"
# Raster and vector graphics handling
image = { version = "0.23", default-features = false, features = ["png", "jpeg"] }
resvg = { version = "0.20", default-features = false }
usvg = { version = "0.20", default-features = false }
# PDF export
miniz_oxide = "0.4"
pdf-writer = "0.4"
svg2pdf = "0.2"
# Command line interface
pico-args = { version = "0.4", optional = true }
codespan-reporting = { version = "0.11", optional = true }
same-file = { version = "1", optional = true }
# File system loading
dirs = { version = "4", optional = true }
memmap2 = { version = "0.5", optional = true }
walkdir = { version = "2", optional = true }
# Still here for layout cache evaluation, but must be activated manually.
rand = { version = "0.8", optional = true }
[dev-dependencies]
filedescriptor = "0.8"
iai = { git = "https://github.com/reknih/iai" }
resvg = { version = "0.20", default-features = false }
tiny-skia = "0.6.2"
walkdir = "2"
[profile.dev]
# Faster compilation
@ -18,43 +71,6 @@ debug = 0
# Faster test execution
opt-level = 2
[dependencies]
fxhash = "0.2"
image = { version = "0.23", default-features = false, features = ["png", "jpeg"] }
itertools = "0.10"
miniz_oxide = "0.4"
once_cell = "1"
pdf-writer = "0.4"
rustybuzz = "0.4"
serde = { version = "1", features = ["derive", "rc"] }
svg2pdf = { version = "0.1", default-features = false, features = ["text", "png", "jpeg"] }
ttf-parser = "0.12"
typst-macros = { path = "./macros" }
unicode-bidi = "0.3.5"
unicode-segmentation = "1"
unicode-xid = "0.2"
usvg = { version = "0.19", default-features = false, features = ["text"] }
xi-unicode = "0.3"
anyhow = { version = "1", optional = true }
codespan-reporting = { version = "0.11", optional = true }
dirs = { version = "4", optional = true }
memmap2 = { version = "0.5", optional = true }
pico-args = { version = "0.4", optional = true }
rand = { version = "0.8", optional = true }
same-file = { version = "1", optional = true }
walkdir = { version = "2", optional = true }
[dev-dependencies]
filedescriptor = "0.8"
iai = { git = "https://github.com/reknih/iai" }
resvg = { version = "0.19", default-features = false, features = ["text"] }
tiny-skia = "0.6.2"
walkdir = "2"
# Dependencies updates:
# - Bump ttf-parser when rustybuzz is updated
# - Bump usvg and resvg in conjunction with svg2pdf
[[bin]]
name = "typst"
required-features = ["cli"]

View File

@ -150,6 +150,7 @@ impl LayoutCache {
entries.retain(|f| f.hits() as f64 / f.age() as f64 > threshold);
}
}
#[cfg(feature = "rand")]
EvictionPolicy::Random => {
// Fraction of items that should be kept.
let threshold = self.max_size as f64 / len as f64;
@ -340,6 +341,7 @@ pub enum EvictionPolicy {
/// Evict the least frequently used item.
LeastFrequentlyUsed,
/// Evict randomly.
#[cfg(feature = "rand")]
Random,
/// Use the pattern verdicts.
Patterns,

View File

@ -3,7 +3,6 @@ use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;
use anyhow::Context as _;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::term::{self, termcolor, Config, Styles};
use same_file::is_same_file;
@ -15,20 +14,34 @@ use typst::loading::FsLoader;
use typst::source::SourceStore;
use typst::Context;
const HELP: &'static str = "\
typst creates PDF files from .typ files
USAGE:
typst [OPTIONS] <input.typ> [output.pdf]
OPTIONS:
-h, --help Print this help
ARGS:
<input.typ> Path input Typst file
[output.pdf] Path to output PDF
";
fn main() {
if let Err(error) = try_main() {
print_error(error).unwrap();
let args = parse_args();
let ok = args.is_ok();
if let Err(msg) = args.and_then(try_main) {
print_error(&msg).unwrap();
if !ok {
println!("\nfor more information, try --help");
}
process::exit(1);
}
}
/// The main compiler logic.
fn try_main() -> anyhow::Result<()> {
let args = Args::from_env().unwrap_or_else(|_| {
print_usage().unwrap();
process::exit(2);
});
fn try_main(args: Args) -> Result<(), String> {
// Create a loader for fonts and files.
let mut loader = FsLoader::new();
@ -51,24 +64,27 @@ fn try_main() -> anyhow::Result<()> {
// Ensure that the source file is not overwritten.
if is_same_file(&args.input, &args.output).unwrap_or(false) {
anyhow::bail!("source and destination files are the same");
Err("source and destination files are the same")?;
}
// Load the source file.
let id = ctx.sources.load(&args.input).context("source file not found")?;
let id = ctx
.sources
.load(&args.input)
.map_err(|_| "failed to load source file")?;
// Typeset.
match ctx.typeset(id) {
// Export the PDF.
Ok(frames) => {
let buffer = export::pdf(&ctx, &frames);
fs::write(&args.output, buffer).context("failed to write PDF file")?;
fs::write(&args.output, buffer).map_err(|_| "failed to write PDF file")?;
}
// Print diagnostics.
Err(errors) => {
print_diagnostics(&ctx.sources, *errors)
.context("failed to print diagnostics")?;
.map_err(|_| "failed to print diagnostics")?;
}
}
@ -80,55 +96,41 @@ struct Args {
output: PathBuf,
}
impl Args {
fn from_env() -> Result<Self, anyhow::Error> {
let mut parser = pico_args::Arguments::from_env();
/// Parse command line arguments.
fn parse_args() -> Result<Args, String> {
let mut args = pico_args::Arguments::from_env();
if args.contains(["-h", "--help"]) {
print!("{}", HELP);
std::process::exit(0);
}
// Parse free-standing arguments.
let input = parser.free_from_str::<PathBuf>()?;
let output = match parser.opt_free_from_str()? {
Some(output) => output,
None => {
let name = input.file_name().context("source path is not a file")?;
Path::new(name).with_extension("pdf")
}
};
// Don't allow excess arguments.
if !parser.finish().is_empty() {
anyhow::bail!("too many arguments");
let input = args.free_from_str::<PathBuf>().map_err(|_| "missing input file")?;
let output = match args.opt_free_from_str().ok().flatten() {
Some(output) => output,
None => {
let name = input.file_name().ok_or("source path does not point to a file")?;
Path::new(name).with_extension("pdf")
}
};
Ok(Self { input, output })
// Don't allow excess arguments.
if !args.finish().is_empty() {
Err("too many arguments")?;
}
Ok(Args { input, output })
}
/// Print a usage message.
fn print_usage() -> io::Result<()> {
/// Print an application-level error (independent from a source file).
fn print_error(msg: &str) -> io::Result<()> {
let mut w = StandardStream::stderr(ColorChoice::Always);
let styles = Styles::default();
w.set_color(&styles.header_help)?;
write!(w, "usage")?;
w.set_color(&styles.header_error)?;
write!(w, "error")?;
w.set_color(&styles.header_message)?;
writeln!(w, ": typst <input.typ> [output.pdf]")
}
/// Print an error outside of a source file.
fn print_error(error: anyhow::Error) -> io::Result<()> {
let mut w = StandardStream::stderr(ColorChoice::Always);
let styles = Styles::default();
for (i, cause) in error.chain().enumerate() {
w.set_color(&styles.header_error)?;
write!(w, "{}", if i == 0 { "error" } else { "cause" })?;
w.set_color(&styles.header_message)?;
writeln!(w, ": {}", cause)?;
}
w.reset()
w.reset()?;
writeln!(w, ": {msg}.")
}
/// Print diagnostics messages to the terminal.

View File

@ -760,7 +760,12 @@ fn draw_image(
let w = (scale * view_width.max(aspect * view_height)).ceil() as u32;
let h = ((w as f32) / aspect).ceil() as u32;
let mut pixmap = sk::Pixmap::new(w, h).unwrap();
resvg::render(&tree, FitTo::Size(w, h), pixmap.as_mut());
resvg::render(
&tree,
FitTo::Size(w, h),
sk::Transform::identity(),
pixmap.as_mut(),
);
pixmap
}
};
@ -838,7 +843,7 @@ fn convert_usvg_fill(fill: &usvg::Fill) -> (sk::Paint<'static>, sk::FillRule) {
let mut paint = sk::Paint::default();
paint.anti_alias = true;
if let usvg::Paint::Color(usvg::Color { red, green, blue, alpha: _ }) = fill.paint {
if let usvg::Paint::Color(usvg::Color { red, green, blue }) = fill.paint {
paint.set_color_rgba8(red, green, blue, fill.opacity.to_u8())
}