diff --git a/Cargo.lock b/Cargo.lock index ec9f290cc..cb6a1c93b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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]] diff --git a/Cargo.toml b/Cargo.toml index 0bf68d74f..3d2d77069 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/src/layout/incremental.rs b/src/layout/incremental.rs index 4c046051b..f737a3ef3 100644 --- a/src/layout/incremental.rs +++ b/src/layout/incremental.rs @@ -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, diff --git a/src/main.rs b/src/main.rs index fa8b61038..daeff033e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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] [output.pdf] + +OPTIONS: + -h, --help Print this help + +ARGS: + 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 { - let mut parser = pico_args::Arguments::from_env(); +/// Parse command line arguments. +fn parse_args() -> Result { + 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::()?; - 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::().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 [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. diff --git a/tests/typeset.rs b/tests/typeset.rs index 60214b9fd..a4e20774f 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -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()) }