Compare commits

..

1 Commits

281 changed files with 1610 additions and 1789 deletions

View File

@ -40,7 +40,7 @@ jobs:
sudo dpkg --add-architecture i386 sudo dpkg --add-architecture i386
sudo apt update sudo apt update
sudo apt install -y gcc-multilib libssl-dev:i386 pkg-config:i386 sudo apt install -y gcc-multilib libssl-dev:i386 pkg-config:i386
- uses: dtolnay/rust-toolchain@1.88.0 - uses: dtolnay/rust-toolchain@1.87.0
with: with:
targets: ${{ matrix.bits == 32 && 'i686-unknown-linux-gnu' || '' }} targets: ${{ matrix.bits == 32 && 'i686-unknown-linux-gnu' || '' }}
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -73,7 +73,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.88.0 - uses: dtolnay/rust-toolchain@1.87.0
with: with:
components: clippy, rustfmt components: clippy, rustfmt
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -88,7 +88,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.88.0 - uses: dtolnay/rust-toolchain@1.83.0
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: cargo check --workspace - run: cargo check --workspace
@ -99,7 +99,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master - uses: dtolnay/rust-toolchain@master
with: with:
toolchain: nightly-2025-05-10 toolchain: nightly-2024-10-29
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: cargo install --locked cargo-fuzz@0.12.0 - run: cargo install --locked cargo-fuzz@0.12.0
- run: cd tests/fuzz && cargo fuzz build --dev - run: cd tests/fuzz && cargo fuzz build --dev
@ -112,6 +112,6 @@ jobs:
- uses: dtolnay/rust-toolchain@master - uses: dtolnay/rust-toolchain@master
with: with:
components: miri components: miri
toolchain: nightly-2025-05-10 toolchain: nightly-2024-10-29
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: cargo miri test -p typst-library test_miri - run: cargo miri test -p typst-library test_miri

View File

@ -44,7 +44,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.88.0 - uses: dtolnay/rust-toolchain@1.87.0
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}

129
Cargo.lock generated
View File

@ -181,9 +181,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.1" version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -214,9 +214,9 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.23.1" version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
dependencies = [ dependencies = [
"bytemuck_derive", "bytemuck_derive",
] ]
@ -970,69 +970,6 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "hayro"
version = "0.1.0"
source = "git+https://github.com/LaurenzV/hayro?rev=e701f95#e701f9569157a2fe4ade68930dc9e9283782dcca"
dependencies = [
"bytemuck",
"hayro-interpret",
"image",
"kurbo",
"rustc-hash",
"smallvec",
]
[[package]]
name = "hayro-font"
version = "0.1.0"
source = "git+https://github.com/LaurenzV/hayro?rev=e701f95#e701f9569157a2fe4ade68930dc9e9283782dcca"
dependencies = [
"log",
"phf",
]
[[package]]
name = "hayro-interpret"
version = "0.1.0"
source = "git+https://github.com/LaurenzV/hayro?rev=e701f95#e701f9569157a2fe4ade68930dc9e9283782dcca"
dependencies = [
"bitflags 2.9.1",
"hayro-font",
"hayro-syntax",
"kurbo",
"log",
"phf",
"qcms",
"skrifa",
"smallvec",
"yoke 0.8.0",
]
[[package]]
name = "hayro-syntax"
version = "0.0.1"
source = "git+https://github.com/LaurenzV/hayro?rev=e701f95#e701f9569157a2fe4ade68930dc9e9283782dcca"
dependencies = [
"flate2",
"kurbo",
"log",
"rustc-hash",
"smallvec",
"zune-jpeg",
]
[[package]]
name = "hayro-write"
version = "0.1.0"
source = "git+https://github.com/LaurenzV/hayro?rev=e701f95#e701f9569157a2fe4ade68930dc9e9283782dcca"
dependencies = [
"flate2",
"hayro-syntax",
"log",
"pdf-writer",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@ -1268,10 +1205,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "image" name = "if_chain"
version = "0.25.6" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
[[package]]
name = "image"
version = "0.25.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"byteorder-lite", "byteorder-lite",
@ -1334,7 +1277,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"inotify-sys", "inotify-sys",
"libc", "libc",
] ]
@ -1430,7 +1373,7 @@ dependencies = [
[[package]] [[package]]
name = "krilla" name = "krilla"
version = "0.4.0" version = "0.4.0"
source = "git+https://github.com/LaurenzV/krilla?branch=main#37b9a00bfac87ed0b347b7cf8e9d37a6f68fcccd" source = "git+https://github.com/LaurenzV/krilla?branch=main#32d070e737cd8ae4c3aa4ff901d15cb22bd052f3"
dependencies = [ dependencies = [
"base64", "base64",
"bumpalo", "bumpalo",
@ -1439,7 +1382,6 @@ dependencies = [
"float-cmp 0.10.0", "float-cmp 0.10.0",
"fxhash", "fxhash",
"gif", "gif",
"hayro-write",
"image-webp", "image-webp",
"imagesize", "imagesize",
"once_cell", "once_cell",
@ -1460,7 +1402,7 @@ dependencies = [
[[package]] [[package]]
name = "krilla-svg" name = "krilla-svg"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/LaurenzV/krilla?branch=main#37b9a00bfac87ed0b347b7cf8e9d37a6f68fcccd" source = "git+https://github.com/LaurenzV/krilla?branch=main#32d070e737cd8ae4c3aa4ff901d15cb22bd052f3"
dependencies = [ dependencies = [
"flate2", "flate2",
"fontdb", "fontdb",
@ -1473,9 +1415,9 @@ dependencies = [
[[package]] [[package]]
name = "kurbo" name = "kurbo"
version = "0.11.2" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c" checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"smallvec", "smallvec",
@ -1527,7 +1469,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"libc", "libc",
"redox_syscall", "redox_syscall",
] ]
@ -1693,7 +1635,7 @@ version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"filetime", "filetime",
"fsevent-sys", "fsevent-sys",
"inotify", "inotify",
@ -1775,7 +1717,7 @@ version = "0.10.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"cfg-if", "cfg-if",
"foreign-types", "foreign-types",
"libc", "libc",
@ -1912,7 +1854,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ea27c5015ab81753fc61e49f8cde74999346605ee148bb20008ef3d3150e0dc" checksum = "3ea27c5015ab81753fc61e49f8cde74999346605ee148bb20008ef3d3150e0dc"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"itoa", "itoa",
"memchr", "memchr",
"ryu", "ryu",
@ -2080,7 +2022,7 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"getopts", "getopts",
"memchr", "memchr",
"unicase", "unicase",
@ -2193,7 +2135,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
] ]
[[package]] [[package]]
@ -2296,7 +2238,7 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@ -2315,7 +2257,7 @@ version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"bytemuck", "bytemuck",
"core_maths", "core_maths",
"log", "log",
@ -2363,7 +2305,7 @@ version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"core-foundation", "core-foundation",
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -2936,7 +2878,7 @@ dependencies = [
[[package]] [[package]]
name = "typst-assets" name = "typst-assets"
version = "0.13.1" version = "0.13.1"
source = "git+https://github.com/typst/typst-assets?rev=fbf00f9#fbf00f9539fdb0825bef4d39fb57d5986c51b756" source = "git+https://github.com/typst/typst-assets?rev=edf0d64#edf0d648376e29738a05a933af9ea99bb81557b1"
[[package]] [[package]]
name = "typst-cli" name = "typst-cli"
@ -2986,7 +2928,7 @@ dependencies = [
[[package]] [[package]]
name = "typst-dev-assets" name = "typst-dev-assets"
version = "0.13.1" version = "0.13.1"
source = "git+https://github.com/typst/typst-dev-assets?rev=c6c2acf#c6c2acf6cdc31f99a23a478d3d614f8bf806a4f5" source = "git+https://github.com/typst/typst-dev-assets?rev=bfa947f#bfa947f3433d7d13a995168c40ae788a2ebfe648"
[[package]] [[package]]
name = "typst-docs" name = "typst-docs"
@ -3018,6 +2960,7 @@ version = "0.13.1"
dependencies = [ dependencies = [
"comemo", "comemo",
"ecow", "ecow",
"if_chain",
"indexmap 2.7.1", "indexmap 2.7.1",
"stacker", "stacker",
"toml", "toml",
@ -3065,6 +3008,7 @@ version = "0.13.1"
dependencies = [ dependencies = [
"comemo", "comemo",
"ecow", "ecow",
"if_chain",
"once_cell", "once_cell",
"pathdiff", "pathdiff",
"serde", "serde",
@ -3136,7 +3080,7 @@ name = "typst-library"
version = "0.13.1" version = "0.13.1"
dependencies = [ dependencies = [
"az", "az",
"bitflags 2.9.1", "bitflags 2.8.0",
"bumpalo", "bumpalo",
"chinese-number", "chinese-number",
"ciborium", "ciborium",
@ -3148,7 +3092,6 @@ dependencies = [
"fontdb", "fontdb",
"glidesort", "glidesort",
"hayagriva", "hayagriva",
"hayro-syntax",
"icu_properties", "icu_properties",
"icu_provider", "icu_provider",
"icu_provider_blob", "icu_provider_blob",
@ -3250,13 +3193,11 @@ version = "0.13.1"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"comemo", "comemo",
"hayro",
"image", "image",
"pixglyph", "pixglyph",
"resvg", "resvg",
"tiny-skia", "tiny-skia",
"ttf-parser", "ttf-parser",
"typst-assets",
"typst-library", "typst-library",
"typst-macros", "typst-macros",
"typst-timing", "typst-timing",
@ -3270,10 +3211,8 @@ dependencies = [
"comemo", "comemo",
"ecow", "ecow",
"flate2", "flate2",
"hayro",
"image", "image",
"ttf-parser", "ttf-parser",
"typst-assets",
"typst-library", "typst-library",
"typst-macros", "typst-macros",
"typst-timing", "typst-timing",
@ -3670,7 +3609,7 @@ version = "0.221.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
"indexmap 2.7.1", "indexmap 2.7.1",
] ]
@ -3805,7 +3744,7 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.8.0",
] ]
[[package]] [[package]]

View File

@ -5,9 +5,9 @@ resolver = "2"
[workspace.package] [workspace.package]
version = "0.13.1" version = "0.13.1"
rust-version = "1.88" # also change in ci.yml rust-version = "1.83" # also change in ci.yml
authors = ["The Typst Project Developers"] authors = ["The Typst Project Developers"]
edition = "2024" edition = "2021"
homepage = "https://typst.app" homepage = "https://typst.app"
repository = "https://github.com/typst/typst" repository = "https://github.com/typst/typst"
license = "Apache-2.0" license = "Apache-2.0"
@ -32,8 +32,8 @@ typst-svg = { path = "crates/typst-svg", version = "0.13.1" }
typst-syntax = { path = "crates/typst-syntax", version = "0.13.1" } typst-syntax = { path = "crates/typst-syntax", version = "0.13.1" }
typst-timing = { path = "crates/typst-timing", version = "0.13.1" } typst-timing = { path = "crates/typst-timing", version = "0.13.1" }
typst-utils = { path = "crates/typst-utils", version = "0.13.1" } typst-utils = { path = "crates/typst-utils", version = "0.13.1" }
typst-assets = { git = "https://github.com/typst/typst-assets", rev = "fbf00f9" } typst-assets = { git = "https://github.com/typst/typst-assets", rev = "edf0d64" }
typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "c6c2acf" } typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "bfa947f" }
arrayvec = "0.7.4" arrayvec = "0.7.4"
az = "1.2" az = "1.2"
base64 = "0.22" base64 = "0.22"
@ -61,8 +61,6 @@ fontdb = { version = "0.23", default-features = false }
fs_extra = "1.3" fs_extra = "1.3"
glidesort = "0.1.2" glidesort = "0.1.2"
hayagriva = "0.8.1" hayagriva = "0.8.1"
hayro-syntax = { git = "https://github.com/LaurenzV/hayro", rev = "e701f95" }
hayro = { git = "https://github.com/LaurenzV/hayro", rev = "e701f95" }
heck = "0.5" heck = "0.5"
hypher = "0.1.4" hypher = "0.1.4"
icu_properties = { version = "1.4", features = ["serde"] } icu_properties = { version = "1.4", features = ["serde"] }
@ -70,11 +68,12 @@ icu_provider = { version = "1.4", features = ["sync"] }
icu_provider_adapters = "1.4" icu_provider_adapters = "1.4"
icu_provider_blob = "1.4" icu_provider_blob = "1.4"
icu_segmenter = { version = "1.4", features = ["serde"] } icu_segmenter = { version = "1.4", features = ["serde"] }
if_chain = "1"
image = { version = "0.25.5", default-features = false, features = ["png", "jpeg", "gif", "webp"] } image = { version = "0.25.5", default-features = false, features = ["png", "jpeg", "gif", "webp"] }
indexmap = { version = "2", features = ["serde"] } indexmap = { version = "2", features = ["serde"] }
infer = { version = "0.19.0", default-features = false } infer = { version = "0.19.0", default-features = false }
kamadak-exif = "0.6" kamadak-exif = "0.6"
krilla = { git = "https://github.com/LaurenzV/krilla", branch = "main", default-features = false, features = ["raster-images", "comemo", "rayon", "pdf"] } krilla = { git = "https://github.com/LaurenzV/krilla", branch = "main", default-features = false, features = ["raster-images", "comemo", "rayon"] }
krilla-svg = { git = "https://github.com/LaurenzV/krilla", branch = "main" } krilla-svg = { git = "https://github.com/LaurenzV/krilla", branch = "main" }
kurbo = "0.11" kurbo = "0.11"
libfuzzer-sys = "0.4" libfuzzer-sys = "0.4"

View File

@ -1,10 +1,10 @@
use std::env; use std::env;
use std::fs::{File, create_dir_all}; use std::fs::{create_dir_all, File};
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use clap::{CommandFactory, ValueEnum}; use clap::{CommandFactory, ValueEnum};
use clap_complete::{Shell, generate_to}; use clap_complete::{generate_to, Shell};
use clap_mangen::Man; use clap_mangen::Man;
#[path = "src/args.rs"] #[path = "src/args.rs"]

View File

@ -10,13 +10,13 @@ use ecow::eco_format;
use parking_lot::RwLock; use parking_lot::RwLock;
use pathdiff::diff_paths; use pathdiff::diff_paths;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use typst::WorldExt;
use typst::diag::{ use typst::diag::{
At, Severity, SourceDiagnostic, SourceResult, StrResult, Warned, bail, bail, At, Severity, SourceDiagnostic, SourceResult, StrResult, Warned,
}; };
use typst::foundations::{Datetime, Smart}; use typst::foundations::{Datetime, Smart};
use typst::layout::{Frame, Page, PageRanges, PagedDocument}; use typst::layout::{Frame, Page, PageRanges, PagedDocument};
use typst::syntax::{FileId, Lines, Span}; use typst::syntax::{FileId, Lines, Span};
use typst::WorldExt;
use typst_html::HtmlDocument; use typst_html::HtmlDocument;
use typst_pdf::{PdfOptions, PdfStandards, Timestamp}; use typst_pdf::{PdfOptions, PdfStandards, Timestamp};
@ -517,9 +517,7 @@ fn write_make_deps(
}) })
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
else { else {
bail!( bail!("failed to create make dependencies file because output path was not valid unicode")
"failed to create make dependencies file because output path was not valid unicode"
)
}; };
if output_paths.is_empty() { if output_paths.is_empty() {
bail!("failed to create make dependencies file because output was stdout") bail!("failed to create make dependencies file because output was stdout")

View File

@ -8,8 +8,8 @@ use codespan_reporting::term::termcolor::WriteColor;
use typst::utils::format_duration; use typst::utils::format_duration;
use typst_kit::download::{DownloadState, Downloader, Progress}; use typst_kit::download::{DownloadState, Downloader, Progress};
use crate::ARGS;
use crate::terminal::{self, TermOut}; use crate::terminal::{self, TermOut};
use crate::ARGS;
/// Prints download progress by writing `downloading {0}` followed by repeatedly /// Prints download progress by writing `downloading {0}` followed by repeatedly
/// updating the last terminal line. /// updating the last terminal line.

View File

@ -4,7 +4,7 @@ use std::path::Path;
use codespan_reporting::term::termcolor::{Color, ColorSpec, WriteColor}; use codespan_reporting::term::termcolor::{Color, ColorSpec, WriteColor};
use ecow::eco_format; use ecow::eco_format;
use fs_extra::dir::CopyOptions; use fs_extra::dir::CopyOptions;
use typst::diag::{FileError, StrResult, bail}; use typst::diag::{bail, FileError, StrResult};
use typst::syntax::package::{ use typst::syntax::package::{
PackageManifest, PackageSpec, TemplateInfo, VersionlessPackageSpec, PackageManifest, PackageSpec, TemplateInfo, VersionlessPackageSpec,
}; };

View File

@ -21,8 +21,8 @@ use std::io::{self, Write};
use std::process::ExitCode; use std::process::ExitCode;
use std::sync::LazyLock; use std::sync::LazyLock;
use clap::Parser;
use clap::error::ErrorKind; use clap::error::ErrorKind;
use clap::Parser;
use codespan_reporting::term; use codespan_reporting::term;
use codespan_reporting::term::termcolor::WriteColor; use codespan_reporting::term::termcolor::WriteColor;
use typst::diag::HintedStrResult; use typst::diag::HintedStrResult;
@ -102,7 +102,7 @@ fn print_error(msg: &str) -> io::Result<()> {
#[cfg(not(feature = "self-update"))] #[cfg(not(feature = "self-update"))]
mod update { mod update {
use typst::diag::{StrResult, bail}; use typst::diag::{bail, StrResult};
use crate::args::UpdateCommand; use crate::args::UpdateCommand;

View File

@ -1,12 +1,12 @@
use comemo::Track; use comemo::Track;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use serde::Serialize; use serde::Serialize;
use typst::World; use typst::diag::{bail, HintedStrResult, StrResult, Warned};
use typst::diag::{HintedStrResult, StrResult, Warned, bail};
use typst::engine::Sink; use typst::engine::Sink;
use typst::foundations::{Content, IntoValue, LocatableSelector, Scope}; use typst::foundations::{Content, IntoValue, LocatableSelector, Scope};
use typst::layout::PagedDocument; use typst::layout::PagedDocument;
use typst::syntax::{Span, SyntaxMode}; use typst::syntax::{Span, SyntaxMode};
use typst::World;
use typst_eval::eval_string; use typst_eval::eval_string;
use crate::args::{QueryCommand, SerializationFormat}; use crate::args::{QueryCommand, SerializationFormat};

View File

@ -5,7 +5,7 @@ use std::sync::Arc;
use ecow::eco_format; use ecow::eco_format;
use parking_lot::{Condvar, Mutex, MutexGuard}; use parking_lot::{Condvar, Mutex, MutexGuard};
use tiny_http::{Header, Request, Response, StatusCode}; use tiny_http::{Header, Request, Response, StatusCode};
use typst::diag::{StrResult, bail}; use typst::diag::{bail, StrResult};
use crate::args::{Input, ServerArgs}; use crate::args::{Input, ServerArgs};
@ -162,7 +162,7 @@ impl<T> Bucket<T> {
} }
/// Retrieves the current data in the bucket. /// Retrieves the current data in the bucket.
fn get(&self) -> MutexGuard<'_, T> { fn get(&self) -> MutexGuard<T> {
self.mutex.lock() self.mutex.lock()
} }

View File

@ -2,9 +2,9 @@ use std::fs::File;
use std::io::BufWriter; use std::io::BufWriter;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use typst::World; use typst::diag::{bail, StrResult};
use typst::diag::{StrResult, bail};
use typst::syntax::Span; use typst::syntax::Span;
use typst::World;
use crate::args::{CliArguments, Command}; use crate::args::{CliArguments, Command};
use crate::world::SystemWorld; use crate::world::SystemWorld;

View File

@ -6,7 +6,7 @@ use ecow::eco_format;
use semver::Version; use semver::Version;
use serde::Deserialize; use serde::Deserialize;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use typst::diag::{StrResult, bail}; use typst::diag::{bail, StrResult};
use typst_kit::download::Downloader; use typst_kit::download::Downloader;
use xz2::bufread::XzDecoder; use xz2::bufread::XzDecoder;
use zip::ZipArchive; use zip::ZipArchive;

View File

@ -10,12 +10,12 @@ use codespan_reporting::term::{self, termcolor};
use ecow::eco_format; use ecow::eco_format;
use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher as _}; use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher as _};
use same_file::is_same_file; use same_file::is_same_file;
use typst::diag::{StrResult, bail, warning}; use typst::diag::{bail, warning, StrResult};
use typst::syntax::Span; use typst::syntax::Span;
use typst::utils::format_duration; use typst::utils::format_duration;
use crate::args::{Input, Output, WatchCommand}; use crate::args::{Input, Output, WatchCommand};
use crate::compile::{CompileConfig, compile_once, print_diagnostics}; use crate::compile::{compile_once, print_diagnostics, CompileConfig};
use crate::timings::Timer; use crate::timings::Timer;
use crate::world::{SystemWorld, WorldCreationError}; use crate::world::{SystemWorld, WorldCreationError};
use crate::{print_error, terminal}; use crate::{print_error, terminal};

View File

@ -5,7 +5,7 @@ use std::sync::{LazyLock, OnceLock};
use std::{fmt, fs, io, mem}; use std::{fmt, fs, io, mem};
use chrono::{DateTime, Datelike, FixedOffset, Local, Utc}; use chrono::{DateTime, Datelike, FixedOffset, Local, Utc};
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use parking_lot::Mutex; use parking_lot::Mutex;
use typst::diag::{FileError, FileResult}; use typst::diag::{FileError, FileResult};
use typst::foundations::{Bytes, Datetime, Dict, IntoValue}; use typst::foundations::{Bytes, Datetime, Dict, IntoValue};
@ -361,22 +361,22 @@ impl<T: Clone> SlotCell<T> {
f: impl FnOnce(Vec<u8>, Option<T>) -> FileResult<T>, f: impl FnOnce(Vec<u8>, Option<T>) -> FileResult<T>,
) -> FileResult<T> { ) -> FileResult<T> {
// If we accessed the file already in this compilation, retrieve it. // If we accessed the file already in this compilation, retrieve it.
if mem::replace(&mut self.accessed, true) if mem::replace(&mut self.accessed, true) {
&& let Some(data) = &self.data if let Some(data) = &self.data {
{
return data.clone(); return data.clone();
} }
}
// Read and hash the file. // Read and hash the file.
let result = timed!("loading file", load()); let result = timed!("loading file", load());
let fingerprint = timed!("hashing file", typst::utils::hash128(&result)); let fingerprint = timed!("hashing file", typst::utils::hash128(&result));
// If the file contents didn't change, yield the old processed data. // If the file contents didn't change, yield the old processed data.
if mem::replace(&mut self.fingerprint, fingerprint) == fingerprint if mem::replace(&mut self.fingerprint, fingerprint) == fingerprint {
&& let Some(data) = &self.data if let Some(data) = &self.data {
{
return data.clone(); return data.clone();
} }
}
let prev = self.data.take().and_then(Result::ok); let prev = self.data.take().and_then(Result::ok);
let value = result.and_then(|data| f(data, prev)); let value = result.and_then(|data| f(data, prev));

View File

@ -20,6 +20,7 @@ typst-timing = { workspace = true }
typst-utils = { workspace = true } typst-utils = { workspace = true }
comemo = { workspace = true } comemo = { workspace = true }
ecow = { workspace = true } ecow = { workspace = true }
if_chain = { workspace = true }
indexmap = { workspace = true } indexmap = { workspace = true }
toml = { workspace = true } toml = { workspace = true }
unicode-segmentation = { workspace = true } unicode-segmentation = { workspace = true }

View File

@ -1,9 +1,9 @@
use ecow::eco_format; use ecow::eco_format;
use typst_library::diag::{At, Hint, SourceResult, Trace, Tracepoint, bail}; use typst_library::diag::{bail, At, Hint, SourceResult, Trace, Tracepoint};
use typst_library::foundations::{Dict, Value}; use typst_library::foundations::{Dict, Value};
use typst_syntax::ast::{self, AstNode}; use typst_syntax::ast::{self, AstNode};
use crate::{Eval, Vm, call_method_access, is_accessor_method}; use crate::{call_method_access, is_accessor_method, Eval, Vm};
/// Access an expression mutably. /// Access an expression mutably.
pub(crate) trait Access { pub(crate) trait Access {
@ -29,11 +29,11 @@ impl Access for ast::Expr<'_> {
impl Access for ast::Ident<'_> { impl Access for ast::Ident<'_> {
fn access<'a>(self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> { fn access<'a>(self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> {
let span = self.span(); let span = self.span();
if vm.inspected == Some(span) if vm.inspected == Some(span) {
&& let Ok(binding) = vm.scopes.get(&self) if let Ok(binding) = vm.scopes.get(&self) {
{
vm.trace(binding.read().clone()); vm.trace(binding.read().clone());
} }
}
vm.scopes vm.scopes
.get_mut(&self) .get_mut(&self)
.and_then(|b| b.write().map_err(Into::into)) .and_then(|b| b.write().map_err(Into::into))

View File

@ -1,7 +1,7 @@
use std::collections::HashSet; use std::collections::HashSet;
use ecow::eco_format; use ecow::eco_format;
use typst_library::diag::{At, SourceDiagnostic, SourceResult, bail, error}; use typst_library::diag::{bail, error, At, SourceDiagnostic, SourceResult};
use typst_library::foundations::{Array, Dict, Value}; use typst_library::foundations::{Array, Dict, Value};
use typst_syntax::ast::{self, AstNode}; use typst_syntax::ast::{self, AstNode};

View File

@ -1,9 +1,8 @@
use comemo::{Tracked, TrackedMut}; use comemo::{Tracked, TrackedMut};
use ecow::{EcoString, EcoVec, eco_format}; use ecow::{eco_format, EcoString, EcoVec};
use typst_library::World;
use typst_library::diag::{ use typst_library::diag::{
At, HintedStrResult, HintedString, SourceDiagnostic, SourceResult, Trace, Tracepoint, bail, error, At, HintedStrResult, HintedString, SourceDiagnostic, SourceResult,
bail, error, Trace, Tracepoint,
}; };
use typst_library::engine::{Engine, Sink, Traced}; use typst_library::engine::{Engine, Sink, Traced};
use typst_library::foundations::{ use typst_library::foundations::{
@ -13,11 +12,12 @@ use typst_library::foundations::{
use typst_library::introspection::Introspector; use typst_library::introspection::Introspector;
use typst_library::math::LrElem; use typst_library::math::LrElem;
use typst_library::routines::Routines; use typst_library::routines::Routines;
use typst_library::World;
use typst_syntax::ast::{self, AstNode, Ident}; use typst_syntax::ast::{self, AstNode, Ident};
use typst_syntax::{Span, Spanned, SyntaxNode}; use typst_syntax::{Span, Spanned, SyntaxNode};
use typst_utils::LazyHash; use typst_utils::LazyHash;
use crate::{Access, Eval, FlowEvent, Route, Vm, call_method_mut, is_mutating_method}; use crate::{call_method_mut, is_mutating_method, Access, Eval, FlowEvent, Route, Vm};
impl Eval for ast::FuncCall<'_> { impl Eval for ast::FuncCall<'_> {
type Output = Value; type Output = Value;

View File

@ -1,9 +1,9 @@
use ecow::{EcoVec, eco_vec}; use ecow::{eco_vec, EcoVec};
use typst_library::diag::{At, SourceResult, bail, error, warning}; use typst_library::diag::{bail, error, warning, At, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{ use typst_library::foundations::{
Array, Capturer, Closure, Content, ContextElem, Dict, Func, NativeElement, Selector, ops, Array, Capturer, Closure, Content, ContextElem, Dict, Func, NativeElement,
Str, Value, ops, Selector, Str, Value,
}; };
use typst_library::introspection::{Counter, State}; use typst_library::introspection::{Counter, State};
use typst_syntax::ast::{self, AstNode}; use typst_syntax::ast::{self, AstNode};
@ -324,18 +324,22 @@ impl Eval for ast::FieldAccess<'_> {
}; };
// Check whether this is a get rule field access. // Check whether this is a get rule field access.
if let Value::Func(func) = &value if_chain::if_chain! {
&& let Some(element) = func.element() if let Value::Func(func) = &value;
&& let Some(id) = element.field_id(&field) if let Some(element) = func.element();
&& let styles = vm.context.styles().at(field.span()) if let Some(id) = element.field_id(&field);
&& let Ok(value) = element let styles = vm.context.styles().at(field.span());
.field_from_styles(id, styles.as_ref().map(|&s| s).unwrap_or_default()) if let Ok(value) = element.field_from_styles(
{ id,
styles.as_ref().map(|&s| s).unwrap_or_default(),
);
then {
// Only validate the context once we know that this is indeed // Only validate the context once we know that this is indeed
// a field from the style chain. // a field from the style chain.
let _ = styles?; let _ = styles?;
return Ok(value); return Ok(value);
} }
}
Err(err) Err(err)
} }

View File

@ -1,10 +1,10 @@
use typst_library::diag::{At, SourceDiagnostic, SourceResult, bail, error}; use typst_library::diag::{bail, error, At, SourceDiagnostic, SourceResult};
use typst_library::foundations::{IntoValue, Value, ops}; use typst_library::foundations::{ops, IntoValue, Value};
use typst_syntax::ast::{self, AstNode}; use typst_syntax::ast::{self, AstNode};
use typst_syntax::{Span, SyntaxKind, SyntaxNode}; use typst_syntax::{Span, SyntaxKind, SyntaxNode};
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use crate::{Eval, Vm, destructure}; use crate::{destructure, Eval, Vm};
/// The maximum number of loop iterations. /// The maximum number of loop iterations.
const MAX_ITERATIONS: usize = 10_000; const MAX_ITERATIONS: usize = 10_000;

View File

@ -1,16 +1,16 @@
use comemo::TrackedMut; use comemo::TrackedMut;
use ecow::{EcoString, eco_format, eco_vec}; use ecow::{eco_format, eco_vec, EcoString};
use typst_library::World;
use typst_library::diag::{ use typst_library::diag::{
At, FileError, SourceResult, Trace, Tracepoint, bail, error, warning, bail, error, warning, At, FileError, SourceResult, Trace, Tracepoint,
}; };
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Binding, Content, Module, Value}; use typst_library::foundations::{Binding, Content, Module, Value};
use typst_library::World;
use typst_syntax::ast::{self, AstNode, BareImportError}; use typst_syntax::ast::{self, AstNode, BareImportError};
use typst_syntax::package::{PackageManifest, PackageSpec}; use typst_syntax::package::{PackageManifest, PackageSpec};
use typst_syntax::{FileId, Span, VirtualPath}; use typst_syntax::{FileId, Span, VirtualPath};
use crate::{Eval, Vm, eval}; use crate::{eval, Eval, Vm};
impl Eval for ast::ModuleImport<'_> { impl Eval for ast::ModuleImport<'_> {
type Output = Value; type Output = Value;
@ -46,15 +46,15 @@ impl Eval for ast::ModuleImport<'_> {
// If there is a rename, import the source itself under that name. // If there is a rename, import the source itself under that name.
let new_name = self.new_name(); let new_name = self.new_name();
if let Some(new_name) = new_name { if let Some(new_name) = new_name {
if let ast::Expr::Ident(ident) = self.source() if let ast::Expr::Ident(ident) = self.source() {
&& ident.as_str() == new_name.as_str() if ident.as_str() == new_name.as_str() {
{
// Warn on `import x as x` // Warn on `import x as x`
vm.engine.sink.warn(warning!( vm.engine.sink.warn(warning!(
new_name.span(), new_name.span(),
"unnecessary import rename to same name", "unnecessary import rename to same name",
)); ));
} }
}
// Define renamed module on the scope. // Define renamed module on the scope.
vm.define(new_name, source.clone()); vm.define(new_name, source.clone());
@ -142,8 +142,8 @@ impl Eval for ast::ModuleImport<'_> {
// it. // it.
// Warn on `import ...: x as x` // Warn on `import ...: x as x`
if let ast::ImportItem::Renamed(renamed_item) = &item if let ast::ImportItem::Renamed(renamed_item) = &item {
&& renamed_item.original_name().as_str() if renamed_item.original_name().as_str()
== renamed_item.new_name().as_str() == renamed_item.new_name().as_str()
{ {
vm.engine.sink.warn(warning!( vm.engine.sink.warn(warning!(
@ -151,6 +151,7 @@ impl Eval for ast::ModuleImport<'_> {
"unnecessary import rename to same name", "unnecessary import rename to same name",
)); ));
} }
}
vm.bind(item.bound_name(), binding.clone()); vm.bind(item.bound_name(), binding.clone());
} }

View File

@ -14,7 +14,7 @@ mod methods;
mod rules; mod rules;
mod vm; mod vm;
pub use self::call::{CapturesVisitor, eval_closure}; pub use self::call::{eval_closure, CapturesVisitor};
pub use self::flow::FlowEvent; pub use self::flow::FlowEvent;
pub use self::import::import; pub use self::import::import;
pub use self::vm::Vm; pub use self::vm::Vm;
@ -24,14 +24,14 @@ use self::binding::*;
use self::methods::*; use self::methods::*;
use comemo::{Track, Tracked, TrackedMut}; use comemo::{Track, Tracked, TrackedMut};
use typst_library::World; use typst_library::diag::{bail, SourceResult};
use typst_library::diag::{SourceResult, bail};
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Context, Module, NativeElement, Scope, Scopes, Value}; use typst_library::foundations::{Context, Module, NativeElement, Scope, Scopes, Value};
use typst_library::introspection::Introspector; use typst_library::introspection::Introspector;
use typst_library::math::EquationElem; use typst_library::math::EquationElem;
use typst_library::routines::Routines; use typst_library::routines::Routines;
use typst_syntax::{Source, Span, SyntaxMode, ast, parse, parse_code, parse_math}; use typst_library::World;
use typst_syntax::{ast, parse, parse_code, parse_math, Source, Span, SyntaxMode};
/// Evaluate a source file and return the resulting module. /// Evaluate a source file and return the resulting module.
#[comemo::memoize] #[comemo::memoize]

View File

@ -1,4 +1,4 @@
use typst_library::diag::{At, SourceResult, warning}; use typst_library::diag::{warning, At, SourceResult};
use typst_library::foundations::{ use typst_library::foundations::{
Content, Label, NativeElement, Repr, Smart, Symbol, Unlabellable, Value, Content, Label, NativeElement, Repr, Smart, Symbol, Unlabellable, Value,
}; };

View File

@ -1,8 +1,8 @@
use typst_library::diag::{At, HintedStrResult, SourceResult}; use typst_library::diag::{At, HintedStrResult, SourceResult};
use typst_library::foundations::{IntoValue, Value, ops}; use typst_library::foundations::{ops, IntoValue, Value};
use typst_syntax::ast::{self, AstNode}; use typst_syntax::ast::{self, AstNode};
use crate::{Access, Eval, Vm, access_dict}; use crate::{access_dict, Access, Eval, Vm};
impl Eval for ast::Unary<'_> { impl Eval for ast::Unary<'_> {
type Output = Value; type Output = Value;
@ -76,13 +76,13 @@ fn apply_assignment(
// An assignment to a dictionary field is different from a normal access // An assignment to a dictionary field is different from a normal access
// since it can create the field instead of just modifying it. // since it can create the field instead of just modifying it.
if binary.op() == ast::BinOp::Assign if binary.op() == ast::BinOp::Assign {
&& let ast::Expr::FieldAccess(access) = lhs if let ast::Expr::FieldAccess(access) = lhs {
{
let dict = access_dict(vm, access)?; let dict = access_dict(vm, access)?;
dict.insert(access.field().get().clone().into(), rhs); dict.insert(access.field().get().clone().into(), rhs);
return Ok(Value::None); return Ok(Value::None);
} }
}
let location = binary.lhs().access(vm)?; let location = binary.lhs().access(vm)?;
let lhs = std::mem::take(&mut *location); let lhs = std::mem::take(&mut *location);

View File

@ -1,4 +1,4 @@
use typst_library::diag::{At, SourceResult, warning}; use typst_library::diag::{warning, At, SourceResult};
use typst_library::foundations::{ use typst_library::foundations::{
Element, Func, Recipe, Selector, ShowableSelector, Styles, Transformation, Element, Func, Recipe, Selector, ShowableSelector, Styles, Transformation,
}; };
@ -12,11 +12,11 @@ impl Eval for ast::SetRule<'_> {
type Output = Styles; type Output = Styles;
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
if let Some(condition) = self.condition() if let Some(condition) = self.condition() {
&& !condition.eval(vm)?.cast::<bool>().at(condition.span())? if !condition.eval(vm)?.cast::<bool>().at(condition.span())? {
{
return Ok(Styles::new()); return Ok(Styles::new());
} }
}
let target = self.target(); let target = self.target();
let target = target let target = target
@ -58,11 +58,12 @@ impl Eval for ast::ShowRule<'_> {
/// Migration hint for `show par: set block(spacing: ..)`. /// Migration hint for `show par: set block(spacing: ..)`.
fn check_show_par_set_block(vm: &mut Vm, recipe: &Recipe) { fn check_show_par_set_block(vm: &mut Vm, recipe: &Recipe) {
if let Some(Selector::Elem(elem, _)) = recipe.selector() if_chain::if_chain! {
&& *elem == Element::of::<ParElem>() if let Some(Selector::Elem(elem, _)) = recipe.selector();
&& let Transformation::Style(styles) = recipe.transform() if *elem == Element::of::<ParElem>();
&& (styles.has(BlockElem::above) || styles.has(BlockElem::below)) if let Transformation::Style(styles) = recipe.transform();
{ if styles.has(BlockElem::above) || styles.has(BlockElem::below);
then {
vm.engine.sink.warn(warning!( vm.engine.sink.warn(warning!(
recipe.span(), recipe.span(),
"`show par: set block(spacing: ..)` has no effect anymore"; "`show par: set block(spacing: ..)` has no effect anymore";
@ -71,3 +72,4 @@ fn check_show_par_set_block(vm: &mut Vm, recipe: &Recipe) {
)) ))
} }
} }
}

View File

@ -1,10 +1,10 @@
use comemo::Tracked; use comemo::Tracked;
use typst_library::World;
use typst_library::diag::warning; use typst_library::diag::warning;
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Binding, Context, IntoValue, Scopes, Value}; use typst_library::foundations::{Binding, Context, IntoValue, Scopes, Value};
use typst_syntax::Span; use typst_library::World;
use typst_syntax::ast::{self, AstNode}; use typst_syntax::ast::{self, AstNode};
use typst_syntax::Span;
use crate::FlowEvent; use crate::FlowEvent;

View File

@ -1,4 +1,4 @@
use typst_library::diag::{SourceResult, warning}; use typst_library::diag::{warning, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Content, StyleChain, Target, TargetElem}; use typst_library::foundations::{Content, StyleChain, Target, TargetElem};
use typst_library::introspection::{SplitLocator, TagElem}; use typst_library::introspection::{SplitLocator, TagElem};
@ -8,7 +8,7 @@ use typst_library::routines::Pair;
use typst_library::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem}; use typst_library::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem};
use crate::fragment::html_fragment; use crate::fragment::html_fragment;
use crate::{FrameElem, HtmlElem, HtmlElement, HtmlFrame, HtmlNode, attr, tag}; use crate::{attr, tag, FrameElem, HtmlElem, HtmlElement, HtmlFrame, HtmlNode};
/// Converts realized content into HTML nodes. /// Converts realized content into HTML nodes.
pub fn convert_to_nodes<'a>( pub fn convert_to_nodes<'a>(

View File

@ -2,8 +2,7 @@ use std::collections::HashSet;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use comemo::{Tracked, TrackedMut}; use comemo::{Tracked, TrackedMut};
use typst_library::World; use typst_library::diag::{bail, SourceResult};
use typst_library::diag::{SourceResult, bail};
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Content, StyleChain}; use typst_library::foundations::{Content, StyleChain};
use typst_library::introspection::{ use typst_library::introspection::{
@ -12,10 +11,11 @@ use typst_library::introspection::{
use typst_library::layout::{Point, Position, Transform}; use typst_library::layout::{Point, Position, Transform};
use typst_library::model::DocumentInfo; use typst_library::model::DocumentInfo;
use typst_library::routines::{Arenas, RealizationKind, Routines}; use typst_library::routines::{Arenas, RealizationKind, Routines};
use typst_library::World;
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::NonZeroExt; use typst_utils::NonZeroExt;
use crate::{HtmlDocument, HtmlElement, HtmlNode, attr, tag}; use crate::{attr, tag, HtmlDocument, HtmlElement, HtmlNode};
/// Produce an HTML document from content. /// Produce an HTML document from content.
/// ///

View File

@ -1,8 +1,8 @@
use std::fmt::{self, Debug, Display, Formatter}; use std::fmt::{self, Debug, Display, Formatter};
use ecow::{EcoString, EcoVec}; use ecow::{EcoString, EcoVec};
use typst_library::diag::{HintedStrResult, StrResult, bail}; use typst_library::diag::{bail, HintedStrResult, StrResult};
use typst_library::foundations::{Dict, Repr, Str, StyleChain, cast}; use typst_library::foundations::{cast, Dict, Repr, Str, StyleChain};
use typst_library::introspection::{Introspector, Tag}; use typst_library::introspection::{Introspector, Tag};
use typst_library::layout::{Abs, Frame, Point}; use typst_library::layout::{Abs, Frame, Point};
use typst_library::model::DocumentInfo; use typst_library::model::DocumentInfo;

View File

@ -1,12 +1,12 @@
use std::fmt::Write; use std::fmt::Write;
use typst_library::diag::{At, SourceResult, StrResult, bail}; use typst_library::diag::{bail, At, SourceResult, StrResult};
use typst_library::foundations::Repr; use typst_library::foundations::Repr;
use typst_library::introspection::Introspector; use typst_library::introspection::Introspector;
use typst_syntax::Span; use typst_syntax::Span;
use crate::{ use crate::{
HtmlDocument, HtmlElement, HtmlFrame, HtmlNode, HtmlTag, attr, charsets, tag, attr, charsets, tag, HtmlDocument, HtmlElement, HtmlFrame, HtmlNode, HtmlTag,
}; };
/// Encodes an HTML document into a string. /// Encodes an HTML document into a string.
@ -262,7 +262,11 @@ impl RawMode {
{ {
// Template literals can be multi-line, so indent may change // Template literals can be multi-line, so indent may change
// the semantics of the JavaScript. // the semantics of the JavaScript.
if text.contains('`') { Self::Wrap } else { Self::Indent } if text.contains('`') {
Self::Wrap
} else {
Self::Indent
}
} }
tag::style => Self::Indent, tag::style => Self::Indent,
_ => Self::Keep, _ => Self::Keep,

View File

@ -4,8 +4,8 @@ use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Content, StyleChain}; use typst_library::foundations::{Content, StyleChain};
use typst_library::introspection::{Introspector, Locator, LocatorLink}; use typst_library::introspection::{Introspector, Locator, LocatorLink};
use typst_library::World;
use typst_library::routines::{Arenas, FragmentKind, RealizationKind, Routines}; use typst_library::routines::{Arenas, FragmentKind, RealizationKind, Routines};
use typst_library::World;
use crate::HtmlNode; use crate::HtmlNode;

View File

@ -19,8 +19,8 @@ pub use self::encode::html;
pub use self::rules::register; pub use self::rules::register;
use ecow::EcoString; use ecow::EcoString;
use typst_library::Category;
use typst_library::foundations::{Content, Module, Scope}; use typst_library::foundations::{Content, Module, Scope};
use typst_library::Category;
use typst_macros::elem; use typst_macros::elem;
/// Creates the module with all HTML definitions. /// Creates the module with all HTML definitions.
@ -86,7 +86,11 @@ impl HtmlElem {
attr: HtmlAttr, attr: HtmlAttr,
value: Option<impl Into<EcoString>>, value: Option<impl Into<EcoString>>,
) -> Self { ) -> Self {
if let Some(value) = value { self.with_attr(attr, value) } else { self } if let Some(value) = value {
self.with_attr(attr, value)
} else {
self
}
} }
/// Adds CSS styles to an element. /// Adds CSS styles to an element.

View File

@ -1,14 +1,14 @@
use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::{HashMap, HashSet, VecDeque};
use comemo::Track; use comemo::Track;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use typst_library::foundations::{Label, NativeElement}; use typst_library::foundations::{Label, NativeElement};
use typst_library::introspection::{Introspector, Location, Tag}; use typst_library::introspection::{Introspector, Location, Tag};
use typst_library::layout::{Frame, FrameItem, Point}; use typst_library::layout::{Frame, FrameItem, Point};
use typst_library::model::{Destination, LinkElem}; use typst_library::model::{Destination, LinkElem};
use typst_utils::PicoStr; use typst_utils::PicoStr;
use crate::{HtmlElement, HtmlNode, attr, tag}; use crate::{attr, tag, HtmlElement, HtmlNode};
/// Searches for links within a frame. /// Searches for links within a frame.
/// ///

View File

@ -1,12 +1,12 @@
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use ecow::{EcoVec, eco_format}; use ecow::{eco_format, EcoVec};
use typst_library::diag::{At, warning}; use typst_library::diag::{warning, At};
use typst_library::foundations::{ use typst_library::foundations::{
Content, NativeElement, NativeRuleMap, ShowFn, Smart, StyleChain, Target, Content, NativeElement, NativeRuleMap, ShowFn, Smart, StyleChain, Target,
}; };
use typst_library::introspection::{Counter, Locator}; use typst_library::introspection::{Counter, Locator};
use typst_library::layout::resolve::{Cell, CellGrid, Entry, table_to_cellgrid}; use typst_library::layout::resolve::{table_to_cellgrid, Cell, CellGrid, Entry};
use typst_library::layout::{OuterVAlignment, Sizing}; use typst_library::layout::{OuterVAlignment, Sizing};
use typst_library::model::{ use typst_library::model::{
Attribution, CiteElem, CiteGroup, Destination, EmphElem, EnumElem, FigureCaption, Attribution, CiteElem, CiteGroup, Destination, EmphElem, EnumElem, FigureCaption,
@ -19,7 +19,7 @@ use typst_library::text::{
}; };
use typst_library::visualize::ImageElem; use typst_library::visualize::ImageElem;
use crate::{FrameElem, HtmlAttrs, HtmlElem, HtmlTag, attr, css, tag}; use crate::{attr, css, tag, FrameElem, HtmlAttrs, HtmlElem, HtmlTag};
/// Registers show rules for the [HTML target](Target::Html). /// Registers show rules for the [HTML target](Target::Html).
pub fn register(rules: &mut NativeRuleMap) { pub fn register(rules: &mut NativeRuleMap) {
@ -238,11 +238,13 @@ const QUOTE_RULE: ShowFn<QuoteElem> = |elem, _, styles| {
if block { if block {
let mut blockquote = HtmlElem::new(tag::blockquote).with_body(Some(realized)); let mut blockquote = HtmlElem::new(tag::blockquote).with_body(Some(realized));
if let Some(Attribution::Content(attribution)) = attribution if let Some(Attribution::Content(attribution)) = attribution {
&& let Some(link) = attribution.to_packed::<LinkElem>() if let Some(link) = attribution.to_packed::<LinkElem>() {
&& let LinkTarget::Dest(Destination::Url(url)) = &link.dest if let LinkTarget::Dest(Destination::Url(url)) = &link.dest {
{ blockquote =
blockquote = blockquote.with_attr(attr::cite, url.clone().into_inner()); blockquote.with_attr(attr::cite, url.clone().into_inner());
}
}
} }
realized = blockquote.pack().spanned(span); realized = blockquote.pack().spanned(span);

View File

@ -9,9 +9,9 @@ use std::sync::LazyLock;
use bumpalo::Bump; use bumpalo::Bump;
use comemo::Tracked; use comemo::Tracked;
use ecow::{EcoString, eco_format, eco_vec}; use ecow::{eco_format, eco_vec, EcoString};
use typst_assets::html as data; use typst_assets::html as data;
use typst_library::diag::{At, Hint, HintedStrResult, SourceResult, bail}; use typst_library::diag::{bail, At, Hint, HintedStrResult, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{ use typst_library::foundations::{
Args, Array, AutoValue, CastInfo, Content, Context, Datetime, Dict, Duration, Args, Array, AutoValue, CastInfo, Content, Context, Datetime, Dict, Duration,
@ -22,7 +22,7 @@ use typst_library::layout::{Axes, Axis, Dir, Length};
use typst_library::visualize::Color; use typst_library::visualize::Color;
use typst_macros::cast; use typst_macros::cast;
use crate::{HtmlAttr, HtmlAttrs, HtmlElem, HtmlTag, css, tag}; use crate::{css, tag, HtmlAttr, HtmlAttrs, HtmlElem, HtmlTag};
/// Hook up all typed HTML definitions. /// Hook up all typed HTML definitions.
pub(super) fn define(html: &mut Scope) { pub(super) fn define(html: &mut Scope) {

View File

@ -17,6 +17,7 @@ typst = { workspace = true }
typst-eval = { workspace = true } typst-eval = { workspace = true }
comemo = { workspace = true } comemo = { workspace = true }
ecow = { workspace = true } ecow = { workspace = true }
if_chain = { workspace = true }
pathdiff = { workspace = true } pathdiff = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
unscanny = { workspace = true } unscanny = { workspace = true }

View File

@ -1,11 +1,11 @@
use std::collections::HashSet; use std::collections::HashSet;
use comemo::Track; use comemo::Track;
use ecow::{EcoString, EcoVec, eco_vec}; use ecow::{eco_vec, EcoString, EcoVec};
use typst::foundations::{Label, Styles, Value}; use typst::foundations::{Label, Styles, Value};
use typst::layout::PagedDocument; use typst::layout::PagedDocument;
use typst::model::{BibliographyElem, FigureElem}; use typst::model::{BibliographyElem, FigureElem};
use typst::syntax::{LinkedNode, SyntaxKind, ast}; use typst::syntax::{ast, LinkedNode, SyntaxKind};
use crate::IdeWorld; use crate::IdeWorld;
@ -27,18 +27,17 @@ pub fn analyze_expr(
ast::Expr::Numeric(v) => Value::numeric(v.get()), ast::Expr::Numeric(v) => Value::numeric(v.get()),
ast::Expr::Str(v) => Value::Str(v.get().into()), ast::Expr::Str(v) => Value::Str(v.get().into()),
_ => { _ => {
if node.kind() == SyntaxKind::Contextual if node.kind() == SyntaxKind::Contextual {
&& let Some(child) = node.children().next_back() if let Some(child) = node.children().next_back() {
{
return analyze_expr(world, &child); return analyze_expr(world, &child);
} }
}
if let Some(parent) = node.parent() if let Some(parent) = node.parent() {
&& parent.kind() == SyntaxKind::FieldAccess if parent.kind() == SyntaxKind::FieldAccess && node.index() > 0 {
&& node.index() > 0
{
return analyze_expr(world, parent); return analyze_expr(world, parent);
} }
}
return typst::trace::<PagedDocument>(world.upcast(), node.span()); return typst::trace::<PagedDocument>(world.upcast(), node.span());
} }

View File

@ -2,17 +2,18 @@ use std::cmp::Reverse;
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use std::ffi::OsStr; use std::ffi::OsStr;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use if_chain::if_chain;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use typst::foundations::{ use typst::foundations::{
AutoValue, CastInfo, Func, Label, NoneValue, ParamInfo, Repr, StyleChain, Styles, fields_on, repr, AutoValue, CastInfo, Func, Label, NoneValue, ParamInfo, Repr,
Type, Value, fields_on, repr, StyleChain, Styles, Type, Value,
}; };
use typst::layout::{Alignment, Dir, PagedDocument}; use typst::layout::{Alignment, Dir, PagedDocument};
use typst::syntax::ast::AstNode; use typst::syntax::ast::AstNode;
use typst::syntax::{ use typst::syntax::{
FileId, LinkedNode, Side, Source, SyntaxKind, ast, is_id_continue, is_id_start, ast, is_id_continue, is_id_start, is_ident, FileId, LinkedNode, Side, Source,
is_ident, SyntaxKind,
}; };
use typst::text::{FontFlags, RawElem}; use typst::text::{FontFlags, RawElem};
use typst::visualize::Color; use typst::visualize::Color;
@ -21,7 +22,7 @@ use unscanny::Scanner;
use crate::utils::{ use crate::utils::{
check_value_recursively, globals, plain_docs_sentence, summarize_font_family, check_value_recursively, globals, plain_docs_sentence, summarize_font_family,
}; };
use crate::{IdeWorld, analyze_expr, analyze_import, analyze_labels, named_items}; use crate::{analyze_expr, analyze_import, analyze_labels, named_items, IdeWorld};
/// Autocomplete a cursor position in a source file. /// Autocomplete a cursor position in a source file.
/// ///
@ -144,23 +145,27 @@ fn complete_markup(ctx: &mut CompletionContext) -> bool {
} }
// Behind a half-completed binding: "#let x = |". // Behind a half-completed binding: "#let x = |".
if let Some(prev) = ctx.leaf.prev_leaf() if_chain! {
&& prev.kind() == SyntaxKind::Eq if let Some(prev) = ctx.leaf.prev_leaf();
&& prev.parent_kind() == Some(SyntaxKind::LetBinding) if prev.kind() == SyntaxKind::Eq;
{ if prev.parent_kind() == Some(SyntaxKind::LetBinding);
then {
ctx.from = ctx.cursor; ctx.from = ctx.cursor;
code_completions(ctx, false); code_completions(ctx, false);
return true; return true;
} }
}
// Behind a half-completed context block: "#context |". // Behind a half-completed context block: "#context |".
if let Some(prev) = ctx.leaf.prev_leaf() if_chain! {
&& prev.kind() == SyntaxKind::Context if let Some(prev) = ctx.leaf.prev_leaf();
{ if prev.kind() == SyntaxKind::Context;
then {
ctx.from = ctx.cursor; ctx.from = ctx.cursor;
code_completions(ctx, false); code_completions(ctx, false);
return true; return true;
} }
}
// Directly after a raw block. // Directly after a raw block.
let mut s = Scanner::new(ctx.text); let mut s = Scanner::new(ctx.text);
@ -368,35 +373,38 @@ fn complete_field_accesses(ctx: &mut CompletionContext) -> bool {
); );
// Behind an expression plus dot: "emoji.|". // Behind an expression plus dot: "emoji.|".
if (ctx.leaf.kind() == SyntaxKind::Dot if_chain! {
if ctx.leaf.kind() == SyntaxKind::Dot
|| (matches!(ctx.leaf.kind(), SyntaxKind::Text | SyntaxKind::MathText) || (matches!(ctx.leaf.kind(), SyntaxKind::Text | SyntaxKind::MathText)
&& ctx.leaf.text() == ".")) && ctx.leaf.text() == ".");
&& ctx.leaf.range().end == ctx.cursor if ctx.leaf.range().end == ctx.cursor;
&& let Some(prev) = ctx.leaf.prev_sibling() if let Some(prev) = ctx.leaf.prev_sibling();
&& (!in_markup || prev.range().end == ctx.leaf.range().start) if !in_markup || prev.range().end == ctx.leaf.range().start;
&& prev.is::<ast::Expr>() if prev.is::<ast::Expr>();
&& (prev.parent_kind() != Some(SyntaxKind::Markup) if prev.parent_kind() != Some(SyntaxKind::Markup) ||
|| prev.prev_sibling_kind() == Some(SyntaxKind::Hash)) prev.prev_sibling_kind() == Some(SyntaxKind::Hash);
&& let Some((value, styles)) = analyze_expr(ctx.world, &prev).into_iter().next() if let Some((value, styles)) = analyze_expr(ctx.world, &prev).into_iter().next();
{ then {
ctx.from = ctx.cursor; ctx.from = ctx.cursor;
field_access_completions(ctx, &value, &styles); field_access_completions(ctx, &value, &styles);
return true; return true;
} }
}
// Behind a started field access: "emoji.fa|". // Behind a started field access: "emoji.fa|".
if ctx.leaf.kind() == SyntaxKind::Ident if_chain! {
&& let Some(prev) = ctx.leaf.prev_sibling() if ctx.leaf.kind() == SyntaxKind::Ident;
&& prev.kind() == SyntaxKind::Dot if let Some(prev) = ctx.leaf.prev_sibling();
&& let Some(prev_prev) = prev.prev_sibling() if prev.kind() == SyntaxKind::Dot;
&& prev_prev.is::<ast::Expr>() if let Some(prev_prev) = prev.prev_sibling();
&& let Some((value, styles)) = if prev_prev.is::<ast::Expr>();
analyze_expr(ctx.world, &prev_prev).into_iter().next() if let Some((value, styles)) = analyze_expr(ctx.world, &prev_prev).into_iter().next();
{ then {
ctx.from = ctx.leaf.offset(); ctx.from = ctx.leaf.offset();
field_access_completions(ctx, &value, &styles); field_access_completions(ctx, &value, &styles);
return true; return true;
} }
}
false false
} }
@ -499,11 +507,14 @@ fn complete_open_labels(ctx: &mut CompletionContext) -> bool {
fn complete_imports(ctx: &mut CompletionContext) -> bool { fn complete_imports(ctx: &mut CompletionContext) -> bool {
// In an import path for a file or package: // In an import path for a file or package:
// "#import "|", // "#import "|",
if let Some(SyntaxKind::ModuleImport | SyntaxKind::ModuleInclude) = if_chain! {
ctx.leaf.parent_kind() if matches!(
&& let Some(ast::Expr::Str(str)) = ctx.leaf.cast() ctx.leaf.parent_kind(),
{ Some(SyntaxKind::ModuleImport | SyntaxKind::ModuleInclude)
);
if let Some(ast::Expr::Str(str)) = ctx.leaf.cast();
let value = str.get(); let value = str.get();
then {
ctx.from = ctx.leaf.offset(); ctx.from = ctx.leaf.offset();
if value.starts_with('@') { if value.starts_with('@') {
let all_versions = value.contains(':'); let all_versions = value.contains(':');
@ -513,36 +524,41 @@ fn complete_imports(ctx: &mut CompletionContext) -> bool {
} }
return true; return true;
} }
}
// Behind an import list: // Behind an import list:
// "#import "path.typ": |", // "#import "path.typ": |",
// "#import "path.typ": a, b, |". // "#import "path.typ": a, b, |".
if let Some(prev) = ctx.leaf.prev_sibling() if_chain! {
&& let Some(ast::Expr::ModuleImport(import)) = prev.get().cast() if let Some(prev) = ctx.leaf.prev_sibling();
&& let Some(ast::Imports::Items(items)) = import.imports() if let Some(ast::Expr::ModuleImport(import)) = prev.get().cast();
&& let Some(source) = prev.children().find(|child| child.is::<ast::Expr>()) if let Some(ast::Imports::Items(items)) = import.imports();
{ if let Some(source) = prev.children().find(|child| child.is::<ast::Expr>());
then {
ctx.from = ctx.cursor; ctx.from = ctx.cursor;
import_item_completions(ctx, items, &source); import_item_completions(ctx, items, &source);
return true; return true;
} }
}
// Behind a half-started identifier in an import list: // Behind a half-started identifier in an import list:
// "#import "path.typ": thi|", // "#import "path.typ": thi|",
if ctx.leaf.kind() == SyntaxKind::Ident if_chain! {
&& let Some(parent) = ctx.leaf.parent() if ctx.leaf.kind() == SyntaxKind::Ident;
&& parent.kind() == SyntaxKind::ImportItemPath if let Some(parent) = ctx.leaf.parent();
&& let Some(grand) = parent.parent() if parent.kind() == SyntaxKind::ImportItemPath;
&& grand.kind() == SyntaxKind::ImportItems if let Some(grand) = parent.parent();
&& let Some(great) = grand.parent() if grand.kind() == SyntaxKind::ImportItems;
&& let Some(ast::Expr::ModuleImport(import)) = great.get().cast() if let Some(great) = grand.parent();
&& let Some(ast::Imports::Items(items)) = import.imports() if let Some(ast::Expr::ModuleImport(import)) = great.get().cast();
&& let Some(source) = great.children().find(|child| child.is::<ast::Expr>()) if let Some(ast::Imports::Items(items)) = import.imports();
{ if let Some(source) = great.children().find(|child| child.is::<ast::Expr>());
then {
ctx.from = ctx.leaf.offset(); ctx.from = ctx.leaf.offset();
import_item_completions(ctx, items, &source); import_item_completions(ctx, items, &source);
return true; return true;
} }
}
false false
} }
@ -591,14 +607,16 @@ fn complete_rules(ctx: &mut CompletionContext) -> bool {
} }
// Behind a half-completed show rule: "show strong: |". // Behind a half-completed show rule: "show strong: |".
if let Some(prev) = ctx.leaf.prev_leaf() if_chain! {
&& matches!(prev.kind(), SyntaxKind::Colon) if let Some(prev) = ctx.leaf.prev_leaf();
&& matches!(prev.parent_kind(), Some(SyntaxKind::ShowRule)) if matches!(prev.kind(), SyntaxKind::Colon);
{ if matches!(prev.parent_kind(), Some(SyntaxKind::ShowRule));
then {
ctx.from = ctx.cursor; ctx.from = ctx.cursor;
show_rule_recipe_completions(ctx); show_rule_recipe_completions(ctx);
return true; return true;
} }
}
false false
} }
@ -664,23 +682,26 @@ fn show_rule_recipe_completions(ctx: &mut CompletionContext) {
/// Complete call and set rule parameters. /// Complete call and set rule parameters.
fn complete_params(ctx: &mut CompletionContext) -> bool { fn complete_params(ctx: &mut CompletionContext) -> bool {
// Ensure that we are in a function call or set rule's argument list. // Ensure that we are in a function call or set rule's argument list.
let (callee, set, args, args_linked) = if let Some(parent) = ctx.leaf.parent() let (callee, set, args, args_linked) = if_chain! {
&& let Some(parent) = match parent.kind() { if let Some(parent) = ctx.leaf.parent();
if let Some(parent) = match parent.kind() {
SyntaxKind::Named => parent.parent(), SyntaxKind::Named => parent.parent(),
_ => Some(parent), _ => Some(parent),
} };
&& let Some(args) = parent.get().cast::<ast::Args>() if let Some(args) = parent.get().cast::<ast::Args>();
&& let Some(grand) = parent.parent() if let Some(grand) = parent.parent();
&& let Some(expr) = grand.get().cast::<ast::Expr>() if let Some(expr) = grand.get().cast::<ast::Expr>();
&& let set = matches!(expr, ast::Expr::SetRule(_)) let set = matches!(expr, ast::Expr::SetRule(_));
&& let Some(callee) = match expr { if let Some(callee) = match expr {
ast::Expr::FuncCall(call) => Some(call.callee()), ast::Expr::FuncCall(call) => Some(call.callee()),
ast::Expr::SetRule(set) => Some(set.target()), ast::Expr::SetRule(set) => Some(set.target()),
_ => None, _ => None,
} { };
then {
(callee, set, args, parent) (callee, set, args, parent)
} else { } else {
return false; return false;
}
}; };
// Find the piece of syntax that decides what we're completing. // Find the piece of syntax that decides what we're completing.
@ -697,10 +718,11 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
} }
// Parameter values: "func(param:|)", "func(param: |)". // Parameter values: "func(param:|)", "func(param: |)".
if let SyntaxKind::Colon = deciding.kind() if_chain! {
&& let Some(prev) = deciding.prev_leaf() if deciding.kind() == SyntaxKind::Colon;
&& let Some(param) = prev.get().cast::<ast::Ident>() if let Some(prev) = deciding.prev_leaf();
{ if let Some(param) = prev.get().cast::<ast::Ident>();
then {
if let Some(next) = deciding.next_leaf() { if let Some(next) = deciding.next_leaf() {
ctx.from = ctx.cursor.min(next.offset()); ctx.from = ctx.cursor.min(next.offset());
} }
@ -708,11 +730,13 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
named_param_value_completions(ctx, callee, &param); named_param_value_completions(ctx, callee, &param);
return true; return true;
} }
}
// Parameters: "func(|)", "func(hi|)", "func(12,|)". // Parameters: "func(|)", "func(hi|)", "func(12,|)".
if let SyntaxKind::LeftParen | SyntaxKind::Comma = deciding.kind() if_chain! {
&& (deciding.kind() != SyntaxKind::Comma || deciding.range().end < ctx.cursor) if matches!(deciding.kind(), SyntaxKind::LeftParen | SyntaxKind::Comma);
{ if deciding.kind() != SyntaxKind::Comma || deciding.range().end < ctx.cursor;
then {
if let Some(next) = deciding.next_leaf() { if let Some(next) = deciding.next_leaf() {
ctx.from = ctx.cursor.min(next.offset()); ctx.from = ctx.cursor.min(next.offset());
} }
@ -720,6 +744,7 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
param_completions(ctx, callee, set, args, args_linked); param_completions(ctx, callee, set, args, args_linked);
return true; return true;
} }
}
false false
} }
@ -834,7 +859,7 @@ fn param_value_completions<'a>(
fn path_completion(func: &Func, param: &ParamInfo) -> Option<&'static [&'static str]> { fn path_completion(func: &Func, param: &ParamInfo) -> Option<&'static [&'static str]> {
Some(match (func.name(), param.name) { Some(match (func.name(), param.name) {
(Some("image"), "source") => { (Some("image"), "source") => {
&["png", "jpg", "jpeg", "gif", "svg", "svgz", "webp", "pdf"] &["png", "jpg", "jpeg", "gif", "svg", "svgz", "webp"]
} }
(Some("csv"), "source") => &["csv"], (Some("csv"), "source") => &["csv"],
(Some("plugin"), "source") => &["wasm"], (Some("plugin"), "source") => &["wasm"],
@ -1079,13 +1104,15 @@ fn code_completions(ctx: &mut CompletionContext, hash: bool) {
fn is_in_equation_show_rule(leaf: &LinkedNode<'_>) -> bool { fn is_in_equation_show_rule(leaf: &LinkedNode<'_>) -> bool {
let mut node = leaf; let mut node = leaf;
while let Some(parent) = node.parent() { while let Some(parent) = node.parent() {
if let Some(expr) = parent.get().cast::<ast::Expr>() if_chain! {
&& let ast::Expr::ShowRule(show) = expr if let Some(expr) = parent.get().cast::<ast::Expr>();
&& let Some(ast::Expr::FieldAccess(field)) = show.selector() if let ast::Expr::ShowRule(show) = expr;
&& field.field().as_str() == "equation" if let Some(ast::Expr::FieldAccess(field)) = show.selector();
{ if field.field().as_str() == "equation";
then {
return true; return true;
} }
}
node = parent; node = parent;
} }
false false
@ -1355,12 +1382,11 @@ impl<'a> CompletionContext<'a> {
} }
} else if at { } else if at {
apply = Some(eco_format!("at(\"{label}\")")); apply = Some(eco_format!("at(\"{label}\")"));
} else if label.starts_with('"') } else if label.starts_with('"') && self.after.starts_with('"') {
&& self.after.starts_with('"') if let Some(trimmed) = label.strip_suffix('"') {
&& let Some(trimmed) = label.strip_suffix('"')
{
apply = Some(trimmed.into()); apply = Some(trimmed.into());
} }
}
self.completions.push(Completion { self.completions.push(Completion {
kind: kind.unwrap_or_else(|| match value { kind: kind.unwrap_or_else(|| match value {
@ -1545,7 +1571,7 @@ mod tests {
use typst::layout::PagedDocument; use typst::layout::PagedDocument;
use super::{Completion, CompletionKind, autocomplete}; use super::{autocomplete, Completion, CompletionKind};
use crate::tests::{FilePos, TestWorld, WorldLike}; use crate::tests::{FilePos, TestWorld, WorldLike};
/// Quote a string. /// Quote a string.

View File

@ -1,12 +1,12 @@
use typst::foundations::{Label, Selector, Value}; use typst::foundations::{Label, Selector, Value};
use typst::layout::PagedDocument; use typst::layout::PagedDocument;
use typst::syntax::{LinkedNode, Side, Source, Span, ast}; use typst::syntax::{ast, LinkedNode, Side, Source, Span};
use typst::utils::PicoStr; use typst::utils::PicoStr;
use crate::utils::globals; use crate::utils::globals;
use crate::{ use crate::{
DerefTarget, IdeWorld, NamedItem, analyze_expr, analyze_import, deref_target, analyze_expr, analyze_import, deref_target, named_items, DerefTarget, IdeWorld,
named_items, NamedItem,
}; };
/// A definition of some item. /// A definition of some item.
@ -90,11 +90,11 @@ mod tests {
use std::borrow::Borrow; use std::borrow::Borrow;
use std::ops::Range; use std::ops::Range;
use typst::WorldExt;
use typst::foundations::{IntoValue, NativeElement}; use typst::foundations::{IntoValue, NativeElement};
use typst::syntax::Side; use typst::syntax::Side;
use typst::WorldExt;
use super::{Definition, definition}; use super::{definition, Definition};
use crate::tests::{FilePos, TestWorld, WorldLike}; use crate::tests::{FilePos, TestWorld, WorldLike};
type Response = (TestWorld, Option<Definition>); type Response = (TestWorld, Option<Definition>);

View File

@ -1,10 +1,10 @@
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use typst::WorldExt;
use typst::layout::{Frame, FrameItem, PagedDocument, Point, Position, Size}; use typst::layout::{Frame, FrameItem, PagedDocument, Point, Position, Size};
use typst::model::{Destination, Url}; use typst::model::{Destination, Url};
use typst::syntax::{FileId, LinkedNode, Side, Source, Span, SyntaxKind}; use typst::syntax::{FileId, LinkedNode, Side, Source, Span, SyntaxKind};
use typst::visualize::{Curve, CurveItem, FillRule, Geometry}; use typst::visualize::{Curve, CurveItem, FillRule, Geometry};
use typst::WorldExt;
use crate::IdeWorld; use crate::IdeWorld;
@ -36,9 +36,8 @@ pub fn jump_from_click(
) -> Option<Jump> { ) -> Option<Jump> {
// Try to find a link first. // Try to find a link first.
for (pos, item) in frame.items() { for (pos, item) in frame.items() {
if let FrameItem::Link(dest, size) = item if let FrameItem::Link(dest, size) = item {
&& is_in_rect(*pos, *size, click) if is_in_rect(*pos, *size, click) {
{
return Some(match dest { return Some(match dest {
Destination::Url(url) => Jump::Url(url.clone()), Destination::Url(url) => Jump::Url(url.clone()),
Destination::Position(pos) => Jump::Position(*pos), Destination::Position(pos) => Jump::Position(*pos),
@ -48,17 +47,18 @@ pub fn jump_from_click(
}); });
} }
} }
}
// If there's no link, search for a jump target. // If there's no link, search for a jump target.
for &(mut pos, ref item) in frame.items().rev() { for (mut pos, item) in frame.items().rev() {
match item { match item {
FrameItem::Group(group) => { FrameItem::Group(group) => {
let pos = click - pos; let pos = click - pos;
if let Some(clip) = &group.clip if let Some(clip) = &group.clip {
&& !clip.contains(FillRule::NonZero, pos) if !clip.contains(FillRule::NonZero, pos) {
{
continue; continue;
} }
}
// Realistic transforms should always be invertible. // Realistic transforms should always be invertible.
// An example of one that isn't is a scale of 0, which would // An example of one that isn't is a scale of 0, which would
// not be clickable anyway. // not be clickable anyway.
@ -177,12 +177,12 @@ pub fn jump_from_cursor(
/// Find the position of a span in a frame. /// Find the position of a span in a frame.
fn find_in_frame(frame: &Frame, span: Span) -> Option<Point> { fn find_in_frame(frame: &Frame, span: Span) -> Option<Point> {
for &(mut pos, ref item) in frame.items() { for (mut pos, item) in frame.items() {
if let FrameItem::Group(group) = item if let FrameItem::Group(group) = item {
&& let Some(point) = find_in_frame(&group.frame, span) if let Some(point) = find_in_frame(&group.frame, span) {
{
return Some(pos + point.transform(group.transform)); return Some(pos + point.transform(group.transform));
} }
}
if let FrameItem::Text(text) = item { if let FrameItem::Text(text) = item {
for glyph in &text.glyphs { for glyph in &text.glyphs {
@ -222,7 +222,7 @@ mod tests {
use typst::layout::{Abs, Point, Position}; use typst::layout::{Abs, Point, Position};
use super::{Jump, jump_from_click, jump_from_cursor}; use super::{jump_from_click, jump_from_cursor, Jump};
use crate::tests::{FilePos, TestWorld, WorldLike}; use crate::tests::{FilePos, TestWorld, WorldLike};
fn point(x: f64, y: f64) -> Point { fn point(x: f64, y: f64) -> Point {

View File

@ -9,16 +9,16 @@ mod tooltip;
mod utils; mod utils;
pub use self::analyze::{analyze_expr, analyze_import, analyze_labels}; pub use self::analyze::{analyze_expr, analyze_import, analyze_labels};
pub use self::complete::{Completion, CompletionKind, autocomplete}; pub use self::complete::{autocomplete, Completion, CompletionKind};
pub use self::definition::{Definition, definition}; pub use self::definition::{definition, Definition};
pub use self::jump::{Jump, jump_from_click, jump_from_cursor}; pub use self::jump::{jump_from_click, jump_from_cursor, Jump};
pub use self::matchers::{DerefTarget, NamedItem, deref_target, named_items}; pub use self::matchers::{deref_target, named_items, DerefTarget, NamedItem};
pub use self::tooltip::{Tooltip, tooltip}; pub use self::tooltip::{tooltip, Tooltip};
use ecow::EcoString; use ecow::EcoString;
use typst::World;
use typst::syntax::FileId;
use typst::syntax::package::PackageSpec; use typst::syntax::package::PackageSpec;
use typst::syntax::FileId;
use typst::World;
/// Extends the `World` for IDE functionality. /// Extends the `World` for IDE functionality.
pub trait IdeWorld: World { pub trait IdeWorld: World {

View File

@ -1,9 +1,9 @@
use ecow::EcoString; use ecow::EcoString;
use typst::foundations::{Module, Value}; use typst::foundations::{Module, Value};
use typst::syntax::ast::AstNode; use typst::syntax::ast::AstNode;
use typst::syntax::{LinkedNode, Span, SyntaxKind, ast}; use typst::syntax::{ast, LinkedNode, Span, SyntaxKind};
use crate::{IdeWorld, analyze_import}; use crate::{analyze_import, IdeWorld};
/// Find the named items starting from the given position. /// Find the named items starting from the given position.
pub fn named_items<T>( pub fn named_items<T>(
@ -59,11 +59,11 @@ pub fn named_items<T>(
}; };
// Seeing the module itself. // Seeing the module itself.
if let Some((name, span)) = name_and_span if let Some((name, span)) = name_and_span {
&& let Some(res) = recv(NamedItem::Module(&name, span, module)) if let Some(res) = recv(NamedItem::Module(&name, span, module)) {
{
return Some(res); return Some(res);
} }
}
// Seeing the imported items. // Seeing the imported items.
match imports { match imports {
@ -124,9 +124,8 @@ pub fn named_items<T>(
} }
if let Some(parent) = node.parent() { if let Some(parent) = node.parent() {
if let Some(v) = parent.cast::<ast::ForLoop>() if let Some(v) = parent.cast::<ast::ForLoop>() {
&& node.prev_sibling_kind() != Some(SyntaxKind::In) if node.prev_sibling_kind() != Some(SyntaxKind::In) {
{
let pattern = v.pattern(); let pattern = v.pattern();
for ident in pattern.bindings() { for ident in pattern.bindings() {
if let Some(res) = recv(NamedItem::Var(ident)) { if let Some(res) = recv(NamedItem::Var(ident)) {
@ -134,6 +133,7 @@ pub fn named_items<T>(
} }
} }
} }
}
if let Some(v) = parent.cast::<ast::Closure>().filter(|v| { if let Some(v) = parent.cast::<ast::Closure>().filter(|v| {
// Check if the node is in the body of the closure. // Check if the node is in the body of the closure.
@ -155,15 +155,15 @@ pub fn named_items<T>(
} }
} }
ast::Param::Spread(s) => { ast::Param::Spread(s) => {
if let Some(sink_ident) = s.sink_ident() if let Some(sink_ident) = s.sink_ident() {
&& let Some(t) = recv(NamedItem::Var(sink_ident)) if let Some(t) = recv(NamedItem::Var(sink_ident)) {
{
return Some(t); return Some(t);
} }
} }
} }
} }
} }
}
ancestor = Some(parent.clone()); ancestor = Some(parent.clone());
continue; continue;
@ -216,7 +216,7 @@ impl<'a> NamedItem<'a> {
/// Categorize an expression into common classes IDE functionality can operate /// Categorize an expression into common classes IDE functionality can operate
/// on. /// on.
pub fn deref_target(node: LinkedNode<'_>) -> Option<DerefTarget<'_>> { pub fn deref_target(node: LinkedNode) -> Option<DerefTarget<'_>> {
// Move to the first ancestor that is an expression. // Move to the first ancestor that is an expression.
let mut ancestor = node; let mut ancestor = node;
while !ancestor.is::<ast::Expr>() { while !ancestor.is::<ast::Expr>() {

View File

@ -9,7 +9,7 @@ use typst::layout::{Abs, Margin, PageElem};
use typst::syntax::package::{PackageSpec, PackageVersion}; use typst::syntax::package::{PackageSpec, PackageVersion};
use typst::syntax::{FileId, Source, VirtualPath}; use typst::syntax::{FileId, Source, VirtualPath};
use typst::text::{Font, FontBook, TextElem, TextSize}; use typst::text::{Font, FontBook, TextElem, TextSize};
use typst::utils::{LazyHash, singleton}; use typst::utils::{singleton, LazyHash};
use typst::{Feature, Library, LibraryExt, World}; use typst::{Feature, Library, LibraryExt, World};
use crate::IdeWorld; use crate::IdeWorld;

View File

@ -1,16 +1,17 @@
use std::fmt::Write; use std::fmt::Write;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use if_chain::if_chain;
use typst::engine::Sink; use typst::engine::Sink;
use typst::foundations::{Binding, Capturer, CastInfo, Repr, Value, repr}; use typst::foundations::{repr, Binding, Capturer, CastInfo, Repr, Value};
use typst::layout::{Length, PagedDocument}; use typst::layout::{Length, PagedDocument};
use typst::syntax::ast::AstNode; use typst::syntax::ast::AstNode;
use typst::syntax::{LinkedNode, Side, Source, SyntaxKind, ast}; use typst::syntax::{ast, LinkedNode, Side, Source, SyntaxKind};
use typst::utils::{Numeric, round_with_precision}; use typst::utils::{round_with_precision, Numeric};
use typst_eval::CapturesVisitor; use typst_eval::CapturesVisitor;
use crate::utils::{plain_docs_sentence, summarize_font_family}; use crate::utils::{plain_docs_sentence, summarize_font_family};
use crate::{IdeWorld, analyze_expr, analyze_import, analyze_labels}; use crate::{analyze_expr, analyze_import, analyze_labels, IdeWorld};
/// Describe the item under the cursor. /// Describe the item under the cursor.
/// ///
@ -65,12 +66,12 @@ fn expr_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> {
return Some(Tooltip::Text(plain_docs_sentence(docs))); return Some(Tooltip::Text(plain_docs_sentence(docs)));
} }
if let &Value::Length(length) = value if let &Value::Length(length) = value {
&& let Some(tooltip) = length_tooltip(length) if let Some(tooltip) = length_tooltip(length) {
{
return Some(tooltip); return Some(tooltip);
} }
} }
}
if expr.is_literal() { if expr.is_literal() {
return None; return None;
@ -92,11 +93,11 @@ fn expr_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> {
last = Some((value, 1)); last = Some((value, 1));
} }
if let Some((_, count)) = last if let Some((_, count)) = last {
&& count > 1 if count > 1 {
{
write!(pieces.last_mut().unwrap(), " (×{count})").unwrap(); write!(pieces.last_mut().unwrap(), " (×{count})").unwrap();
} }
}
if iter.next().is_some() { if iter.next().is_some() {
pieces.push("...".into()); pieces.push("...".into());
@ -108,18 +109,20 @@ fn expr_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> {
/// Tooltips for imports. /// Tooltips for imports.
fn import_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> { fn import_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> {
if leaf.kind() == SyntaxKind::Star if_chain! {
&& let Some(parent) = leaf.parent() if leaf.kind() == SyntaxKind::Star;
&& let Some(import) = parent.cast::<ast::ModuleImport>() if let Some(parent) = leaf.parent();
&& let Some(node) = parent.find(import.source().span()) if let Some(import) = parent.cast::<ast::ModuleImport>();
&& let Some(value) = analyze_import(world, &node) if let Some(node) = parent.find(import.source().span());
&& let Some(scope) = value.scope() if let Some(value) = analyze_import(world, &node);
{ if let Some(scope) = value.scope();
then {
let names: Vec<_> = let names: Vec<_> =
scope.iter().map(|(name, ..)| eco_format!("`{name}`")).collect(); scope.iter().map(|(name, ..)| eco_format!("`{name}`")).collect();
let list = repr::separated_list(&names, "and"); let list = repr::separated_list(&names, "and");
return Some(Tooltip::Text(eco_format!("This star imports {list}"))); return Some(Tooltip::Text(eco_format!("This star imports {list}")));
} }
}
None None
} }
@ -187,46 +190,51 @@ fn label_tooltip(document: &PagedDocument, leaf: &LinkedNode) -> Option<Tooltip>
/// Tooltips for components of a named parameter. /// Tooltips for components of a named parameter.
fn named_param_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> { fn named_param_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> {
let (func, named) = let (func, named) = if_chain! {
// Ensure that we are in a named pair in the arguments to a function // Ensure that we are in a named pair in the arguments to a function
// call or set rule. // call or set rule.
if let Some(parent) = leaf.parent() if let Some(parent) = leaf.parent();
&& let Some(named) = parent.cast::<ast::Named>() if let Some(named) = parent.cast::<ast::Named>();
&& let Some(grand) = parent.parent() if let Some(grand) = parent.parent();
&& matches!(grand.kind(), SyntaxKind::Args) if matches!(grand.kind(), SyntaxKind::Args);
&& let Some(grand_grand) = grand.parent() if let Some(grand_grand) = grand.parent();
&& let Some(expr) = grand_grand.cast::<ast::Expr>() if let Some(expr) = grand_grand.cast::<ast::Expr>();
&& let Some(ast::Expr::Ident(callee)) = match expr { if let Some(ast::Expr::Ident(callee)) = match expr {
ast::Expr::FuncCall(call) => Some(call.callee()), ast::Expr::FuncCall(call) => Some(call.callee()),
ast::Expr::SetRule(set) => Some(set.target()), ast::Expr::SetRule(set) => Some(set.target()),
_ => None, _ => None,
} };
// Find metadata about the function. // Find metadata about the function.
&& let Some(Value::Func(func)) = world if let Some(Value::Func(func)) = world
.library() .library()
.global .global
.scope() .scope()
.get(&callee) .get(&callee)
.map(Binding::read) .map(Binding::read);
{ (func, named) } then { (func, named) }
else { return None; }; else { return None; }
};
// Hovering over the parameter name. // Hovering over the parameter name.
if leaf.index() == 0 if_chain! {
&& let Some(ident) = leaf.cast::<ast::Ident>() if leaf.index() == 0;
&& let Some(param) = func.param(&ident) if let Some(ident) = leaf.cast::<ast::Ident>();
{ if let Some(param) = func.param(&ident);
then {
return Some(Tooltip::Text(plain_docs_sentence(param.docs))); return Some(Tooltip::Text(plain_docs_sentence(param.docs)));
} }
}
// Hovering over a string parameter value. // Hovering over a string parameter value.
if let Some(string) = leaf.cast::<ast::Str>() if_chain! {
&& let Some(param) = func.param(&named.name()) if let Some(string) = leaf.cast::<ast::Str>();
&& let Some(docs) = find_string_doc(&param.input, &string.get()) if let Some(param) = func.param(&named.name());
{ if let Some(docs) = find_string_doc(&param.input, &string.get());
then {
return Some(Tooltip::Text(docs.into())); return Some(Tooltip::Text(docs.into()));
} }
}
None None
} }
@ -244,24 +252,27 @@ fn find_string_doc(info: &CastInfo, string: &str) -> Option<&'static str> {
/// Tooltip for font. /// Tooltip for font.
fn font_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> { fn font_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Tooltip> {
if_chain! {
// Ensure that we are on top of a string. // Ensure that we are on top of a string.
if let Some(string) = leaf.cast::<ast::Str>() if let Some(string) = leaf.cast::<ast::Str>();
&& let lower = string.get().to_lowercase() let lower = string.get().to_lowercase();
// Ensure that we are in the arguments to the text function. // Ensure that we are in the arguments to the text function.
&& let Some(parent) = leaf.parent() if let Some(parent) = leaf.parent();
&& let Some(named) = parent.cast::<ast::Named>() if let Some(named) = parent.cast::<ast::Named>();
&& named.name().as_str() == "font" if named.name().as_str() == "font";
// Find the font family. // Find the font family.
&& let Some((_, iter)) = world if let Some((_, iter)) = world
.book() .book()
.families() .families()
.find(|&(family, _)| family.to_lowercase().as_str() == lower.as_str()) .find(|&(family, _)| family.to_lowercase().as_str() == lower.as_str());
{
then {
let detail = summarize_font_family(iter.collect()); let detail = summarize_font_family(iter.collect());
return Some(Tooltip::Text(detail)); return Some(Tooltip::Text(detail));
} }
};
None None
} }
@ -272,7 +283,7 @@ mod tests {
use typst::syntax::Side; use typst::syntax::Side;
use super::{Tooltip, tooltip}; use super::{tooltip, Tooltip};
use crate::tests::{FilePos, TestWorld, WorldLike}; use crate::tests::{FilePos, TestWorld, WorldLike};
type Response = Option<Tooltip>; type Response = Option<Tooltip>;

View File

@ -2,7 +2,7 @@ use std::fmt::Write;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use comemo::Track; use comemo::Track;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use typst::engine::{Engine, Route, Sink, Traced}; use typst::engine::{Engine, Route, Sink, Traced};
use typst::foundations::{Scope, Value}; use typst::foundations::{Scope, Value};
use typst::introspection::Introspector; use typst::introspection::Introspector;
@ -119,7 +119,11 @@ pub fn globals<'a>(world: &'a dyn IdeWorld, leaf: &LinkedNode) -> &'a Scope {
.is_none_or(|prev| !matches!(prev.kind(), SyntaxKind::Hash)); .is_none_or(|prev| !matches!(prev.kind(), SyntaxKind::Hash));
let library = world.library(); let library = world.library();
if in_math { library.math.scope() } else { library.global.scope() } if in_math {
library.math.scope()
} else {
library.global.scope()
}
} }
/// Checks whether the given value or any of its constituent parts satisfy the /// Checks whether the given value or any of its constituent parts satisfy the

View File

@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
use ecow::eco_format; use ecow::eco_format;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use serde::Deserialize; use serde::Deserialize;
use typst_library::diag::{PackageError, PackageResult, StrResult, bail}; use typst_library::diag::{bail, PackageError, PackageResult, StrResult};
use typst_syntax::package::{PackageSpec, PackageVersion, VersionlessPackageSpec}; use typst_syntax::package::{PackageSpec, PackageVersion, VersionlessPackageSpec};
use crate::download::{Downloader, Progress}; use crate::download::{Downloader, Progress};
@ -189,7 +189,7 @@ impl PackageStorage {
} }
} }
Err(err) => { Err(err) => {
return Err(PackageError::NetworkFailed(Some(eco_format!("{err}")))); return Err(PackageError::NetworkFailed(Some(eco_format!("{err}"))))
} }
}; };

View File

@ -407,11 +407,11 @@ fn distribute<'a>(
// If there is still something remaining, apply it to the // If there is still something remaining, apply it to the
// last region (it will overflow, but there's nothing else // last region (it will overflow, but there's nothing else
// we can do). // we can do).
if !remaining.approx_empty() if !remaining.approx_empty() {
&& let Some(last) = buf.last_mut() if let Some(last) = buf.last_mut() {
{
*last += remaining; *last += remaining;
} }
}
// Distribute the heights to the first region and the // Distribute the heights to the first region and the
// backlog. There is no last region, since the height is // backlog. There is no last region, since the height is

View File

@ -2,11 +2,10 @@ use std::cell::{LazyCell, RefCell};
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::Hash; use std::hash::Hash;
use bumpalo::Bump;
use bumpalo::boxed::Box as BumpBox; use bumpalo::boxed::Box as BumpBox;
use bumpalo::Bump;
use comemo::{Track, Tracked, TrackedMut}; use comemo::{Track, Tracked, TrackedMut};
use typst_library::World; use typst_library::diag::{bail, warning, SourceResult};
use typst_library::diag::{SourceResult, bail, warning};
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Packed, Resolve, Smart, StyleChain}; use typst_library::foundations::{Packed, Resolve, Smart, StyleChain};
use typst_library::introspection::{ use typst_library::introspection::{
@ -20,9 +19,10 @@ use typst_library::layout::{
use typst_library::model::ParElem; use typst_library::model::ParElem;
use typst_library::routines::{Pair, Routines}; use typst_library::routines::{Pair, Routines};
use typst_library::text::TextElem; use typst_library::text::TextElem;
use typst_library::World;
use typst_utils::SliceExt; use typst_utils::SliceExt;
use super::{FlowMode, layout_multi_block, layout_single_block}; use super::{layout_multi_block, layout_single_block, FlowMode};
use crate::inline::ParSituation; use crate::inline::ParSituation;
use crate::modifiers::layout_and_modify; use crate::modifiers::layout_and_modify;
@ -684,11 +684,11 @@ impl<T> CachedCell<T> {
let input_hash = typst_utils::hash128(&input); let input_hash = typst_utils::hash128(&input);
let mut slot = self.0.borrow_mut(); let mut slot = self.0.borrow_mut();
if let Some((hash, output)) = &*slot if let Some((hash, output)) = &*slot {
&& *hash == input_hash if *hash == input_hash {
{
return output.clone(); return output.clone();
} }
}
let output = f(input); let output = f(input);
*slot = Some((input_hash, output.clone())); *slot = Some((input_hash, output.clone()));

View File

@ -18,7 +18,7 @@ use typst_syntax::Span;
use typst_utils::{NonZeroExt, Numeric}; use typst_utils::{NonZeroExt, Numeric};
use super::{ use super::{
Config, FlowMode, FlowResult, LineNumberConfig, PlacedChild, Stop, Work, distribute, distribute, Config, FlowMode, FlowResult, LineNumberConfig, PlacedChild, Stop, Work,
}; };
/// Composes the contents of a single page/region. A region can have multiple /// Composes the contents of a single page/region. A region can have multiple
@ -319,7 +319,11 @@ impl<'a, 'b> Composer<'a, 'b, '_, '_> {
let used = base.y - remaining; let used = base.y - remaining;
let half = need / 2.0; let half = need / 2.0;
let ratio = (used + half) / base.y; let ratio = (used + half) / base.y;
if ratio <= 0.5 { FixedAlignment::Start } else { FixedAlignment::End } if ratio <= 0.5 {
FixedAlignment::Start
} else {
FixedAlignment::End
}
}); });
// Select the insertion area where we'll put this float. // Select the insertion area where we'll put this float.

View File

@ -14,8 +14,7 @@ use std::rc::Rc;
use bumpalo::Bump; use bumpalo::Bump;
use comemo::{Track, Tracked, TrackedMut}; use comemo::{Track, Tracked, TrackedMut};
use ecow::EcoVec; use ecow::EcoVec;
use typst_library::World; use typst_library::diag::{bail, At, SourceDiagnostic, SourceResult};
use typst_library::diag::{At, SourceDiagnostic, SourceResult, bail};
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Content, Packed, Resolve, StyleChain}; use typst_library::foundations::{Content, Packed, Resolve, StyleChain};
use typst_library::introspection::{ use typst_library::introspection::{
@ -28,13 +27,14 @@ use typst_library::layout::{
use typst_library::model::{FootnoteElem, FootnoteEntry, LineNumberingScope, ParLine}; use typst_library::model::{FootnoteElem, FootnoteEntry, LineNumberingScope, ParLine};
use typst_library::routines::{Arenas, FragmentKind, Pair, RealizationKind, Routines}; use typst_library::routines::{Arenas, FragmentKind, Pair, RealizationKind, Routines};
use typst_library::text::TextElem; use typst_library::text::TextElem;
use typst_library::World;
use typst_utils::{NonZeroExt, Numeric}; use typst_utils::{NonZeroExt, Numeric};
use self::block::{layout_multi_block, layout_single_block}; use self::block::{layout_multi_block, layout_single_block};
use self::collect::{ use self::collect::{
Child, LineChild, MultiChild, MultiSpill, PlacedChild, SingleChild, collect, collect, Child, LineChild, MultiChild, MultiSpill, PlacedChild, SingleChild,
}; };
use self::compose::{Composer, compose}; use self::compose::{compose, Composer};
use self::distribute::distribute; use self::distribute::distribute;
/// Lays out content into a single region, producing a single frame. /// Lays out content into a single region, producing a single frame.

View File

@ -1,6 +1,6 @@
use std::fmt::Debug; use std::fmt::Debug;
use typst_library::diag::{SourceResult, bail}; use typst_library::diag::{bail, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Resolve, StyleChain}; use typst_library::foundations::{Resolve, StyleChain};
use typst_library::layout::grid::resolve::{ use typst_library::layout::grid::resolve::{
@ -16,8 +16,8 @@ use typst_syntax::Span;
use typst_utils::Numeric; use typst_utils::Numeric;
use super::{ use super::{
LineSegment, Rowspan, UnbreakableRowGroup, generate_line_segments, generate_line_segments, hline_stroke_at_column, layout_cell, vline_stroke_at_row,
hline_stroke_at_column, layout_cell, vline_stroke_at_row, LineSegment, Rowspan, UnbreakableRowGroup,
}; };
/// Performs grid layout. /// Performs grid layout.
@ -274,33 +274,32 @@ impl<'a> GridLayouter<'a> {
pub fn layout(mut self, engine: &mut Engine) -> SourceResult<Fragment> { pub fn layout(mut self, engine: &mut Engine) -> SourceResult<Fragment> {
self.measure_columns(engine)?; self.measure_columns(engine)?;
if let Some(footer) = &self.grid.footer if let Some(footer) = &self.grid.footer {
&& footer.repeated if footer.repeated {
{
// Ensure rows in the first region will be aware of the // Ensure rows in the first region will be aware of the
// possible presence of the footer. // possible presence of the footer.
self.prepare_footer(footer, engine, 0)?; self.prepare_footer(footer, engine, 0)?;
self.regions.size.y -= self.current.footer_height; self.regions.size.y -= self.current.footer_height;
self.current.initial_after_repeats = self.regions.size.y; self.current.initial_after_repeats = self.regions.size.y;
} }
}
let mut y = 0; let mut y = 0;
let mut consecutive_header_count = 0; let mut consecutive_header_count = 0;
while y < self.grid.rows.len() { while y < self.grid.rows.len() {
if let Some(next_header) = self.upcoming_headers.get(consecutive_header_count) if let Some(next_header) = self.upcoming_headers.get(consecutive_header_count)
&& next_header.range.contains(&y)
{ {
if next_header.range.contains(&y) {
self.place_new_headers(&mut consecutive_header_count, engine)?; self.place_new_headers(&mut consecutive_header_count, engine)?;
y = next_header.range.end; y = next_header.range.end;
// Skip header rows during normal layout. // Skip header rows during normal layout.
continue; continue;
} }
}
if let Some(footer) = &self.grid.footer if let Some(footer) = &self.grid.footer {
&& footer.repeated if footer.repeated && y >= footer.start {
&& y >= footer.start
{
if y == footer.start { if y == footer.start {
self.layout_footer(footer, engine, self.finished.len())?; self.layout_footer(footer, engine, self.finished.len())?;
self.flush_orphans(); self.flush_orphans();
@ -308,6 +307,7 @@ impl<'a> GridLayouter<'a> {
y = footer.end; y = footer.end;
continue; continue;
} }
}
self.layout_row(y, engine, 0)?; self.layout_row(y, engine, 0)?;
@ -1228,7 +1228,7 @@ impl<'a> GridLayouter<'a> {
.skip(parent.y) .skip(parent.y)
.take(rowspan) .take(rowspan)
.rev() .rev()
.find(|&(_, &row)| row == Sizing::Auto) .find(|(_, &row)| row == Sizing::Auto)
.map(|(y, _)| y); .map(|(y, _)| y);
if last_spanned_auto_row != Some(y) { if last_spanned_auto_row != Some(y) {
@ -1279,6 +1279,11 @@ impl<'a> GridLayouter<'a> {
let frames = let frames =
layout_cell(cell, engine, disambiguator, self.styles, pod)?.into_frames(); layout_cell(cell, engine, disambiguator, self.styles, pod)?.into_frames();
// Skip the first region if one cell in it is empty. Then,
// remeasure.
if let Some([first, rest @ ..]) =
frames.get(measurement_data.frames_in_previous_regions..)
{
// HACK: reconsider if this is the right decision // HACK: reconsider if this is the right decision
fn is_empty_frame(frame: &Frame) -> bool { fn is_empty_frame(frame: &Frame) -> bool {
!frame.items().any(|(_, item)| match item { !frame.items().any(|(_, item)| match item {
@ -1287,18 +1292,14 @@ impl<'a> GridLayouter<'a> {
_ => true, _ => true,
}) })
} }
if can_skip
// Skip the first region if one cell in it is empty. Then,
// remeasure.
if let Some([first, rest @ ..]) =
frames.get(measurement_data.frames_in_previous_regions..)
&& can_skip
&& breakable && breakable
&& is_empty_frame(first) && is_empty_frame(first)
&& rest.iter().any(|frame| !is_empty_frame(frame)) && rest.iter().any(|frame| !is_empty_frame(frame))
{ {
return Ok(None); return Ok(None);
} }
}
// Skip frames from previous regions if applicable. // Skip frames from previous regions if applicable.
let mut sizes = frames let mut sizes = frames
@ -1536,9 +1537,8 @@ impl<'a> GridLayouter<'a> {
// The latest rows have orphan prevention (headers) and no other rows // The latest rows have orphan prevention (headers) and no other rows
// were placed, so remove those rows and try again in a new region, // were placed, so remove those rows and try again in a new region,
// unless this is the last region. // unless this is the last region.
if let Some(orphan_snapshot) = self.current.lrows_orphan_snapshot.take() if let Some(orphan_snapshot) = self.current.lrows_orphan_snapshot.take() {
&& !last if !last {
{
self.current.lrows.truncate(orphan_snapshot); self.current.lrows.truncate(orphan_snapshot);
self.current.repeated_header_rows = self.current.repeated_header_rows =
self.current.repeated_header_rows.min(orphan_snapshot); self.current.repeated_header_rows.min(orphan_snapshot);
@ -1548,6 +1548,7 @@ impl<'a> GridLayouter<'a> {
self.current.last_repeated_header_end = 0; self.current.last_repeated_header_end = 0;
} }
} }
}
if self if self
.current .current
@ -1578,7 +1579,8 @@ impl<'a> GridLayouter<'a> {
&& self.current.could_progress_at_top; && self.current.could_progress_at_top;
let mut laid_out_footer_start = None; let mut laid_out_footer_start = None;
if !footer_would_be_widow && let Some(footer) = &self.grid.footer { if !footer_would_be_widow {
if let Some(footer) = &self.grid.footer {
// Don't layout the footer if it would be alone with the header // Don't layout the footer if it would be alone with the header
// in the page (hence the widow check), and don't layout it // in the page (hence the widow check), and don't layout it
// twice (check below). // twice (check below).
@ -1593,6 +1595,7 @@ impl<'a> GridLayouter<'a> {
self.layout_footer(footer, engine, self.finished.len())?; self.layout_footer(footer, engine, self.finished.len())?;
} }
} }
}
// Determine the height of existing rows in the region. // Determine the height of existing rows in the region.
let mut used = Abs::zero(); let mut used = Abs::zero();

View File

@ -1,8 +1,8 @@
use std::sync::Arc; use std::sync::Arc;
use typst_library::foundations::{AlternativeFold, Fold}; use typst_library::foundations::{AlternativeFold, Fold};
use typst_library::layout::Abs;
use typst_library::layout::grid::resolve::{CellGrid, Line, Repeatable}; use typst_library::layout::grid::resolve::{CellGrid, Line, Repeatable};
use typst_library::layout::Abs;
use typst_library::visualize::Stroke; use typst_library::visualize::Stroke;
use super::RowPiece; use super::RowPiece;
@ -291,14 +291,14 @@ pub fn vline_stroke_at_row(
// We would then analyze the cell one column after (if at a gutter // We would then analyze the cell one column after (if at a gutter
// column), and/or one row below (if at a gutter row), in order to // column), and/or one row below (if at a gutter row), in order to
// check if it would be merged with a cell before the vline. // check if it would be merged with a cell before the vline.
if let Some(parent) = grid.effective_parent_cell_position(x, y) if let Some(parent) = grid.effective_parent_cell_position(x, y) {
&& parent.x < x if parent.x < x {
{
// There is a colspan cell going through this vline's position, // There is a colspan cell going through this vline's position,
// so don't draw it here. // so don't draw it here.
return None; return None;
} }
} }
}
let (left_cell_stroke, left_cell_prioritized) = x let (left_cell_stroke, left_cell_prioritized) = x
.checked_sub(1) .checked_sub(1)
@ -416,9 +416,8 @@ pub fn hline_stroke_at_column(
// We would then analyze the cell one column after (if at a gutter // We would then analyze the cell one column after (if at a gutter
// column), and/or one row below (if at a gutter row), in order to // column), and/or one row below (if at a gutter row), in order to
// check if it would be merged with a cell before the hline. // check if it would be merged with a cell before the hline.
if let Some(parent) = grid.effective_parent_cell_position(x, y) if let Some(parent) = grid.effective_parent_cell_position(x, y) {
&& parent.y < y if parent.y < y {
{
// Get the first 'y' spanned by the possible rowspan in this region. // Get the first 'y' spanned by the possible rowspan in this region.
// The 'parent.y' row and any other spanned rows above 'y' could be // The 'parent.y' row and any other spanned rows above 'y' could be
// missing from this region, which could have lead the check above // missing from this region, which could have lead the check above
@ -439,6 +438,7 @@ pub fn hline_stroke_at_column(
} }
} }
} }
}
// When the hline is at the top of the region and this isn't the first // When the hline is at the top of the region and this isn't the first
// region, fold with the top stroke of the topmost cell at this column, // region, fold with the top stroke of the topmost cell at this column,

View File

@ -9,13 +9,13 @@ use typst_library::diag::SourceResult;
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Packed, StyleChain}; use typst_library::foundations::{Packed, StyleChain};
use typst_library::introspection::Locator; use typst_library::introspection::Locator;
use typst_library::layout::grid::resolve::{Cell, grid_to_cellgrid, table_to_cellgrid}; use typst_library::layout::grid::resolve::{grid_to_cellgrid, table_to_cellgrid, Cell};
use typst_library::layout::{Fragment, GridElem, Regions}; use typst_library::layout::{Fragment, GridElem, Regions};
use typst_library::model::TableElem; use typst_library::model::TableElem;
use self::layouter::RowPiece; use self::layouter::RowPiece;
use self::lines::{ use self::lines::{
LineSegment, generate_line_segments, hline_stroke_at_column, vline_stroke_at_row, generate_line_segments, hline_stroke_at_column, vline_stroke_at_row, LineSegment,
}; };
use self::rowspans::{Rowspan, UnbreakableRowGroup}; use self::rowspans::{Rowspan, UnbreakableRowGroup};

View File

@ -240,10 +240,8 @@ impl<'a> GridLayouter<'a> {
self.current.initial_after_repeats = self.regions.size.y; self.current.initial_after_repeats = self.regions.size.y;
} }
if let Some(footer) = &self.grid.footer if let Some(footer) = &self.grid.footer {
&& footer.repeated if footer.repeated && skipped_region {
&& skipped_region
{
// Simulate the footer again; the region's 'full' might have // Simulate the footer again; the region's 'full' might have
// changed. // changed.
self.regions.size.y += self.current.footer_height; self.regions.size.y += self.current.footer_height;
@ -252,6 +250,7 @@ impl<'a> GridLayouter<'a> {
.height; .height;
self.regions.size.y -= self.current.footer_height; self.regions.size.y -= self.current.footer_height;
} }
}
let repeating_header_rows = let repeating_header_rows =
total_header_row_count(self.repeating_headers.iter().copied()); total_header_row_count(self.repeating_headers.iter().copied());

View File

@ -4,8 +4,8 @@ use typst_library::foundations::Resolve;
use typst_library::layout::grid::resolve::Repeatable; use typst_library::layout::grid::resolve::Repeatable;
use typst_library::layout::{Abs, Axes, Frame, Point, Region, Regions, Size, Sizing}; use typst_library::layout::{Abs, Axes, Frame, Point, Region, Regions, Size, Sizing};
use super::layouter::{Row, points}; use super::layouter::{points, Row};
use super::{Cell, GridLayouter, layout_cell}; use super::{layout_cell, Cell, GridLayouter};
/// All information needed to layout a single rowspan. /// All information needed to layout a single rowspan.
pub struct Rowspan { pub struct Rowspan {
@ -238,10 +238,8 @@ impl GridLayouter<'_> {
// current row is dynamic and depends on the amount of upcoming // current row is dynamic and depends on the amount of upcoming
// unbreakable cells (with or without a rowspan setting). // unbreakable cells (with or without a rowspan setting).
let mut amount_unbreakable_rows = None; let mut amount_unbreakable_rows = None;
if let Some(footer) = &self.grid.footer if let Some(footer) = &self.grid.footer {
&& !footer.repeated if !footer.repeated && current_row >= footer.start {
&& current_row >= footer.start
{
// Non-repeated footer, so keep it unbreakable. // Non-repeated footer, so keep it unbreakable.
// //
// TODO(subfooters): This will become unnecessary // TODO(subfooters): This will become unnecessary
@ -249,6 +247,7 @@ impl GridLayouter<'_> {
// have widow prevention. // have widow prevention.
amount_unbreakable_rows = Some(self.grid.rows.len() - footer.start); amount_unbreakable_rows = Some(self.grid.rows.len() - footer.start);
} }
}
let row_group = self.simulate_unbreakable_row_group( let row_group = self.simulate_unbreakable_row_group(
current_row, current_row,
@ -1269,9 +1268,9 @@ fn subtract_end_sizes(sizes: &mut Vec<Abs>, mut subtract: Abs) {
while subtract > Abs::zero() && sizes.last().is_some_and(|&size| size <= subtract) { while subtract > Abs::zero() && sizes.last().is_some_and(|&size| size <= subtract) {
subtract -= sizes.pop().unwrap(); subtract -= sizes.pop().unwrap();
} }
if subtract > Abs::zero() if subtract > Abs::zero() {
&& let Some(last_size) = sizes.last_mut() if let Some(last_size) = sizes.last_mut() {
{
*last_size -= subtract; *last_size -= subtract;
} }
} }
}

View File

@ -6,14 +6,14 @@ use typst_library::layout::{
}; };
use typst_library::routines::Pair; use typst_library::routines::Pair;
use typst_library::text::{ use typst_library::text::{
LinebreakElem, SmartQuoteElem, SmartQuoter, SmartQuotes, SpaceElem, TextElem, is_default_ignorable, LinebreakElem, SmartQuoteElem, SmartQuoter, SmartQuotes,
is_default_ignorable, SpaceElem, TextElem,
}; };
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::Numeric; use typst_utils::Numeric;
use super::*; use super::*;
use crate::modifiers::{FrameModifiers, FrameModify, layout_and_modify}; use crate::modifiers::{layout_and_modify, FrameModifiers, FrameModify};
// The characters by which spacing, inline content and pins are replaced in the // The characters by which spacing, inline content and pins are replaced in the
// full text. // full text.
@ -274,12 +274,12 @@ impl<'a> Collector<'a> {
let segment_len = self.full.len() - prev; let segment_len = self.full.len() - prev;
// Merge adjacent text segments with the same styles. // Merge adjacent text segments with the same styles.
if let Some(Segment::Text(last_len, last_styles)) = self.segments.last_mut() if let Some(Segment::Text(last_len, last_styles)) = self.segments.last_mut() {
&& *last_styles == styles if *last_styles == styles {
{
*last_len += segment_len; *last_len += segment_len;
return; return;
} }
}
self.segments.push(Segment::Text(segment_len, styles)); self.segments.push(Segment::Text(segment_len, styles));
} }

View File

@ -6,7 +6,7 @@ use typst_library::foundations::Resolve;
use typst_library::introspection::{SplitLocator, Tag}; use typst_library::introspection::{SplitLocator, Tag};
use typst_library::layout::{Abs, Dir, Em, Fr, Frame, FrameItem, Point}; use typst_library::layout::{Abs, Dir, Em, Fr, Frame, FrameItem, Point};
use typst_library::model::ParLineMarker; use typst_library::model::ParLineMarker;
use typst_library::text::{Lang, TextElem, variant}; use typst_library::text::{variant, Lang, TextElem};
use typst_utils::Numeric; use typst_utils::Numeric;
use super::*; use super::*;
@ -155,18 +155,18 @@ pub fn line<'a>(
let mut items = collect_items(engine, p, range, trim); let mut items = collect_items(engine, p, range, trim);
// Add a hyphen at the line start, if a previous dash should be repeated. // Add a hyphen at the line start, if a previous dash should be repeated.
if pred.is_some_and(|pred| should_repeat_hyphen(pred, full)) if pred.is_some_and(|pred| should_repeat_hyphen(pred, full)) {
&& let Some(shaped) = items.first_text_mut() if let Some(shaped) = items.first_text_mut() {
{
shaped.prepend_hyphen(engine, p.config.fallback); shaped.prepend_hyphen(engine, p.config.fallback);
} }
}
// Add a hyphen at the line end, if we ended on a soft hyphen. // Add a hyphen at the line end, if we ended on a soft hyphen.
if dash == Some(Dash::Soft) if dash == Some(Dash::Soft) {
&& let Some(shaped) = items.last_text_mut() if let Some(shaped) = items.last_text_mut() {
{
shaped.push_hyphen(engine, p.config.fallback); shaped.push_hyphen(engine, p.config.fallback);
} }
}
// Deal with CJ characters at line boundaries. // Deal with CJ characters at line boundaries.
adjust_cj_at_line_boundaries(p, full, &mut items); adjust_cj_at_line_boundaries(p, full, &mut items);
@ -218,11 +218,11 @@ fn collect_items<'a>(
} }
// Add fallback text to expand the line height, if necessary. // Add fallback text to expand the line height, if necessary.
if !items.iter().any(|item| matches!(item, Item::Text(_))) if !items.iter().any(|item| matches!(item, Item::Text(_))) {
&& let Some(fallback) = fallback if let Some(fallback) = fallback {
{
items.push(fallback, usize::MAX); items.push(fallback, usize::MAX);
} }
}
items items
} }
@ -461,9 +461,9 @@ pub fn commit(
} }
// Handle hanging punctuation to the left. // Handle hanging punctuation to the left.
if let Some(Item::Text(text)) = line.items.first() if let Some(Item::Text(text)) = line.items.first() {
&& let Some(glyph) = text.glyphs.first() if let Some(glyph) = text.glyphs.first() {
&& !text.dir.is_positive() if !text.dir.is_positive()
&& text.styles.get(TextElem::overhang) && text.styles.get(TextElem::overhang)
&& (line.items.len() > 1 || text.glyphs.len() > 1) && (line.items.len() > 1 || text.glyphs.len() > 1)
{ {
@ -471,17 +471,21 @@ pub fn commit(
offset -= amount; offset -= amount;
remaining += amount; remaining += amount;
} }
}
}
// Handle hanging punctuation to the right. // Handle hanging punctuation to the right.
if let Some(Item::Text(text)) = line.items.last() if let Some(Item::Text(text)) = line.items.last() {
&& let Some(glyph) = text.glyphs.last() if let Some(glyph) = text.glyphs.last() {
&& text.dir.is_positive() if text.dir.is_positive()
&& text.styles.get(TextElem::overhang) && text.styles.get(TextElem::overhang)
&& (line.items.len() > 1 || text.glyphs.len() > 1) && (line.items.len() > 1 || text.glyphs.len() > 1)
{ {
let amount = overhang(glyph.c) * glyph.x_advance.at(glyph.size); let amount = overhang(glyph.c) * glyph.x_advance.at(glyph.size);
remaining += amount; remaining += amount;
} }
}
}
// Determine how much additional space is needed. The justification_ratio is // Determine how much additional space is needed. The justification_ratio is
// for the first step justification, extra_justification is for the last // for the first step justification, extra_justification is for the last

View File

@ -2,8 +2,8 @@ use std::ops::{Add, Sub};
use std::sync::LazyLock; use std::sync::LazyLock;
use az::SaturatingAs; use az::SaturatingAs;
use icu_properties::LineBreak;
use icu_properties::maps::{CodePointMapData, CodePointMapDataBorrowed}; use icu_properties::maps::{CodePointMapData, CodePointMapDataBorrowed};
use icu_properties::LineBreak;
use icu_provider::AsDeserializingBufferProvider; use icu_provider::AsDeserializingBufferProvider;
use icu_provider_adapters::fork::ForkByKeyProvider; use icu_provider_adapters::fork::ForkByKeyProvider;
use icu_provider_blob::BlobDataProvider; use icu_provider_blob::BlobDataProvider;
@ -11,7 +11,7 @@ use icu_segmenter::LineSegmenter;
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::layout::{Abs, Em}; use typst_library::layout::{Abs, Em};
use typst_library::model::Linebreaks; use typst_library::model::Linebreaks;
use typst_library::text::{Lang, TextElem, is_default_ignorable}; use typst_library::text::{is_default_ignorable, Lang, TextElem};
use typst_syntax::link_prefix; use typst_syntax::link_prefix;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
@ -136,13 +136,13 @@ fn linebreak_simple<'a>(
// If the line doesn't fit anymore, we push the last fitting attempt // If the line doesn't fit anymore, we push the last fitting attempt
// into the stack and rebuild the line from the attempt's end. The // into the stack and rebuild the line from the attempt's end. The
// resulting line cannot be broken up further. // resulting line cannot be broken up further.
if !width.fits(attempt.width) if !width.fits(attempt.width) {
&& let Some((last_attempt, last_end)) = last.take() if let Some((last_attempt, last_end)) = last.take() {
{
lines.push(last_attempt); lines.push(last_attempt);
start = last_end; start = last_end;
attempt = line(engine, p, start..end, breakpoint, lines.last()); attempt = line(engine, p, start..end, breakpoint, lines.last());
} }
}
// Finish the current line if there is a mandatory line break (i.e. due // Finish the current line if there is a mandatory line break (i.e. due
// to "\n") or if the line doesn't fit horizontally already since then // to "\n") or if the line doesn't fit horizontally already since then
@ -894,7 +894,11 @@ impl CostMetrics {
/// we allow less because otherwise we get an invalid layout fairly often, /// we allow less because otherwise we get an invalid layout fairly often,
/// which makes our bound useless. /// which makes our bound useless.
fn min_ratio(&self, approx: bool) -> f64 { fn min_ratio(&self, approx: bool) -> f64 {
if approx { self.min_approx_ratio } else { self.min_ratio } if approx {
self.min_approx_ratio
} else {
self.min_ratio
}
} }
} }

View File

@ -12,7 +12,6 @@ pub use self::box_::layout_box;
pub use self::shaping::create_shape_plan; pub use self::shaping::create_shape_plan;
use comemo::{Track, Tracked, TrackedMut}; use comemo::{Track, Tracked, TrackedMut};
use typst_library::World;
use typst_library::diag::SourceResult; use typst_library::diag::SourceResult;
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Packed, Smart, StyleChain}; use typst_library::foundations::{Packed, Smart, StyleChain};
@ -24,17 +23,18 @@ use typst_library::model::{
}; };
use typst_library::routines::{Arenas, Pair, RealizationKind, Routines}; use typst_library::routines::{Arenas, Pair, RealizationKind, Routines};
use typst_library::text::{Costs, Lang, TextElem}; use typst_library::text::{Costs, Lang, TextElem};
use typst_library::World;
use typst_utils::{Numeric, SliceExt}; use typst_utils::{Numeric, SliceExt};
use self::collect::{Item, Segment, SpanMapper, collect}; use self::collect::{collect, Item, Segment, SpanMapper};
use self::deco::decorate; use self::deco::decorate;
use self::finalize::finalize; use self::finalize::finalize;
use self::line::{Line, apply_shift, commit, line}; use self::line::{apply_shift, commit, line, Line};
use self::linebreak::{Breakpoint, linebreak}; use self::linebreak::{linebreak, Breakpoint};
use self::prepare::{Preparation, prepare}; use self::prepare::{prepare, Preparation};
use self::shaping::{ use self::shaping::{
BEGIN_PUNCT_PAT, END_PUNCT_PAT, ShapedGlyph, ShapedText, cjk_punct_style, cjk_punct_style, is_of_cj_script, shape_range, ShapedGlyph, ShapedText,
is_of_cj_script, shape_range, BEGIN_PUNCT_PAT, END_PUNCT_PAT,
}; };
/// Range of a substring of text. /// Range of a substring of text.
@ -190,7 +190,11 @@ fn configuration(
Config { Config {
justify, justify,
linebreaks: base.linebreaks.unwrap_or_else(|| { linebreaks: base.linebreaks.unwrap_or_else(|| {
if justify { Linebreaks::Optimized } else { Linebreaks::Simple } if justify {
Linebreaks::Optimized
} else {
Linebreaks::Simple
}
}), }),
first_line_indent: { first_line_indent: {
let FirstLineIndent { amount, all } = base.first_line_indent; let FirstLineIndent { amount, all } = base.first_line_indent;

View File

@ -4,21 +4,21 @@ use std::sync::Arc;
use az::SaturatingAs; use az::SaturatingAs;
use rustybuzz::{BufferFlags, Feature, ShapePlan, UnicodeBuffer}; use rustybuzz::{BufferFlags, Feature, ShapePlan, UnicodeBuffer};
use ttf_parser::Tag;
use ttf_parser::gsub::SubstitutionSubtable; use ttf_parser::gsub::SubstitutionSubtable;
use typst_library::World; use ttf_parser::Tag;
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Smart, StyleChain}; use typst_library::foundations::{Smart, StyleChain};
use typst_library::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size}; use typst_library::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size};
use typst_library::text::{ use typst_library::text::{
Font, FontFamily, FontVariant, Glyph, Lang, Region, ShiftSettings, TextEdgeBounds, families, features, is_default_ignorable, language, variant, Font, FontFamily,
TextElem, TextItem, families, features, is_default_ignorable, language, variant, FontVariant, Glyph, Lang, Region, ShiftSettings, TextEdgeBounds, TextElem, TextItem,
}; };
use typst_library::World;
use typst_utils::SliceExt; use typst_utils::SliceExt;
use unicode_bidi::{BidiInfo, Level as BidiLevel}; use unicode_bidi::{BidiInfo, Level as BidiLevel};
use unicode_script::{Script, UnicodeScript}; use unicode_script::{Script, UnicodeScript};
use super::{Item, Range, SpanMapper, decorate}; use super::{decorate, Item, Range, SpanMapper};
use crate::modifiers::FrameModifyText; use crate::modifiers::FrameModifyText;
/// The result of shaping text. /// The result of shaping text.
@ -539,7 +539,11 @@ impl<'a> ShapedText<'a> {
// Find any glyph with the text index. // Find any glyph with the text index.
let found = self.glyphs.binary_search_by(|g: &ShapedGlyph| { let found = self.glyphs.binary_search_by(|g: &ShapedGlyph| {
let ordering = g.range.start.cmp(&text_index); let ordering = g.range.start.cmp(&text_index);
if ltr { ordering } else { ordering.reverse() } if ltr {
ordering
} else {
ordering.reverse()
}
}); });
let mut idx = match found { let mut idx = match found {

View File

@ -25,7 +25,11 @@ pub fn layout_list(
let body_indent = elem.body_indent.get(styles); let body_indent = elem.body_indent.get(styles);
let tight = elem.tight.get(styles); let tight = elem.tight.get(styles);
let gutter = elem.spacing.get(styles).unwrap_or_else(|| { let gutter = elem.spacing.get(styles).unwrap_or_else(|| {
if tight { styles.get(ParElem::leading) } else { styles.get(ParElem::spacing) } if tight {
styles.get(ParElem::leading)
} else {
styles.get(ParElem::spacing)
}
}); });
let Depth(depth) = styles.get(ListElem::depth); let Depth(depth) = styles.get(ListElem::depth);
@ -89,15 +93,22 @@ pub fn layout_enum(
let body_indent = elem.body_indent.get(styles); let body_indent = elem.body_indent.get(styles);
let tight = elem.tight.get(styles); let tight = elem.tight.get(styles);
let gutter = elem.spacing.get(styles).unwrap_or_else(|| { let gutter = elem.spacing.get(styles).unwrap_or_else(|| {
if tight { styles.get(ParElem::leading) } else { styles.get(ParElem::spacing) } if tight {
styles.get(ParElem::leading)
} else {
styles.get(ParElem::spacing)
}
}); });
let mut cells = vec![]; let mut cells = vec![];
let mut locator = locator.split(); let mut locator = locator.split();
let mut number = elem let mut number = elem.start.get(styles).unwrap_or_else(|| {
.start if reversed {
.get(styles) elem.children.len() as u64
.unwrap_or_else(|| if reversed { elem.children.len() as u64 } else { 1 }); } else {
1
}
});
let mut parents = styles.get_cloned(EnumElem::parents); let mut parents = styles.get_cloned(EnumElem::parents);
let full = elem.full.get(styles); let full = elem.full.get(styles);

View File

@ -4,8 +4,8 @@ use typst_library::layout::{Em, Frame, Point, Size};
use typst_library::math::AccentElem; use typst_library::math::AccentElem;
use super::{ use super::{
FrameFragment, GlyphFragment, MathContext, MathFragment, style_cramped, style_dtls, style_cramped, style_dtls, style_flac, FrameFragment, GlyphFragment, MathContext,
style_flac, MathFragment,
}; };
/// How much the accent can be shorter than the base. /// How much the accent can be shorter than the base.

View File

@ -7,8 +7,8 @@ use typst_library::math::{
use typst_utils::OptionExt; use typst_utils::OptionExt;
use super::{ use super::{
FrameFragment, Limits, MathContext, MathFragment, stretch_fragment, stretch_fragment, style_for_subscript, style_for_superscript, FrameFragment, Limits,
style_for_subscript, style_for_superscript, MathContext, MathFragment,
}; };
macro_rules! measure { macro_rules! measure {

View File

@ -7,8 +7,8 @@ use typst_library::visualize::{FixedStroke, Geometry};
use typst_syntax::Span; use typst_syntax::Span;
use super::{ use super::{
DELIM_SHORT_FALL, FrameFragment, GlyphFragment, MathContext, style_for_denominator, style_for_denominator, style_for_numerator, FrameFragment, GlyphFragment,
style_for_numerator, MathContext, DELIM_SHORT_FALL,
}; };
const FRAC_AROUND: Em = Em::new(0.1); const FRAC_AROUND: Em = Em::new(0.1);

View File

@ -2,18 +2,18 @@ use std::fmt::{self, Debug, Formatter};
use az::SaturatingAs; use az::SaturatingAs;
use rustybuzz::{BufferFlags, UnicodeBuffer}; use rustybuzz::{BufferFlags, UnicodeBuffer};
use ttf_parser::GlyphId;
use ttf_parser::math::{GlyphAssembly, GlyphConstruction, GlyphPart}; use ttf_parser::math::{GlyphAssembly, GlyphConstruction, GlyphPart};
use typst_library::diag::{SourceResult, bail, warning}; use ttf_parser::GlyphId;
use typst_library::diag::{bail, warning, SourceResult};
use typst_library::foundations::StyleChain; use typst_library::foundations::StyleChain;
use typst_library::introspection::Tag; use typst_library::introspection::Tag;
use typst_library::layout::{ use typst_library::layout::{
Abs, Axes, Axis, Corner, Em, Frame, FrameItem, Point, Size, VAlignment, Abs, Axes, Axis, Corner, Em, Frame, FrameItem, Point, Size, VAlignment,
}; };
use typst_library::math::{EquationElem, MathSize}; use typst_library::math::{EquationElem, MathSize};
use typst_library::text::{Font, Glyph, TextElem, TextItem, features, language}; use typst_library::text::{features, language, Font, Glyph, TextElem, TextItem};
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::{Get, default_math_class}; use typst_utils::{default_math_class, Get};
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use super::MathContext; use super::MathContext;
@ -681,11 +681,7 @@ fn min_connector_overlap(font: &Font) -> Option<Em> {
.map(|variants| font.to_em(variants.min_connector_overlap)) .map(|variants| font.to_em(variants.min_connector_overlap))
} }
fn glyph_construction( fn glyph_construction(font: &Font, id: GlyphId, axis: Axis) -> Option<GlyphConstruction> {
font: &Font,
id: GlyphId,
axis: Axis,
) -> Option<GlyphConstruction<'_>> {
font.ttf() font.ttf()
.tables() .tables()
.math? .math?
@ -814,10 +810,7 @@ fn assemble(
/// Return an iterator over the assembly's parts with extenders repeated the /// Return an iterator over the assembly's parts with extenders repeated the
/// specified number of times. /// specified number of times.
fn parts( fn parts(assembly: GlyphAssembly, repeat: usize) -> impl Iterator<Item = GlyphPart> + '_ {
assembly: GlyphAssembly<'_>,
repeat: usize,
) -> impl Iterator<Item = GlyphPart> + '_ {
assembly.parts.into_iter().flat_map(move |part| { assembly.parts.into_iter().flat_map(move |part| {
let count = if part.part_flags.extender() { repeat } else { 1 }; let count = if part.part_flags.extender() { repeat } else { 1 };
std::iter::repeat_n(part, count) std::iter::repeat_n(part, count)

View File

@ -5,7 +5,7 @@ use typst_library::math::{EquationElem, LrElem, MidElem};
use typst_utils::SliceExt; use typst_utils::SliceExt;
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use super::{DELIM_SHORT_FALL, MathContext, MathFragment, stretch_fragment}; use super::{stretch_fragment, MathContext, MathFragment, DELIM_SHORT_FALL};
/// Lays out an [`LrElem`]. /// Lays out an [`LrElem`].
#[typst_macros::time(name = "math.lr", span = elem.span())] #[typst_macros::time(name = "math.lr", span = elem.span())]
@ -21,11 +21,11 @@ pub fn layout_lr(
} }
// Extract implicit LrElem. // Extract implicit LrElem.
if let Some(lr) = body.to_packed::<LrElem>() if let Some(lr) = body.to_packed::<LrElem>() {
&& lr.size.get(styles).is_one() if lr.size.get(styles).is_one() {
{
body = &lr.body; body = &lr.body;
} }
}
let mut fragments = ctx.layout_into_fragments(body, styles)?; let mut fragments = ctx.layout_into_fragments(body, styles)?;
@ -55,13 +55,13 @@ pub fn layout_lr(
// Handle MathFragment::Glyph fragments that should be scaled up. // Handle MathFragment::Glyph fragments that should be scaled up.
for fragment in inner_fragments.iter_mut() { for fragment in inner_fragments.iter_mut() {
if let MathFragment::Glyph(glyph) = fragment if let MathFragment::Glyph(ref mut glyph) = fragment {
&& glyph.mid_stretched == Some(false) if glyph.mid_stretched == Some(false) {
{
glyph.mid_stretched = Some(true); glyph.mid_stretched = Some(true);
scale(ctx, fragment, relative_to, height); scale(ctx, fragment, relative_to, height);
} }
} }
}
// Remove weak SpacingFragment immediately after the opening or immediately // Remove weak SpacingFragment immediately after the opening or immediately
// before the closing. // before the closing.
@ -95,7 +95,7 @@ pub fn layout_mid(
let mut fragments = ctx.layout_into_fragments(&elem.body, styles)?; let mut fragments = ctx.layout_into_fragments(&elem.body, styles)?;
for fragment in &mut fragments { for fragment in &mut fragments {
if let MathFragment::Glyph(glyph) = fragment { if let MathFragment::Glyph(ref mut glyph) = fragment {
glyph.mid_stretched = Some(false); glyph.mid_stretched = Some(false);
glyph.class = MathClass::Relation; glyph.class = MathClass::Relation;
} }

View File

@ -1,4 +1,4 @@
use typst_library::diag::{SourceResult, bail, warning}; use typst_library::diag::{bail, warning, SourceResult};
use typst_library::foundations::{Content, Packed, Resolve, StyleChain}; use typst_library::foundations::{Content, Packed, Resolve, StyleChain};
use typst_library::layout::{ use typst_library::layout::{
Abs, Axes, Em, FixedAlignment, Frame, FrameItem, Point, Ratio, Rel, Size, Abs, Axes, Em, FixedAlignment, Frame, FrameItem, Point, Ratio, Rel, Size,
@ -9,8 +9,8 @@ use typst_library::visualize::{FillRule, FixedStroke, Geometry, LineCap, Shape};
use typst_syntax::Span; use typst_syntax::Span;
use super::{ use super::{
AlignmentResult, DELIM_SHORT_FALL, FrameFragment, GlyphFragment, LeftRightAlternator, alignments, style_for_denominator, AlignmentResult, FrameFragment, GlyphFragment,
MathContext, alignments, style_for_denominator, LeftRightAlternator, MathContext, DELIM_SHORT_FALL,
}; };
const VERTICAL_PADDING: Ratio = Ratio::new(0.1); const VERTICAL_PADDING: Ratio = Ratio::new(0.1);

View File

@ -13,8 +13,7 @@ mod stretch;
mod text; mod text;
mod underover; mod underover;
use typst_library::World; use typst_library::diag::{bail, SourceResult};
use typst_library::diag::{SourceResult, bail};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{ use typst_library::foundations::{
Content, NativeElement, Packed, Resolve, StyleChain, SymbolElem, Content, NativeElement, Packed, Resolve, StyleChain, SymbolElem,
@ -29,14 +28,15 @@ use typst_library::math::*;
use typst_library::model::ParElem; use typst_library::model::ParElem;
use typst_library::routines::{Arenas, RealizationKind}; use typst_library::routines::{Arenas, RealizationKind};
use typst_library::text::{ use typst_library::text::{
Font, LinebreakElem, SpaceElem, TextEdgeBounds, TextElem, families, variant, families, variant, Font, LinebreakElem, SpaceElem, TextEdgeBounds, TextElem,
}; };
use typst_library::World;
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::Numeric; use typst_utils::Numeric;
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use self::fragment::{ use self::fragment::{
FrameFragment, GlyphFragment, Limits, MathFragment, has_dtls_feat, stretch_axes, has_dtls_feat, stretch_axes, FrameFragment, GlyphFragment, Limits, MathFragment,
}; };
use self::run::{LeftRightAlternator, MathRun, MathRunFrameBuilder}; use self::run::{LeftRightAlternator, MathRun, MathRunFrameBuilder};
use self::shared::*; use self::shared::*;
@ -603,10 +603,13 @@ fn layout_h(
ctx: &mut MathContext, ctx: &mut MathContext,
styles: StyleChain, styles: StyleChain,
) -> SourceResult<()> { ) -> SourceResult<()> {
if let Spacing::Rel(rel) = elem.amount if let Spacing::Rel(rel) = elem.amount {
&& rel.rel.is_zero() if rel.rel.is_zero() {
{ ctx.push(MathFragment::Spacing(
ctx.push(MathFragment::Spacing(rel.abs.resolve(styles), elem.weak.get(styles))); rel.abs.resolve(styles),
elem.weak.get(styles),
));
}
} }
Ok(()) Ok(())
} }

View File

@ -5,7 +5,7 @@ use typst_library::math::{EquationElem, MathSize, RootElem};
use typst_library::text::TextElem; use typst_library::text::TextElem;
use typst_library::visualize::{FixedStroke, Geometry}; use typst_library::visualize::{FixedStroke, Geometry};
use super::{FrameFragment, GlyphFragment, MathContext, style_cramped}; use super::{style_cramped, FrameFragment, GlyphFragment, MathContext};
/// Lays out a [`RootElem`]. /// Lays out a [`RootElem`].
/// ///

View File

@ -2,11 +2,11 @@ use std::iter::once;
use typst_library::foundations::{Resolve, StyleChain}; use typst_library::foundations::{Resolve, StyleChain};
use typst_library::layout::{Abs, AlignElem, Em, Frame, InlineItem, Point, Size}; use typst_library::layout::{Abs, AlignElem, Em, Frame, InlineItem, Point, Size};
use typst_library::math::{EquationElem, MEDIUM, MathSize, THICK, THIN}; use typst_library::math::{EquationElem, MathSize, MEDIUM, THICK, THIN};
use typst_library::model::ParElem; use typst_library::model::ParElem;
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use super::{FrameFragment, MathFragment, alignments}; use super::{alignments, FrameFragment, MathFragment};
const TIGHT_LEADING: Em = Em::new(0.25); const TIGHT_LEADING: Em = Em::new(0.25);
@ -87,11 +87,11 @@ impl MathRun {
// Insert spacing between the last and this non-ignorant item. // Insert spacing between the last and this non-ignorant item.
if !fragment.is_ignorant() { if !fragment.is_ignorant() {
if let Some(i) = last if let Some(i) = last {
&& let Some(s) = spacing(&resolved[i], space.take(), &fragment) if let Some(s) = spacing(&resolved[i], space.take(), &fragment) {
{
resolved.insert(i + 1, s); resolved.insert(i + 1, s);
} }
}
last = Some(resolved.len()); last = Some(resolved.len());
} }
@ -123,11 +123,11 @@ impl MathRun {
1 + self.0.iter().filter(|f| matches!(f, MathFragment::Linebreak)).count(); 1 + self.0.iter().filter(|f| matches!(f, MathFragment::Linebreak)).count();
// A linebreak at the very end does not introduce an extra row. // A linebreak at the very end does not introduce an extra row.
if let Some(f) = self.0.last() if let Some(f) = self.0.last() {
&& matches!(f, MathFragment::Linebreak) if matches!(f, MathFragment::Linebreak) {
{
count -= 1 count -= 1
} }
}
count count
} }
@ -344,11 +344,11 @@ impl MathRun {
descent = Abs::zero(); descent = Abs::zero();
space_is_visible = true; space_is_visible = true;
if let Some(f_next) = iter.peek() if let Some(f_next) = iter.peek() {
&& !is_space(f_next) if !is_space(f_next) {
{
items.push(InlineItem::Space(Abs::zero(), true)); items.push(InlineItem::Space(Abs::zero(), true));
} }
}
} else { } else {
space_is_visible = false; space_is_visible = false;
} }

View File

@ -1,5 +1,5 @@
use ttf_parser::Tag;
use ttf_parser::math::MathValue; use ttf_parser::math::MathValue;
use ttf_parser::Tag;
use typst_library::foundations::{Style, StyleChain}; use typst_library::foundations::{Style, StyleChain};
use typst_library::layout::{Abs, Em, FixedAlignment, Frame, Point, Size}; use typst_library::layout::{Abs, Em, FixedAlignment, Frame, Point, Size};
use typst_library::math::{EquationElem, MathSize}; use typst_library::math::{EquationElem, MathSize};

View File

@ -1,10 +1,10 @@
use typst_library::diag::{SourceResult, warning}; use typst_library::diag::{warning, SourceResult};
use typst_library::foundations::{Packed, StyleChain}; use typst_library::foundations::{Packed, StyleChain};
use typst_library::layout::{Abs, Axis, Rel}; use typst_library::layout::{Abs, Axis, Rel};
use typst_library::math::StretchElem; use typst_library::math::StretchElem;
use typst_utils::Get; use typst_utils::Get;
use super::{MathContext, MathFragment, stretch_axes}; use super::{stretch_axes, MathContext, MathFragment};
/// Lays out a [`StretchElem`]. /// Lays out a [`StretchElem`].
#[typst_macros::time(name = "math.stretch", span = elem.span())] #[typst_macros::time(name = "math.stretch", span = elem.span())]
@ -37,7 +37,7 @@ pub fn stretch_fragment(
) { ) {
let size = fragment.size(); let size = fragment.size();
let MathFragment::Glyph(glyph) = fragment else { return }; let MathFragment::Glyph(ref mut glyph) = fragment else { return };
// Return if we attempt to stretch along an axis which isn't stretchable, // Return if we attempt to stretch along an axis which isn't stretchable,
// so that the original fragment isn't modified. // so that the original fragment isn't modified.

View File

@ -1,6 +1,6 @@
use std::f64::consts::SQRT_2; use std::f64::consts::SQRT_2;
use codex::styling::{MathStyle, to_style}; use codex::styling::{to_style, MathStyle};
use ecow::EcoString; use ecow::EcoString;
use typst_library::diag::SourceResult; use typst_library::diag::SourceResult;
use typst_library::foundations::{Packed, StyleChain, SymbolElem}; use typst_library::foundations::{Packed, StyleChain, SymbolElem};
@ -9,13 +9,13 @@ use typst_library::math::{EquationElem, MathSize};
use typst_library::text::{ use typst_library::text::{
BottomEdge, BottomEdgeMetric, TextElem, TopEdge, TopEdgeMetric, BottomEdge, BottomEdgeMetric, TextElem, TopEdge, TopEdgeMetric,
}; };
use typst_syntax::{Span, is_newline}; use typst_syntax::{is_newline, Span};
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use super::{ use super::{
FrameFragment, GlyphFragment, MathContext, MathFragment, MathRun, has_dtls_feat, has_dtls_feat, style_dtls, FrameFragment, GlyphFragment, MathContext, MathFragment,
style_dtls, MathRun,
}; };
/// Lays out a [`TextElem`]. /// Lays out a [`TextElem`].

View File

@ -10,8 +10,8 @@ use typst_library::visualize::{FixedStroke, Geometry};
use typst_syntax::Span; use typst_syntax::Span;
use super::{ use super::{
FrameFragment, GlyphFragment, LeftRightAlternator, MathContext, MathRun, stack, stack, style_cramped, style_for_subscript, style_for_superscript, FrameFragment,
style_cramped, style_for_subscript, style_for_superscript, GlyphFragment, LeftRightAlternator, MathContext, MathRun,
}; };
const BRACE_GAP: Em = Em::new(0.25); const BRACE_GAP: Em = Em::new(0.25);

View File

@ -7,7 +7,6 @@ mod run;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use comemo::{Tracked, TrackedMut}; use comemo::{Tracked, TrackedMut};
use typst_library::World;
use typst_library::diag::SourceResult; use typst_library::diag::SourceResult;
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Content, StyleChain}; use typst_library::foundations::{Content, StyleChain};
@ -17,10 +16,11 @@ use typst_library::introspection::{
use typst_library::layout::{FrameItem, Page, PagedDocument, Point, Transform}; use typst_library::layout::{FrameItem, Page, PagedDocument, Point, Transform};
use typst_library::model::DocumentInfo; use typst_library::model::DocumentInfo;
use typst_library::routines::{Arenas, Pair, RealizationKind, Routines}; use typst_library::routines::{Arenas, Pair, RealizationKind, Routines};
use typst_library::World;
use self::collect::{Item, collect}; use self::collect::{collect, Item};
use self::finalize::finalize; use self::finalize::finalize;
use self::run::{LayoutedPage, layout_blank_page, layout_page_run}; use self::run::{layout_blank_page, layout_page_run, LayoutedPage};
/// Layout content into a document. /// Layout content into a document.
/// ///

View File

@ -1,5 +1,4 @@
use comemo::{Track, Tracked, TrackedMut}; use comemo::{Track, Tracked, TrackedMut};
use typst_library::World;
use typst_library::diag::SourceResult; use typst_library::diag::SourceResult;
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{ use typst_library::foundations::{
@ -18,9 +17,10 @@ use typst_library::pdf::ArtifactKind;
use typst_library::routines::{Pair, Routines}; use typst_library::routines::{Pair, Routines};
use typst_library::text::{LocalName, TextElem}; use typst_library::text::{LocalName, TextElem};
use typst_library::visualize::Paint; use typst_library::visualize::Paint;
use typst_library::World;
use typst_utils::Numeric; use typst_utils::Numeric;
use crate::flow::{FlowMode, layout_flow}; use crate::flow::{layout_flow, FlowMode};
/// A mostly finished layout for one page. Needs only knowledge of its exact /// A mostly finished layout for one page. Needs only knowledge of its exact
/// page number to be finalized into a `Page`. (Because the margins can depend /// page number to be finalized into a `Page`. (Because the margins can depend

View File

@ -1,4 +1,4 @@
use typst_library::diag::{SourceResult, bail}; use typst_library::diag::{bail, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Packed, Resolve, StyleChain}; use typst_library::foundations::{Packed, Resolve, StyleChain};
use typst_library::introspection::Locator; use typst_library::introspection::Locator;

View File

@ -1,11 +1,12 @@
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use comemo::Track; use comemo::Track;
use ecow::{EcoVec, eco_format}; use ecow::{eco_format, EcoVec};
use smallvec::smallvec; use smallvec::smallvec;
use typst_library::diag::{At, SourceResult, bail}; use typst_library::diag::{bail, At, SourceResult};
use typst_library::foundations::{ use typst_library::foundations::{
dict, Content, Context, LinkMarker, NativeElement, NativeRuleMap, Packed, Resolve, ShowFn, Smart, StyleChain, Target dict, Content, Context, LinkMarker, NativeElement, NativeRuleMap, Packed, Resolve,
ShowFn, Smart, StyleChain, Target,
}; };
use typst_library::introspection::{Counter, Locator, LocatorLink}; use typst_library::introspection::{Counter, Locator, LocatorLink};
use typst_library::layout::{ use typst_library::layout::{
@ -163,7 +164,11 @@ const TERMS_RULE: ShowFn<TermsElem> = |elem, _, styles| {
let indent = elem.indent.get(styles); let indent = elem.indent.get(styles);
let hanging_indent = elem.hanging_indent.get(styles); let hanging_indent = elem.hanging_indent.get(styles);
let gutter = elem.spacing.get(styles).unwrap_or_else(|| { let gutter = elem.spacing.get(styles).unwrap_or_else(|| {
if tight { styles.get(ParElem::leading) } else { styles.get(ParElem::spacing) } if tight {
styles.get(ParElem::leading)
} else {
styles.get(ParElem::spacing)
}
}); });
let pad = hanging_indent + indent; let pad = hanging_indent + indent;

View File

@ -1,7 +1,7 @@
use std::f64::consts::SQRT_2; use std::f64::consts::SQRT_2;
use kurbo::{CubicBez, ParamCurveExtrema}; use kurbo::{CubicBez, ParamCurveExtrema};
use typst_library::diag::{SourceResult, bail}; use typst_library::diag::{bail, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Content, Packed, Resolve, Smart, StyleChain}; use typst_library::foundations::{Content, Packed, Resolve, Smart, StyleChain};
use typst_library::introspection::Locator; use typst_library::introspection::Locator;

View File

@ -1,4 +1,4 @@
use typst_library::diag::{SourceResult, bail}; use typst_library::diag::{bail, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Content, Packed, Resolve, StyleChain, StyledElem}; use typst_library::foundations::{Content, Packed, Resolve, StyleChain, StyledElem};
use typst_library::introspection::{Locator, SplitLocator}; use typst_library::introspection::{Locator, SplitLocator};

View File

@ -1,6 +1,6 @@
use std::cell::LazyCell; use std::cell::LazyCell;
use typst_library::diag::{SourceResult, bail}; use typst_library::diag::{bail, SourceResult};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Content, Packed, Resolve, Smart, StyleChain}; use typst_library::foundations::{Content, Packed, Resolve, Smart, StyleChain};
use typst_library::introspection::Locator; use typst_library::introspection::Locator;

View File

@ -31,7 +31,6 @@ flate2 = { workspace = true }
fontdb = { workspace = true } fontdb = { workspace = true }
glidesort = { workspace = true } glidesort = { workspace = true }
hayagriva = { workspace = true } hayagriva = { workspace = true }
hayro-syntax = { workspace = true }
icu_properties = { workspace = true } icu_properties = { workspace = true }
icu_provider = { workspace = true } icu_provider = { workspace = true }
icu_provider_blob = { workspace = true } icu_provider_blob = { workspace = true }

View File

@ -8,7 +8,7 @@ use std::string::FromUtf8Error;
use az::SaturatingAs; use az::SaturatingAs;
use comemo::Tracked; use comemo::Tracked;
use ecow::{EcoVec, eco_vec}; use ecow::{eco_vec, EcoVec};
use typst_syntax::package::{PackageSpec, PackageVersion}; use typst_syntax::package::{PackageSpec, PackageVersion};
use typst_syntax::{Lines, Span, Spanned, SyntaxError}; use typst_syntax::{Lines, Span, Spanned, SyntaxError};
use utf8_iter::ErrorReportingUtf8Chars; use utf8_iter::ErrorReportingUtf8Chars;
@ -296,13 +296,14 @@ impl<T> Trace<T> for SourceResult<T> {
let Some(trace_range) = world.range(span) else { return errors }; let Some(trace_range) = world.range(span) else { return errors };
for error in errors.make_mut().iter_mut() { for error in errors.make_mut().iter_mut() {
// Skip traces that surround the error. // Skip traces that surround the error.
if let Some(error_range) = world.range(error.span) if let Some(error_range) = world.range(error.span) {
&& error.span.id() == span.id() if error.span.id() == span.id()
&& trace_range.start <= error_range.start && trace_range.start <= error_range.start
&& trace_range.end >= error_range.end && trace_range.end >= error_range.end
{ {
continue; continue;
} }
}
error.trace.push(Spanned::new(make_point(), span)); error.trace.push(Spanned::new(make_point(), span));
} }
@ -838,9 +839,7 @@ pub fn format_xml_like_error(format: &str, error: roxmltree::Error) -> LoadError
let pos = LineCol::one_based(error.pos().row as usize, error.pos().col as usize); let pos = LineCol::one_based(error.pos().row as usize, error.pos().col as usize);
let message = match error { let message = match error {
roxmltree::Error::UnexpectedCloseTag(expected, actual, _) => { roxmltree::Error::UnexpectedCloseTag(expected, actual, _) => {
eco_format!( eco_format!("failed to parse {format} (found closing tag '{actual}' instead of '{expected}')")
"failed to parse {format} (found closing tag '{actual}' instead of '{expected}')"
)
} }
roxmltree::Error::UnknownEntityReference(entity, _) => { roxmltree::Error::UnknownEntityReference(entity, _) => {
eco_format!("failed to parse {format} (unknown entity '{entity}')") eco_format!("failed to parse {format} (unknown entity '{entity}')")

View File

@ -8,11 +8,11 @@ use ecow::EcoVec;
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use typst_syntax::{FileId, Span}; use typst_syntax::{FileId, Span};
use crate::World; use crate::diag::{bail, HintedStrResult, SourceDiagnostic, SourceResult, StrResult};
use crate::diag::{HintedStrResult, SourceDiagnostic, SourceResult, StrResult, bail};
use crate::foundations::{Styles, Value}; use crate::foundations::{Styles, Value};
use crate::introspection::Introspector; use crate::introspection::Introspector;
use crate::routines::Routines; use crate::routines::Routines;
use crate::World;
/// Holds all data needed during compilation. /// Holds all data needed during compilation.
pub struct Engine<'a> { pub struct Engine<'a> {
@ -47,11 +47,7 @@ impl Engine<'_> {
} }
/// Runs tasks on the engine in parallel. /// Runs tasks on the engine in parallel.
pub fn parallelize<P, I, T, U, F>( pub fn parallelize<P, I, T, U, F>(&mut self, iter: P, f: F) -> impl Iterator<Item = U>
&mut self,
iter: P,
f: F,
) -> impl Iterator<Item = U> + use<P, I, T, U, F>
where where
P: IntoIterator<IntoIter = I>, P: IntoIterator<IntoIter = I>,
I: Iterator<Item = T>, I: Iterator<Item = T>,
@ -115,7 +111,11 @@ impl Traced {
/// We hide the span if it isn't in the given file so that only results for /// We hide the span if it isn't in the given file so that only results for
/// the file with the traced span are invalidated. /// the file with the traced span are invalidated.
pub fn get(&self, id: FileId) -> Option<Span> { pub fn get(&self, id: FileId) -> Option<Span> {
if self.0.and_then(Span::id) == Some(id) { self.0 } else { None } if self.0.and_then(Span::id) == Some(id) {
self.0
} else {
None
}
} }
} }

View File

@ -1,12 +1,12 @@
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::ops::Add; use std::ops::Add;
use ecow::{EcoString, EcoVec, eco_format, eco_vec}; use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use typst_syntax::{Span, Spanned}; use typst_syntax::{Span, Spanned};
use crate::diag::{At, SourceDiagnostic, SourceResult, StrResult, bail, error}; use crate::diag::{bail, error, At, SourceDiagnostic, SourceResult, StrResult};
use crate::foundations::{ use crate::foundations::{
Array, Dict, FromValue, IntoValue, Repr, Str, Value, cast, func, repr, scope, ty, cast, func, repr, scope, ty, Array, Dict, FromValue, IntoValue, Repr, Str, Value,
}; };
/// Captured arguments to a function. /// Captured arguments to a function.

View File

@ -4,16 +4,16 @@ use std::num::{NonZeroI64, NonZeroUsize};
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use comemo::Tracked; use comemo::Tracked;
use ecow::{EcoString, EcoVec, eco_format}; use ecow::{eco_format, EcoString, EcoVec};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smallvec::SmallVec; use smallvec::SmallVec;
use typst_syntax::{Span, Spanned}; use typst_syntax::{Span, Spanned};
use crate::diag::{At, HintedStrResult, SourceDiagnostic, SourceResult, StrResult, bail}; use crate::diag::{bail, At, HintedStrResult, SourceDiagnostic, SourceResult, StrResult};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
Args, Bytes, CastInfo, Context, Dict, FromValue, Func, IntoValue, Reflect, Repr, Str, cast, func, ops, repr, scope, ty, Args, Bytes, CastInfo, Context, Dict, FromValue,
Value, Version, cast, func, ops, repr, scope, ty, Func, IntoValue, Reflect, Repr, Str, Value, Version,
}; };
/// Create a new [`Array`] from values. /// Create a new [`Array`] from values.

View File

@ -4,8 +4,8 @@ use ecow::EcoString;
use crate::diag::HintedStrResult; use crate::diag::HintedStrResult;
use crate::foundations::{ use crate::foundations::{
CastInfo, Fold, FromValue, IntoValue, Reflect, Repr, Resolve, StyleChain, Type, ty, CastInfo, Fold, FromValue, IntoValue, Reflect, Repr, Resolve, StyleChain, Type,
Value, ty, Value,
}; };
/// A value that indicates a smart default. /// A value that indicates a smart default.

View File

@ -1,6 +1,6 @@
use ecow::EcoString; use ecow::EcoString;
use crate::foundations::{Repr, ty}; use crate::foundations::{ty, Repr};
/// A type with two states. /// A type with two states.
/// ///

View File

@ -5,13 +5,13 @@ use std::ops::{Add, AddAssign, Deref};
use std::str::Utf8Error; use std::str::Utf8Error;
use std::sync::Arc; use std::sync::Arc;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use typst_syntax::Lines; use typst_syntax::Lines;
use typst_utils::LazyHash; use typst_utils::LazyHash;
use crate::diag::{StrResult, bail}; use crate::diag::{bail, StrResult};
use crate::foundations::{Array, Reflect, Repr, Str, Value, cast, func, scope, ty}; use crate::foundations::{cast, func, scope, ty, Array, Reflect, Repr, Str, Value};
/// A sequence of bytes. /// A sequence of bytes.
/// ///

View File

@ -7,8 +7,8 @@ use az::SaturatingAs;
use typst_syntax::{Span, Spanned}; use typst_syntax::{Span, Spanned};
use typst_utils::{round_int_with_precision, round_with_precision}; use typst_utils::{round_int_with_precision, round_with_precision};
use crate::diag::{At, HintedString, SourceResult, StrResult, bail}; use crate::diag::{bail, At, HintedString, SourceResult, StrResult};
use crate::foundations::{Decimal, IntoValue, Module, Scope, Value, cast, func, ops}; use crate::foundations::{cast, func, ops, Decimal, IntoValue, Module, Scope, Value};
use crate::layout::{Angle, Fr, Length, Ratio}; use crate::layout::{Angle, Fr, Length, Ratio};
/// A module with calculation definitions. /// A module with calculation definitions.

View File

@ -14,7 +14,7 @@ use unicode_math_class::MathClass;
use crate::diag::{At, HintedStrResult, HintedString, SourceResult, StrResult}; use crate::diag::{At, HintedStrResult, HintedString, SourceResult, StrResult};
use crate::foundations::{ use crate::foundations::{
Fold, NativeElement, Packed, Repr, Str, Type, Value, array, repr, array, repr, Fold, NativeElement, Packed, Repr, Str, Type, Value,
}; };
/// Determine details of a type. /// Determine details of a type.
@ -347,15 +347,14 @@ impl CastInfo {
msg.hint(eco_format!("use `label({})` to create a label", s.repr())); msg.hint(eco_format!("use `label({})` to create a label", s.repr()));
} }
} }
} else if let Value::Decimal(_) = found } else if let Value::Decimal(_) = found {
&& !matching_type if !matching_type && parts.iter().any(|p| p == "float") {
&& parts.iter().any(|p| p == "float")
{
msg.hint(eco_format!( msg.hint(eco_format!(
"if loss of precision is acceptable, explicitly cast the \ "if loss of precision is acceptable, explicitly cast the \
decimal to a float with `float(value)`" decimal to a float with `float(value)`"
)); ));
} }
}
msg msg
} }

View File

@ -11,8 +11,8 @@ use typst_utils::Static;
use crate::diag::SourceResult; use crate::diag::SourceResult;
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
Args, Content, ContentVtable, FieldAccessError, Func, ParamInfo, Repr, Scope, cast, Args, Content, ContentVtable, FieldAccessError, Func, ParamInfo, Repr, Scope,
Selector, StyleChain, Styles, Value, cast, Selector, StyleChain, Styles, Value,
}; };
use crate::text::{Lang, Region}; use crate::text::{Lang, Region};

View File

@ -3,7 +3,7 @@ use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::OnceLock; use std::sync::OnceLock;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use crate::foundations::{ use crate::foundations::{
Container, Content, FieldVtable, Fold, FoldFn, IntoValue, NativeElement, Packed, Container, Content, FieldVtable, Fold, FoldFn, IntoValue, NativeElement, Packed,

View File

@ -17,17 +17,17 @@ use std::iter::{self, Sum};
use std::ops::{Add, AddAssign, ControlFlow}; use std::ops::{Add, AddAssign, ControlFlow};
use comemo::Tracked; use comemo::Tracked;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::singleton; use typst_utils::singleton;
use crate::diag::{SourceResult, StrResult, bail}; use crate::diag::{bail, SourceResult, StrResult};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
Args, Context, Dict, IntoValue, Label, Property, Recipe, RecipeIndex, Repr, Selector, func, repr, scope, ty, Args, Context, Dict, IntoValue, Label, Property, Recipe,
Str, Style, StyleChain, Styles, Value, func, repr, scope, ty, RecipeIndex, Repr, Selector, Str, Style, StyleChain, Styles, Value,
}; };
use crate::introspection::{Locatable, Location}; use crate::introspection::{Locatable, Location};
use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides}; use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides};
@ -175,11 +175,11 @@ impl Content {
id: u8, id: u8,
styles: Option<StyleChain>, styles: Option<StyleChain>,
) -> Result<Value, FieldAccessError> { ) -> Result<Value, FieldAccessError> {
if id == 255 if id == 255 {
&& let Some(label) = self.label() if let Some(label) = self.label() {
{
return Ok(label.into_value()); return Ok(label.into_value());
} }
}
match self.0.handle().field(id) { match self.0.handle().field(id) {
Some(handle) => match styles { Some(handle) => match styles {

View File

@ -5,7 +5,7 @@ use std::ptr::NonNull;
use std::sync::atomic::{self, AtomicUsize, Ordering}; use std::sync::atomic::{self, AtomicUsize, Ordering};
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::{HashLock, SmallBitSet, fat}; use typst_utils::{fat, HashLock, SmallBitSet};
use super::vtable; use super::vtable;
use crate::foundations::{Element, Label, NativeElement, Packed}; use crate::foundations::{Element, Label, NativeElement, Packed};

View File

@ -1,9 +1,9 @@
use comemo::Track; use comemo::Track;
use crate::diag::{Hint, HintedStrResult, SourceResult, bail}; use crate::diag::{bail, Hint, HintedStrResult, SourceResult};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
Args, Construct, Content, Func, ShowFn, StyleChain, Value, elem, elem, Args, Construct, Content, Func, ShowFn, StyleChain, Value,
}; };
use crate::introspection::{Locatable, Location}; use crate::introspection::{Locatable, Location};

View File

@ -2,17 +2,17 @@ use std::cmp::Ordering;
use std::hash::Hash; use std::hash::Hash;
use std::ops::{Add, Sub}; use std::ops::{Add, Sub};
use ecow::{EcoString, EcoVec, eco_format}; use ecow::{eco_format, EcoString, EcoVec};
use time::error::{Format, InvalidFormatDescription}; use time::error::{Format, InvalidFormatDescription};
use time::macros::format_description; use time::macros::format_description;
use time::{Month, PrimitiveDateTime, format_description}; use time::{format_description, Month, PrimitiveDateTime};
use crate::World; use crate::diag::{bail, StrResult};
use crate::diag::{StrResult, bail};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
Dict, Duration, Repr, Smart, Str, Value, cast, func, repr, scope, ty, cast, func, repr, scope, ty, Dict, Duration, Repr, Smart, Str, Value,
}; };
use crate::World;
/// Represents a date, a time, or a combination of both. /// Represents a date, a time, or a combination of both.
/// ///

View File

@ -3,14 +3,14 @@ use std::hash::{Hash, Hasher};
use std::ops::Neg; use std::ops::Neg;
use std::str::FromStr; use std::str::FromStr;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use rust_decimal::MathematicalOps; use rust_decimal::MathematicalOps;
use typst_syntax::{Span, Spanned, ast}; use typst_syntax::{ast, Span, Spanned};
use crate::World; use crate::diag::{warning, At, SourceResult};
use crate::diag::{At, SourceResult, warning};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{Repr, Str, cast, func, repr, scope, ty}; use crate::foundations::{cast, func, repr, scope, ty, Repr, Str};
use crate::World;
/// A fixed-point decimal number type. /// A fixed-point decimal number type.
/// ///

View File

@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use std::sync::Arc; use std::sync::Arc;
use ecow::{EcoString, eco_format}; use ecow::{eco_format, EcoString};
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use typst_syntax::is_ident; use typst_syntax::is_ident;
@ -11,7 +11,7 @@ use typst_utils::ArcExt;
use crate::diag::{Hint, HintedStrResult, StrResult}; use crate::diag::{Hint, HintedStrResult, StrResult};
use crate::foundations::{ use crate::foundations::{
Array, Module, Repr, Str, Value, array, cast, func, repr, scope, ty, array, cast, func, repr, scope, ty, Array, Module, Repr, Str, Value,
}; };
/// Create a new [`Dict`] from key-value pairs. /// Create a new [`Dict`] from key-value pairs.

Some files were not shown because too many files have changed in this diff Show More