diff options
Diffstat (limited to 'docs')
24 files changed, 535 insertions, 74 deletions
diff --git a/docs/Cargo.toml b/docs/Cargo.toml index 41a5645e..acc55175 100644 --- a/docs/Cargo.toml +++ b/docs/Cargo.toml @@ -17,6 +17,8 @@ cli = ["clap", "typst-render", "serde_json"] [dependencies] typst = { workspace = true } +typst-render = { workspace = true, optional = true } +typst-utils = { workspace = true } typst-assets = { workspace = true, features = ["fonts"] } typst-dev-assets = { workspace = true } clap = { workspace = true, optional = true } @@ -28,7 +30,7 @@ serde_json = { workspace = true, optional = true } serde_yaml = { workspace = true } syntect = { workspace = true, features = ["html"] } typed-arena = { workspace = true } -typst-render = { workspace = true, optional = true } +unicode-math-class = { workspace = true } unscanny = { workspace = true } yaml-front-matter = { workspace = true } diff --git a/docs/guides/guide-for-latex-users.md b/docs/guides/guide-for-latex-users.md index 743afa5a..5137ae1a 100644 --- a/docs/guides/guide-for-latex-users.md +++ b/docs/guides/guide-for-latex-users.md @@ -657,7 +657,8 @@ applicable, contains possible workarounds. - **Well-established plotting ecosystem.** LaTeX users often create elaborate charts along with their documents in PGF/TikZ. The Typst ecosystem does not yet offer the same breadth of available options, but the ecosystem around the - [`cetz`](https://github.com/cetz-package/cetz) package is catching up quickly. + [`cetz` package](https://typst.app/universe/package/cetz) is catching up + quickly. - **Change page margins without a pagebreak.** In LaTeX, margins can always be adjusted, even without a pagebreak. To change margins in Typst, you use the @@ -670,4 +671,6 @@ applicable, contains possible workarounds. format, but you can easily convert both into SVG files with [online tools](https://cloudconvert.com/pdf-to-svg) or [Inkscape](https://inkscape.org/). The web app will automatically convert PDF - files to SVG files upon uploading them. + files to SVG files upon uploading them. You can also use the + community-provided [`muchpdf` package](https://typst.app/universe/package/muchpdf) + to embed PDFs. It internally converts PDFs to SVGs on-the-fly. diff --git a/docs/reference/export/html.md b/docs/reference/export/html.md new file mode 100644 index 00000000..330c2e13 --- /dev/null +++ b/docs/reference/export/html.md @@ -0,0 +1,61 @@ +<div class="info-box"> + +Typst's HTML export is currently under active development. The feature is still +very incomplete and only available for experimentation behind a feature flag. Do +not use this feature for production use cases. In the CLI, you can experiment +with HTML export by passing `--features html` or setting the `TYPST_FEATURES` +environment variables to `html`. In the web app, HTML export is not available at +this time. Visit the [tracking issue](https://github.com/typst/typst/issues/5512) +to follow progress on HTML export and learn more about planned features. +</div> + +HTML files describe a document structurally. The aim of Typst's HTML export is +to capture the structure of an input document and produce semantically rich HTML +that retains this structure. The resulting HTML should be accessible, +human-readable, and editable by hand and downstream tools. + +PDF, PNG, and SVG export, in contrast, all produce _visual_ representations of a +fully-laid out document. This divergence in the formats' intents means that +Typst cannot simply produce perfect HTML for your existing Typst documents. It +cannot always know what the best semantic HTML representation of your content +is. + +Instead, it gives _you_ full control: You can check the current export format +through the [`target`] function and when it is set to HTML, generate [raw HTML +elements]($html.elem). The primary intended use of these elements is in +templates and show rules. This way, the document's contents can be fully +agnostic to the export target and content can be shared between PDF and HTML +export. + +Currently, Typst will always output a single HTML file. Support for outputting +directories with multiple HTML documents and assets, as well as support for +outputting fragments that can be integrated into other HTML documents is +planned. + +Typst currently does not output CSS style sheets, instead focussing on emitting +semantic markup. You can of course write your own CSS styles and still benefit +from sharing your _content_ between PDF and HTML. For the future, we plan to +give you the option of automatically emitting CSS, taking more of your existing +set rules into account. + +# Exporting as HTML +## Command Line +Pass `--format html` to the `compile` or `watch` subcommand or provide an output +file name that ends with `.html`. Note that you must also pass `--features html` +or set `TYPST_FEATURES=html` to enable this experimental export target. + +When using `typst watch`, Typst will spin up a live-reloading HTTP server. You +can configure it as follows: + +- Pass `--port` to change the port. (Defaults to the first free port in the + range 3000-3005.) +- Pass `--no-reload` to disable injection of a live reload script. (The HTML + that is written to disk isn't affected either way.) +- Pass `--no-serve` to disable the server altogether. + +## Web App +Not currently available. + +# HTML-specific functionality +Typst exposes HTML-specific functionality in the global `html` module. See below +for the definitions it contains. diff --git a/docs/reference/export/pdf.md b/docs/reference/export/pdf.md new file mode 100644 index 00000000..b220ae94 --- /dev/null +++ b/docs/reference/export/pdf.md @@ -0,0 +1,71 @@ +PDF files focus on accurately describing documents visually, but also have +facilities for annotating their structure. This hybrid approach makes +them a good fit for document exchange: They render exactly the same on every +device, but also support extraction of a document's content and structure (at +least to an extent). Unlike PNG files, PDFs are not bound to a specific +resolution. Hence, you can view them at any size without incurring a loss of +quality. + +# PDF standards +The International Standards Organization (ISO) has published the base PDF +standard and various standards that extend it to make PDFs more suitable for +specific use-cases. By default, Typst exports PDF 1.7 files. Adobe Acrobat 8 and +later as well as all other commonly used PDF viewers are compatible with this +PDF version. + +## PDF/A +Typst optionally supports emitting PDF/A-conformant files. PDF/A files are +geared towards maximum compatibility with current and future PDF tooling. They +do not rely on difficult-to-implement or proprietary features and contain +exhaustive metadata. This makes them suitable for long-term archival. + +The PDF/A Standard has multiple versions (_parts_ in ISO terminology) and most +parts have multiple profiles that indicate the file's conformance level. +Currently, Typst supports these PDF/A output profiles: + +- PDF/A-2b: The basic conformance level of ISO 19005-2. This version of PDF/A is + based on PDF 1.7 and results in self-contained, archivable PDF files. + +- PDF/A-3b: The basic conformance level of ISO 19005-3. This version of PDF/A is + based on PDF 1.7 and results in archivable PDF files that can contain + arbitrary other related files as [attachments]($pdf.embed). The only + difference between it and PDF/A-2b is the capability to embed + non-PDF/A-conformant files within. + +When choosing between exporting PDF/A and regular PDF, keep in mind that PDF/A +files contain additional metadata, and that some readers will prevent the user +from modifying a PDF/A file. Some features of Typst may be disabled depending on +the PDF standard you choose. + +# Exporting as PDF +## Command Line +PDF is Typst's default export format. Running the `compile` or `watch` +subcommand without specifying a format will create a PDF. When exporting to PDF, +you have the following configuration options: + +- Which PDF standards Typst should enforce conformance with by specifying + `--pdf-standard` followed by one or multiple comma-separated standards. Valid + standards are `1.7`, `a-2b`, and `a-3b`. By default, Typst outputs + PDF-1.7-compliant files. + +- Which pages to export by specifying `--pages` followed by a comma-separated + list of numbers or dash-separated number ranges. Ranges can be half-open. + Example: `2,3,7-9,11-`. + +## Web App +Click the quick download button at the top right to export a PDF with default +settings. For further configuration, click "File" > "Export as" > "PDF" or click +the downwards-facing arrow next to the quick download button and select "Export +as PDF". When exporting to PDF, you have the following configuration options: + +- Which PDF standards Typst should enforce conformance with. By default, Typst + outputs PDF-1.7-compliant files. Valid additional standards are `A-2b` and + `A-3b`. + +- Which pages to export. Valid options are "All pages", "Current page", and + "Custom ranges". Custom ranges are a comma-separated list of numbers or + dash-separated number ranges. Ranges can be half-open. Example: `2,3,7-9,11-`. + +# PDF-specific functionality +Typst exposes PDF-specific functionality in the global `pdf` module. See below +for the definitions it contains. diff --git a/docs/reference/export/png.md b/docs/reference/export/png.md new file mode 100644 index 00000000..fe122f4d --- /dev/null +++ b/docs/reference/export/png.md @@ -0,0 +1,61 @@ +Instead of creating a PDF, Typst can also directly render pages to PNG raster +graphics. PNGs are losslessly compressed images that can contain one page at a +time. When exporting a multi-page document, Typst will emit multiple PNGs. PNGs +are a good choice when you want to use Typst's output in an image editing +software or when you can use none of Typst's other export formats. + +In contrast to Typst's other export formats, PNGs are bound to a specific +resolution. When exporting to PNG, you can configure the resolution as pixels +per inch (PPI). If the medium you view the PNG on has a finer resolution than +the PNG you exported, you will notice a loss of quality. Typst calculates the +resolution of your PNGs based on each page's physical dimensions and the PPI. If +you need guidance for choosing a PPI value, consider the following: + +- A DPI value of 300 or 600 is typical for desktop printing. +- Professional prints of detailed graphics can go up to 1200 PPI. +- If your document is only viewed at a distance, e.g. a poster, you may choose a + smaller value than 300. +- If your document is viewed on screens, a typical PPI value for a smartphone is + 400-500. + +Because PNGs only contain a pixel raster, the text within cannot be extracted +automatically (without OCR), for example by copy/paste or a screen reader. If +you need the text to be accessible, export a PDF or HTML file instead. + +PNGs can have transparent backgrounds. By default, Typst will output a PNG with +an opaque white background. You can make the background transparent using +`[#set page(fill: none)]`. Learn more on the +[`page` function's reference page]($page.fill). + +# Exporting as PNG +## Command Line +Pass `--format png` to the `compile` or `watch` subcommand or provide an output +file name that ends with `.png`. + +If your document has more than one page, Typst will create multiple image files. +The output file name must then be a template string containing at least one of +- `[{p}]`, which will be replaced by the page number +- `[{0p}]`, which will be replaced by the zero-padded page number (so that all + numbers have the same length) +- `[{t}]`, which will be replaced by the total number of pages + +When exporting to PNG, you have the following configuration options: + +- Which resolution to render at by specifying `--ppi` followed by a number of + pixels per inch. The default is `144`. + +- Which pages to export by specifying `--pages` followed by a comma-separated + list of numbers or dash-separated number ranges. Ranges can be half-open. + Example: `2,3,7-9,11-`. + +## Web App +Click "File" > "Export as" > "PNG" or click the downwards-facing arrow next to +the quick download button and select "Export as PNG". When exporting to PNG, you +have the following configuration options: + +- The resolution at which the pages should be rendered, as a number of pixels + per inch. The default is `144`. + +- Which pages to export. Valid options are "All pages", "Current page", and + "Custom ranges". Custom ranges are a comma-separated list of numbers or + dash-separated number ranges. Ranges can be half-open. Example: `2,3,7-9,11-`. diff --git a/docs/reference/export/svg.md b/docs/reference/export/svg.md new file mode 100644 index 00000000..630ab845 --- /dev/null +++ b/docs/reference/export/svg.md @@ -0,0 +1,48 @@ +Instead of creating a PDF, Typst can also directly render pages to scalable +vector graphics (SVGs), which are the preferred format for embedding vector +graphics in web pages. Like PDF files, SVGs display your document exactly how +you have laid it out in Typst. Likewise, they share the benefit of not being +bound to a specific resolution. Hence, you can print or view SVG files on any +device without incurring a loss of quality. (Note that font printing quality may +be better with a PDF.) In contrast to a PDF, an SVG cannot contain multiple +pages. When exporting a multi-page document, Typst will emit multiple SVGs. + +SVGs can represent text in two ways: By embedding the text itself and rendering +it with the fonts available on the viewer's computer or by embedding the shapes +of each glyph in the font used to create the document. To ensure that the SVG +file looks the same across all devices it is viewed on, Typst chooses the latter +method. This means that the text in the SVG cannot be extracted automatically, +for example by copy/paste or a screen reader. If you need the text to be +accessible, export a PDF or HTML file instead. + +SVGs can have transparent backgrounds. By default, Typst will output an SVG with +an opaque white background. You can make the background transparent using +`[#set page(fill: none)]`. Learn more on the +[`page` function's reference page]($page.fill). + +# Exporting as SVG +## Command Line +Pass `--format svg` to the `compile` or `watch` subcommand or provide an output +file name that ends with `.svg`. + +If your document has more than one page, Typst will create multiple image files. +The output file name must then be a template string containing at least one of +- `[{p}]`, which will be replaced by the page number +- `[{0p}]`, which will be replaced by the zero-padded page number (so that all + numbers have the same length) +- `[{t}]`, which will be replaced by the total number of pages + +When exporting to SVG, you have the following configuration options: + +- Which pages to export by specifying `--pages` followed by a comma-separated + list of numbers or dash-separated number ranges. Ranges can be half-open. + Example: `2,3,7-9,11-`. + +## Web App +Click "File" > "Export as" > "SVG" or click the downwards-facing arrow next to +the quick download button and select "Export as SVG". When exporting to SVG, you +have the following configuration options: + +- Which pages to export. Valid options are "All pages", "Current page", and + "Custom ranges". Custom ranges are a comma-separated list of numbers or + dash-separated number ranges. Ranges can be half-open. Example: `2,3,7-9,11-`. diff --git a/docs/reference/context.md b/docs/reference/language/context.md index bdd520f5..bdd520f5 100644 --- a/docs/reference/context.md +++ b/docs/reference/language/context.md diff --git a/docs/reference/scripting.md b/docs/reference/language/scripting.md index 5e0f1555..5e0f1555 100644 --- a/docs/reference/scripting.md +++ b/docs/reference/language/scripting.md diff --git a/docs/reference/styling.md b/docs/reference/language/styling.md index b0b7ab71..b0b7ab71 100644 --- a/docs/reference/styling.md +++ b/docs/reference/language/styling.md diff --git a/docs/reference/syntax.md b/docs/reference/language/syntax.md index fdc4d154..fdc4d154 100644 --- a/docs/reference/syntax.md +++ b/docs/reference/language/syntax.md diff --git a/docs/reference/library/data-loading.md b/docs/reference/library/data-loading.md new file mode 100644 index 00000000..659a8ccc --- /dev/null +++ b/docs/reference/library/data-loading.md @@ -0,0 +1,4 @@ +Data loading from external files. + +These functions help you with loading and embedding data, for example from the +results of an experiment. diff --git a/docs/reference/library/foundations.md b/docs/reference/library/foundations.md new file mode 100644 index 00000000..738c3789 --- /dev/null +++ b/docs/reference/library/foundations.md @@ -0,0 +1,4 @@ +Foundational types and functions. + +Here, you'll find documentation for basic data types like [integers]($int) and +[strings]($str) as well as details about core computational functions. diff --git a/docs/reference/library/introspection.md b/docs/reference/library/introspection.md new file mode 100644 index 00000000..f48a9937 --- /dev/null +++ b/docs/reference/library/introspection.md @@ -0,0 +1,10 @@ +Interactions between document parts. + +This category is home to Typst's introspection capabilities: With the `counter` +function, you can access and manipulate page, section, figure, and equation +counters or create custom ones. Meanwhile, the `query` function lets you search +for elements in the document to construct things like a list of figures or +headers which show the current chapter title. + +Most of the functions are _contextual._ It is recommended to read the chapter on +[context] before continuing here. diff --git a/docs/reference/library/layout.md b/docs/reference/library/layout.md new file mode 100644 index 00000000..450058d4 --- /dev/null +++ b/docs/reference/library/layout.md @@ -0,0 +1,3 @@ +Arranging elements on the page in different ways. + +By combining layout functions, you can create complex and automatic layouts. diff --git a/docs/reference/library/math.md b/docs/reference/library/math.md new file mode 100644 index 00000000..61f2bb58 --- /dev/null +++ b/docs/reference/library/math.md @@ -0,0 +1,101 @@ +Typst has special [syntax]($syntax/#math) and library functions to typeset +mathematical formulas. Math formulas can be displayed inline with text or as +separate blocks. They will be typeset into their own block if they start and end +with at least one space (e.g. `[$ x^2 $]`). + +# Variables +In math, single letters are always displayed as is. Multiple letters, however, +are interpreted as variables and functions. To display multiple letters +verbatim, you can place them into quotes and to access single letter variables, +you can use the [hash syntax]($scripting/#expressions). + +```example +$ A = pi r^2 $ +$ "area" = pi dot "radius"^2 $ +$ cal(A) := + { x in RR | x "is natural" } $ +#let x = 5 +$ #x < 17 $ +``` + +# Symbols +Math mode makes a wide selection of [symbols]($category/symbols/sym) like `pi`, +`dot`, or `RR` available. Many mathematical symbols are available in different +variants. You can select between different variants by applying +[modifiers]($symbol) to the symbol. Typst further recognizes a number of +shorthand sequences like `=>` that approximate a symbol. When such a shorthand +exists, the symbol's documentation lists it. + +```example +$ x < y => x gt.eq.not y $ +``` + +# Line Breaks +Formulas can also contain line breaks. Each line can contain one or multiple +_alignment points_ (`&`) which are then aligned. + +```example +$ sum_(k=0)^n k + &= 1 + ... + n \ + &= (n(n+1)) / 2 $ +``` + +# Function calls +Math mode supports special function calls without the hash prefix. In these +"math calls", the argument list works a little differently than in code: + +- Within them, Typst is still in "math mode". Thus, you can write math directly + into them, but need to use hash syntax to pass code expressions (except for + strings, which are available in the math syntax). +- They support positional and named arguments, as well as argument spreading. +- They don't support trailing content blocks. +- They provide additional syntax for 2-dimensional argument lists. The semicolon + (`;`) merges preceding arguments separated by commas into an array argument. + +```example +$ frac(a^2, 2) $ +$ vec(1, 2, delim: "[") $ +$ mat(1, 2; 3, 4) $ +$ mat(..#range(1, 5).chunks(2)) $ +$ lim_x = + op("lim", limits: #true)_x $ +``` + +To write a verbatim comma or semicolon in a math call, escape it with a +backslash. The colon on the other hand is only recognized in a special way if +directly preceded by an identifier, so to display it verbatim in those cases, +you can just insert a space before it. + +Functions calls preceded by a hash are normal code function calls and not +affected by these rules. + +# Alignment +When equations include multiple _alignment points_ (`&`), this creates blocks of +alternatingly right- and left-aligned columns. In the example below, the +expression `(3x + y) / 7` is right-aligned and `= 9` is left-aligned. The word +"given" is also left-aligned because `&&` creates two alignment points in a row, +alternating the alignment twice. `& &` and `&&` behave exactly the same way. +Meanwhile, "multiply by 7" is right-aligned because just one `&` precedes it. +Each alignment point simply alternates between right-aligned/left-aligned. + +```example +$ (3x + y) / 7 &= 9 && "given" \ + 3x + y &= 63 & "multiply by 7" \ + 3x &= 63 - y && "subtract y" \ + x &= 21 - y/3 & "divide by 3" $ +``` + +# Math fonts +You can set the math font by with a [show-set rule]($styling/#show-rules) as +demonstrated below. Note that only special OpenType math fonts are suitable for +typesetting maths. + +```example +#show math.equation: set text(font: "Fira Math") +$ sum_(i in NN) 1 + i $ +``` + +# Math module +All math functions are part of the `math` [module]($scripting/#modules), which +is available by default in equations. Outside of equations, they can be accessed +with the `math.` prefix. diff --git a/docs/reference/library/model.md b/docs/reference/library/model.md new file mode 100644 index 00000000..e433ed53 --- /dev/null +++ b/docs/reference/library/model.md @@ -0,0 +1,5 @@ +Document structuring. + +Here, you can find functions to structure your document and interact with that +structure. This includes section headings, figures, bibliography management, +cross-referencing and more. diff --git a/docs/reference/library/symbols.md b/docs/reference/library/symbols.md new file mode 100644 index 00000000..2e6f48cd --- /dev/null +++ b/docs/reference/library/symbols.md @@ -0,0 +1,5 @@ +These two modules give names to symbols and emoji to make them easy to insert +with a normal keyboard. Alternatively, you can also always directly enter +Unicode symbols into your text and formulas. In addition to the symbols listed +below, math mode defines `dif` and `Dif`. These are not normal symbol values +because they also affect spacing and font style. diff --git a/docs/reference/library/text.md b/docs/reference/library/text.md new file mode 100644 index 00000000..239c0b26 --- /dev/null +++ b/docs/reference/library/text.md @@ -0,0 +1,3 @@ +Text styling. + +The [text function]($text) is of particular interest. diff --git a/docs/reference/library/visualize.md b/docs/reference/library/visualize.md new file mode 100644 index 00000000..9259401f --- /dev/null +++ b/docs/reference/library/visualize.md @@ -0,0 +1,5 @@ +Drawing and data visualization. + +If you want to create more advanced drawings or plots, also have a look at the +[CetZ](https://github.com/johannes-wolf/cetz) package as well as more +specialized [packages]($universe) for your use case. diff --git a/docs/reference/packages.md b/docs/reference/packages.md deleted file mode 100644 index bfd1ef58..00000000 --- a/docs/reference/packages.md +++ /dev/null @@ -1,6 +0,0 @@ -Typst [packages]($scripting/#packages) encapsulate reusable building blocks -and make them reusable across projects. Below is a list of Typst packages -created by the community. Due to the early and experimental nature of Typst's -package management, they all live in a `preview` namespace. Click on a package's -name to view its documentation and use the copy button on the right to get a -full import statement for it. diff --git a/docs/src/html.rs b/docs/src/html.rs index 4eb3954c..9077d5c4 100644 --- a/docs/src/html.rs +++ b/docs/src/html.rs @@ -301,7 +301,10 @@ impl<'a> Handler<'a> { return; } - let default = self.peeked.as_ref().map(|text| text.to_kebab_case()); + let body = self.peeked.as_ref(); + let default = body.map(|text| text.to_kebab_case()); + let has_id = id_slot.is_some(); + let id: &'a str = match (&id_slot, default) { (Some(id), default) => { if Some(*id) == default.as_deref() { @@ -316,10 +319,10 @@ impl<'a> Handler<'a> { *id_slot = (!id.is_empty()).then_some(id); // Special case for things like "v0.3.0". - let name = if id.starts_with('v') && id.contains('.') { - id.into() - } else { - id.to_title_case().into() + let name = match &body { + _ if id.starts_with('v') && id.contains('.') => id.into(), + Some(body) if !has_id => body.as_ref().into(), + _ => id.to_title_case().into(), }; let mut children = &mut self.outline; diff --git a/docs/src/lib.rs b/docs/src/lib.rs index ff745c9c..f9ee05bb 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -12,27 +12,20 @@ pub use self::model::*; use std::collections::HashSet; use ecow::{eco_format, EcoString}; +use heck::ToTitleCase; use serde::Deserialize; use serde_yaml as yaml; use std::sync::LazyLock; use typst::diag::{bail, StrResult}; -use typst::foundations::Binding; use typst::foundations::{ - AutoValue, Bytes, CastInfo, Category, Func, Module, NoneValue, ParamInfo, Repr, - Scope, Smart, Type, Value, FOUNDATIONS, + AutoValue, Binding, Bytes, CastInfo, Func, Module, NoneValue, ParamInfo, Repr, Scope, + Smart, Type, Value, }; -use typst::html::HTML; -use typst::introspection::INTROSPECTION; -use typst::layout::{Abs, Margin, PageElem, PagedDocument, LAYOUT}; -use typst::loading::DATA_LOADING; -use typst::math::MATH; -use typst::model::MODEL; -use typst::pdf::PDF; -use typst::symbols::SYMBOLS; -use typst::text::{Font, FontBook, TEXT}; +use typst::layout::{Abs, Margin, PageElem, PagedDocument}; +use typst::text::{Font, FontBook}; use typst::utils::LazyHash; -use typst::visualize::VISUALIZE; -use typst::{Feature, Library, LibraryBuilder}; +use typst::{Category, Feature, Library, LibraryBuilder}; +use unicode_math_class::MathClass; macro_rules! load { ($path:literal) => { @@ -64,9 +57,10 @@ static LIBRARY: LazyLock<LazyHash<Library>> = LazyLock::new(|| { let scope = lib.global.scope_mut(); // Add those types, so that they show up in the docs. - scope.start_category(FOUNDATIONS); + scope.start_category(Category::Foundations); scope.define_type::<NoneValue>(); scope.define_type::<AutoValue>(); + scope.reset_category(); // Adjust the default look. lib.styles @@ -155,21 +149,24 @@ fn reference_pages(resolver: &dyn Resolver) -> PageModel { let mut page = md_page(resolver, resolver.base(), load!("reference/welcome.md")); let base = format!("{}reference/", resolver.base()); page.children = vec![ - md_page(resolver, &base, load!("reference/syntax.md")).with_part("Language"), - md_page(resolver, &base, load!("reference/styling.md")), - md_page(resolver, &base, load!("reference/scripting.md")), - md_page(resolver, &base, load!("reference/context.md")), - 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), - category_page(resolver, PDF), - category_page(resolver, HTML), + md_page(resolver, &base, load!("reference/language/syntax.md")) + .with_part("Language"), + md_page(resolver, &base, load!("reference/language/styling.md")), + md_page(resolver, &base, load!("reference/language/scripting.md")), + md_page(resolver, &base, load!("reference/language/context.md")), + category_page(resolver, Category::Foundations).with_part("Library"), + category_page(resolver, Category::Model), + category_page(resolver, Category::Text), + category_page(resolver, Category::Math), + category_page(resolver, Category::Symbols), + category_page(resolver, Category::Layout), + category_page(resolver, Category::Visualize), + category_page(resolver, Category::Introspection), + category_page(resolver, Category::DataLoading), + category_page(resolver, Category::Pdf).with_part("Export"), + category_page(resolver, Category::Html), + category_page(resolver, Category::Png), + category_page(resolver, Category::Svg), ]; page } @@ -219,14 +216,16 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { let mut markup = vec![]; let mut math = vec![]; - let (module, path): (&Module, &[&str]) = if category == MATH { - (&LIBRARY.math, &["math"]) - } else { - (&LIBRARY.global, &[]) + let docs = category_docs(category); + let (module, path): (&Module, &[&str]) = match category { + Category::Math => (&LIBRARY.math, &["math"]), + Category::Pdf => (get_module(&LIBRARY.global, "pdf").unwrap(), &["pdf"]), + Category::Html => (get_module(&LIBRARY.global, "html").unwrap(), &["html"]), + _ => (&LIBRARY.global, &[]), }; // Add groups. - for group in GROUPS.iter().filter(|g| g.category == category.name()).cloned() { + for group in GROUPS.iter().filter(|g| g.category == category).cloned() { if matches!(group.name.as_str(), "sym" | "emoji") { let subpage = symbols_page(resolver, &route, &group); let BodyModel::Symbols(model) = &subpage.body else { continue }; @@ -243,7 +242,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { items.push(CategoryItem { name: group.name.clone(), route: subpage.route.clone(), - oneliner: oneliner(category.docs()).into(), + oneliner: oneliner(docs).into(), code: true, }); children.push(subpage); @@ -256,15 +255,15 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { } // Add symbol pages. These are ordered manually. - if category == SYMBOLS { + if category == Category::Symbols { shorthands = Some(ShorthandsModel { markup, math }); } let mut skip = HashSet::new(); - if category == MATH { + if category == Category::Math { skip = GROUPS .iter() - .filter(|g| g.category == category.name()) + .filter(|g| g.category == category) .flat_map(|g| &g.filter) .map(|s| s.as_str()) .collect(); @@ -273,6 +272,11 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { skip.insert("text"); } + // Tiling would be duplicate otherwise. + if category == Category::Visualize { + skip.insert("pattern"); + } + // Add values and types. let scope = module.scope(); for (name, binding) in scope.iter() { @@ -287,8 +291,8 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { match binding.read() { Value::Func(func) => { let name = func.name().unwrap(); - - let subpage = func_page(resolver, &route, func, path); + let subpage = + func_page(resolver, &route, func, path, binding.deprecation()); items.push(CategoryItem { name: name.into(), route: subpage.route.clone(), @@ -311,31 +315,39 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { } } - if category != SYMBOLS { + if category != Category::Symbols { children.sort_by_cached_key(|child| child.title.clone()); items.sort_by_cached_key(|item| item.name.clone()); } - let name = category.title(); - let details = Html::markdown(resolver, category.docs(), Some(1)); + let title = EcoString::from(match category { + Category::Pdf | Category::Html | Category::Png | Category::Svg => { + category.name().to_uppercase() + } + _ => category.name().to_title_case(), + }); + + let details = Html::markdown(resolver, docs, Some(1)); let mut outline = vec![OutlineItem::from_name("Summary")]; outline.extend(details.outline()); - outline.push(OutlineItem::from_name("Definitions")); + if !items.is_empty() { + outline.push(OutlineItem::from_name("Definitions")); + } if shorthands.is_some() { outline.push(OutlineItem::from_name("Shorthands")); } PageModel { route, - title: name.into(), + title: title.clone(), description: eco_format!( - "Documentation for functions related to {name} in Typst." + "Documentation for functions related to {title} in Typst." ), part: None, outline, body: BodyModel::Category(CategoryModel { name: category.name(), - title: category.title(), + title, details, items, shorthands, @@ -344,14 +356,34 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { } } +/// Retrieve the docs for a category. +fn category_docs(category: Category) -> &'static str { + match category { + Category::Foundations => load!("reference/library/foundations.md"), + Category::Introspection => load!("reference/library/introspection.md"), + Category::Layout => load!("reference/library/layout.md"), + Category::DataLoading => load!("reference/library/data-loading.md"), + Category::Math => load!("reference/library/math.md"), + Category::Model => load!("reference/library/model.md"), + Category::Symbols => load!("reference/library/symbols.md"), + Category::Text => load!("reference/library/text.md"), + Category::Visualize => load!("reference/library/visualize.md"), + Category::Pdf => load!("reference/export/pdf.md"), + Category::Html => load!("reference/export/html.md"), + Category::Svg => load!("reference/export/svg.md"), + Category::Png => load!("reference/export/png.md"), + } +} + /// Create a page for a function. fn func_page( resolver: &dyn Resolver, parent: &str, func: &Func, path: &[&str], + deprecation: Option<&'static str>, ) -> PageModel { - let model = func_model(resolver, func, path, false); + let model = func_model(resolver, func, path, false, deprecation); let name = func.name().unwrap(); PageModel { route: eco_format!("{parent}{}/", urlify(name)), @@ -370,6 +402,7 @@ fn func_model( func: &Func, path: &[&str], nested: bool, + deprecation: Option<&'static str>, ) -> FuncModel { let name = func.name().unwrap(); let scope = func.scope().unwrap(); @@ -383,7 +416,11 @@ fn func_model( } let mut returns = vec![]; - casts(resolver, &mut returns, &mut vec![], func.returns().unwrap()); + let mut strings = vec![]; + casts(resolver, &mut returns, &mut strings, func.returns().unwrap()); + if !strings.is_empty() && !returns.contains(&"str") { + returns.push("str"); + } returns.sort_by_key(|ty| type_index(ty)); if returns == ["none"] { returns.clear(); @@ -401,6 +438,7 @@ fn func_model( oneliner: oneliner(details), element: func.element().is_some(), contextual: func.contextual().unwrap_or(false), + deprecation, details: Html::markdown(resolver, details, nesting), example: example.map(|md| Html::markdown(resolver, md, None)), self_, @@ -483,7 +521,7 @@ fn scope_models(resolver: &dyn Resolver, name: &str, scope: &Scope) -> Vec<FuncM .iter() .filter_map(|(_, binding)| { let Value::Func(func) = binding.read() else { return None }; - Some(func_model(resolver, func, &[name], true)) + Some(func_model(resolver, func, &[name], true, binding.deprecation())) }) .collect() } @@ -559,9 +597,11 @@ fn group_page( let mut outline_items = vec![]; for name in &group.filter { - let value = group.module().scope().get(name).unwrap().read(); - let Ok(ref func) = value.clone().cast::<Func>() else { panic!("not a function") }; - let func = func_model(resolver, func, &path, true); + let binding = group.module().scope().get(name).unwrap(); + let Ok(ref func) = binding.read().clone().cast::<Func>() else { + panic!("not a function") + }; + let func = func_model(resolver, func, &path, true, binding.deprecation()); let id_base = urlify(&eco_format!("functions-{}", func.name)); let children = func_outline(&func, &id_base); outline_items.push(OutlineItem { @@ -628,7 +668,7 @@ fn type_model(resolver: &dyn Resolver, ty: &Type) -> TypeModel { constructor: ty .constructor() .ok() - .map(|func| func_model(resolver, &func, &[], true)), + .map(|func| func_model(resolver, &func, &[], true, None)), scope: scope_models(resolver, ty.short_name(), ty.scope()), } } @@ -682,10 +722,19 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel { list.iter().copied().find(|&(_, x)| x == c).map(|(s, _)| s) }; + let name = complete(variant); + let deprecation = match name.as_str() { + "integral.sect" => { + Some("`integral.sect` is deprecated, use `integral.inter` instead") + } + _ => binding.deprecation(), + }; + list.push(SymbolModel { - name: complete(variant), + name, markup_shorthand: shorthand(typst::syntax::ast::Shorthand::LIST), math_shorthand: shorthand(typst::syntax::ast::MathShorthand::LIST), + math_class: typst_utils::default_math_class(c).map(math_class_name), codepoint: c as _, accent: typst::math::Accent::combine(c).is_some(), alternates: symbol @@ -693,6 +742,7 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel { .filter(|(other, _)| other != &variant) .map(|(other, _)| complete(other)) .collect(), + deprecation, }); } } @@ -769,12 +819,32 @@ const TYPE_ORDER: &[&str] = &[ "stroke", ]; +fn math_class_name(class: MathClass) -> &'static str { + match class { + MathClass::Normal => "Normal", + MathClass::Alphabetic => "Alphabetic", + MathClass::Binary => "Binary", + MathClass::Closing => "Closing", + MathClass::Diacritic => "Diacritic", + MathClass::Fence => "Fence", + MathClass::GlyphPart => "Glyph Part", + MathClass::Large => "Large", + MathClass::Opening => "Opening", + MathClass::Punctuation => "Punctuation", + MathClass::Relation => "Relation", + MathClass::Space => "Space", + MathClass::Unary => "Unary", + MathClass::Vary => "Vary", + MathClass::Special => "Special", + } +} + /// Data about a collection of functions. #[derive(Debug, Clone, Deserialize)] struct GroupData { name: EcoString, title: EcoString, - category: EcoString, + category: Category, #[serde(default)] path: Vec<EcoString>, #[serde(default)] diff --git a/docs/src/link.rs b/docs/src/link.rs index c55261b8..2e836b6c 100644 --- a/docs/src/link.rs +++ b/docs/src/link.rs @@ -44,6 +44,8 @@ fn resolve_known(head: &str, base: &str) -> Option<String> { "$styling" => format!("{base}reference/styling"), "$scripting" => format!("{base}reference/scripting"), "$context" => format!("{base}reference/context"), + "$html" => format!("{base}reference/html"), + "$pdf" => format!("{base}reference/pdf"), "$guides" => format!("{base}guides"), "$changelog" => format!("{base}changelog"), "$universe" => "https://typst.app/universe".into(), @@ -73,11 +75,14 @@ fn resolve_definition(head: &str, base: &str) -> StrResult<String> { // Handle grouped functions. if let Some(group) = GROUPS.iter().find(|group| { - group.category == category.name() && group.filter.iter().any(|func| func == name) + group.category == category && group.filter.iter().any(|func| func == name) }) { let mut route = format!( "{}reference/{}/{}/#functions-{}", - base, group.category, group.name, name + base, + group.category.name(), + group.name, + name ); if let Some(param) = parts.next() { route.push('-'); diff --git a/docs/src/model.rs b/docs/src/model.rs index b222322a..801c60c7 100644 --- a/docs/src/model.rs +++ b/docs/src/model.rs @@ -64,7 +64,7 @@ pub enum BodyModel { #[derive(Debug, Serialize)] pub struct CategoryModel { pub name: &'static str, - pub title: &'static str, + pub title: EcoString, pub details: Html, pub items: Vec<CategoryItem>, pub shorthands: Option<ShorthandsModel>, @@ -89,6 +89,7 @@ pub struct FuncModel { pub oneliner: &'static str, pub element: bool, pub contextual: bool, + pub deprecation: Option<&'static str>, pub details: Html, /// This example is only for nested function models. Others can have /// their example directly in their details. @@ -163,6 +164,8 @@ pub struct SymbolModel { pub alternates: Vec<EcoString>, pub markup_shorthand: Option<&'static str>, pub math_shorthand: Option<&'static str>, + pub math_class: Option<&'static str>, + pub deprecation: Option<&'static str>, } /// Shorthands listed on a category page. |
