mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Add instrumentation (Part 1) (#761)
This commit is contained in:
parent
2fbb14f712
commit
561ff979d5
296
Cargo.lock
generated
296
Cargo.lock
generated
@ -8,6 +8,18 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
@ -483,6 +495,19 @@ dependencies = [
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.1.1"
|
||||
@ -558,6 +583,15 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
@ -589,6 +623,15 @@ dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.0"
|
||||
@ -606,7 +649,7 @@ checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -870,6 +913,29 @@ dependencies = [
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inferno"
|
||||
version = "0.11.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fb7c1b80a1dfa604bb4a649a5c5aeef3d913f7c520cb42b40e534e8a61bcdfc"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"clap 4.2.4",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-utils",
|
||||
"dashmap",
|
||||
"env_logger",
|
||||
"indexmap",
|
||||
"is-terminal",
|
||||
"itoa",
|
||||
"log",
|
||||
"num-format",
|
||||
"once_cell",
|
||||
"quick-xml",
|
||||
"rgb",
|
||||
"str_stack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
@ -890,6 +956,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.10"
|
||||
@ -1067,6 +1142,16 @@ dependencies = [
|
||||
"rand_chacha",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
@ -1164,6 +1249,16 @@ dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
@ -1175,6 +1270,16 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-format"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.2",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
@ -1243,6 +1348,12 @@ version = "6.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "oxipng"
|
||||
version = "8.0.0"
|
||||
@ -1267,6 +1378,19 @@ dependencies = [
|
||||
"zopfli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.12"
|
||||
@ -1320,6 +1444,12 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "pixglyph"
|
||||
version = "0.1.0"
|
||||
@ -1357,6 +1487,15 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psm"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.9.2"
|
||||
@ -1369,6 +1508,15 @@ dependencies = [
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
@ -1446,6 +1594,15 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.3"
|
||||
@ -1453,7 +1610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@ -1688,6 +1845,15 @@ dependencies = [
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.5"
|
||||
@ -1727,6 +1893,19 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stderrlog"
|
||||
version = "0.5.4"
|
||||
@ -1739,6 +1918,12 @@ dependencies = [
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "str_stack"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@ -1843,6 +2028,19 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
@ -1932,6 +2130,85 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-error"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-flame"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bae117ee14789185e129aaee5d93750abe67fdc5a9a62650452bfe4e122a3a9"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.15.2"
|
||||
@ -1980,10 +2257,12 @@ dependencies = [
|
||||
"rustybuzz",
|
||||
"serde",
|
||||
"siphasher",
|
||||
"stacker",
|
||||
"subsetter",
|
||||
"svg2pdf",
|
||||
"thin-vec",
|
||||
"tiny-skia",
|
||||
"tracing",
|
||||
"ttf-parser 0.18.1",
|
||||
"typst-macros",
|
||||
"unicode-math-class",
|
||||
@ -2006,12 +2285,18 @@ dependencies = [
|
||||
"comemo",
|
||||
"dirs",
|
||||
"elsa",
|
||||
"inferno",
|
||||
"memmap2",
|
||||
"notify",
|
||||
"once_cell",
|
||||
"open",
|
||||
"same-file",
|
||||
"siphasher",
|
||||
"tempfile",
|
||||
"tracing",
|
||||
"tracing-error",
|
||||
"tracing-flame",
|
||||
"tracing-subscriber",
|
||||
"typst",
|
||||
"typst-library",
|
||||
"walkdir",
|
||||
@ -2056,6 +2341,7 @@ dependencies = [
|
||||
"serde_yaml",
|
||||
"smallvec",
|
||||
"syntect",
|
||||
"tracing",
|
||||
"ttf-parser 0.18.1",
|
||||
"typed-arena",
|
||||
"typst",
|
||||
@ -2276,6 +2562,12 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -51,10 +51,12 @@ unicode-xid = "0.2"
|
||||
unscanny = "0.1"
|
||||
usvg = { version = "0.22", default-features = false, features = ["text"] }
|
||||
xmp-writer = "0.1"
|
||||
tracing = "0.1.37"
|
||||
indexmap = "1.9.3"
|
||||
stacker = "0.1.15"
|
||||
|
||||
[profile.dev]
|
||||
debug = 0
|
||||
debug = false
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 2
|
||||
|
@ -34,6 +34,12 @@ siphasher = "0.3"
|
||||
walkdir = "2"
|
||||
clap = { version = "4.2.1", features = ["derive", "env"] }
|
||||
open = "4.0.1"
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = "0.3.16"
|
||||
tracing-flame = "0.2.0"
|
||||
tracing-error = "0.2"
|
||||
inferno = "0.11.15"
|
||||
tempfile = "3.5.0"
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "4.2.1", features = ["derive", "string"] }
|
||||
|
@ -24,9 +24,9 @@ pub fn typst_version() -> String {
|
||||
format!("{pkg} ({hash})")
|
||||
}
|
||||
|
||||
mod args {
|
||||
include!("src/args.rs");
|
||||
}
|
||||
#[path = "src/args.rs"]
|
||||
#[allow(dead_code)]
|
||||
mod args;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-env-changed=TYPST_VERSION");
|
||||
|
@ -17,6 +17,10 @@ pub struct CliArguments {
|
||||
/// The typst command to run
|
||||
#[command(subcommand)]
|
||||
pub command: Command,
|
||||
|
||||
/// Sets the level of verbosity: 0 = none, 1 = warning & error, 2 = info, 3 = debug, 4 = trace
|
||||
#[clap(short, long, action = ArgAction::Count)]
|
||||
pub verbosity: u8,
|
||||
}
|
||||
|
||||
/// What to do.
|
||||
@ -35,6 +39,22 @@ pub enum Command {
|
||||
Fonts(FontsCommand),
|
||||
}
|
||||
|
||||
impl Command {
|
||||
/// Returns the compile command if this is a compile or watch command.
|
||||
pub fn as_compile(&self) -> Option<&CompileCommand> {
|
||||
match self {
|
||||
Command::Compile(cmd) => Some(cmd),
|
||||
Command::Watch(cmd) => Some(cmd),
|
||||
Command::Fonts(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this is a watch command.
|
||||
pub fn is_watch(&self) -> bool {
|
||||
matches!(self, Command::Watch(_))
|
||||
}
|
||||
}
|
||||
|
||||
/// Compiles the input file into a PDF file
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
pub struct CompileCommand {
|
||||
@ -47,6 +67,11 @@ pub struct CompileCommand {
|
||||
/// Opens the output file after compilation using the default PDF viewer
|
||||
#[arg(long = "open")]
|
||||
pub open: Option<Option<String>>,
|
||||
|
||||
/// Produces a flamegraph of the compilation process and saves it to the
|
||||
/// given file or to `flamegraph.svg` in the current working directory.
|
||||
#[arg(long = "flamegraph", value_name = "OUTPUT_SVG")]
|
||||
pub flamegraph: Option<Option<PathBuf>>,
|
||||
}
|
||||
|
||||
/// List all discovered fonts in system and custom font paths
|
||||
|
@ -1,4 +1,5 @@
|
||||
mod args;
|
||||
mod trace;
|
||||
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::collections::HashMap;
|
||||
@ -28,6 +29,7 @@ use typst::World;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::args::{CliArguments, Command, CompileCommand};
|
||||
use crate::trace::init_tracing;
|
||||
|
||||
type CodespanResult<T> = Result<T, CodespanError>;
|
||||
type CodespanError = codespan_reporting::files::Error;
|
||||
@ -80,7 +82,7 @@ impl CompileSettings {
|
||||
/// Panics if the command is not a compile or watch command.
|
||||
pub fn with_arguments(args: CliArguments) -> Self {
|
||||
let watch = matches!(args.command, Command::Watch(_));
|
||||
let CompileCommand { input, output, open } = match args.command {
|
||||
let CompileCommand { input, output, open, .. } = match args.command {
|
||||
Command::Compile(command) => command,
|
||||
Command::Watch(command) => command,
|
||||
_ => unreachable!(),
|
||||
@ -118,6 +120,13 @@ impl FontsSettings {
|
||||
/// Entry point.
|
||||
fn main() {
|
||||
let arguments = CliArguments::parse();
|
||||
let _guard = match init_tracing(&arguments) {
|
||||
Ok(guard) => guard,
|
||||
Err(err) => {
|
||||
eprintln!("failed to initialize tracing, reason: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let res = match &arguments.command {
|
||||
Command::Compile(_) | Command::Watch(_) => {
|
||||
@ -225,7 +234,10 @@ fn compile(mut command: CompileSettings) -> StrResult<()> {
|
||||
}
|
||||
|
||||
/// Compile a single time.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn compile_once(world: &mut SystemWorld, command: &CompileSettings) -> StrResult<bool> {
|
||||
tracing::info!("Starting compilation");
|
||||
|
||||
status(command, Status::Compiling).unwrap();
|
||||
|
||||
world.reset();
|
||||
@ -237,6 +249,8 @@ fn compile_once(world: &mut SystemWorld, command: &CompileSettings) -> StrResult
|
||||
let buffer = typst::export::pdf(&document);
|
||||
fs::write(&command.output, buffer).map_err(|_| "failed to write PDF file")?;
|
||||
status(command, Status::Success).unwrap();
|
||||
|
||||
tracing::info!("Compilation succeeded");
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
@ -245,12 +259,15 @@ fn compile_once(world: &mut SystemWorld, command: &CompileSettings) -> StrResult
|
||||
status(command, Status::Error).unwrap();
|
||||
print_diagnostics(world, *errors)
|
||||
.map_err(|_| "failed to print diagnostics")?;
|
||||
|
||||
tracing::info!("Compilation failed");
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the terminal and render the status message.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn status(command: &CompileSettings, status: Status) -> io::Result<()> {
|
||||
if !command.watch {
|
||||
return Ok(());
|
||||
@ -431,6 +448,7 @@ impl World for SystemWorld {
|
||||
self.source(self.main)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId> {
|
||||
self.slot(path)?
|
||||
.source
|
||||
@ -469,6 +487,7 @@ impl World for SystemWorld {
|
||||
}
|
||||
|
||||
impl SystemWorld {
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn slot(&self, path: &Path) -> FileResult<RefMut<PathSlot>> {
|
||||
let mut hashes = self.hashes.borrow_mut();
|
||||
let hash = match hashes.get(path).cloned() {
|
||||
@ -488,6 +507,7 @@ impl SystemWorld {
|
||||
}))
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn insert(&self, path: &Path, text: String) -> SourceId {
|
||||
let id = SourceId::from_u16(self.sources.len() as u16);
|
||||
let source = Source::new(id, path, text);
|
||||
@ -520,6 +540,7 @@ impl SystemWorld {
|
||||
.map_or(false, |hash| self.paths.borrow().contains_key(&hash))
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn reset(&mut self) {
|
||||
self.sources.as_mut().clear();
|
||||
self.hashes.borrow_mut().clear();
|
||||
@ -542,6 +563,7 @@ impl PathHash {
|
||||
}
|
||||
|
||||
/// Read a file.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn read(path: &Path) -> FileResult<Vec<u8>> {
|
||||
let f = |e| FileError::from_io(e, path);
|
||||
if fs::metadata(path).map_err(f)?.is_dir() {
|
||||
|
135
cli/src/trace.rs
Normal file
135
cli/src/trace.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter, Error, ErrorKind, Seek, SeekFrom};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use inferno::flamegraph::Options;
|
||||
use tracing::metadata::LevelFilter;
|
||||
use tracing_error::ErrorLayer;
|
||||
use tracing_flame::{FlameLayer, FlushGuard};
|
||||
use tracing_subscriber::fmt;
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
use crate::args::CliArguments;
|
||||
|
||||
/// Will flush the flamegraph to disk when dropped.
|
||||
pub struct TracingGuard {
|
||||
flush_guard: Option<FlushGuard<BufWriter<File>>>,
|
||||
temp_file: File,
|
||||
output_svg: PathBuf,
|
||||
}
|
||||
|
||||
impl TracingGuard {
|
||||
pub fn finish(&mut self) -> Result<(), Error> {
|
||||
if self.flush_guard.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
tracing::info!("Flushing tracing flamegraph...");
|
||||
|
||||
// At this point, we're done tracing, so we can drop the guard.
|
||||
// This will flush the tracing output to disk.
|
||||
// We can then read the file and generate the flamegraph.
|
||||
drop(self.flush_guard.take());
|
||||
|
||||
// Reset the file pointer to the beginning.
|
||||
self.temp_file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
// Create the readers and writers.
|
||||
let reader = BufReader::new(&mut self.temp_file);
|
||||
let output = BufWriter::new(File::create(&self.output_svg)?);
|
||||
|
||||
// Create the options: default in flame chart mode
|
||||
let mut options = Options::default();
|
||||
options.flame_chart = true;
|
||||
|
||||
inferno::flamegraph::from_reader(&mut options, reader, output)
|
||||
.map_err(|e| Error::new(ErrorKind::Other, e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TracingGuard {
|
||||
fn drop(&mut self) {
|
||||
if !std::thread::panicking() {
|
||||
if let Err(e) = self.finish() {
|
||||
// Since we are finished, we cannot rely on tracing to log the
|
||||
// error.
|
||||
eprintln!("Failed to flush tracing flamegraph: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the tracing system and returns a guard that will flush the
|
||||
/// flamegraph to disk when dropped.
|
||||
pub fn init_tracing(args: &CliArguments) -> Result<Option<TracingGuard>, Error> {
|
||||
let flamegraph = args.command.as_compile().and_then(|c| c.flamegraph.as_ref());
|
||||
|
||||
if flamegraph.is_some() && args.command.is_watch() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"cannot use --flamegraph with watch command",
|
||||
));
|
||||
}
|
||||
|
||||
// Short circuit if we don't need to initialize flamegraph or debugging.
|
||||
if flamegraph.is_none() && args.verbosity == 0 {
|
||||
tracing_subscriber::fmt()
|
||||
.without_time()
|
||||
.with_max_level(level_filter(args))
|
||||
.init();
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Build the FMT layer printing to the console.
|
||||
let fmt_layer = fmt::Layer::default().without_time().with_filter(level_filter(args));
|
||||
|
||||
// Error layer for building backtraces
|
||||
let error_layer = ErrorLayer::default();
|
||||
|
||||
// Build the registry.
|
||||
let registry = tracing_subscriber::registry().with(fmt_layer).with(error_layer);
|
||||
|
||||
let Some(path) = flamegraph else {
|
||||
registry.init();
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Create a temporary file to store the flamegraph data.
|
||||
let temp_file = tempfile::tempfile()?;
|
||||
let writer = BufWriter::new(temp_file.try_clone()?);
|
||||
|
||||
// Build the flamegraph layer.
|
||||
let flame_layer = FlameLayer::new(writer)
|
||||
.with_empty_samples(false)
|
||||
.with_threads_collapsed(true)
|
||||
.with_module_path(false)
|
||||
.with_file_and_line(true);
|
||||
let flush_guard = flame_layer.flush_on_drop();
|
||||
|
||||
// Build the subscriber.
|
||||
registry.with(flame_layer).init();
|
||||
|
||||
tracing::warn!(
|
||||
"Flamegraph is enabled, this can create a large temporary \
|
||||
file and slow down the compilation process."
|
||||
);
|
||||
|
||||
Ok(Some(TracingGuard {
|
||||
flush_guard: Some(flush_guard),
|
||||
temp_file,
|
||||
output_svg: path.clone().unwrap_or_else(|| "flamegraph.svg".into()),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Returns the log level filter for the given verbosity level.
|
||||
fn level_filter(args: &CliArguments) -> LevelFilter {
|
||||
match args.verbosity {
|
||||
0 => LevelFilter::WARN,
|
||||
1 => LevelFilter::INFO,
|
||||
2 => LevelFilter::DEBUG,
|
||||
_ => LevelFilter::TRACE,
|
||||
}
|
||||
}
|
@ -39,3 +39,4 @@ unicode-script = "0.5"
|
||||
unicode-segmentation = "1"
|
||||
xi-unicode = "0.3"
|
||||
chinese-number = { version = "0.7.1", default-features = false, features = ["number-to-chinese"] }
|
||||
tracing = "0.1.37"
|
||||
|
@ -58,6 +58,7 @@ pub struct AlignElem {
|
||||
}
|
||||
|
||||
impl Show for AlignElem {
|
||||
#[tracing::instrument(name = "AlignElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self
|
||||
.body()
|
||||
|
@ -50,6 +50,7 @@ pub struct ColumnsElem {
|
||||
}
|
||||
|
||||
impl Layout for ColumnsElem {
|
||||
#[tracing::instrument(name = "ColumnsElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -99,6 +99,7 @@ pub struct BoxElem {
|
||||
}
|
||||
|
||||
impl Layout for BoxElem {
|
||||
#[tracing::instrument(name = "BoxElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -326,6 +327,7 @@ pub struct BlockElem {
|
||||
}
|
||||
|
||||
impl Layout for BlockElem {
|
||||
#[tracing::instrument(name = "BlockElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -154,6 +154,7 @@ pub struct EnumElem {
|
||||
}
|
||||
|
||||
impl Layout for EnumElem {
|
||||
#[tracing::instrument(name = "EnumElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -19,6 +19,7 @@ pub struct FlowElem {
|
||||
}
|
||||
|
||||
impl Layout for FlowElem {
|
||||
#[tracing::instrument(name = "FlowElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -122,6 +123,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
}
|
||||
|
||||
/// Layout vertical spacing.
|
||||
#[tracing::instrument(name = "FlowLayouter::layout_spacing", skip_all)]
|
||||
fn layout_spacing(&mut self, v: &VElem, styles: StyleChain) {
|
||||
self.layout_item(match v.amount() {
|
||||
Spacing::Rel(rel) => FlowItem::Absolute(
|
||||
@ -133,6 +135,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
}
|
||||
|
||||
/// Layout a paragraph.
|
||||
#[tracing::instrument(name = "FlowLayouter::layout_par", skip_all)]
|
||||
fn layout_par(
|
||||
&mut self,
|
||||
vt: &mut Vt,
|
||||
@ -179,6 +182,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
}
|
||||
|
||||
/// Layout into a single region.
|
||||
#[tracing::instrument(name = "FlowLayouter::layout_single", skip_all)]
|
||||
fn layout_single(
|
||||
&mut self,
|
||||
vt: &mut Vt,
|
||||
@ -237,6 +241,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
}
|
||||
|
||||
/// Layout a finished frame.
|
||||
#[tracing::instrument(name = "FlowLayouter::layout_item", skip_all)]
|
||||
fn layout_item(&mut self, item: FlowItem) {
|
||||
match item {
|
||||
FlowItem::Absolute(v, _) => self.regions.size.y -= v,
|
||||
|
@ -102,6 +102,7 @@ pub struct GridElem {
|
||||
}
|
||||
|
||||
impl Layout for GridElem {
|
||||
#[tracing::instrument(name = "GridElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -289,6 +290,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
}
|
||||
|
||||
/// Determines the columns sizes and then layouts the grid row-by-row.
|
||||
#[tracing::instrument(name = "grid layout", skip(self))]
|
||||
pub fn layout(mut self) -> SourceResult<GridLayout> {
|
||||
self.measure_columns()?;
|
||||
|
||||
|
@ -23,6 +23,7 @@ pub struct HideElem {
|
||||
}
|
||||
|
||||
impl Show for HideElem {
|
||||
#[tracing::instrument(name = "HideElem::show", skip(self))]
|
||||
fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.body().styled(MetaElem::set_data(vec![Meta::Hide])))
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ pub struct ListElem {
|
||||
}
|
||||
|
||||
impl Layout for ListElem {
|
||||
#[tracing::instrument(name = "ListElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -68,6 +68,7 @@ pub trait LayoutRoot {
|
||||
}
|
||||
|
||||
impl LayoutRoot for Content {
|
||||
#[tracing::instrument(name = "Content::layout_root", skip_all)]
|
||||
fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> {
|
||||
#[comemo::memoize]
|
||||
fn cached(
|
||||
@ -87,6 +88,8 @@ impl LayoutRoot for Content {
|
||||
.layout_root(&mut vt, styles)
|
||||
}
|
||||
|
||||
tracing::info!("Starting layout");
|
||||
|
||||
cached(
|
||||
self,
|
||||
vt.world,
|
||||
@ -126,6 +129,7 @@ pub trait Layout {
|
||||
}
|
||||
|
||||
impl Layout for Content {
|
||||
#[tracing::instrument(name = "Content::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -151,6 +155,8 @@ impl Layout for Content {
|
||||
.layout(&mut vt, styles, regions)
|
||||
}
|
||||
|
||||
tracing::info!("Layouting `Content`");
|
||||
|
||||
cached(
|
||||
self,
|
||||
vt.world,
|
||||
@ -164,6 +170,7 @@ impl Layout for Content {
|
||||
}
|
||||
|
||||
/// Realize into an element that is capable of root-level layout.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn realize_root<'a>(
|
||||
vt: &mut Vt,
|
||||
scratch: &'a Scratch<'a>,
|
||||
@ -245,6 +252,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn accept(
|
||||
&mut self,
|
||||
mut content: &'a Content,
|
||||
@ -310,6 +318,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn styled(
|
||||
&mut self,
|
||||
elem: &'a Content,
|
||||
@ -324,6 +333,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self, local, outer))]
|
||||
fn interrupt_style(
|
||||
&mut self,
|
||||
local: &Styles,
|
||||
@ -358,6 +368,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
fn interrupt_list(&mut self) -> SourceResult<()> {
|
||||
if !self.list.items.is_empty() {
|
||||
let staged = mem::take(&mut self.list.staged);
|
||||
@ -371,6 +382,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
fn interrupt_par(&mut self) -> SourceResult<()> {
|
||||
self.interrupt_list()?;
|
||||
if !self.par.0.is_empty() {
|
||||
@ -382,6 +394,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn interrupt_page(&mut self, styles: Option<StyleChain<'a>>) -> SourceResult<()> {
|
||||
self.interrupt_par()?;
|
||||
let Some(doc) = &mut self.doc else { return Ok(()) };
|
||||
|
@ -60,6 +60,7 @@ pub struct PadElem {
|
||||
}
|
||||
|
||||
impl Layout for PadElem {
|
||||
#[tracing::instrument(name = "PadElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -272,7 +272,10 @@ pub struct PageElem {
|
||||
|
||||
impl PageElem {
|
||||
/// Layout the page run into a sequence of frames, one per page.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn layout(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Fragment> {
|
||||
tracing::info!("Page layout");
|
||||
|
||||
// When one of the lengths is infinite the page fits its content along
|
||||
// that axis.
|
||||
let width = self.width(styles).unwrap_or(Abs::inf());
|
||||
@ -330,12 +333,20 @@ impl PageElem {
|
||||
);
|
||||
|
||||
// Realize overlays.
|
||||
for frame in &mut fragment {
|
||||
for (i, frame) in fragment.iter_mut().enumerate() {
|
||||
tracing::info!("Layouting page #{i}");
|
||||
frame.prepend(Point::zero(), numbering_meta.clone());
|
||||
let size = frame.size();
|
||||
let pad = padding.resolve(styles).relative_to(size);
|
||||
let pw = size.x - pad.left - pad.right;
|
||||
for marginal in [&header, &footer, &background, &foreground] {
|
||||
for (name, marginal) in [
|
||||
("header", &header),
|
||||
("footer", &footer),
|
||||
("background", &background),
|
||||
("foreground", &foreground),
|
||||
] {
|
||||
tracing::info!("Layouting {name}");
|
||||
|
||||
let Some(content) = marginal else { continue };
|
||||
|
||||
let (pos, area, align);
|
||||
|
@ -126,6 +126,7 @@ impl Construct for ParElem {
|
||||
|
||||
impl ParElem {
|
||||
/// Layout the paragraph into a collection of lines.
|
||||
#[tracing::instrument(name = "ParElement::layout", skip_all)]
|
||||
pub fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -54,6 +54,7 @@ pub struct PlaceElem {
|
||||
}
|
||||
|
||||
impl Layout for PlaceElem {
|
||||
#[tracing::instrument(name = "PlaceElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -34,6 +34,7 @@ pub struct RepeatElem {
|
||||
}
|
||||
|
||||
impl Layout for RepeatElem {
|
||||
#[tracing::instrument(name = "RepeatElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -38,6 +38,7 @@ pub struct StackElem {
|
||||
}
|
||||
|
||||
impl Layout for StackElem {
|
||||
#[tracing::instrument(name = "StackElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -161,6 +162,7 @@ impl<'a> StackLayouter<'a> {
|
||||
}
|
||||
|
||||
/// Add spacing along the spacing direction.
|
||||
#[tracing::instrument(name = "StackLayouter::layout_spacing", skip_all)]
|
||||
fn layout_spacing(&mut self, spacing: Spacing) {
|
||||
match spacing {
|
||||
Spacing::Rel(v) => {
|
||||
@ -184,6 +186,7 @@ impl<'a> StackLayouter<'a> {
|
||||
}
|
||||
|
||||
/// Layout an arbitrary block.
|
||||
#[tracing::instrument(name = "StackLayouter::layout_block", skip_all)]
|
||||
fn layout_block(
|
||||
&mut self,
|
||||
vt: &mut Vt,
|
||||
|
@ -122,6 +122,7 @@ pub struct TableElem {
|
||||
}
|
||||
|
||||
impl Layout for TableElem {
|
||||
#[tracing::instrument(name = "TableElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -92,6 +92,7 @@ pub struct TermsElem {
|
||||
}
|
||||
|
||||
impl Layout for TermsElem {
|
||||
#[tracing::instrument(name = "TermsElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -37,6 +37,7 @@ pub struct MoveElem {
|
||||
}
|
||||
|
||||
impl Layout for MoveElem {
|
||||
#[tracing::instrument(name = "MoveElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -105,6 +106,7 @@ pub struct RotateElem {
|
||||
}
|
||||
|
||||
impl Layout for RotateElem {
|
||||
#[tracing::instrument(name = "RotateElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -173,6 +175,7 @@ pub struct ScaleElem {
|
||||
}
|
||||
|
||||
impl Layout for ScaleElem {
|
||||
#[tracing::instrument(name = "ScaleElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -29,6 +29,7 @@ pub fn build() -> Library {
|
||||
}
|
||||
|
||||
/// Construct the module with global definitions.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn global(math: Module, calc: Module) -> Module {
|
||||
let mut global = Scope::deduplicating();
|
||||
|
||||
|
@ -52,6 +52,7 @@ pub struct AccentElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for AccentElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
ctx.style(ctx.style.with_cramped(true));
|
||||
let base = ctx.layout_fragment(&self.base())?;
|
||||
|
@ -8,6 +8,7 @@ use super::*;
|
||||
pub struct AlignPointElem {}
|
||||
|
||||
impl LayoutMath for AlignPointElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
ctx.push(MathFragment::Align);
|
||||
Ok(())
|
||||
|
@ -27,6 +27,7 @@ pub struct AttachElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for AttachElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let base = self.base();
|
||||
let display_limits = base.is::<LimitsElem>();
|
||||
@ -83,6 +84,7 @@ pub struct ScriptsElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for ScriptsElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
self.body().layout_math(ctx)
|
||||
}
|
||||
@ -105,6 +107,7 @@ pub struct LimitsElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for LimitsElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
self.body().layout_math(ctx)
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ pub struct LrElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for LrElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let mut body = self.body();
|
||||
if let Some(elem) = body.to::<LrElem>() {
|
||||
|
@ -30,6 +30,7 @@ pub struct FracElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for FracElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(ctx, &self.num(), &self.denom(), false, self.span())
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ pub struct VecElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for VecElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let delim = self.delim(ctx.styles());
|
||||
let frame = layout_vec_body(ctx, &self.children(), Align::Center)?;
|
||||
@ -115,6 +116,7 @@ pub struct MatElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for MatElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let delim = self.delim(ctx.styles());
|
||||
let frame = layout_mat_body(ctx, &self.rows())?;
|
||||
@ -161,6 +163,7 @@ pub struct CasesElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for CasesElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let delim = self.delim(ctx.styles());
|
||||
let frame = layout_vec_body(ctx, &self.children(), Align::Left)?;
|
||||
|
@ -173,6 +173,7 @@ impl Synthesize for EquationElem {
|
||||
}
|
||||
|
||||
impl Show for EquationElem {
|
||||
#[tracing::instrument(name = "EquationElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
let mut realized = self.clone().pack().guarded(Guard::Base(Self::func()));
|
||||
if self.block(styles) {
|
||||
@ -193,6 +194,7 @@ impl Finalize for EquationElem {
|
||||
}
|
||||
|
||||
impl Layout for EquationElem {
|
||||
#[tracing::instrument(name = "EquationElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -340,12 +342,14 @@ pub trait LayoutMath {
|
||||
}
|
||||
|
||||
impl LayoutMath for EquationElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
self.body().layout_math(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutMath for Content {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
// Directly layout the body of nested equations instead of handling it
|
||||
// like a normal equation so that things like this work:
|
||||
|
@ -34,6 +34,7 @@ pub struct OpElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for OpElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let fragment =
|
||||
ctx.layout_text(&TextElem::new(self.text()).spanned(self.span()))?;
|
||||
|
@ -39,6 +39,7 @@ pub struct RootElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for RootElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(ctx, self.index(ctx.styles()).as_ref(), &self.radicand(), self.span())
|
||||
}
|
||||
|
@ -199,6 +199,7 @@ pub struct MathStyleElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for MathStyleElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let mut style = ctx.style;
|
||||
if let Some(variant) = self.variant(StyleChain::default()) {
|
||||
|
@ -21,6 +21,7 @@ pub struct UnderlineElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for UnderlineElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(ctx, &self.body(), &None, '\u{305}', LINE_GAP, false, self.span())
|
||||
}
|
||||
@ -43,6 +44,7 @@ pub struct OverlineElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for OverlineElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(ctx, &self.body(), &None, '\u{332}', LINE_GAP, true, self.span())
|
||||
}
|
||||
@ -69,6 +71,7 @@ pub struct UnderbraceElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for UnderbraceElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(
|
||||
ctx,
|
||||
@ -103,6 +106,7 @@ pub struct OverbraceElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for OverbraceElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(
|
||||
ctx,
|
||||
@ -137,6 +141,7 @@ pub struct UnderbracketElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for UnderbracketElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(
|
||||
ctx,
|
||||
@ -171,6 +176,7 @@ pub struct OverbracketElem {
|
||||
}
|
||||
|
||||
impl LayoutMath for OverbracketElem {
|
||||
#[tracing::instrument(skip(ctx))]
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(
|
||||
ctx,
|
||||
|
@ -140,6 +140,7 @@ impl Synthesize for BibliographyElem {
|
||||
}
|
||||
|
||||
impl Show for BibliographyElem {
|
||||
#[tracing::instrument(name = "BibliographyElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
const COLUMN_GUTTER: Em = Em::new(0.65);
|
||||
const INDENT: Em = Em::new(1.5);
|
||||
@ -336,6 +337,7 @@ impl Synthesize for CiteElem {
|
||||
}
|
||||
|
||||
impl Show for CiteElem {
|
||||
#[tracing::instrument(name = "CiteElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
|
@ -72,6 +72,7 @@ struct LocateElem {
|
||||
}
|
||||
|
||||
impl Show for LocateElem {
|
||||
#[tracing::instrument(name = "LocateElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
@ -127,6 +128,7 @@ struct StyleElem {
|
||||
}
|
||||
|
||||
impl Show for StyleElem {
|
||||
#[tracing::instrument(name = "StyleElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.func().call_vt(vt, [styles.to_map().into()])?.display())
|
||||
}
|
||||
@ -204,6 +206,7 @@ struct LayoutElem {
|
||||
}
|
||||
|
||||
impl Layout for LayoutElem {
|
||||
#[tracing::instrument(name = "LayoutElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -302,6 +302,7 @@ impl Counter {
|
||||
}
|
||||
|
||||
/// Call a method on counter.
|
||||
#[tracing::instrument(skip(vm))]
|
||||
pub fn call_method(
|
||||
self,
|
||||
vm: &mut Vm,
|
||||
@ -618,6 +619,7 @@ struct DisplayElem {
|
||||
}
|
||||
|
||||
impl Show for DisplayElem {
|
||||
#[tracing::instrument(name = "DisplayElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
@ -669,6 +671,7 @@ struct UpdateElem {
|
||||
}
|
||||
|
||||
impl Show for UpdateElem {
|
||||
#[tracing::instrument(name = "UpdateElem::show", skip(self))]
|
||||
fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(Content::empty())
|
||||
}
|
||||
|
@ -43,7 +43,10 @@ impl Construct for DocumentElem {
|
||||
|
||||
impl LayoutRoot for DocumentElem {
|
||||
/// Layout the document into a sequence of frames, one per page.
|
||||
#[tracing::instrument(name = "DocumentElem::layout_root", skip_all)]
|
||||
fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> {
|
||||
tracing::info!("Document layout");
|
||||
|
||||
let mut pages = vec![];
|
||||
|
||||
for mut child in &self.children() {
|
||||
|
@ -237,6 +237,7 @@ impl Synthesize for FigureElem {
|
||||
}
|
||||
|
||||
impl Show for FigureElem {
|
||||
#[tracing::instrument(name = "FigureElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
// We build the body of the figure.
|
||||
let mut realized = self.body();
|
||||
|
@ -108,6 +108,7 @@ impl Synthesize for HeadingElem {
|
||||
}
|
||||
|
||||
impl Show for HeadingElem {
|
||||
#[tracing::instrument(name = "HeadingElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
let mut realized = self.body();
|
||||
if let Some(numbering) = self.numbering(styles) {
|
||||
|
@ -88,6 +88,7 @@ impl LinkElem {
|
||||
}
|
||||
|
||||
impl Show for LinkElem {
|
||||
#[tracing::instrument(name = "LinkElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
let body = self.body();
|
||||
let dest = match self.dest() {
|
||||
|
@ -131,6 +131,7 @@ pub struct OutlineElem {
|
||||
}
|
||||
|
||||
impl Show for OutlineElem {
|
||||
#[tracing::instrument(name = "OutlineElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
let mut seq = vec![ParbreakElem::new().pack()];
|
||||
// Build the outline title.
|
||||
|
@ -146,6 +146,7 @@ impl Synthesize for RefElem {
|
||||
}
|
||||
|
||||
impl Show for RefElem {
|
||||
#[tracing::instrument(name = "RefElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
|
@ -256,6 +256,7 @@ pub struct State {
|
||||
|
||||
impl State {
|
||||
/// Call a method on a state.
|
||||
#[tracing::instrument(skip(vm))]
|
||||
pub fn call_method(
|
||||
self,
|
||||
vm: &mut Vm,
|
||||
@ -280,6 +281,7 @@ impl State {
|
||||
}
|
||||
|
||||
/// Get the value of the state at the given location.
|
||||
#[tracing::instrument(skip(self, vt))]
|
||||
pub fn at(self, vt: &mut Vt, location: Location) -> SourceResult<Value> {
|
||||
let sequence = self.sequence(vt)?;
|
||||
let offset = vt
|
||||
@ -290,6 +292,7 @@ impl State {
|
||||
}
|
||||
|
||||
/// Get the value of the state at the final location.
|
||||
#[tracing::instrument(skip(self, vt))]
|
||||
pub fn final_(self, vt: &mut Vt, _: Location) -> SourceResult<Value> {
|
||||
let sequence = self.sequence(vt)?;
|
||||
Ok(sequence.last().unwrap().clone())
|
||||
@ -395,6 +398,7 @@ struct DisplayElem {
|
||||
}
|
||||
|
||||
impl Show for DisplayElem {
|
||||
#[tracing::instrument(name = "DisplayElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
@ -425,6 +429,7 @@ struct UpdateElem {
|
||||
}
|
||||
|
||||
impl Show for UpdateElem {
|
||||
#[tracing::instrument(name = "UpdateElem::show")]
|
||||
fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(Content::empty())
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ pub struct UnderlineElem {
|
||||
}
|
||||
|
||||
impl Show for UnderlineElem {
|
||||
#[tracing::instrument(name = "UnderlineElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.body().styled(TextElem::set_deco(Decoration {
|
||||
line: DecoLine::Underline,
|
||||
@ -145,6 +146,7 @@ pub struct OverlineElem {
|
||||
}
|
||||
|
||||
impl Show for OverlineElem {
|
||||
#[tracing::instrument(name = "OverlineElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.body().styled(TextElem::set_deco(Decoration {
|
||||
line: DecoLine::Overline,
|
||||
@ -209,6 +211,7 @@ pub struct StrikeElem {
|
||||
}
|
||||
|
||||
impl Show for StrikeElem {
|
||||
#[tracing::instrument(name = "StrikeElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.body().styled(TextElem::set_deco(Decoration {
|
||||
line: DecoLine::Strikethrough,
|
||||
|
@ -105,6 +105,7 @@ pub struct StrongElem {
|
||||
}
|
||||
|
||||
impl Show for StrongElem {
|
||||
#[tracing::instrument(name = "StrongElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.body().styled(TextElem::set_delta(Delta(self.delta(styles)))))
|
||||
}
|
||||
@ -165,6 +166,7 @@ pub struct EmphElem {
|
||||
}
|
||||
|
||||
impl Show for EmphElem {
|
||||
#[tracing::instrument(name = "EmphElem::show", skip(self))]
|
||||
fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
Ok(self.body().styled(TextElem::set_emph(Toggle)))
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ impl Synthesize for RawElem {
|
||||
}
|
||||
|
||||
impl Show for RawElem {
|
||||
#[tracing::instrument(name = "RawElem::show", skip_all)]
|
||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
let text = self.text();
|
||||
let lang = self.lang(styles).as_ref().map(|s| s.to_lowercase());
|
||||
|
@ -45,6 +45,7 @@ pub struct SubElem {
|
||||
}
|
||||
|
||||
impl Show for SubElem {
|
||||
#[tracing::instrument(name = "SubElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
let body = self.body();
|
||||
let mut transformed = None;
|
||||
@ -107,6 +108,7 @@ pub struct SuperElem {
|
||||
}
|
||||
|
||||
impl Show for SuperElem {
|
||||
#[tracing::instrument(name = "SuperElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
let body = self.body();
|
||||
let mut transformed = None;
|
||||
|
@ -52,6 +52,7 @@ pub struct ImageElem {
|
||||
}
|
||||
|
||||
impl Layout for ImageElem {
|
||||
#[tracing::instrument(name = "ImageElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
|
@ -73,6 +73,7 @@ pub struct LineElem {
|
||||
}
|
||||
|
||||
impl Layout for LineElem {
|
||||
#[tracing::instrument(name = "LineElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
_: &mut Vt,
|
||||
|
@ -60,6 +60,7 @@ pub struct PathElem {
|
||||
}
|
||||
|
||||
impl Layout for PathElem {
|
||||
#[tracing::instrument(name = "PathElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
_: &mut Vt,
|
||||
|
@ -49,6 +49,7 @@ pub struct PolygonElem {
|
||||
}
|
||||
|
||||
impl Layout for PolygonElem {
|
||||
#[tracing::instrument(name = "PolygonElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
_: &mut Vt,
|
||||
|
@ -154,6 +154,7 @@ pub struct RectElem {
|
||||
}
|
||||
|
||||
impl Layout for RectElem {
|
||||
#[tracing::instrument(name = "RectElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -264,6 +265,7 @@ pub struct SquareElem {
|
||||
}
|
||||
|
||||
impl Layout for SquareElem {
|
||||
#[tracing::instrument(name = "SquareElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -346,6 +348,7 @@ pub struct EllipseElem {
|
||||
}
|
||||
|
||||
impl Layout for EllipseElem {
|
||||
#[tracing::instrument(name = "EllipseElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -453,6 +456,7 @@ pub struct CircleElem {
|
||||
}
|
||||
|
||||
impl Layout for CircleElem {
|
||||
#[tracing::instrument(name = "CircleElem::layout", skip_all)]
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -477,6 +481,7 @@ impl Layout for CircleElem {
|
||||
}
|
||||
|
||||
/// Layout a shape.
|
||||
#[tracing::instrument(name = "shape::layout", skip_all)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn layout(
|
||||
vt: &mut Vt,
|
||||
|
@ -75,6 +75,12 @@ impl Func {
|
||||
|
||||
/// Call the function with the given arguments.
|
||||
pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> {
|
||||
let _span = tracing::info_span!(
|
||||
"call",
|
||||
name = self.name().unwrap_or("<anon>"),
|
||||
file = 0,
|
||||
);
|
||||
|
||||
match &self.repr {
|
||||
Repr::Native(native) => {
|
||||
let value = (native.func)(vm, &mut args)?;
|
||||
@ -111,6 +117,7 @@ impl Func {
|
||||
}
|
||||
|
||||
/// Call the function with a Vt.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn call_vt(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -281,6 +288,7 @@ pub enum Param {
|
||||
impl Closure {
|
||||
/// Call the function in the context with the arguments.
|
||||
#[comemo::memoize]
|
||||
#[tracing::instrument(skip_all)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn call(
|
||||
this: &Func,
|
||||
@ -399,6 +407,7 @@ impl<'a> CapturesVisitor<'a> {
|
||||
}
|
||||
|
||||
/// Visit any node and collect all captured variables.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn visit(&mut self, node: &SyntaxNode) {
|
||||
match node.cast() {
|
||||
// Every identifier is a potential variable that we need to capture.
|
||||
|
@ -64,6 +64,7 @@ const MAX_CALL_DEPTH: usize = 64;
|
||||
|
||||
/// Evaluate a source file and return the resulting module.
|
||||
#[comemo::memoize]
|
||||
#[tracing::instrument(skip(world, route, tracer, source))]
|
||||
pub fn eval(
|
||||
world: Tracked<dyn World>,
|
||||
route: Tracked<Route>,
|
||||
@ -203,6 +204,7 @@ impl<'a> Vm<'a> {
|
||||
}
|
||||
|
||||
/// Define a variable in the current scope.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn define(&mut self, var: ast::Ident, value: impl Into<Value>) {
|
||||
let value = value.into();
|
||||
if self.traced == Some(var.span()) {
|
||||
@ -213,6 +215,7 @@ impl<'a> Vm<'a> {
|
||||
|
||||
/// Resolve a user-entered path to be relative to the compilation
|
||||
/// environment's root.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn locate(&self, path: &str) -> StrResult<PathBuf> {
|
||||
if !self.location.is_detached() {
|
||||
if let Some(path) = path.strip_prefix('/') {
|
||||
@ -402,6 +405,7 @@ fn eval_markup(
|
||||
impl Eval for ast::Expr {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Expr::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let span = self.span();
|
||||
let forbidden = |name| {
|
||||
@ -482,6 +486,7 @@ impl ast::Expr {
|
||||
impl Eval for ast::Text {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Text::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.text)(self.get().clone()))
|
||||
}
|
||||
@ -490,6 +495,7 @@ impl Eval for ast::Text {
|
||||
impl Eval for ast::Space {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Space::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.space)())
|
||||
}
|
||||
@ -498,6 +504,7 @@ impl Eval for ast::Space {
|
||||
impl Eval for ast::Linebreak {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Linebreak::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.linebreak)())
|
||||
}
|
||||
@ -506,6 +513,7 @@ impl Eval for ast::Linebreak {
|
||||
impl Eval for ast::Parbreak {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Parbreak::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.parbreak)())
|
||||
}
|
||||
@ -514,6 +522,7 @@ impl Eval for ast::Parbreak {
|
||||
impl Eval for ast::Escape {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Escape::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Symbol(Symbol::new(self.get())))
|
||||
}
|
||||
@ -522,6 +531,7 @@ impl Eval for ast::Escape {
|
||||
impl Eval for ast::Shorthand {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Shorthand::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Symbol(Symbol::new(self.get())))
|
||||
}
|
||||
@ -530,6 +540,7 @@ impl Eval for ast::Shorthand {
|
||||
impl Eval for ast::SmartQuote {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "SmartQuote::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.smart_quote)(self.double()))
|
||||
}
|
||||
@ -538,6 +549,7 @@ impl Eval for ast::SmartQuote {
|
||||
impl Eval for ast::Strong {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Strong::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.strong)(self.body().eval(vm)?))
|
||||
}
|
||||
@ -546,6 +558,7 @@ impl Eval for ast::Strong {
|
||||
impl Eval for ast::Emph {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Emph::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.emph)(self.body().eval(vm)?))
|
||||
}
|
||||
@ -554,6 +567,7 @@ impl Eval for ast::Emph {
|
||||
impl Eval for ast::Raw {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Raw::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let text = self.text();
|
||||
let lang = self.lang().map(Into::into);
|
||||
@ -565,6 +579,7 @@ impl Eval for ast::Raw {
|
||||
impl Eval for ast::Link {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Link::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.link)(self.get().clone()))
|
||||
}
|
||||
@ -573,6 +588,7 @@ impl Eval for ast::Link {
|
||||
impl Eval for ast::Label {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Label::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Label(Label(self.get().into())))
|
||||
}
|
||||
@ -581,6 +597,7 @@ impl Eval for ast::Label {
|
||||
impl Eval for ast::Ref {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Ref::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let label = Label(self.target().into());
|
||||
let supplement = self.supplement().map(|block| block.eval(vm)).transpose()?;
|
||||
@ -591,6 +608,7 @@ impl Eval for ast::Ref {
|
||||
impl Eval for ast::Heading {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Heading::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let level = self.level();
|
||||
let body = self.body().eval(vm)?;
|
||||
@ -601,6 +619,7 @@ impl Eval for ast::Heading {
|
||||
impl Eval for ast::ListItem {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "ListItem::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.list_item)(self.body().eval(vm)?))
|
||||
}
|
||||
@ -609,6 +628,7 @@ impl Eval for ast::ListItem {
|
||||
impl Eval for ast::EnumItem {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "EnumItem::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let number = self.number();
|
||||
let body = self.body().eval(vm)?;
|
||||
@ -619,6 +639,7 @@ impl Eval for ast::EnumItem {
|
||||
impl Eval for ast::TermItem {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "TermItem::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let term = self.term().eval(vm)?;
|
||||
let description = self.description().eval(vm)?;
|
||||
@ -629,6 +650,7 @@ impl Eval for ast::TermItem {
|
||||
impl Eval for ast::Equation {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Equation::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let body = self.body().eval(vm)?;
|
||||
let block = self.block();
|
||||
@ -639,6 +661,7 @@ impl Eval for ast::Equation {
|
||||
impl Eval for ast::Math {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "Math::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Content::sequence(
|
||||
self.exprs()
|
||||
@ -651,6 +674,7 @@ impl Eval for ast::Math {
|
||||
impl Eval for ast::MathIdent {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "MathIdent::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
vm.scopes.get_in_math(self).cloned().at(self.span())
|
||||
}
|
||||
@ -659,6 +683,7 @@ impl Eval for ast::MathIdent {
|
||||
impl Eval for ast::MathAlignPoint {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "MathAlignPoint::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.math_align_point)())
|
||||
}
|
||||
@ -667,6 +692,7 @@ impl Eval for ast::MathAlignPoint {
|
||||
impl Eval for ast::MathDelimited {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "MathDelimited::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let open = self.open().eval_display(vm)?;
|
||||
let body = self.body().eval(vm)?;
|
||||
@ -678,6 +704,7 @@ impl Eval for ast::MathDelimited {
|
||||
impl Eval for ast::MathAttach {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "MathAttach::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let base = self.base().eval_display(vm)?;
|
||||
let bottom = self.bottom().map(|expr| expr.eval_display(vm)).transpose()?;
|
||||
@ -689,6 +716,7 @@ impl Eval for ast::MathAttach {
|
||||
impl Eval for ast::MathFrac {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "MathFrac::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let num = self.num().eval_display(vm)?;
|
||||
let denom = self.denom().eval_display(vm)?;
|
||||
@ -699,6 +727,7 @@ impl Eval for ast::MathFrac {
|
||||
impl Eval for ast::Ident {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Ident::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
vm.scopes.get(self).cloned().at(self.span())
|
||||
}
|
||||
@ -707,6 +736,7 @@ impl Eval for ast::Ident {
|
||||
impl Eval for ast::None {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "None::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::None)
|
||||
}
|
||||
@ -715,6 +745,7 @@ impl Eval for ast::None {
|
||||
impl Eval for ast::Auto {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Auto::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Auto)
|
||||
}
|
||||
@ -723,6 +754,7 @@ impl Eval for ast::Auto {
|
||||
impl Eval for ast::Bool {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Bool::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Bool(self.get()))
|
||||
}
|
||||
@ -731,6 +763,7 @@ impl Eval for ast::Bool {
|
||||
impl Eval for ast::Int {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Int::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Int(self.get()))
|
||||
}
|
||||
@ -739,6 +772,7 @@ impl Eval for ast::Int {
|
||||
impl Eval for ast::Float {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Float::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Float(self.get()))
|
||||
}
|
||||
@ -747,6 +781,7 @@ impl Eval for ast::Float {
|
||||
impl Eval for ast::Numeric {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Numeric::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::numeric(self.get()))
|
||||
}
|
||||
@ -755,6 +790,7 @@ impl Eval for ast::Numeric {
|
||||
impl Eval for ast::Str {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Str::eval", skip_all)]
|
||||
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok(Value::Str(self.get().into()))
|
||||
}
|
||||
@ -763,6 +799,7 @@ impl Eval for ast::Str {
|
||||
impl Eval for ast::CodeBlock {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "CodeBlock::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
vm.scopes.enter();
|
||||
let output = self.body().eval(vm)?;
|
||||
@ -828,6 +865,7 @@ fn eval_code(
|
||||
impl Eval for ast::ContentBlock {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "ContentBlock::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
vm.scopes.enter();
|
||||
let content = self.body().eval(vm)?;
|
||||
@ -839,6 +877,7 @@ impl Eval for ast::ContentBlock {
|
||||
impl Eval for ast::Parenthesized {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Parenthesized::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
self.expr().eval(vm)
|
||||
}
|
||||
@ -847,6 +886,7 @@ impl Eval for ast::Parenthesized {
|
||||
impl Eval for ast::Array {
|
||||
type Output = Array;
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let items = self.items();
|
||||
|
||||
@ -869,6 +909,7 @@ impl Eval for ast::Array {
|
||||
impl Eval for ast::Dict {
|
||||
type Output = Dict;
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let mut map = indexmap::IndexMap::new();
|
||||
|
||||
@ -899,6 +940,7 @@ impl Eval for ast::Dict {
|
||||
impl Eval for ast::Unary {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Unary::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let value = self.expr().eval(vm)?;
|
||||
let result = match self.op() {
|
||||
@ -913,6 +955,7 @@ impl Eval for ast::Unary {
|
||||
impl Eval for ast::Binary {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Binary::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
match self.op() {
|
||||
ast::BinOp::Add => self.apply(vm, ops::add),
|
||||
@ -987,6 +1030,7 @@ impl ast::Binary {
|
||||
impl Eval for ast::FieldAccess {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "FieldAccess::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let value = self.target().eval(vm)?;
|
||||
let field = self.field();
|
||||
@ -997,6 +1041,7 @@ impl Eval for ast::FieldAccess {
|
||||
impl Eval for ast::FuncCall {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "FuncCall::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let span = self.span();
|
||||
if vm.depth >= MAX_CALL_DEPTH {
|
||||
@ -1074,7 +1119,10 @@ impl Eval for ast::FuncCall {
|
||||
|
||||
let callee = callee.cast::<Func>().at(callee_span)?;
|
||||
let point = || Tracepoint::Call(callee.name().map(Into::into));
|
||||
callee.call_vm(vm, args).trace(vm.world(), point, span)
|
||||
|
||||
stacker::maybe_grow(32 * 1024, 2 * 1024 * 1024, || {
|
||||
callee.call_vm(vm, args).trace(vm.world(), point, span)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1138,6 +1186,7 @@ impl Eval for ast::Args {
|
||||
impl Eval for ast::Closure {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Closure::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
// The closure's name is defined by its let binding if there's one.
|
||||
let name = self.name();
|
||||
@ -1179,6 +1228,7 @@ impl Eval for ast::Closure {
|
||||
|
||||
impl ast::Pattern {
|
||||
// Destruct the given value into the pattern.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn define(&self, vm: &mut Vm, value: Value) -> SourceResult<Value> {
|
||||
match self {
|
||||
ast::Pattern::Ident(ident) => {
|
||||
@ -1274,6 +1324,7 @@ impl ast::Pattern {
|
||||
impl Eval for ast::LetBinding {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "LetBinding::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let value = match self.init() {
|
||||
Some(expr) => expr.eval(vm)?,
|
||||
@ -1339,6 +1390,7 @@ impl Eval for ast::ShowRule {
|
||||
impl Eval for ast::Conditional {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "Conditional::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let condition = self.condition();
|
||||
if condition.eval(vm)?.cast::<bool>().at(condition.span())? {
|
||||
@ -1354,6 +1406,7 @@ impl Eval for ast::Conditional {
|
||||
impl Eval for ast::WhileLoop {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "WhileLoop::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let flow = vm.flow.take();
|
||||
let mut output = Value::None;
|
||||
@ -1421,6 +1474,7 @@ fn can_diverge(expr: &SyntaxNode) -> bool {
|
||||
impl Eval for ast::ForLoop {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "ForLoop::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let flow = vm.flow.take();
|
||||
let mut output = Value::None;
|
||||
@ -1487,6 +1541,7 @@ impl Eval for ast::ForLoop {
|
||||
impl Eval for ast::ModuleImport {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "ModuleImport::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let span = self.source().span();
|
||||
let source = self.source().eval(vm)?;
|
||||
@ -1523,6 +1578,7 @@ impl Eval for ast::ModuleImport {
|
||||
impl Eval for ast::ModuleInclude {
|
||||
type Output = Content;
|
||||
|
||||
#[tracing::instrument(name = "ModuleInclude::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let span = self.source().span();
|
||||
let source = self.source().eval(vm)?;
|
||||
@ -1559,6 +1615,7 @@ fn import(vm: &mut Vm, source: Value, span: Span) -> SourceResult<Module> {
|
||||
impl Eval for ast::LoopBreak {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "LoopBreak::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
if vm.flow.is_none() {
|
||||
vm.flow = Some(Flow::Break(self.span()));
|
||||
@ -1570,6 +1627,7 @@ impl Eval for ast::LoopBreak {
|
||||
impl Eval for ast::LoopContinue {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "LoopContinue::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
if vm.flow.is_none() {
|
||||
vm.flow = Some(Flow::Continue(self.span()));
|
||||
@ -1581,6 +1639,7 @@ impl Eval for ast::LoopContinue {
|
||||
impl Eval for ast::FuncReturn {
|
||||
type Output = Value;
|
||||
|
||||
#[tracing::instrument(name = "FuncReturn::eval", skip_all)]
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let value = self.body().map(|body| body.eval(vm)).transpose()?;
|
||||
if vm.flow.is_none() {
|
||||
|
@ -310,6 +310,7 @@ where
|
||||
T::TYPE_NAME
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn hash128(&self) -> u128 {
|
||||
// Also hash the TypeId since values with different types but
|
||||
// equal data should be different.
|
||||
|
@ -9,6 +9,7 @@ use super::{deflate, EmExt, PdfContext, RefExt};
|
||||
use crate::util::SliceExt;
|
||||
|
||||
/// Embed all used fonts into the PDF.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn write_fonts(ctx: &mut PdfContext) {
|
||||
for font in ctx.font_map.items() {
|
||||
let type0_ref = ctx.alloc.bump();
|
||||
|
@ -7,6 +7,7 @@ use super::{deflate, PdfContext, RefExt};
|
||||
use crate::image::{DecodedImage, RasterFormat};
|
||||
|
||||
/// Embed all used images into the PDF.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn write_images(ctx: &mut PdfContext) {
|
||||
for image in ctx.image_map.items() {
|
||||
let image_ref = ctx.alloc.bump();
|
||||
@ -67,6 +68,7 @@ pub fn write_images(ctx: &mut PdfContext) {
|
||||
/// whether the image has color.
|
||||
///
|
||||
/// Skips the alpha channel as that's encoded separately.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn encode_image(
|
||||
format: RasterFormat,
|
||||
dynamic: &DynamicImage,
|
||||
@ -111,6 +113,7 @@ fn encode_image(
|
||||
}
|
||||
|
||||
/// Encode an image's alpha channel if present.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn encode_alpha(dynamic: &DynamicImage) -> (Vec<u8>, Filter) {
|
||||
let pixels: Vec<_> = dynamic.pixels().map(|(_, _, Rgba([_, _, _, a]))| a).collect();
|
||||
(deflate(&pixels), Filter::FlateDecode)
|
||||
|
@ -23,6 +23,7 @@ use crate::model::Introspector;
|
||||
/// Export a document into a PDF file.
|
||||
///
|
||||
/// Returns the raw bytes making up the PDF file.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn pdf(document: &Document) -> Vec<u8> {
|
||||
let mut ctx = PdfContext::new(document);
|
||||
page::construct_pages(&mut ctx, &document.pages);
|
||||
@ -79,6 +80,7 @@ impl<'a> PdfContext<'a> {
|
||||
}
|
||||
|
||||
/// Write the document catalog.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn write_catalog(ctx: &mut PdfContext) {
|
||||
let lang = ctx
|
||||
.languages
|
||||
@ -140,6 +142,7 @@ fn write_catalog(ctx: &mut PdfContext) {
|
||||
}
|
||||
|
||||
/// Compress data with the DEFLATE algorithm.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn deflate(data: &[u8]) -> Vec<u8> {
|
||||
const COMPRESSION_LEVEL: u8 = 6;
|
||||
miniz_oxide::deflate::compress_to_vec_zlib(data, COMPRESSION_LEVEL)
|
||||
|
@ -8,6 +8,7 @@ use crate::model::Content;
|
||||
use crate::util::NonZeroExt;
|
||||
|
||||
/// Construct the outline for the document.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn write_outline(ctx: &mut PdfContext) -> Option<Ref> {
|
||||
let mut tree: Vec<HeadingNode> = vec![];
|
||||
for heading in ctx.introspector.query(&item!(heading_func).select()) {
|
||||
@ -81,6 +82,7 @@ impl HeadingNode {
|
||||
}
|
||||
|
||||
/// Write an outline item and all its children.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn write_outline_item(
|
||||
ctx: &mut PdfContext,
|
||||
node: &HeadingNode,
|
||||
|
@ -15,6 +15,7 @@ use crate::geom::{
|
||||
use crate::image::Image;
|
||||
|
||||
/// Construct page objects.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn construct_pages(ctx: &mut PdfContext, frames: &[Frame]) {
|
||||
for frame in frames {
|
||||
construct_page(ctx, frame);
|
||||
@ -22,6 +23,7 @@ pub fn construct_pages(ctx: &mut PdfContext, frames: &[Frame]) {
|
||||
}
|
||||
|
||||
/// Construct a page object.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn construct_page(ctx: &mut PdfContext, frame: &Frame) {
|
||||
let page_ref = ctx.alloc.bump();
|
||||
ctx.page_refs.push(page_ref);
|
||||
@ -64,6 +66,7 @@ pub fn construct_page(ctx: &mut PdfContext, frame: &Frame) {
|
||||
}
|
||||
|
||||
/// Write the page tree.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn write_page_tree(ctx: &mut PdfContext) {
|
||||
for page in std::mem::take(&mut ctx.pages).into_iter() {
|
||||
write_page(ctx, page);
|
||||
@ -100,6 +103,7 @@ pub fn write_page_tree(ctx: &mut PdfContext) {
|
||||
}
|
||||
|
||||
/// Write a page tree node.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn write_page(ctx: &mut PdfContext, page: Page) {
|
||||
let content_id = ctx.alloc.bump();
|
||||
|
||||
|
@ -64,6 +64,7 @@ use crate::syntax::{Source, SourceId};
|
||||
use crate::util::Buffer;
|
||||
|
||||
/// Compile a source file into a fully layouted document.
|
||||
#[tracing::instrument(skip(world))]
|
||||
pub fn compile(world: &(dyn World + 'static)) -> SourceResult<Document> {
|
||||
// Evaluate the source file into a module.
|
||||
let route = Route::default();
|
||||
@ -71,6 +72,8 @@ pub fn compile(world: &(dyn World + 'static)) -> SourceResult<Document> {
|
||||
let module =
|
||||
eval::eval(world.track(), route.track(), tracer.track_mut(), world.main())?;
|
||||
|
||||
tracing::info!("Evaluation successful");
|
||||
|
||||
// Typeset the module's contents.
|
||||
model::typeset(world.track(), tracer.track_mut(), &module.content())
|
||||
}
|
||||
|
@ -39,16 +39,19 @@ enum Attr {
|
||||
|
||||
impl Content {
|
||||
/// Create an empty element.
|
||||
#[tracing::instrument()]
|
||||
pub fn new(func: ElemFunc) -> Self {
|
||||
Self { func, attrs: EcoVec::new() }
|
||||
}
|
||||
|
||||
/// Create empty content.
|
||||
#[tracing::instrument()]
|
||||
pub fn empty() -> Self {
|
||||
Self::new(SequenceElem::func())
|
||||
}
|
||||
|
||||
/// Create a new sequence element from multiples elements.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn sequence(iter: impl IntoIterator<Item = Self>) -> Self {
|
||||
let mut iter = iter.into_iter();
|
||||
let Some(first) = iter.next() else { return Self::empty() };
|
||||
@ -91,6 +94,7 @@ impl Content {
|
||||
}
|
||||
|
||||
/// Access the child and styles.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn to_styled(&self) -> Option<(&Content, &Styles)> {
|
||||
if !self.is::<StyledElem>() {
|
||||
return None;
|
||||
@ -116,6 +120,7 @@ impl Content {
|
||||
|
||||
/// Cast to a trait object if the contained element has the given
|
||||
/// capability.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn with<C>(&self) -> Option<&C>
|
||||
where
|
||||
C: ?Sized + 'static,
|
||||
@ -127,6 +132,7 @@ impl Content {
|
||||
|
||||
/// Cast to a mutable trait object if the contained element has the given
|
||||
/// capability.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn with_mut<C>(&mut self) -> Option<&mut C>
|
||||
where
|
||||
C: ?Sized + 'static,
|
||||
@ -174,6 +180,7 @@ impl Content {
|
||||
}
|
||||
|
||||
/// Access a field on the content.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn field(&self, name: &str) -> Option<Value> {
|
||||
if let (Some(iter), "children") = (self.to_sequence(), name) {
|
||||
Some(Value::Array(iter.cloned().map(Value::Content).collect()))
|
||||
@ -360,6 +367,7 @@ impl Content {
|
||||
/// Queries the content tree for all elements that match the given selector.
|
||||
///
|
||||
/// Elements produced in `show` rules will not be included in the results.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn query(&self, selector: Selector) -> Vec<&Content> {
|
||||
let mut results = Vec::new();
|
||||
self.traverse(&mut |element| {
|
||||
|
@ -94,6 +94,7 @@ pub struct Introspector {
|
||||
|
||||
impl Introspector {
|
||||
/// Create a new introspector.
|
||||
#[tracing::instrument(skip(frames))]
|
||||
pub fn new(frames: &[Frame]) -> Self {
|
||||
let mut introspector = Self {
|
||||
pages: frames.len(),
|
||||
@ -113,6 +114,7 @@ impl Introspector {
|
||||
}
|
||||
|
||||
/// Extract metadata from a frame.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn extract(&mut self, frame: &Frame, page: NonZeroUsize, ts: Transform) {
|
||||
for (pos, item) in frame.items() {
|
||||
match item {
|
||||
@ -154,6 +156,7 @@ impl Introspector {
|
||||
}
|
||||
|
||||
/// Query for all matching elements.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn query<'a>(&'a self, selector: &'a Selector) -> Vec<Content> {
|
||||
match selector {
|
||||
Selector::Location(location) => self
|
||||
@ -168,6 +171,7 @@ impl Introspector {
|
||||
}
|
||||
|
||||
/// Query for the first matching element.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn query_first<'a>(&'a self, selector: &'a Selector) -> Option<Content> {
|
||||
match selector {
|
||||
Selector::Location(location) => {
|
||||
@ -178,6 +182,7 @@ impl Introspector {
|
||||
}
|
||||
|
||||
/// Query for a unique element with the label.
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn query_label(&self, label: &Label) -> StrResult<Content> {
|
||||
let mut found = None;
|
||||
for elem in self.all().filter(|elem| elem.label() == Some(label)) {
|
||||
@ -200,12 +205,14 @@ impl Introspector {
|
||||
}
|
||||
|
||||
/// Gets the page numbering for the given location, if any.
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn page_numbering(&self, location: Location) -> Value {
|
||||
let page = self.page(location);
|
||||
self.page_numberings.get(page.get() - 1).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Find the position for the given location.
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn position(&self, location: Location) -> Position {
|
||||
self.elems
|
||||
.get(&location)
|
||||
|
@ -23,11 +23,13 @@ use crate::World;
|
||||
|
||||
/// Typeset content into a fully layouted document.
|
||||
#[comemo::memoize]
|
||||
#[tracing::instrument(skip(world, tracer, content))]
|
||||
pub fn typeset(
|
||||
world: Tracked<dyn World>,
|
||||
mut tracer: TrackedMut<Tracer>,
|
||||
content: &Content,
|
||||
) -> SourceResult<Document> {
|
||||
tracing::info!("Starting layout");
|
||||
let library = world.library();
|
||||
let styles = StyleChain::new(&library.styles);
|
||||
|
||||
@ -38,6 +40,8 @@ pub fn typeset(
|
||||
// Relayout until all introspections stabilize.
|
||||
// If that doesn't happen within five attempts, we give up.
|
||||
loop {
|
||||
tracing::info!("Layout iteration {iter}");
|
||||
|
||||
let constraint = Constraint::new();
|
||||
let mut provider = StabilityProvider::new();
|
||||
let mut vt = Vt {
|
||||
|
@ -360,7 +360,7 @@ impl Selector {
|
||||
Self::Before { selector, end: location, inclusive } => {
|
||||
if let Some(content) = introspector.query_first(location) {
|
||||
let loc = content.location().unwrap();
|
||||
Box::new(selector.match_iter_inner(introspector, parent).filter(
|
||||
Box::new(selector.match_iter_inner(introspector, parent).take_while(
|
||||
move |elem| {
|
||||
introspector.is_before(
|
||||
elem.location().unwrap(),
|
||||
@ -376,12 +376,12 @@ impl Selector {
|
||||
Self::After { selector, start: location, inclusive } => {
|
||||
if let Some(content) = introspector.query_first(location) {
|
||||
let loc = content.location().unwrap();
|
||||
Box::new(selector.match_iter_inner(introspector, parent).filter(
|
||||
Box::new(selector.match_iter_inner(introspector, parent).skip_while(
|
||||
move |elem| {
|
||||
introspector.is_after(
|
||||
introspector.is_before(
|
||||
elem.location().unwrap(),
|
||||
loc,
|
||||
*inclusive,
|
||||
!*inclusive,
|
||||
)
|
||||
},
|
||||
))
|
||||
@ -586,6 +586,7 @@ impl<'a> StyleChain<'a> {
|
||||
/// The resulting style chain contains styles from `local` as well as
|
||||
/// `self`. The ones from `local` take precedence over the ones from
|
||||
/// `self`. For folded properties `local` contributes the inner value.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn chain<'b>(&'b self, local: &'b Styles) -> StyleChain<'b> {
|
||||
if local.is_empty() {
|
||||
*self
|
||||
@ -595,6 +596,7 @@ impl<'a> StyleChain<'a> {
|
||||
}
|
||||
|
||||
/// Cast the first value for the given property in the chain.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn get<T: Cast>(
|
||||
self,
|
||||
func: ElemFunc,
|
||||
@ -608,6 +610,7 @@ impl<'a> StyleChain<'a> {
|
||||
}
|
||||
|
||||
/// Cast the first value for the given property in the chain.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn get_resolve<T: Cast + Resolve>(
|
||||
self,
|
||||
func: ElemFunc,
|
||||
@ -619,6 +622,7 @@ impl<'a> StyleChain<'a> {
|
||||
}
|
||||
|
||||
/// Cast the first value for the given property in the chain.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn get_fold<T: Cast + Fold>(
|
||||
self,
|
||||
func: ElemFunc,
|
||||
@ -640,6 +644,7 @@ impl<'a> StyleChain<'a> {
|
||||
}
|
||||
|
||||
/// Cast the first value for the given property in the chain.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn get_resolve_fold<T>(
|
||||
self,
|
||||
func: ElemFunc,
|
||||
@ -674,6 +679,7 @@ impl<'a> StyleChain<'a> {
|
||||
}
|
||||
|
||||
/// Iterate over all values for the given property in the chain.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn properties<T: Cast + 'a>(
|
||||
self,
|
||||
func: ElemFunc,
|
||||
|
@ -190,6 +190,7 @@ impl SyntaxNode {
|
||||
}
|
||||
|
||||
/// Assign spans to each node.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(super) fn numberize(
|
||||
&mut self,
|
||||
id: SourceId,
|
||||
|
@ -28,6 +28,7 @@ pub struct Source {
|
||||
|
||||
impl Source {
|
||||
/// Create a new source file.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn new(id: SourceId, path: &Path, text: String) -> Self {
|
||||
let mut root = parse(&text);
|
||||
root.numberize(id, Span::FULL).unwrap();
|
||||
|
@ -34,6 +34,7 @@ where
|
||||
}
|
||||
|
||||
/// Calculate a 128-bit siphash of a value.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn hash128<T: Hash + ?Sized>(value: &T) -> u128 {
|
||||
let mut state = SipHasher13::new();
|
||||
value.hash(&mut state);
|
||||
@ -128,6 +129,7 @@ pub trait PathExt {
|
||||
}
|
||||
|
||||
impl PathExt for Path {
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn normalize(&self) -> PathBuf {
|
||||
let mut out = PathBuf::new();
|
||||
for component in self.components() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user