From 7eebafa7837ec173a7b2064ae60fd45b5413d17c Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 23 Nov 2023 16:25:49 +0100 Subject: [PATCH] Merge `typst` and `typst-library` --- Cargo.lock | 61 +- Cargo.toml | 3 +- crates/typst-cli/Cargo.toml | 1 - crates/typst-cli/src/args.rs | 3 +- crates/typst-cli/src/compile.rs | 8 +- crates/typst-cli/src/fonts.rs | 4 +- crates/typst-cli/src/query.rs | 9 +- crates/typst-cli/src/tracing.rs | 5 +- crates/typst-cli/src/update.rs | 5 +- crates/typst-cli/src/watch.rs | 2 +- crates/typst-cli/src/world.rs | 11 +- crates/typst-docs/Cargo.toml | 1 - crates/typst-docs/src/contribs.rs | 2 +- crates/typst-docs/src/html.rs | 13 +- crates/typst-docs/src/lib.rs | 252 ++- crates/typst-docs/src/link.rs | 30 +- crates/typst-docs/src/model.rs | 6 +- crates/typst-ide/src/analyze.rs | 17 +- crates/typst-ide/src/complete.rs | 26 +- crates/typst-ide/src/jump.rs | 7 +- crates/typst-ide/src/lib.rs | 4 +- crates/typst-ide/src/tooltip.rs | 21 +- crates/typst-library/Cargo.toml | 53 - crates/typst-library/src/compute/data.rs | 609 ----- crates/typst-library/src/compute/mod.rs | 20 - crates/typst-library/src/layout/align.rs | 46 - crates/typst-library/src/lib.rs | 170 -- crates/typst-library/src/meta/mod.rs | 76 - crates/typst-library/src/prelude.rs | 42 - crates/typst-library/src/shared/ext.rs | 92 - crates/typst-library/src/shared/mod.rs | 7 - crates/typst-library/src/symbols/mod.rs | 17 - crates/typst-library/src/text/misc.rs | 315 --- crates/typst-library/src/visualize/shape.rs | 547 ----- crates/typst-macros/src/cast.rs | 59 +- crates/typst-macros/src/category.rs | 57 + crates/typst-macros/src/elem.rs | 234 +- crates/typst-macros/src/func.rs | 50 +- crates/typst-macros/src/lib.rs | 23 +- crates/typst-macros/src/scope.rs | 18 +- crates/typst-macros/src/symbols.rs | 11 +- crates/typst-macros/src/ty.rs | 30 +- crates/typst-macros/src/util.rs | 39 +- crates/typst-pdf/src/color.rs | 2 +- crates/typst-pdf/src/font.rs | 2 +- crates/typst-pdf/src/gradient.rs | 15 +- crates/typst-pdf/src/image.rs | 5 +- crates/typst-pdf/src/lib.rs | 12 +- crates/typst-pdf/src/outline.rs | 8 +- crates/typst-pdf/src/page.rs | 29 +- crates/typst-render/src/lib.rs | 32 +- crates/typst-svg/src/lib.rs | 32 +- crates/typst-syntax/src/reparser.rs | 2 +- crates/typst-syntax/src/span.rs | 4 +- crates/typst/Cargo.toml | 18 + .../assets/cj_linebreak_data.postcard | Bin .../assets/icudata.postcard | Bin .../assets/syntect.bin | Bin crates/typst/src/diag.rs | 29 +- crates/typst/src/eval/access.rs | 99 + crates/typst/src/eval/binding.rs | 179 ++ crates/typst/src/eval/call.rs | 587 +++++ crates/typst/src/eval/code.rs | 317 +++ crates/typst/src/eval/flow.rs | 227 ++ crates/typst/src/eval/import.rs | 227 ++ crates/typst/src/eval/library.rs | 179 -- crates/typst/src/eval/markup.rs | 272 +++ crates/typst/src/eval/math.rs | 113 + crates/typst/src/eval/mod.rs | 1986 +---------------- crates/typst/src/eval/ops.rs | 145 +- crates/typst/src/eval/rules.rs | 51 + crates/typst/src/eval/tracer.rs | 4 +- crates/typst/src/eval/vm.rs | 127 ++ .../typst/src/{eval => foundations}/args.rs | 2 +- .../typst/src/{eval => foundations}/array.rs | 22 +- .../typst/src/{eval => foundations}/auto.rs | 6 +- .../typst/src/{eval => foundations}/bool.rs | 2 +- .../typst/src/{eval => foundations}/bytes.rs | 2 +- .../compute => typst/src/foundations}/calc.rs | 19 +- .../typst/src/{eval => foundations}/cast.rs | 7 +- .../src/{model => foundations}/content.rs | 152 +- .../src/{eval => foundations}/datetime.rs | 65 +- .../typst/src/{eval => foundations}/dict.rs | 8 +- .../src/{eval => foundations}/duration.rs | 6 +- .../src/{model => foundations}/element.rs | 87 +- .../typst/src/{eval => foundations}/fields.rs | 7 +- .../typst/src/{eval => foundations}/float.rs | 4 +- .../typst/src/{eval => foundations}/func.rs | 368 +-- crates/typst/src/{eval => foundations}/int.rs | 2 +- .../typst/src/{model => foundations}/label.rs | 4 +- .../src/{eval => foundations}/methods.rs | 26 +- .../src/foundations/mod.rs} | 119 +- .../typst/src/{eval => foundations}/module.rs | 4 +- .../typst/src/{eval => foundations}/none.rs | 6 +- .../typst/src/{eval => foundations}/plugin.rs | 7 +- .../typst/src/{eval => foundations}/repr.rs | 29 + .../typst/src/{eval => foundations}/scope.rs | 75 +- .../src/{model => foundations}/selector.rs | 26 +- crates/typst/src/{eval => foundations}/str.rs | 12 +- .../src/{model => foundations}/styles.rs | 87 +- .../compute => typst/src/foundations}/sys.rs | 11 +- crates/typst/src/{eval => foundations}/ty.rs | 6 +- .../typst/src/{eval => foundations}/value.rs | 36 +- .../src/{eval => foundations}/version.rs | 2 +- crates/typst/src/geom/ellipse.rs | 22 - crates/typst/src/geom/mod.rs | 124 - crates/typst/src/geom/path.rs | 102 - crates/typst/src/geom/rect.rs | 599 ----- crates/typst/src/geom/shape.rs | 44 - crates/typst/src/geom/transform.rs | 126 -- crates/typst/src/image/mod.rs | 175 -- .../src/introspection}/counter.rs | 21 +- .../introspector.rs} | 128 +- crates/typst/src/introspection/locate.rs | 47 + .../src/{model => introspection}/location.rs | 11 +- crates/typst/src/introspection/locator.rs | 117 + .../src/introspection}/metadata.rs | 5 +- crates/typst/src/introspection/mod.rs | 109 + .../meta => typst/src/introspection}/query.rs | 4 +- .../meta => typst/src/introspection}/state.rs | 17 +- crates/typst/src/{geom => layout}/abs.rs | 11 +- crates/typst/src/{geom => layout}/align.rs | 60 +- crates/typst/src/{geom => layout}/angle.rs | 12 +- crates/typst/src/{geom => layout}/axes.rs | 8 +- .../src/layout/columns.rs | 9 +- .../src/layout/container.rs | 14 +- crates/typst/src/{geom => layout}/corners.rs | 10 +- crates/typst/src/{geom => layout}/dir.rs | 5 +- crates/typst/src/{geom => layout}/em.rs | 15 +- .../src/layout/flow.rs | 21 +- crates/typst/src/{geom => layout}/fr.rs | 12 +- .../src/layout/fragment.rs | 4 +- crates/typst/src/{doc.rs => layout/frame.rs} | 326 +-- .../src/layout/grid.rs | 16 +- .../src/layout/hide.rs | 5 +- .../src/layout/inline}/linebreak.rs | 15 +- .../par.rs => typst/src/layout/inline/mod.rs} | 362 +-- .../src/layout/inline}/shaping.rs | 161 +- .../context.rs => typst/src/layout/layout.rs} | 91 +- crates/typst/src/{geom => layout}/length.rs | 10 +- .../src/layout/measure.rs | 5 +- crates/typst/src/layout/mod.rs | 256 +++ .../src/layout/pad.rs | 6 +- .../src/layout/page.rs | 21 +- .../src/layout/place.rs | 8 +- crates/typst/src/{geom => layout}/point.rs | 6 +- crates/typst/src/{geom => layout}/ratio.rs | 10 +- .../src/layout/regions.rs | 2 +- crates/typst/src/{geom => layout}/rel.rs | 10 +- .../src/layout/repeat.rs | 8 +- crates/typst/src/{geom => layout}/sides.rs | 9 +- crates/typst/src/{geom => layout}/size.rs | 5 +- .../src/layout/spacing.rs | 4 +- .../src/layout/stack.rs | 11 +- .../src/layout/transform.rs | 134 +- crates/typst/src/layout/vt.rs | 43 + crates/typst/src/lib.rs | 242 +- crates/typst/src/loading/cbor.rs | 57 + crates/typst/src/loading/csv.rs | 118 + crates/typst/src/loading/json.rs | 94 + crates/typst/src/loading/mod.rs | 82 + crates/typst/src/loading/read.rs | 57 + crates/typst/src/loading/toml.rs | 90 + crates/typst/src/loading/xml.rs | 116 + crates/typst/src/loading/yaml.rs | 78 + .../src/math/accent.rs | 12 +- .../src/math/align.rs | 5 +- .../src/math/attach.rs | 10 +- .../src/math/cancel.rs | 12 +- .../src/math/class.rs | 6 +- .../{typst-library => typst}/src/math/ctx.rs | 76 +- .../mod.rs => typst/src/math/equation.rs} | 223 +- .../{typst-library => typst}/src/math/frac.rs | 11 +- .../src/math/fragment.rs | 67 +- .../{typst-library => typst}/src/math/lr.rs | 8 +- .../src/math/matrix.rs | 38 +- crates/typst/src/math/mod.rs | 311 +++ .../{typst-library => typst}/src/math/op.rs | 9 +- .../{typst-library => typst}/src/math/root.rs | 10 +- .../{typst-library => typst}/src/math/row.rs | 10 +- .../src/math/spacing.rs | 6 +- .../src/math/stretch.rs | 3 +- .../src/math/style.rs | 6 +- .../src/math/underover.rs | 13 +- .../meta => typst/src/model}/bibliography.rs | 58 +- .../src/meta => typst/src/model}/cite.rs | 13 +- .../src/meta => typst/src/model}/document.rs | 38 +- crates/typst/src/model/emph.rs | 41 + .../src/layout => typst/src/model}/enum.rs | 12 +- .../src/meta => typst/src/model}/figure.rs | 21 +- .../src/meta => typst/src/model}/footnote.rs | 18 +- .../src/meta => typst/src/model}/heading.rs | 18 +- .../src/meta => typst/src/model}/link.rs | 38 +- .../src/layout => typst/src/model}/list.rs | 12 +- crates/typst/src/model/mod.rs | 218 +- .../src/meta => typst/src/model}/numbering.rs | 12 +- .../src/meta => typst/src/model}/outline.rs | 27 +- crates/typst/src/model/par.rs | 180 ++ .../src/text => typst/src/model}/quote.rs | 15 +- crates/typst/src/model/realize.rs | 242 -- .../src/meta => typst/src/model}/reference.rs | 15 +- crates/typst/src/model/strong.rs | 48 + .../src/layout => typst/src/model}/table.rs | 17 +- .../src/layout => typst/src/model}/terms.rs | 11 +- .../shared => typst/src/realize}/behave.rs | 9 +- .../src/layout => typst/src/realize}/mod.rs | 400 ++-- .../src/symbols/emoji.rs | 3 +- crates/typst/src/symbols/mod.rs | 27 + .../src/symbols/sym.rs | 3 +- crates/typst/src/{eval => symbols}/symbol.rs | 10 +- crates/typst/src/text/case.rs | 79 + .../{typst-library => typst}/src/text/deco.rs | 20 +- crates/typst/src/{ => text}/font/book.rs | 2 +- crates/typst/src/{ => text}/font/mod.rs | 4 +- crates/typst/src/{ => text}/font/variant.rs | 6 +- crates/typst/src/text/item.rs | 63 + crates/typst/src/text/lang.rs | 182 ++ crates/typst/src/text/linebreak.rs | 43 + crates/typst/src/text/lorem.rs | 24 + .../{typst-library => typst}/src/text/mod.rs | 214 +- .../{typst-library => typst}/src/text/raw.rs | 44 +- .../src/text/shift.rs | 7 +- crates/typst/src/text/smallcaps.rs | 32 + .../src/text/smartquote.rs} | 48 +- crates/typst/src/text/space.rs | 26 + crates/typst/src/util/deferred.rs | 11 +- crates/typst/src/util/fat.rs | 55 + crates/typst/src/{geom => util}/macros.rs | 0 crates/typst/src/util/mod.rs | 63 +- crates/typst/src/util/pico.rs | 3 +- crates/typst/src/{geom => util}/scalar.rs | 54 +- crates/typst/src/{geom => visualize}/color.rs | 29 +- .../typst/src/{geom => visualize}/gradient.rs | 82 +- .../src/visualize/image/mod.rs} | 191 +- .../typst/src/{ => visualize}/image/raster.rs | 3 +- crates/typst/src/{ => visualize}/image/svg.rs | 6 +- .../src/visualize/line.rs | 11 +- .../src/visualize/mod.rs | 20 +- crates/typst/src/{geom => visualize}/paint.rs | 15 +- .../src/visualize/path.rs | 110 +- .../src/visualize/polygon.rs | 13 +- crates/typst/src/visualize/shape.rs | 1221 ++++++++++ .../typst/src/{geom => visualize}/stroke.rs | 15 +- docs/dev/architecture.md | 23 +- docs/reference/categories.yml | 178 -- docs/reference/groups.yml | 82 +- docs/reference/packages.md | 6 + tests/Cargo.toml | 1 - tests/src/benches.rs | 27 +- tests/src/tests.rs | 30 +- 250 files changed, 9566 insertions(+), 9027 deletions(-) delete mode 100644 crates/typst-library/Cargo.toml delete mode 100644 crates/typst-library/src/compute/data.rs delete mode 100644 crates/typst-library/src/compute/mod.rs delete mode 100644 crates/typst-library/src/layout/align.rs delete mode 100644 crates/typst-library/src/lib.rs delete mode 100644 crates/typst-library/src/meta/mod.rs delete mode 100644 crates/typst-library/src/prelude.rs delete mode 100644 crates/typst-library/src/shared/ext.rs delete mode 100644 crates/typst-library/src/shared/mod.rs delete mode 100644 crates/typst-library/src/symbols/mod.rs delete mode 100644 crates/typst-library/src/text/misc.rs delete mode 100644 crates/typst-library/src/visualize/shape.rs create mode 100644 crates/typst-macros/src/category.rs rename crates/{typst-library => typst}/assets/cj_linebreak_data.postcard (100%) rename crates/{typst-library => typst}/assets/icudata.postcard (100%) rename crates/{typst-library => typst}/assets/syntect.bin (100%) create mode 100644 crates/typst/src/eval/access.rs create mode 100644 crates/typst/src/eval/binding.rs create mode 100644 crates/typst/src/eval/call.rs create mode 100644 crates/typst/src/eval/code.rs create mode 100644 crates/typst/src/eval/flow.rs create mode 100644 crates/typst/src/eval/import.rs delete mode 100644 crates/typst/src/eval/library.rs create mode 100644 crates/typst/src/eval/markup.rs create mode 100644 crates/typst/src/eval/math.rs create mode 100644 crates/typst/src/eval/rules.rs create mode 100644 crates/typst/src/eval/vm.rs rename crates/typst/src/{eval => foundations}/args.rs (99%) rename crates/typst/src/{eval => foundations}/array.rs (97%) rename crates/typst/src/{eval => foundations}/auto.rs (97%) rename crates/typst/src/{eval => foundations}/bool.rs (92%) rename crates/typst/src/{eval => foundations}/bytes.rs (98%) rename crates/{typst-library/src/compute => typst/src/foundations}/calc.rs (98%) rename crates/typst/src/{eval => foundations}/cast.rs (99%) rename crates/typst/src/{model => foundations}/content.rs (87%) rename crates/typst/src/{eval => foundations}/datetime.rs (95%) rename crates/typst/src/{eval => foundations}/dict.rs (97%) rename crates/typst/src/{eval => foundations}/duration.rs (98%) rename crates/typst/src/{model => foundations}/element.rs (74%) rename crates/typst/src/{eval => foundations}/fields.rs (95%) rename crates/typst/src/{eval => foundations}/float.rs (94%) rename crates/typst/src/{eval => foundations}/func.rs (57%) rename crates/typst/src/{eval => foundations}/int.rs (98%) rename crates/typst/src/{model => foundations}/label.rs (96%) rename crates/typst/src/{eval => foundations}/methods.rs (92%) rename crates/{typst-library/src/compute/foundations.rs => typst/src/foundations/mod.rs} (74%) rename crates/typst/src/{eval => foundations}/module.rs (97%) rename crates/typst/src/{eval => foundations}/none.rs (95%) rename crates/typst/src/{eval => foundations}/plugin.rs (99%) rename crates/typst/src/{eval => foundations}/repr.rs (85%) rename crates/typst/src/{eval => foundations}/scope.rs (83%) rename crates/typst/src/{model => foundations}/selector.rs (95%) rename crates/typst/src/{eval => foundations}/str.rs (99%) rename crates/typst/src/{model => foundations}/styles.rs (90%) rename crates/{typst-library/src/compute => typst/src/foundations}/sys.rs (64%) rename crates/typst/src/{eval => foundations}/ty.rs (95%) rename crates/typst/src/{eval => foundations}/value.rs (95%) rename crates/typst/src/{eval => foundations}/version.rs (98%) delete mode 100644 crates/typst/src/geom/ellipse.rs delete mode 100644 crates/typst/src/geom/mod.rs delete mode 100644 crates/typst/src/geom/path.rs delete mode 100644 crates/typst/src/geom/rect.rs delete mode 100644 crates/typst/src/geom/shape.rs delete mode 100644 crates/typst/src/geom/transform.rs delete mode 100644 crates/typst/src/image/mod.rs rename crates/{typst-library/src/meta => typst/src/introspection}/counter.rs (97%) rename crates/typst/src/{model/introspect.rs => introspection/introspector.rs} (64%) create mode 100644 crates/typst/src/introspection/locate.rs rename crates/typst/src/{model => introspection}/location.rs (88%) create mode 100644 crates/typst/src/introspection/locator.rs rename crates/{typst-library/src/meta => typst/src/introspection}/metadata.rs (87%) create mode 100644 crates/typst/src/introspection/mod.rs rename crates/{typst-library/src/meta => typst/src/introspection}/query.rs (97%) rename crates/{typst-library/src/meta => typst/src/introspection}/state.rs (96%) rename crates/typst/src/{geom => layout}/abs.rs (95%) rename crates/typst/src/{geom => layout}/align.rs (87%) rename crates/typst/src/{geom => layout}/angle.rs (94%) rename crates/typst/src/{geom => layout}/axes.rs (96%) rename crates/{typst-library => typst}/src/layout/columns.rs (95%) rename crates/{typst-library => typst}/src/layout/container.rs (97%) rename crates/typst/src/{geom => layout}/corners.rs (97%) rename crates/typst/src/{geom => layout}/dir.rs (96%) rename crates/typst/src/{geom => layout}/em.rs (88%) rename crates/{typst-library => typst}/src/layout/flow.rs (97%) rename crates/typst/src/{geom => layout}/fr.rs (90%) rename crates/{typst-library => typst}/src/layout/fragment.rs (96%) rename crates/typst/src/{doc.rs => layout/frame.rs} (64%) rename crates/{typst-library => typst}/src/layout/grid.rs (98%) rename crates/{typst-library => typst}/src/layout/hide.rs (83%) rename crates/{typst-library/src/text => typst/src/layout/inline}/linebreak.rs (96%) rename crates/{typst-library/src/layout/par.rs => typst/src/layout/inline/mod.rs} (83%) rename crates/{typst-library/src/text => typst/src/layout/inline}/shaping.rs (90%) rename crates/{typst-library/src/meta/context.rs => typst/src/layout/layout.rs} (50%) rename crates/typst/src/{geom => layout}/length.rs (96%) rename crates/{typst-library => typst}/src/layout/measure.rs (90%) create mode 100644 crates/typst/src/layout/mod.rs rename crates/{typst-library => typst}/src/layout/pad.rs (94%) rename crates/{typst-library => typst}/src/layout/page.rs (98%) rename crates/{typst-library => typst}/src/layout/place.rs (93%) rename crates/typst/src/{geom => layout}/point.rs (95%) rename crates/typst/src/{geom => layout}/ratio.rs (91%) rename crates/{typst-library => typst}/src/layout/regions.rs (99%) rename crates/typst/src/{geom => layout}/rel.rs (95%) rename crates/{typst-library => typst}/src/layout/repeat.rs (89%) rename crates/typst/src/{geom => layout}/sides.rs (96%) rename crates/typst/src/{geom => layout}/size.rs (93%) rename crates/{typst-library => typst}/src/layout/spacing.rs (97%) rename crates/{typst-library => typst}/src/layout/stack.rs (97%) rename crates/{typst-library => typst}/src/layout/transform.rs (57%) create mode 100644 crates/typst/src/layout/vt.rs create mode 100644 crates/typst/src/loading/cbor.rs create mode 100644 crates/typst/src/loading/csv.rs create mode 100644 crates/typst/src/loading/json.rs create mode 100644 crates/typst/src/loading/mod.rs create mode 100644 crates/typst/src/loading/read.rs create mode 100644 crates/typst/src/loading/toml.rs create mode 100644 crates/typst/src/loading/xml.rs create mode 100644 crates/typst/src/loading/yaml.rs rename crates/{typst-library => typst}/src/math/accent.rs (93%) rename crates/{typst-library => typst}/src/math/align.rs (91%) rename crates/{typst-library => typst}/src/math/attach.rs (97%) rename crates/{typst-library => typst}/src/math/cancel.rs (94%) rename crates/{typst-library => typst}/src/math/class.rs (85%) rename crates/{typst-library => typst}/src/math/ctx.rs (80%) rename crates/{typst-library/src/math/mod.rs => typst/src/math/equation.rs} (61%) rename crates/{typst-library => typst}/src/math/frac.rs (92%) rename crates/{typst-library => typst}/src/math/fragment.rs (86%) rename crates/{typst-library => typst}/src/math/lr.rs (94%) rename crates/{typst-library => typst}/src/math/matrix.rs (94%) create mode 100644 crates/typst/src/math/mod.rs rename crates/{typst-library => typst}/src/math/op.rs (90%) rename crates/{typst-library => typst}/src/math/root.rs (92%) rename crates/{typst-library => typst}/src/math/row.rs (96%) rename crates/{typst-library => typst}/src/math/spacing.rs (93%) rename crates/{typst-library => typst}/src/math/stretch.rs (98%) rename crates/{typst-library => typst}/src/math/style.rs (98%) rename crates/{typst-library => typst}/src/math/underover.rs (95%) rename crates/{typst-library/src/meta => typst/src/model}/bibliography.rs (95%) rename crates/{typst-library/src/meta => typst/src/model}/cite.rs (93%) rename crates/{typst-library/src/meta => typst/src/model}/document.rs (80%) create mode 100644 crates/typst/src/model/emph.rs rename crates/{typst-library/src/layout => typst/src/model}/enum.rs (96%) rename crates/{typst-library/src/meta => typst/src/model}/figure.rs (96%) rename crates/{typst-library/src/meta => typst/src/model}/footnote.rs (94%) rename crates/{typst-library/src/meta => typst/src/model}/heading.rs (94%) rename crates/{typst-library/src/meta => typst/src/model}/link.rs (81%) rename crates/{typst-library/src/layout => typst/src/model}/list.rs (95%) rename crates/{typst-library/src/meta => typst/src/model}/numbering.rs (98%) rename crates/{typst-library/src/meta => typst/src/model}/outline.rs (95%) create mode 100644 crates/typst/src/model/par.rs rename crates/{typst-library/src/text => typst/src/model}/quote.rs (93%) delete mode 100644 crates/typst/src/model/realize.rs rename crates/{typst-library/src/meta => typst/src/model}/reference.rs (95%) create mode 100644 crates/typst/src/model/strong.rs rename crates/{typst-library/src/layout => typst/src/model}/table.rs (96%) rename crates/{typst-library/src/layout => typst/src/model}/terms.rs (94%) rename crates/{typst-library/src/shared => typst/src/realize}/behave.rs (92%) rename crates/{typst-library/src/layout => typst/src/realize}/mod.rs (73%) rename crates/{typst-library => typst}/src/symbols/emoji.rs (99%) create mode 100644 crates/typst/src/symbols/mod.rs rename crates/{typst-library => typst}/src/symbols/sym.rs (99%) rename crates/typst/src/{eval => symbols}/symbol.rs (97%) create mode 100644 crates/typst/src/text/case.rs rename crates/{typst-library => typst}/src/text/deco.rs (96%) rename crates/typst/src/{ => text}/font/book.rs (99%) rename crates/typst/src/{ => text}/font/mod.rs (99%) rename crates/typst/src/{ => text}/font/variant.rs (99%) create mode 100644 crates/typst/src/text/item.rs create mode 100644 crates/typst/src/text/lang.rs create mode 100644 crates/typst/src/text/linebreak.rs create mode 100644 crates/typst/src/text/lorem.rs rename crates/{typst-library => typst}/src/text/mod.rs (85%) rename crates/{typst-library => typst}/src/text/raw.rs (95%) rename crates/{typst-library => typst}/src/text/shift.rs (97%) create mode 100644 crates/typst/src/text/smallcaps.rs rename crates/{typst-library/src/text/quotes.rs => typst/src/text/smartquote.rs} (91%) create mode 100644 crates/typst/src/text/space.rs create mode 100644 crates/typst/src/util/fat.rs rename crates/typst/src/{geom => util}/macros.rs (100%) rename crates/typst/src/{geom => util}/scalar.rs (92%) rename crates/typst/src/{geom => visualize}/color.rs (99%) rename crates/typst/src/{geom => visualize}/gradient.rs (95%) rename crates/{typst-library/src/visualize/image.rs => typst/src/visualize/image/mod.rs} (64%) rename crates/typst/src/{ => visualize}/image/raster.rs (98%) rename crates/typst/src/{ => visualize}/image/svg.rs (98%) rename crates/{typst-library => typst}/src/visualize/line.rs (87%) rename crates/{typst-library => typst}/src/visualize/mod.rs (57%) rename crates/typst/src/{geom => visualize}/paint.rs (79%) rename crates/{typst-library => typst}/src/visualize/path.rs (66%) rename crates/{typst-library => typst}/src/visualize/polygon.rs (92%) create mode 100644 crates/typst/src/visualize/shape.rs rename crates/typst/src/{geom => visualize}/stroke.rs (98%) delete mode 100644 docs/reference/categories.yml create mode 100644 docs/reference/packages.md diff --git a/Cargo.lock b/Cargo.lock index 2bd65a400..8279a4847 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2704,14 +2704,26 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" name = "typst" version = "0.9.0" dependencies = [ + "az", "bitflags 2.4.1", + "chinese-number", + "ciborium", "comemo", + "csv", "ecow", "fontdb", + "hayagriva", + "hypher", + "icu_properties", + "icu_provider", + "icu_provider_adapters", + "icu_provider_blob", + "icu_segmenter", "image", "indexmap 2.0.2", "kurbo", "lasso", + "lipsum", "log", "once_cell", "palette", @@ -2720,16 +2732,22 @@ dependencies = [ "roxmltree", "rustybuzz", "serde", + "serde_json", + "serde_yaml 0.9.27", "siphasher", "smallvec", "stacker", + "syntect", "time", "toml", "tracing", "ttf-parser", + "typed-arena", "typst-macros", "typst-syntax", + "unicode-bidi", "unicode-math-class", + "unicode-script", "unicode-segmentation", "usvg", "wasmi", @@ -2771,7 +2789,6 @@ dependencies = [ "tracing-flame", "tracing-subscriber", "typst", - "typst-library", "typst-pdf", "typst-render", "typst-svg", @@ -2795,7 +2812,6 @@ dependencies = [ "syntect", "typed-arena", "typst", - "typst-library", "unicode_names2", "unscanny", "yaml-front-matter", @@ -2814,46 +2830,6 @@ dependencies = [ "unscanny", ] -[[package]] -name = "typst-library" -version = "0.9.0" -dependencies = [ - "az", - "chinese-number", - "ciborium", - "comemo", - "csv", - "ecow", - "hayagriva", - "hypher", - "icu_properties", - "icu_provider", - "icu_provider_adapters", - "icu_provider_blob", - "icu_segmenter", - "indexmap 2.0.2", - "kurbo", - "lipsum", - "log", - "once_cell", - "roxmltree", - "rustybuzz", - "serde_json", - "serde_yaml 0.9.27", - "smallvec", - "syntect", - "time", - "toml", - "tracing", - "ttf-parser", - "typed-arena", - "typst", - "unicode-bidi", - "unicode-math-class", - "unicode-script", - "unicode-segmentation", -] - [[package]] name = "typst-macros" version = "0.9.0" @@ -2948,7 +2924,6 @@ dependencies = [ "tiny-skia", "ttf-parser", "typst", - "typst-library", "typst-pdf", "typst-render", "typst-svg", diff --git a/Cargo.toml b/Cargo.toml index 57c869cbd..3edde258b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ typst = { path = "crates/typst" } typst-cli = { path = "crates/typst-cli" } typst-docs = { path = "crates/typst-docs" } typst-ide = { path = "crates/typst-ide" } -typst-library = { path = "crates/typst-library" } typst-macros = { path = "crates/typst-macros" } typst-pdf = { path = "crates/typst-pdf" } typst-render = { path = "crates/typst-render" } @@ -98,7 +97,7 @@ tar = "0.4" tempfile = "3.7.0" time = { version = "0.3.20", features = ["formatting", "macros", "parsing"] } tiny-skia = "0.11" -toml = { version = "0.8", default-features = false, features = ["parse"] } +toml = { version = "0.8", default-features = false, features = ["parse", "display"] } tracing = "0.1.37" tracing-error = "0.2" tracing-flame = "0.2.0" diff --git a/crates/typst-cli/Cargo.toml b/crates/typst-cli/Cargo.toml index 7ac4ee5e0..3819469e4 100644 --- a/crates/typst-cli/Cargo.toml +++ b/crates/typst-cli/Cargo.toml @@ -21,7 +21,6 @@ doc = false [dependencies] typst = { workspace = true } -typst-library = { workspace = true } typst-pdf = { workspace = true } typst-render = { workspace = true } typst-svg = { workspace = true } diff --git a/crates/typst-cli/src/args.rs b/crates/typst-cli/src/args.rs index cfd1ae087..075412cd2 100644 --- a/crates/typst-cli/src/args.rs +++ b/crates/typst-cli/src/args.rs @@ -1,9 +1,8 @@ use std::fmt::{self, Display, Formatter}; use std::path::PathBuf; -use semver::Version; - use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum}; +use semver::Version; /// The character typically used to separate path components /// in environment variables. diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs index 48d6401c6..731159248 100644 --- a/crates/typst-cli/src/compile.rs +++ b/crates/typst-cli/src/compile.rs @@ -4,12 +4,14 @@ use std::path::{Path, PathBuf}; use chrono::{Datelike, Timelike}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::term::{self, termcolor}; +use ecow::eco_format; use termcolor::{ColorChoice, StandardStream}; use typst::diag::{bail, Severity, SourceDiagnostic, StrResult}; -use typst::doc::Document; -use typst::eval::{eco_format, Datetime, Tracer}; -use typst::geom::Color; +use typst::eval::Tracer; +use typst::foundations::Datetime; +use typst::model::Document; use typst::syntax::{FileId, Source, Span}; +use typst::visualize::Color; use typst::{World, WorldExt}; use crate::args::{CompileCommand, DiagnosticFormat, OutputFormat}; diff --git a/crates/typst-cli/src/fonts.rs b/crates/typst-cli/src/fonts.rs index 7c7857167..f4711b826 100644 --- a/crates/typst-cli/src/fonts.rs +++ b/crates/typst-cli/src/fonts.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use fontdb::{Database, Source}; use typst::diag::StrResult; -use typst::font::{Font, FontBook, FontInfo, FontVariant}; +use typst::text::{Font, FontBook, FontInfo, FontVariant}; use crate::args::FontsCommand; @@ -106,7 +106,7 @@ impl FontSearcher { #[cfg(feature = "embed-fonts")] fn add_embedded(&mut self) { let mut process = |bytes: &'static [u8]| { - let buffer = typst::eval::Bytes::from_static(bytes); + let buffer = typst::foundations::Bytes::from_static(bytes); for (i, font) in Font::iter(buffer).enumerate() { self.book.push(font.info().clone()); self.fonts.push(FontSlot { diff --git a/crates/typst-cli/src/query.rs b/crates/typst-cli/src/query.rs index cc9cfc230..a84cef79a 100644 --- a/crates/typst-cli/src/query.rs +++ b/crates/typst-cli/src/query.rs @@ -1,10 +1,13 @@ use comemo::Track; +use ecow::{eco_format, EcoString}; use serde::Serialize; use typst::diag::{bail, StrResult}; use typst::eval::{eval_string, EvalMode, Tracer}; -use typst::model::Introspector; +use typst::foundations::{Content, IntoValue, LocatableSelector, Scope}; +use typst::introspection::Introspector; +use typst::model::Document; +use typst::syntax::Span; use typst::World; -use typst_library::prelude::*; use crate::args::{QueryCommand, SerializationFormat}; use crate::compile::print_diagnostics; @@ -95,7 +98,7 @@ fn format(elements: Vec, command: &QueryCommand) -> StrResult { .collect(); if command.one { - let Some(value) = mapped.get(0) else { + let Some(value) = mapped.first() else { bail!("no such field found for element"); }; serialize(value, command.format) diff --git a/crates/typst-cli/src/tracing.rs b/crates/typst-cli/src/tracing.rs index c01efd6d0..331c6327f 100644 --- a/crates/typst-cli/src/tracing.rs +++ b/crates/typst-cli/src/tracing.rs @@ -6,8 +6,9 @@ use inferno::flamegraph::Options; use tracing::metadata::LevelFilter; use tracing_error::ErrorLayer; use tracing_flame::{FlameLayer, FlushGuard}; -use tracing_subscriber::fmt; -use tracing_subscriber::prelude::*; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{fmt, Layer}; use crate::args::{CliArguments, Command}; diff --git a/crates/typst-cli/src/update.rs b/crates/typst-cli/src/update.rs index c94515b64..3cd65c9d7 100644 --- a/crates/typst-cli/src/update.rs +++ b/crates/typst-cli/src/update.rs @@ -1,13 +1,12 @@ -use std::env; -use std::fs; use std::io::{Cursor, Read, Write}; use std::path::PathBuf; +use std::{env, fs}; +use ecow::eco_format; use semver::Version; use serde::Deserialize; use tempfile::NamedTempFile; use typst::diag::{bail, StrResult}; -use typst::eval::eco_format; use xz2::bufread::XzDecoder; use zip::ZipArchive; diff --git a/crates/typst-cli/src/watch.rs b/crates/typst-cli/src/watch.rs index 138f473aa..aea3ca48b 100644 --- a/crates/typst-cli/src/watch.rs +++ b/crates/typst-cli/src/watch.rs @@ -3,11 +3,11 @@ use std::io::{self, IsTerminal, Write}; use std::path::{Path, PathBuf}; use codespan_reporting::term::{self, termcolor}; +use ecow::eco_format; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use same_file::is_same_file; use termcolor::WriteColor; use typst::diag::StrResult; -use typst::eval::eco_format; use crate::args::CompileCommand; use crate::color_stream; diff --git a/crates/typst-cli/src/world.rs b/crates/typst-cli/src/world.rs index 3b774f1da..f375c6488 100644 --- a/crates/typst-cli/src/world.rs +++ b/crates/typst-cli/src/world.rs @@ -5,13 +5,14 @@ use std::path::{Path, PathBuf}; use chrono::{DateTime, Datelike, Local}; use comemo::Prehashed; +use ecow::eco_format; use typst::diag::{FileError, FileResult, StrResult}; -use typst::doc::Frame; -use typst::eval::{eco_format, Bytes, Datetime, Library}; -use typst::font::{Font, FontBook}; +use typst::foundations::{Bytes, Datetime}; +use typst::layout::Frame; use typst::syntax::{FileId, Source, VirtualPath}; +use typst::text::{Font, FontBook}; use typst::util::hash128; -use typst::World; +use typst::{Library, World}; use crate::args::SharedArgs; use crate::fonts::{FontSearcher, FontSlot}; @@ -75,7 +76,7 @@ impl SystemWorld { input, root, main: FileId::new(None, main_path), - library: Prehashed::new(typst_library::build()), + library: Prehashed::new(Library::build()), book: Prehashed::new(searcher.book), fonts: searcher.fonts, slots: RefCell::default(), diff --git a/crates/typst-docs/Cargo.toml b/crates/typst-docs/Cargo.toml index b2e82e437..152f5e790 100644 --- a/crates/typst-docs/Cargo.toml +++ b/crates/typst-docs/Cargo.toml @@ -12,7 +12,6 @@ bench = false [dependencies] typst = { workspace = true } -typst-library = { workspace = true } comemo = { workspace = true } ecow = { workspace = true } heck = { workspace = true } diff --git a/crates/typst-docs/src/contribs.rs b/crates/typst-docs/src/contribs.rs index cbd87dc6d..58a730e22 100644 --- a/crates/typst-docs/src/contribs.rs +++ b/crates/typst-docs/src/contribs.rs @@ -4,7 +4,7 @@ use std::fmt::Write; use serde::{Deserialize, Serialize}; -use super::{Html, Resolver}; +use crate::{Html, Resolver}; /// Build HTML detailing the contributors between two tags. pub fn contributors(resolver: &dyn Resolver, from: &str, to: &str) -> Option { diff --git a/crates/typst-docs/src/html.rs b/crates/typst-docs/src/html.rs index 1210545f1..7481b050c 100644 --- a/crates/typst-docs/src/html.rs +++ b/crates/typst-docs/src/html.rs @@ -8,11 +8,12 @@ use pulldown_cmark as md; use serde::{Deserialize, Serialize}; use typed_arena::Arena; use typst::diag::{FileResult, StrResult}; -use typst::eval::{Bytes, Datetime, Library, Tracer}; -use typst::font::{Font, FontBook}; -use typst::geom::{Abs, Point, Size}; +use typst::eval::Tracer; +use typst::foundations::{Bytes, Datetime}; +use typst::layout::{Abs, Point, Size}; use typst::syntax::{FileId, Source, VirtualPath}; -use typst::World; +use typst::text::{Font, FontBook}; +use typst::{Library, World}; use unscanny::Scanner; use yaml_front_matter::YamlFrontMatter; @@ -360,13 +361,13 @@ fn code_block(resolver: &dyn Resolver, lang: &str, text: &str) -> Html { buf.push_str(""); return Html::new(buf); } else if !matches!(lang, "example" | "typ" | "preview") { - let set = &*typst_library::text::SYNTAXES; + let set = &*typst::text::RAW_SYNTAXES; let buf = syntect::html::highlighted_html_for_string( &display, set, set.find_syntax_by_token(lang) .unwrap_or_else(|| panic!("unsupported highlighting language: {lang}")), - &typst_library::text::THEME, + &typst::text::RAW_THEME, ) .expect("failed to highlight code"); return Html::new(buf); diff --git a/crates/typst-docs/src/lib.rs b/crates/typst-docs/src/lib.rs index d58734c6f..444dda32c 100644 --- a/crates/typst-docs/src/lib.rs +++ b/crates/typst-docs/src/lib.rs @@ -5,9 +5,9 @@ mod html; mod link; mod model; -pub use contribs::{contributors, Author, Commit}; -pub use html::Html; -pub use model::*; +pub use self::contribs::*; +pub use self::html::*; +pub use self::model::*; use std::path::Path; @@ -20,30 +20,48 @@ use serde::de::DeserializeOwned; use serde::Deserialize; use serde_yaml as yaml; use typst::diag::{bail, StrResult}; -use typst::doc::Frame; -use typst::eval::{ - CastInfo, Func, Library, Module, ParamInfo, Repr, Scope, Smart, Type, Value, +use typst::foundations::{ + CastInfo, Category, Func, Module, ParamInfo, Repr, Scope, Smart, Type, Value, + FOUNDATIONS, }; -use typst::font::{Font, FontBook}; -use typst::geom::Abs; -use typst_library::layout::{Margin, PageElem}; +use typst::introspection::INTROSPECTION; +use typst::layout::{Abs, Frame, Margin, PageElem, LAYOUT}; +use typst::loading::DATA_LOADING; +use typst::math::MATH; +use typst::model::MODEL; +use typst::symbols::SYMBOLS; +use typst::text::{Font, FontBook, TEXT}; +use typst::visualize::VISUALIZE; +use typst::Library; static DOCS_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../docs"); static FILE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../assets/files"); static FONT_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../assets/fonts"); -static CATEGORIES: Lazy = Lazy::new(|| yaml("reference/categories.yml")); -static GROUPS: Lazy> = Lazy::new(|| yaml("reference/groups.yml")); +static GROUPS: Lazy> = Lazy::new(|| { + let mut groups: Vec = yaml("reference/groups.yml"); + for group in &mut groups { + if group.filter.is_empty() { + group.filter = group + .module() + .scope() + .iter() + .filter(|(_, v)| matches!(v, Value::Func(_))) + .map(|(k, _)| k.clone()) + .collect(); + } + } + groups +}); static LIBRARY: Lazy> = Lazy::new(|| { - let mut lib = typst_library::build(); + let mut lib = Library::build(); lib.styles .set(PageElem::set_width(Smart::Custom(Abs::pt(240.0).into()))); lib.styles.set(PageElem::set_height(Smart::Auto)); lib.styles.set(PageElem::set_margin(Margin::splat(Some(Smart::Custom( Abs::pt(15.0).into(), ))))); - typst::eval::set_lang_items(lib.items.clone()); Prehashed::new(lib) }); @@ -128,14 +146,15 @@ fn reference_pages(resolver: &dyn Resolver) -> PageModel { .with_part("Language"), markdown_page(resolver, "/docs/reference/", "reference/styling.md"), markdown_page(resolver, "/docs/reference/", "reference/scripting.md"), - category_page(resolver, "foundations").with_part("Library"), - category_page(resolver, "text"), - category_page(resolver, "math"), - category_page(resolver, "layout"), - category_page(resolver, "visualize"), - category_page(resolver, "meta"), - category_page(resolver, "symbols"), - category_page(resolver, "data-loading"), + category_page(resolver, FOUNDATIONS).with_part("Library"), + category_page(resolver, MODEL), + category_page(resolver, TEXT), + category_page(resolver, MATH), + category_page(resolver, SYMBOLS), + category_page(resolver, LAYOUT), + category_page(resolver, VISUALIZE), + category_page(resolver, INTROSPECTION), + category_page(resolver, DATA_LOADING), ]; page } @@ -152,50 +171,73 @@ fn guide_pages(resolver: &dyn Resolver) -> PageModel { /// Build the packages section. fn packages_page(resolver: &dyn Resolver) -> PageModel { + let md = DOCS_DIR + .get_file("reference/packages.md") + .unwrap() + .contents_utf8() + .unwrap(); PageModel { route: "/docs/packages/".into(), title: "Packages".into(), description: "Packages for Typst.".into(), part: None, outline: vec![], - body: BodyModel::Packages(Html::markdown( - resolver, - category_details("packages"), - Some(1), - )), + body: BodyModel::Packages(Html::markdown(resolver, md, Some(1))), children: vec![], } } /// Create a page for a category. #[track_caller] -fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { - let route = eco_format!("/docs/reference/{category}/"); +fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { + let route = eco_format!("/docs/reference/{}/", category.name()); let mut children = vec![]; let mut items = vec![]; + let mut shorthands = None; + let mut markup = vec![]; + let mut math = vec![]; - let (module, path): (&Module, &[&str]) = match category { - "math" => (&LIBRARY.math, &["math"]), - _ => (&LIBRARY.global, &[]), + let (module, path): (&Module, &[&str]) = if category == MATH { + (&LIBRARY.math, &["math"]) + } else { + (&LIBRARY.global, &[]) }; // Add groups. - for mut group in GROUPS.iter().filter(|g| g.category == category).cloned() { - let mut focus = module; - if matches!(group.name.as_str(), "calc" | "sys") { - focus = get_module(focus, &group.name).unwrap(); - group.functions = focus - .scope() - .iter() - .filter(|(_, v)| matches!(v, Value::Func(_))) - .map(|(k, _)| k.clone()) - .collect(); + for group in GROUPS.iter().filter(|g| g.category == category.name()).cloned() { + if matches!(group.name.as_str(), "sym" | "emoji") { + let subpage = symbols_page(resolver, &route, &group); + let BodyModel::Symbols(model) = &subpage.body else { continue }; + let list = &model.list; + markup.extend( + list.iter() + .filter(|symbol| symbol.markup_shorthand.is_some()) + .cloned(), + ); + math.extend( + list.iter().filter(|symbol| symbol.math_shorthand.is_some()).cloned(), + ); + + items.push(CategoryItem { + name: group.name.clone(), + route: subpage.route.clone(), + oneliner: oneliner(category.docs()).into(), + code: true, + }); + children.push(subpage); + continue; } - let (child, item) = group_page(resolver, &route, &group, focus.scope()); + + let (child, item) = group_page(resolver, &route, &group); children.push(child); items.push(item); } + // Add symbol pages. These are ordered manually. + if category == SYMBOLS { + shorthands = Some(ShorthandsModel { markup, math }); + } + // Add functions. let scope = module.scope(); for (name, value) in scope.iter() { @@ -203,9 +245,9 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { continue; } - if category == "math" { + if category == MATH { // Skip grouped functions. - if GROUPS.iter().flat_map(|group| &group.functions).any(|f| f == name) { + if GROUPS.iter().flat_map(|group| &group.filter).any(|f| f == name) { continue; } @@ -242,54 +284,35 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { } } - children.sort_by_cached_key(|child| child.title.clone()); - items.sort_by_cached_key(|item| item.name.clone()); - - // Add symbol pages. These are ordered manually. - let mut shorthands = None; - if category == "symbols" { - let mut markup = vec![]; - let mut math = vec![]; - for module in ["sym", "emoji"] { - let subpage = symbols_page(resolver, &route, module); - let BodyModel::Symbols(model) = &subpage.body else { continue }; - let list = &model.list; - markup.extend( - list.iter() - .filter(|symbol| symbol.markup_shorthand.is_some()) - .cloned(), - ); - math.extend( - list.iter().filter(|symbol| symbol.math_shorthand.is_some()).cloned(), - ); - - items.push(CategoryItem { - name: module.into(), - route: subpage.route.clone(), - oneliner: oneliner(category_details(module)).into(), - code: true, - }); - children.push(subpage); - } - shorthands = Some(ShorthandsModel { markup, math }); + if category != SYMBOLS { + children.sort_by_cached_key(|child| child.title.clone()); + items.sort_by_cached_key(|item| item.name.clone()); } - let name: EcoString = category.to_title_case().into(); - - let details = Html::markdown(resolver, category_details(category), Some(1)); + let name = category.title(); + let details = Html::markdown(resolver, category.docs(), Some(1)); let mut outline = vec![OutlineItem::from_name("Summary")]; outline.extend(details.outline()); outline.push(OutlineItem::from_name("Definitions")); + if shorthands.is_some() { + outline.push(OutlineItem::from_name("Shorthands")); + } PageModel { route, - title: name.clone(), + title: name.into(), description: eco_format!( "Documentation for functions related to {name} in Typst." ), part: None, outline, - body: BodyModel::Category(CategoryModel { name, details, items, shorthands }), + body: BodyModel::Category(CategoryModel { + name: category.name(), + title: category.title(), + details, + items, + shorthands, + }), children, } } @@ -498,18 +521,17 @@ fn group_page( resolver: &dyn Resolver, parent: &str, group: &GroupData, - scope: &Scope, ) -> (PageModel, CategoryItem) { let mut functions = vec![]; let mut outline = vec![OutlineItem::from_name("Summary")]; let path: Vec<_> = group.path.iter().map(|s| s.as_str()).collect(); - let details = Html::markdown(resolver, &group.description, Some(1)); + let details = Html::markdown(resolver, &group.details, Some(1)); outline.extend(details.outline()); let mut outline_items = vec![]; - for name in &group.functions { - let value = scope.get(name).unwrap(); + for name in &group.filter { + let value = group.module().scope().get(name).unwrap(); let Value::Func(func) = value else { panic!("not a function") }; let func = func_model(resolver, func, &path, true); let id_base = urlify(&eco_format!("functions-{}", func.name)); @@ -530,13 +552,13 @@ fn group_page( let model = PageModel { route: eco_format!("{parent}{}", group.name), - title: group.display.clone(), + title: group.title.clone(), description: eco_format!("Documentation for the {} functions.", group.name), part: None, outline, body: BodyModel::Group(GroupModel { name: group.name.clone(), - title: group.display.clone(), + title: group.title.clone(), details, functions, }), @@ -546,7 +568,7 @@ fn group_page( let item = CategoryItem { name: group.name.clone(), route: model.route.clone(), - oneliner: oneliner(&group.description).into(), + oneliner: oneliner(&group.details).into(), code: false, }; @@ -601,19 +623,12 @@ fn type_outline(model: &TypeModel) -> Vec { } /// Create a page for symbols. -fn symbols_page(resolver: &dyn Resolver, parent: &str, name: &str) -> PageModel { - let module = get_module(&LIBRARY.global, name).unwrap(); - let title = match name { - "sym" => "General", - "emoji" => "Emoji", - _ => unreachable!(), - }; - - let model = symbols_model(resolver, name, title, module.scope()); +fn symbols_page(resolver: &dyn Resolver, parent: &str, group: &GroupData) -> PageModel { + let model = symbols_model(resolver, group); PageModel { - route: eco_format!("{parent}{name}/"), - title: title.into(), - description: eco_format!("Documentation for the `{name}` module."), + route: eco_format!("{parent}{}/", group.name), + title: group.title.clone(), + description: eco_format!("Documentation for the `{}` module.", group.name), part: None, outline: vec![], body: BodyModel::Symbols(model), @@ -622,14 +637,9 @@ fn symbols_page(resolver: &dyn Resolver, parent: &str, name: &str) -> PageModel } /// Produce a symbol list's model. -fn symbols_model( - resolver: &dyn Resolver, - name: &str, - title: &'static str, - scope: &Scope, -) -> SymbolsModel { +fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel { let mut list = vec![]; - for (name, value) in scope.iter() { + for (name, value) in group.module().scope().iter() { let Value::Symbol(symbol) = value else { continue }; let complete = |variant: &str| { if variant.is_empty() { @@ -649,7 +659,7 @@ fn symbols_model( markup_shorthand: shorthand(typst::syntax::ast::Shorthand::MARKUP_LIST), math_shorthand: shorthand(typst::syntax::ast::Shorthand::MATH_LIST), codepoint: c as u32, - accent: typst::eval::Symbol::combining_accent(c).is_some(), + accent: typst::symbols::Symbol::combining_accent(c).is_some(), unicode_name: unicode_names2::name(c) .map(|s| s.to_string().to_title_case().into()), alternates: symbol @@ -662,8 +672,9 @@ fn symbols_model( } SymbolsModel { - name: title, - details: Html::markdown(resolver, category_details(name), Some(1)), + name: group.name.clone(), + title: group.title.clone(), + details: Html::markdown(resolver, &group.details, Some(1)), list, } } @@ -684,15 +695,6 @@ fn yaml(path: &str) -> T { yaml::from_slice(file.contents()).unwrap() } -/// Load details for an identifying key. -#[track_caller] -fn category_details(key: &str) -> &str { - CATEGORIES - .get(&yaml::Value::String(key.into())) - .and_then(|value| value.as_str()) - .unwrap_or_else(|| panic!("missing details for {key}")) -} - /// Turn a title into an URL fragment. pub fn urlify(title: &str) -> EcoString { title @@ -752,13 +754,23 @@ const TYPE_ORDER: &[&str] = &[ #[derive(Debug, Clone, Deserialize)] struct GroupData { name: EcoString, + title: EcoString, category: EcoString, - display: EcoString, #[serde(default)] path: Vec, #[serde(default)] - functions: Vec, - description: EcoString, + filter: Vec, + details: EcoString, +} + +impl GroupData { + fn module(&self) -> &'static Module { + let mut focus = &LIBRARY.global; + for path in &self.path { + focus = get_module(focus, path).unwrap(); + } + focus + } } #[cfg(test)] diff --git a/crates/typst-docs/src/link.rs b/crates/typst-docs/src/link.rs index 38730c324..e2721b95e 100644 --- a/crates/typst-docs/src/link.rs +++ b/crates/typst-docs/src/link.rs @@ -1,5 +1,5 @@ use typst::diag::{bail, StrResult}; -use typst::eval::Func; +use typst::foundations::Func; use crate::{get_module, GROUPS, LIBRARY}; @@ -55,6 +55,15 @@ fn resolve_known(head: &str) -> Option<&'static str> { fn resolve_definition(head: &str) -> StrResult { let mut parts = head.trim_start_matches('$').split('.').peekable(); let mut focus = &LIBRARY.global; + + let Some(name) = parts.peek() else { + bail!("missing first link component"); + }; + + let Some(category) = focus.scope().get_category(name) else { + bail!("{name} has no category"); + }; + while let Some(m) = parts.peek().and_then(|&name| get_module(focus, name).ok()) { focus = m; parts.next(); @@ -62,18 +71,15 @@ fn resolve_definition(head: &str) -> StrResult { let name = parts.next().ok_or("link is missing first part")?; let value = focus.field(name)?; - let Some(category) = focus.scope().get_category(name) else { - bail!("{name} has no category"); - }; // Handle grouped functions. - if let Some(group) = GROUPS - .iter() - .filter(|_| category == "math") - .find(|group| group.functions.iter().any(|func| func == name)) - { - let mut route = - format!("/docs/reference/math/{}/#functions-{}", group.name, name); + if let Some(group) = GROUPS.iter().find(|group| { + group.category == category.name() && group.filter.iter().any(|func| func == name) + }) { + let mut route = format!( + "/docs/reference/{}/{}/#functions-{}", + group.category, group.name, name + ); if let Some(param) = parts.next() { route.push('-'); route.push_str(param); @@ -81,7 +87,7 @@ fn resolve_definition(head: &str) -> StrResult { return Ok(route); } - let mut route = format!("/docs/reference/{category}/{name}/"); + let mut route = format!("/docs/reference/{}/{name}/", category.name()); if let Some(next) = parts.next() { if value.field(next).is_ok() { route.push_str("#definitions-"); diff --git a/crates/typst-docs/src/model.rs b/crates/typst-docs/src/model.rs index 580ae0d3c..937428258 100644 --- a/crates/typst-docs/src/model.rs +++ b/crates/typst-docs/src/model.rs @@ -62,7 +62,8 @@ pub enum BodyModel { /// Details about a category. #[derive(Debug, Serialize)] pub struct CategoryModel { - pub name: EcoString, + pub name: &'static str, + pub title: &'static str, pub details: Html, pub items: Vec, pub shorthands: Option, @@ -144,7 +145,8 @@ pub struct TypeModel { /// A collection of symbols. #[derive(Debug, Serialize)] pub struct SymbolsModel { - pub name: &'static str, + pub name: EcoString, + pub title: EcoString, pub details: Html, pub list: Vec, } diff --git a/crates/typst-ide/src/analyze.rs b/crates/typst-ide/src/analyze.rs index 4d12e1c5d..2d48039b6 100644 --- a/crates/typst-ide/src/analyze.rs +++ b/crates/typst-ide/src/analyze.rs @@ -1,8 +1,11 @@ use comemo::Track; use ecow::{eco_vec, EcoString, EcoVec}; -use typst::doc::Frame; -use typst::eval::{Route, Scopes, Tracer, Value, Vm}; -use typst::model::{DelayedErrors, Introspector, Label, Locator, Vt}; +use typst::diag::DelayedErrors; +use typst::eval::{Route, Tracer, Vm}; +use typst::foundations::{Label, Scopes, Value}; +use typst::introspection::{Introspector, Locator}; +use typst::layout::{Frame, Vt}; +use typst::model::BibliographyElem; use typst::syntax::{ast, LinkedNode, Span, SyntaxKind}; use typst::World; @@ -75,13 +78,9 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option { /// - All labels and descriptions for them, if available /// - A split offset: All labels before this offset belong to nodes, all after /// belong to a bibliography. -pub fn analyze_labels( - world: &dyn World, - frames: &[Frame], -) -> (Vec<(Label, Option)>, usize) { +pub fn analyze_labels(frames: &[Frame]) -> (Vec<(Label, Option)>, usize) { let mut output = vec![]; let introspector = Introspector::new(frames); - let items = &world.library().items; // Labels in the document. for elem in introspector.all() { @@ -102,7 +101,7 @@ pub fn analyze_labels( let split = output.len(); // Bibliography keys. - for (key, detail) in (items.bibliography_keys)(introspector.track()) { + for (key, detail) in BibliographyElem::keys(introspector.track()) { output.push((Label::new(&key), detail)); } diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs index 71ae95dbe..5cff5a819 100644 --- a/crates/typst-ide/src/complete.rs +++ b/crates/typst-ide/src/complete.rs @@ -4,21 +4,21 @@ use std::collections::{BTreeSet, HashSet}; use ecow::{eco_format, EcoString}; use if_chain::if_chain; use serde::{Deserialize, Serialize}; -use typst::doc::Frame; -use typst::eval::{ - format_str, repr, AutoValue, CastInfo, Func, Library, NoneValue, Repr, Scope, Type, - Value, +use typst::foundations::{ + fields_on, format_str, mutable_methods_on, repr, AutoValue, CastInfo, Func, Label, + NoneValue, Repr, Scope, Type, Value, }; -use typst::geom::Color; -use typst::model::Label; +use typst::layout::Frame; use typst::syntax::{ ast, is_id_continue, is_id_start, is_ident, LinkedNode, Source, SyntaxKind, }; +use typst::text::RawElem; +use typst::visualize::Color; use typst::World; use unscanny::Scanner; -use crate::analyze::analyze_labels; -use crate::{analyze_expr, analyze_import, plain_docs_sentence, summarize_font_family}; +use crate::analyze::{analyze_expr, analyze_import, analyze_labels}; +use crate::{plain_docs_sentence, summarize_font_family}; /// Autocomplete a cursor position in a source file. /// @@ -367,7 +367,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value) { } } - for &(method, args) in typst::eval::mutable_methods_on(value.ty()) { + for &(method, args) in mutable_methods_on(value.ty()) { ctx.completions.push(Completion { kind: CompletionKind::Func, label: method.into(), @@ -380,7 +380,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value) { }) } - for &field in typst::eval::fields_on(value.ty()) { + for &field in fields_on(value.ty()) { // Complete the field name along with its value. Notes: // 1. No parentheses since function fields cannot currently be called // with method syntax; @@ -967,7 +967,6 @@ fn code_completions(ctx: &mut CompletionContext, hash: bool) { struct CompletionContext<'a> { world: &'a (dyn World + 'a), frames: &'a [Frame], - library: &'a Library, global: &'a Scope, math: &'a Scope, text: &'a str, @@ -996,7 +995,6 @@ impl<'a> CompletionContext<'a> { Some(Self { world, frames, - library, global: library.global.scope(), math: library.math.scope(), text, @@ -1074,7 +1072,7 @@ impl<'a> CompletionContext<'a> { /// Add completions for raw block tags. fn raw_completions(&mut self) { - for (name, mut tags) in (self.library.items.raw_languages)() { + for (name, mut tags) in RawElem::languages() { let lower = name.to_lowercase(); if !tags.contains(&lower.as_str()) { tags.push(lower.as_str()); @@ -1096,7 +1094,7 @@ impl<'a> CompletionContext<'a> { /// Add completions for labels and references. fn label_completions(&mut self) { - let (labels, split) = analyze_labels(self.world, self.frames); + let (labels, split) = analyze_labels(self.frames); let head = &self.text[..self.from]; let at = head.ends_with('@'); diff --git a/crates/typst-ide/src/jump.rs b/crates/typst-ide/src/jump.rs index a33e743c1..700f475f2 100644 --- a/crates/typst-ide/src/jump.rs +++ b/crates/typst-ide/src/jump.rs @@ -1,10 +1,11 @@ use std::num::NonZeroUsize; use ecow::EcoString; -use typst::doc::{Destination, Frame, FrameItem, Meta, Position}; -use typst::geom::{Geometry, Point, Size}; -use typst::model::Introspector; +use typst::introspection::{Introspector, Meta}; +use typst::layout::{Frame, FrameItem, Point, Position, Size}; +use typst::model::Destination; use typst::syntax::{FileId, LinkedNode, Source, Span, SyntaxKind}; +use typst::visualize::Geometry; use typst::World; /// Where to [jump](jump_from_click) to. diff --git a/crates/typst-ide/src/lib.rs b/crates/typst-ide/src/lib.rs index 3ab367dc8..173a4264b 100644 --- a/crates/typst-ide/src/lib.rs +++ b/crates/typst-ide/src/lib.rs @@ -13,9 +13,7 @@ pub use self::tooltip::{tooltip, Tooltip}; use std::fmt::Write; use ecow::{eco_format, EcoString}; -use typst::font::{FontInfo, FontStyle}; - -use self::analyze::*; +use typst::text::{FontInfo, FontStyle}; /// Extract the first sentence of plain text of a piece of documentation. /// diff --git a/crates/typst-ide/src/tooltip.rs b/crates/typst-ide/src/tooltip.rs index d3f040e72..4f079166f 100644 --- a/crates/typst-ide/src/tooltip.rs +++ b/crates/typst-ide/src/tooltip.rs @@ -2,14 +2,15 @@ use std::fmt::Write; use ecow::{eco_format, EcoString}; use if_chain::if_chain; -use typst::doc::Frame; -use typst::eval::{repr, CapturesVisitor, CastInfo, Repr, Tracer, Value}; -use typst::geom::{round_2, Length, Numeric}; +use typst::eval::{CapturesVisitor, Tracer}; +use typst::foundations::{repr, CastInfo, Repr, Value}; +use typst::layout::{Frame, Length}; use typst::syntax::{ast, LinkedNode, Source, SyntaxKind}; +use typst::util::{round_2, Numeric}; use typst::World; -use crate::analyze::analyze_labels; -use crate::{analyze_expr, plain_docs_sentence, summarize_font_family}; +use crate::analyze::{analyze_expr, analyze_labels}; +use crate::{plain_docs_sentence, summarize_font_family}; /// Describe the item under the cursor. pub fn tooltip( @@ -25,7 +26,7 @@ pub fn tooltip( named_param_tooltip(world, &leaf) .or_else(|| font_tooltip(world, &leaf)) - .or_else(|| label_tooltip(world, frames, &leaf)) + .or_else(|| label_tooltip(frames, &leaf)) .or_else(|| expr_tooltip(world, &leaf)) .or_else(|| closure_tooltip(&leaf)) } @@ -144,18 +145,14 @@ fn length_tooltip(length: Length) -> Option { } /// Tooltip for a hovered reference or label. -fn label_tooltip( - world: &dyn World, - frames: &[Frame], - leaf: &LinkedNode, -) -> Option { +fn label_tooltip(frames: &[Frame], leaf: &LinkedNode) -> Option { let target = match leaf.kind() { SyntaxKind::RefMarker => leaf.text().trim_start_matches('@'), SyntaxKind::Label => leaf.text().trim_start_matches('<').trim_end_matches('>'), _ => return None, }; - for (label, detail) in analyze_labels(world, frames).0 { + for (label, detail) in analyze_labels(frames).0 { if label.as_str() == target { return Some(Tooltip::Text(detail?)); } diff --git a/crates/typst-library/Cargo.toml b/crates/typst-library/Cargo.toml deleted file mode 100644 index 426c56f32..000000000 --- a/crates/typst-library/Cargo.toml +++ /dev/null @@ -1,53 +0,0 @@ -[package] -name = "typst-library" -description = "The standard library for Typst." -version.workspace = true -rust-version.workspace = true -authors.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true -license.workspace = true -categories.workspace = true -keywords.workspace = true - -[lib] -test = false -doctest = false -bench = false - -[dependencies] -typst = { workspace = true } -az = { workspace = true } -chinese-number = { workspace = true } -ciborium = { workspace = true } -comemo = { workspace = true } -csv = { workspace = true } -ecow = { workspace = true } -hayagriva = { workspace = true } -hypher = { workspace = true } -icu_properties = { workspace = true } -icu_provider = { workspace = true } -icu_provider_adapters = { workspace = true } -icu_provider_blob = { workspace = true } -icu_segmenter = { workspace = true } -indexmap = { workspace = true } -kurbo = { workspace = true } -lipsum = { workspace = true } -log = { workspace = true } -once_cell = { workspace = true } -roxmltree = { workspace = true } -rustybuzz = { workspace = true } -serde_json = { workspace = true } -serde_yaml = { workspace = true } -smallvec = { workspace = true } -syntect = { workspace = true } -time = { workspace = true } -toml = { workspace = true, features = ["display"] } -tracing = { workspace = true } -ttf-parser = { workspace = true } -typed-arena = { workspace = true } -unicode-bidi = { workspace = true } -unicode-math-class = { workspace = true } -unicode-script = { workspace = true } -unicode-segmentation = { workspace = true } diff --git a/crates/typst-library/src/compute/data.rs b/crates/typst-library/src/compute/data.rs deleted file mode 100644 index e4767ebf3..000000000 --- a/crates/typst-library/src/compute/data.rs +++ /dev/null @@ -1,609 +0,0 @@ -use typst::diag::{format_xml_like_error, FileError}; -use typst::eval::Bytes; -use typst::syntax::is_newline; - -use crate::prelude::*; - -/// Hook up all data loading definitions. -pub(super) fn define(global: &mut Scope) { - global.category("data-loading"); - global.define_func::(); - global.define_func::(); - global.define_func::(); - global.define_func::(); - global.define_func::(); - global.define_func::(); - global.define_func::(); -} - -/// Reads plain text or data from a file. -/// -/// By default, the file will be read as UTF-8 and returned as a [string]($str). -/// -/// If you specify `{encoding: none}`, this returns raw [bytes]($bytes) instead. -/// -/// # Example -/// ```example -/// An example for a HTML file: \ -/// #let text = read("data.html") -/// #raw(text, lang: "html") -/// -/// Raw bytes: -/// #read("tiger.jpg", encoding: none) -/// ``` -#[func] -pub fn read( - /// The virtual machine. - vm: &mut Vm, - /// Path to a file. - path: Spanned, - /// The encoding to read the file with. - /// - /// If set to `{none}`, this function returns raw bytes. - #[named] - #[default(Some(Encoding::Utf8))] - encoding: Option, -) -> SourceResult { - let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; - Ok(match encoding { - None => Readable::Bytes(data), - Some(Encoding::Utf8) => Readable::Str( - std::str::from_utf8(&data) - .map_err(|_| "file is not valid utf-8") - .at(span)? - .into(), - ), - }) -} - -/// An encoding of a file. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] -pub enum Encoding { - /// The Unicode UTF-8 encoding. - Utf8, -} - -/// A value that can be read from a file. -#[derive(Debug, Clone, PartialEq, Hash)] -pub enum Readable { - /// A decoded string. - Str(Str), - /// Raw bytes. - Bytes(Bytes), -} - -impl Readable { - fn as_slice(&self) -> &[u8] { - match self { - Readable::Bytes(v) => v, - Readable::Str(v) => v.as_bytes(), - } - } -} - -cast! { - Readable, - self => match self { - Self::Str(v) => v.into_value(), - Self::Bytes(v) => v.into_value(), - }, - v: Str => Self::Str(v), - v: Bytes => Self::Bytes(v), -} - -impl From for Bytes { - fn from(value: Readable) -> Self { - match value { - Readable::Bytes(v) => v, - Readable::Str(v) => v.as_bytes().into(), - } - } -} - -/// Reads structured data from a CSV file. -/// -/// The CSV file will be read and parsed into a 2-dimensional array of strings: -/// Each row in the CSV file will be represented as an array of strings, and all -/// rows will be collected into a single array. Header rows will not be -/// stripped. -/// -/// # Example -/// ```example -/// #let results = csv("data.csv") -/// -/// #table( -/// columns: 2, -/// [*Condition*], [*Result*], -/// ..results.flatten(), -/// ) -/// ``` -#[func(scope, title = "CSV")] -pub fn csv( - /// The virtual machine. - vm: &mut Vm, - /// Path to a CSV file. - path: Spanned, - /// The delimiter that separates columns in the CSV file. - /// Must be a single ASCII character. - #[named] - #[default] - delimiter: Delimiter, -) -> SourceResult { - let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; - self::csv::decode(Spanned::new(Readable::Bytes(data), span), delimiter) -} - -#[scope] -impl csv { - /// Reads structured data from a CSV string/bytes. - #[func(title = "Decode CSV")] - pub fn decode( - /// CSV data. - data: Spanned, - /// The delimiter that separates columns in the CSV file. - /// Must be a single ASCII character. - #[named] - #[default] - delimiter: Delimiter, - ) -> SourceResult { - let Spanned { v: data, span } = data; - let mut builder = ::csv::ReaderBuilder::new(); - builder.has_headers(false); - builder.delimiter(delimiter.0 as u8); - let mut reader = builder.from_reader(data.as_slice()); - let mut array = Array::new(); - - for (line, result) in reader.records().enumerate() { - // Original solution use line from error, but that is incorrect with - // `has_headers` set to `false`. See issue: - // https://github.com/BurntSushi/rust-csv/issues/184 - let line = line + 1; // Counting lines from 1 - let row = result.map_err(|err| format_csv_error(err, line)).at(span)?; - let sub = row.into_iter().map(|field| field.into_value()).collect(); - array.push(Value::Array(sub)) - } - - Ok(array) - } -} - -/// The delimiter to use when parsing CSV files. -pub struct Delimiter(char); - -impl Default for Delimiter { - fn default() -> Self { - Self(',') - } -} - -cast! { - Delimiter, - self => self.0.into_value(), - v: EcoString => { - let mut chars = v.chars(); - let first = chars.next().ok_or("delimiter must not be empty")?; - if chars.next().is_some() { - bail!("delimiter must be a single character"); - } - - if !first.is_ascii() { - bail!("delimiter must be an ASCII character"); - } - - Self(first) - }, -} - -/// Format the user-facing CSV error message. -fn format_csv_error(err: ::csv::Error, line: usize) -> EcoString { - match err.kind() { - ::csv::ErrorKind::Utf8 { .. } => "file is not valid utf-8".into(), - ::csv::ErrorKind::UnequalLengths { expected_len, len, .. } => { - eco_format!( - "failed to parse CSV (found {len} instead of \ - {expected_len} fields in line {line})" - ) - } - _ => eco_format!("failed to parse CSV ({err})"), - } -} - -/// Reads structured data from a JSON file. -/// -/// The file must contain a valid JSON object or array. JSON objects will be -/// converted into Typst dictionaries, and JSON arrays will be converted into -/// Typst arrays. Strings and booleans will be converted into the Typst -/// equivalents, `null` will be converted into `{none}`, and numbers will be -/// converted to floats or integers depending on whether they are whole numbers. -/// -/// The function returns a dictionary or an array, depending on the JSON file. -/// -/// The JSON files in the example contain objects with the keys `temperature`, -/// `unit`, and `weather`. -/// -/// # Example -/// ```example -/// #let forecast(day) = block[ -/// #box(square( -/// width: 2cm, -/// inset: 8pt, -/// fill: if day.weather == "sunny" { -/// yellow -/// } else { -/// aqua -/// }, -/// align( -/// bottom + right, -/// strong(day.weather), -/// ), -/// )) -/// #h(6pt) -/// #set text(22pt, baseline: -8pt) -/// #day.temperature °#day.unit -/// ] -/// -/// #forecast(json("monday.json")) -/// #forecast(json("tuesday.json")) -/// ``` -#[func(scope, title = "JSON")] -pub fn json( - /// The virtual machine. - vm: &mut Vm, - /// Path to a JSON file. - path: Spanned, -) -> SourceResult { - let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; - json::decode(Spanned::new(Readable::Bytes(data), span)) -} - -#[scope] -impl json { - /// Reads structured data from a JSON string/bytes. - #[func(title = "Decode JSON")] - pub fn decode( - /// JSON data. - data: Spanned, - ) -> SourceResult { - let Spanned { v: data, span } = data; - serde_json::from_slice(data.as_slice()) - .map_err(|err| eco_format!("failed to parse JSON ({err})")) - .at(span) - } - - /// Encodes structured data into a JSON string. - #[func(title = "Encode JSON")] - pub fn encode( - /// Value to be encoded. - value: Spanned, - /// Whether to pretty print the JSON with newlines and indentation. - #[named] - #[default(true)] - pretty: bool, - ) -> SourceResult { - let Spanned { v: value, span } = value; - if pretty { - serde_json::to_string_pretty(&value) - } else { - serde_json::to_string(&value) - } - .map(|v| v.into()) - .map_err(|err| eco_format!("failed to encode value as JSON ({err})")) - .at(span) - } -} - -/// Reads structured data from a TOML file. -/// -/// The file must contain a valid TOML table. TOML tables will be converted into -/// Typst dictionaries, and TOML arrays will be converted into Typst arrays. -/// Strings, booleans and datetimes will be converted into the Typst equivalents -/// and numbers will be converted to floats or integers depending on whether -/// they are whole numbers. -/// -/// The TOML file in the example consists of a table with the keys `title`, -/// `version`, and `authors`. -/// -/// # Example -/// ```example -/// #let details = toml("details.toml") -/// -/// Title: #details.title \ -/// Version: #details.version \ -/// Authors: #(details.authors -/// .join(", ", last: " and ")) -/// ``` -#[func(scope, title = "TOML")] -pub fn toml( - /// The virtual machine. - vm: &mut Vm, - /// Path to a TOML file. - path: Spanned, -) -> SourceResult { - let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; - toml::decode(Spanned::new(Readable::Bytes(data), span)) -} - -#[scope] -impl toml { - /// Reads structured data from a TOML string/bytes. - #[func(title = "Decode TOML")] - pub fn decode( - /// TOML data. - data: Spanned, - ) -> SourceResult { - let Spanned { v: data, span } = data; - let raw = std::str::from_utf8(data.as_slice()) - .map_err(|_| "file is not valid utf-8") - .at(span)?; - ::toml::from_str(raw) - .map_err(|err| format_toml_error(err, raw)) - .at(span) - } - - /// Encodes structured data into a TOML string. - #[func(title = "Encode TOML")] - pub fn encode( - /// Value to be encoded. - value: Spanned, - /// Whether to pretty-print the resulting TOML. - #[named] - #[default(true)] - pretty: bool, - ) -> SourceResult { - let Spanned { v: value, span } = value; - if pretty { ::toml::to_string_pretty(&value) } else { ::toml::to_string(&value) } - .map(|v| v.into()) - .map_err(|err| eco_format!("failed to encode value as TOML ({err})")) - .at(span) - } -} - -/// Format the user-facing TOML error message. -fn format_toml_error(error: ::toml::de::Error, raw: &str) -> EcoString { - if let Some(head) = error.span().and_then(|range| raw.get(..range.start)) { - let line = head.lines().count(); - let column = 1 + head.chars().rev().take_while(|&c| !is_newline(c)).count(); - eco_format!( - "failed to parse TOML ({} at line {line} column {column})", - error.message(), - ) - } else { - eco_format!("failed to parse TOML ({})", error.message()) - } -} - -/// Reads structured data from a YAML file. -/// -/// The file must contain a valid YAML object or array. YAML mappings will be -/// converted into Typst dictionaries, and YAML sequences will be converted into -/// Typst arrays. Strings and booleans will be converted into the Typst -/// equivalents, null-values (`null`, `~` or empty ``) will be converted into -/// `{none}`, and numbers will be converted to floats or integers depending on -/// whether they are whole numbers. Custom YAML tags are ignored, though the -/// loaded value will still be present. -/// -/// The YAML files in the example contain objects with authors as keys, -/// each with a sequence of their own submapping with the keys -/// "title" and "published" -/// -/// # Example -/// ```example -/// #let bookshelf(contents) = { -/// for (author, works) in contents { -/// author -/// for work in works [ -/// - #work.title (#work.published) -/// ] -/// } -/// } -/// -/// #bookshelf( -/// yaml("scifi-authors.yaml") -/// ) -/// ``` -#[func(scope, title = "YAML")] -pub fn yaml( - /// The virtual machine. - vm: &mut Vm, - /// Path to a YAML file. - path: Spanned, -) -> SourceResult { - let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; - yaml::decode(Spanned::new(Readable::Bytes(data), span)) -} - -#[scope] -impl yaml { - /// Reads structured data from a YAML string/bytes. - #[func(title = "Decode YAML")] - pub fn decode( - /// YAML data. - data: Spanned, - ) -> SourceResult { - let Spanned { v: data, span } = data; - serde_yaml::from_slice(data.as_slice()) - .map_err(|err| eco_format!("failed to parse YAML ({err})")) - .at(span) - } - - /// Encode structured data into a YAML string. - #[func(title = "Encode YAML")] - pub fn encode( - /// Value to be encoded. - value: Spanned, - ) -> SourceResult { - let Spanned { v: value, span } = value; - serde_yaml::to_string(&value) - .map(|v| v.into()) - .map_err(|err| eco_format!("failed to encode value as YAML ({err})")) - .at(span) - } -} - -/// Reads structured data from a CBOR file. -/// -/// The file must contain a valid cbor serialization. Mappings will be -/// converted into Typst dictionaries, and sequences will be converted into -/// Typst arrays. Strings and booleans will be converted into the Typst -/// equivalents, null-values (`null`, `~` or empty ``) will be converted into -/// `{none}`, and numbers will be converted to floats or integers depending on -/// whether they are whole numbers. -#[func(scope, title = "CBOR")] -pub fn cbor( - /// The virtual machine. - vm: &mut Vm, - /// Path to a CBOR file. - path: Spanned, -) -> SourceResult { - let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; - cbor::decode(Spanned::new(data, span)) -} - -#[scope] -impl cbor { - /// Reads structured data from CBOR bytes. - #[func(title = "Decode CBOR")] - pub fn decode( - /// cbor data. - data: Spanned, - ) -> SourceResult { - let Spanned { v: data, span } = data; - ciborium::from_reader(data.as_slice()) - .map_err(|err| eco_format!("failed to parse CBOR ({err})")) - .at(span) - } - - /// Encode structured data into CBOR bytes. - #[func(title = "Encode CBOR")] - pub fn encode( - /// Value to be encoded. - value: Spanned, - ) -> SourceResult { - let Spanned { v: value, span } = value; - let mut res = Vec::new(); - ciborium::into_writer(&value, &mut res) - .map(|_| res.into()) - .map_err(|err| eco_format!("failed to encode value as CBOR ({err})")) - .at(span) - } -} - -/// Reads structured data from an XML file. -/// -/// The XML file is parsed into an array of dictionaries and strings. XML nodes -/// can be elements or strings. Elements are represented as dictionaries with -/// the the following keys: -/// -/// - `tag`: The name of the element as a string. -/// - `attrs`: A dictionary of the element's attributes as strings. -/// - `children`: An array of the element's child nodes. -/// -/// The XML file in the example contains a root `news` tag with multiple -/// `article` tags. Each article has a `title`, `author`, and `content` tag. The -/// `content` tag contains one or more paragraphs, which are represented as `p` -/// tags. -/// -/// # Example -/// ```example -/// #let find-child(elem, tag) = { -/// elem.children -/// .find(e => "tag" in e and e.tag == tag) -/// } -/// -/// #let article(elem) = { -/// let title = find-child(elem, "title") -/// let author = find-child(elem, "author") -/// let pars = find-child(elem, "content") -/// -/// heading(title.children.first()) -/// text(10pt, weight: "medium")[ -/// Published by -/// #author.children.first() -/// ] -/// -/// for p in pars.children { -/// if (type(p) == "dictionary") { -/// parbreak() -/// p.children.first() -/// } -/// } -/// } -/// -/// #let data = xml("example.xml") -/// #for elem in data.first().children { -/// if (type(elem) == "dictionary") { -/// article(elem) -/// } -/// } -/// ``` -#[func(scope, title = "XML")] -pub fn xml( - /// The virtual machine. - vm: &mut Vm, - /// Path to an XML file. - path: Spanned, -) -> SourceResult { - let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; - xml::decode(Spanned::new(Readable::Bytes(data), span)) -} - -#[scope] -impl xml { - /// Reads structured data from an XML string/bytes. - #[func(title = "Decode XML")] - pub fn decode( - /// XML data. - data: Spanned, - ) -> SourceResult { - let Spanned { v: data, span } = data; - let text = std::str::from_utf8(data.as_slice()) - .map_err(FileError::from) - .at(span)?; - let document = - roxmltree::Document::parse(text).map_err(format_xml_error).at(span)?; - Ok(convert_xml(document.root())) - } -} - -/// Convert an XML node to a Typst value. -fn convert_xml(node: roxmltree::Node) -> Value { - if node.is_text() { - return node.text().unwrap_or_default().into_value(); - } - - let children: Array = node.children().map(convert_xml).collect(); - if node.is_root() { - return Value::Array(children); - } - - let tag: Str = node.tag_name().name().into(); - let attrs: Dict = node - .attributes() - .map(|attr| (attr.name().into(), attr.value().into_value())) - .collect(); - - Value::Dict(dict! { - "tag" => tag, - "attrs" => attrs, - "children" => children, - }) -} - -/// Format the user-facing XML error message. -fn format_xml_error(error: roxmltree::Error) -> EcoString { - format_xml_like_error("XML", error) -} diff --git a/crates/typst-library/src/compute/mod.rs b/crates/typst-library/src/compute/mod.rs deleted file mode 100644 index f1af24c55..000000000 --- a/crates/typst-library/src/compute/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Computational functions. - -pub mod calc; -pub mod sys; - -mod data; -mod foundations; - -pub use self::data::*; -pub use self::foundations::*; - -use crate::prelude::*; - -/// Hook up all compute definitions. -pub(super) fn define(global: &mut Scope) { - self::foundations::define(global); - self::data::define(global); - self::calc::define(global); - self::sys::define(global); -} diff --git a/crates/typst-library/src/layout/align.rs b/crates/typst-library/src/layout/align.rs deleted file mode 100644 index 9c18266db..000000000 --- a/crates/typst-library/src/layout/align.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::prelude::*; - -/// Aligns content horizontally and vertically. -/// -/// # Example -/// ```example -/// #set align(center) -/// -/// Centered text, a sight to see \ -/// In perfect balance, visually \ -/// Not left nor right, it stands alone \ -/// A work of art, a visual throne -/// ``` -#[elem(Show)] -pub struct AlignElem { - /// The [alignment]($alignment) along both axes. - /// - /// ```example - /// #set page(height: 6cm) - /// #set text(lang: "ar") - /// - /// مثال - /// #align( - /// end + horizon, - /// rect(inset: 12pt)[ركن] - /// ) - /// ``` - #[positional] - #[fold] - #[default] - pub alignment: Align, - - /// The content to align. - #[required] - pub body: Content, -} - -impl Show for AlignElem { - #[tracing::instrument(name = "AlignElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { - Ok(self - .body() - .clone() - .styled(Self::set_alignment(self.alignment(styles)))) - } -} diff --git a/crates/typst-library/src/lib.rs b/crates/typst-library/src/lib.rs deleted file mode 100644 index 212debb05..000000000 --- a/crates/typst-library/src/lib.rs +++ /dev/null @@ -1,170 +0,0 @@ -//! Typst's standard library. - -#![allow(clippy::wildcard_in_or_patterns)] -#![allow(clippy::manual_range_contains)] -#![allow(clippy::comparison_chain)] - -pub mod compute; -pub mod layout; -pub mod math; -pub mod meta; -pub mod prelude; -pub mod shared; -pub mod symbols; -pub mod text; -pub mod visualize; - -use typst::eval::{Array, LangItems, Library, Module, Scope, Smart}; -use typst::geom::{Align, Color, Dir}; -use typst::model::{NativeElement, Styles}; - -use self::layout::LayoutRoot; - -/// Construct the standard library. -pub fn build() -> Library { - let math = math::module(); - let global = global(math.clone()); - Library { global, math, styles: styles(), items: items() } -} - -/// Construct the module with global definitions. -#[tracing::instrument(skip_all)] -fn global(math: Module) -> Module { - let mut global = Scope::deduplicating(); - text::define(&mut global); - global.define_module(math); - layout::define(&mut global); - visualize::define(&mut global); - meta::define(&mut global); - symbols::define(&mut global); - compute::define(&mut global); - prelude(&mut global); - Module::new("global", global) -} - -/// Defines scoped values that are globally available, too. -fn prelude(global: &mut Scope) { - global.reset_category(); - global.define("black", Color::BLACK); - global.define("gray", Color::GRAY); - global.define("silver", Color::SILVER); - global.define("white", Color::WHITE); - global.define("navy", Color::NAVY); - global.define("blue", Color::BLUE); - global.define("aqua", Color::AQUA); - global.define("teal", Color::TEAL); - global.define("eastern", Color::EASTERN); - global.define("purple", Color::PURPLE); - global.define("fuchsia", Color::FUCHSIA); - global.define("maroon", Color::MAROON); - global.define("red", Color::RED); - global.define("orange", Color::ORANGE); - global.define("yellow", Color::YELLOW); - global.define("olive", Color::OLIVE); - global.define("green", Color::GREEN); - global.define("lime", Color::LIME); - global.define("luma", Color::luma_data()); - global.define("oklab", Color::oklab_data()); - global.define("oklch", Color::oklch_data()); - global.define("rgb", Color::rgb_data()); - global.define("cmyk", Color::cmyk_data()); - global.define("range", Array::range_data()); - global.define("ltr", Dir::LTR); - global.define("rtl", Dir::RTL); - global.define("ttb", Dir::TTB); - global.define("btt", Dir::BTT); - global.define("start", Align::START); - global.define("left", Align::LEFT); - global.define("center", Align::CENTER); - global.define("right", Align::RIGHT); - global.define("end", Align::END); - global.define("top", Align::TOP); - global.define("horizon", Align::HORIZON); - global.define("bottom", Align::BOTTOM); -} - -/// Construct the standard style map. -fn styles() -> Styles { - Styles::new() -} - -/// Construct the standard lang item mapping. -fn items() -> LangItems { - LangItems { - layout: |world, content, styles| content.layout_root(world, styles), - em: text::TextElem::size_in, - dir: text::TextElem::dir_in, - space: || text::SpaceElem::new().pack(), - linebreak: || text::LinebreakElem::new().pack(), - text: |text| text::TextElem::new(text).pack(), - text_elem: text::TextElem::elem(), - text_str: |content| Some(content.to::()?.text()), - smart_quote: |double| text::SmartquoteElem::new().with_double(double).pack(), - parbreak: || layout::ParbreakElem::new().pack(), - strong: |body| text::StrongElem::new(body).pack(), - emph: |body| text::EmphElem::new(body).pack(), - raw: |text, lang, block| { - let mut elem = text::RawElem::new(text).with_block(block); - if let Some(lang) = lang { - elem.push_lang(Some(lang)); - } - elem.pack() - }, - raw_languages: text::RawElem::languages, - link: |url| meta::LinkElem::from_url(url).pack(), - reference: |target, supplement| { - let mut elem = meta::RefElem::new(target); - if let Some(supplement) = supplement { - elem.push_supplement(Smart::Custom(Some(meta::Supplement::Content( - supplement, - )))); - } - elem.pack() - }, - bibliography_keys: meta::BibliographyElem::keys, - heading: |level, title| meta::HeadingElem::new(title).with_level(level).pack(), - heading_elem: meta::HeadingElem::elem(), - list_item: |body| layout::ListItem::new(body).pack(), - enum_item: |number, body| { - let mut elem = layout::EnumItem::new(body); - if let Some(number) = number { - elem.push_number(Some(number)); - } - elem.pack() - }, - term_item: |term, description| layout::TermItem::new(term, description).pack(), - equation: |body, block| math::EquationElem::new(body).with_block(block).pack(), - math_align_point: || math::AlignPointElem::new().pack(), - math_delimited: |open, body, close| math::LrElem::new(open + body + close).pack(), - math_attach: |base, t, b, tl, bl, tr, br| { - let mut elem = math::AttachElem::new(base); - if let Some(t) = t { - elem.push_t(Some(t)); - } - if let Some(b) = b { - elem.push_b(Some(b)); - } - if let Some(tl) = tl { - elem.push_tl(Some(tl)); - } - if let Some(bl) = bl { - elem.push_bl(Some(bl)); - } - if let Some(tr) = tr { - elem.push_tr(Some(tr)); - } - if let Some(br) = br { - elem.push_br(Some(br)); - } - elem.pack() - }, - math_primes: |count| math::PrimesElem::new(count).pack(), - math_accent: |base, accent| { - math::AccentElem::new(base, math::Accent::new(accent)).pack() - }, - math_frac: |num, denom| math::FracElem::new(num, denom).pack(), - math_root: |index, radicand| { - math::RootElem::new(radicand).with_index(index).pack() - }, - } -} diff --git a/crates/typst-library/src/meta/mod.rs b/crates/typst-library/src/meta/mod.rs deleted file mode 100644 index ffe861abf..000000000 --- a/crates/typst-library/src/meta/mod.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! Interaction between document parts. - -mod bibliography; -mod cite; -mod context; -mod counter; -mod document; -mod figure; -mod footnote; -mod heading; -mod link; -mod metadata; -#[path = "numbering.rs"] -mod numbering_; -mod outline; -#[path = "query.rs"] -mod query_; -mod reference; -mod state; - -pub use self::bibliography::*; -pub use self::cite::*; -pub use self::context::*; -pub use self::counter::*; -pub use self::document::*; -pub use self::figure::*; -pub use self::footnote::*; -pub use self::heading::*; -pub use self::link::*; -pub use self::metadata::*; -pub use self::numbering_::*; -pub use self::outline::*; -pub use self::query_::*; -pub use self::reference::*; -pub use self::state::*; - -use crate::prelude::*; -use crate::text::TextElem; - -/// Hook up all meta definitions. -pub(super) fn define(global: &mut Scope) { - global.category("meta"); - global.define_type::