Compare commits

..

3 Commits

Author SHA1 Message Date
Laurenz
4a9a5d2716
0.13 changelog (#5801) 2025-02-05 13:47:32 +00:00
Laurenz
029ae4a5ea
Export target docs (#5812)
Co-authored-by: Martin Haug <3874949+reknih@users.noreply.github.com>
2025-02-05 13:24:10 +00:00
Laurenz
25f6a7ab16
Bump more dependencies (#5813) 2025-02-05 12:58:43 +00:00
56 changed files with 1046 additions and 459 deletions

18
Cargo.lock generated
View File

@ -312,9 +312,9 @@ dependencies = [
[[package]]
name = "citationberg"
version = "0.4.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92fea693c83bd967604be367dc1e1b4895625eabafec2eec66c51092e18e700e"
checksum = "e4595e03beafb40235070080b5286d3662525efc622cca599585ff1d63f844fa"
dependencies = [
"quick-xml 0.36.2",
"serde",
@ -398,9 +398,9 @@ dependencies = [
[[package]]
name = "codex"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e0ee2092c3513f63588d51c3f81b98e6b1aa8ddcca3b5892b288f093516497d"
checksum = "724d27a0ee38b700e5e164350e79aba601a0db673ac47fce1cb74c3e38864036"
[[package]]
name = "color-print"
@ -898,9 +898,9 @@ dependencies = [
[[package]]
name = "hayagriva"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a3635c2577f77499c9dc3dceeef2e64e6c146e711b1861507a0f15b20641348"
checksum = "954907554bb7fcba29a4f917c2d43e289ec21b69d872ccf97db160eca6caeed8"
dependencies = [
"biblatex",
"ciborium",
@ -2718,9 +2718,9 @@ dependencies = [
[[package]]
name = "two-face"
version = "0.4.0"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ccd4843ea031c609fe9c16cae00e9657bad8a9f735a3cc2e420955d802b4268"
checksum = "384eda438ddf62e2c6f39a174452d952d9d9df5a8ad5ade22198609f8dcaf852"
dependencies = [
"once_cell",
"serde",
@ -2822,6 +2822,8 @@ dependencies = [
"typst-assets",
"typst-dev-assets",
"typst-render",
"typst-utils",
"unicode-math-class",
"unscanny",
"yaml-front-matter",
]

View File

@ -47,7 +47,7 @@ clap = { version = "4.4", features = ["derive", "env", "wrap_help"] }
clap_complete = "4.2.1"
clap_mangen = "0.2.10"
codespan-reporting = "0.11"
codex = "0.1.0"
codex = "0.1.1"
color-print = "0.3.6"
comemo = "0.4"
csv = "1"
@ -58,7 +58,7 @@ env_proxy = "0.4"
flate2 = "1"
fontdb = { version = "0.21", default-features = false }
fs_extra = "1.3"
hayagriva = "0.8"
hayagriva = "0.8.1"
heck = "0.5"
hypher = "0.1.4"
icu_properties = { version = "1.4", features = ["serde"] }
@ -122,7 +122,7 @@ tiny_http = "0.12"
tiny-skia = "0.11"
toml = { version = "0.8", default-features = false, features = ["parse", "display"] }
ttf-parser = "0.24.1"
two-face = { version = "0.4.0", default-features = false, features = ["syntect-fancy"] }
two-face = { version = "0.4.3", default-features = false, features = ["syntect-fancy"] }
typed-arena = "2"
unicode-bidi = "0.3.18"
unicode-ident = "1.0"

View File

@ -85,16 +85,9 @@ use crate::engine::Engine;
use crate::routines::EvalMode;
use crate::{Feature, Features};
/// 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.
#[category]
pub static FOUNDATIONS: Category;
/// Hook up all `foundations` definitions.
pub(super) fn define(global: &mut Scope, inputs: Dict, features: &Features) {
global.start_category(FOUNDATIONS);
global.start_category(crate::Category::Foundations);
global.define_type::<bool>();
global.define_type::<i64>();
global.define_type::<f64>();
@ -125,6 +118,7 @@ pub(super) fn define(global: &mut Scope, inputs: Dict, features: &Features) {
}
global.define("calc", calc::module());
global.define("sys", sys::module(inputs));
global.reset_category();
}
/// Fails with an error.

View File

@ -1,6 +1,3 @@
#[doc(inline)]
pub use typst_macros::category;
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
@ -8,14 +5,13 @@ use ecow::{eco_format, EcoString};
use indexmap::map::Entry;
use indexmap::IndexMap;
use typst_syntax::Span;
use typst_utils::Static;
use crate::diag::{bail, DeprecationSink, HintedStrResult, HintedString, StrResult};
use crate::foundations::{
Element, Func, IntoValue, NativeElement, NativeFunc, NativeFuncData, NativeType,
Type, Value,
};
use crate::Library;
use crate::{Category, Library};
/// A stack of scopes.
#[derive(Debug, Default, Clone)]
@ -361,46 +357,6 @@ pub enum Capturer {
Context,
}
/// A group of related definitions.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Category(Static<CategoryData>);
impl Category {
/// Create a new category from raw data.
pub const fn from_data(data: &'static CategoryData) -> Self {
Self(Static(data))
}
/// The category's name.
pub fn name(&self) -> &'static str {
self.0.name
}
/// The type's title case name, for use in documentation (e.g. `String`).
pub fn title(&self) -> &'static str {
self.0.title
}
/// Documentation for the category.
pub fn docs(&self) -> &'static str {
self.0.docs
}
}
impl Debug for Category {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Category({})", self.name())
}
}
/// Defines a category.
#[derive(Debug)]
pub struct CategoryData {
pub name: &'static str,
pub title: &'static str,
pub docs: &'static str,
}
/// The error message when trying to mutate a variable from the standard
/// library.
#[cold]

View File

@ -3,7 +3,7 @@ use comemo::Tracked;
use crate::diag::HintedStrResult;
use crate::foundations::{elem, func, Cast, Context};
/// The compilation target.
/// The export target.
#[derive(Debug, Default, Copy, Clone, PartialEq, Hash, Cast)]
pub enum Target {
/// The target that is used for paged, fully laid-out content.
@ -28,7 +28,49 @@ pub struct TargetElem {
pub target: Target,
}
/// Returns the current compilation target.
/// Returns the current export target.
///
/// This function returns either
/// - `{"paged"}` (for PDF, PNG, and SVG export), or
/// - `{"html"}` (for HTML export).
///
/// The design of this function is not yet finalized and for this reason it is
/// guarded behind the `html` feature. Visit the [HTML documentation
/// page]($html) for more details.
///
/// # When to use it
/// This function allows you to format your document properly across both HTML
/// and paged export targets. It should primarily be used in templates and show
/// rules, rather than directly in content. This way, the document's contents
/// can be fully agnostic to the export target and content can be shared between
/// PDF and HTML export.
///
/// # Varying targets
/// This function is [contextual]($context) as the target can vary within a
/// single compilation: When exporting to HTML, the target will be `{"paged"}`
/// while within an [`html.frame`].
///
/// # Example
/// ```example
/// #let kbd(it) = context {
/// if target() == "html" {
/// html.elem("kbd", it)
/// } else {
/// set text(fill: rgb("#1f2328"))
/// let r = 3pt
/// box(
/// fill: rgb("#f6f8fa"),
/// stroke: rgb("#d1d9e0b3"),
/// outset: (y: r),
/// inset: (x: r),
/// radius: r,
/// raw(it)
/// )
/// }
/// }
///
/// Press #kbd("F1") for help.
/// ```
#[func(contextual)]
pub fn target(context: Tracked<Context>) -> HintedStrResult<Target> {
Ok(TargetElem::target_in(context.styles()?))

View File

@ -6,53 +6,77 @@ pub use self::dom::*;
use ecow::EcoString;
use crate::foundations::{category, elem, Category, Content, Module, Scope};
/// HTML output.
#[category]
pub static HTML: Category;
use crate::foundations::{elem, Content, Module, Scope};
/// Create a module with all HTML definitions.
pub fn module() -> Module {
let mut html = Scope::deduplicating();
html.start_category(HTML);
html.start_category(crate::Category::Html);
html.define_elem::<HtmlElem>();
html.define_elem::<FrameElem>();
Module::new("html", html)
}
/// A HTML element that can contain Typst content.
/// An HTML element that can contain Typst content.
///
/// Typst's HTML export automatically generates the appropriate tags for most
/// elements. However, sometimes, it is desirable to retain more control. For
/// example, when using Typst to generate your blog, you could use this function
/// to wrap each article in an `<article>` tag.
///
/// Typst is aware of what is valid HTML. A tag and its attributes must form
/// syntactically valid HTML. Some tags, like `meta` do not accept content.
/// Hence, you must not provide a body for them. We may add more checks in the
/// future, so be sure that you are generating valid HTML when using this
/// function.
///
/// Normally, Typst will generate `html`, `head`, and `body` tags for you. If
/// you instead create them with this function, Typst will omit its own tags.
///
/// ```typ
/// #html.elem("div", attrs: (style: "background: aqua"))[
/// A div with _Typst content_ inside!
/// ]
/// ```
#[elem(name = "elem")]
pub struct HtmlElem {
/// The element's tag.
#[required]
pub tag: HtmlTag,
/// The element's attributes.
/// The element's HTML attributes.
#[borrowed]
pub attrs: HtmlAttrs,
/// The contents of the HTML element.
///
/// The body can be arbitrary Typst content.
#[positional]
#[borrowed]
pub body: Option<Content>,
}
impl HtmlElem {
/// Add an atribute to the element.
/// Add an attribute to the element.
pub fn with_attr(mut self, attr: HtmlAttr, value: impl Into<EcoString>) -> Self {
self.attrs.get_or_insert_with(Default::default).push(attr, value);
self
}
}
/// An element that forces its contents to be laid out.
/// An element that lays out its content as an inline SVG.
///
/// Integrates content that requires layout (e.g. a plot) into HTML output
/// by turning it into an inline SVG.
/// Sometimes, converting Typst content to HTML is not desirable. This can be
/// the case for plots and other content that relies on positioning and styling
/// to convey its message.
///
/// This function allows you to use the Typst layout engine that would also be
/// used for PDF, SVG, and PNG export to render a part of your document exactly
/// how it would appear when exported in one of these formats. It embeds the
/// content as an inline SVG.
#[elem]
pub struct FrameElem {
/// The contents that shall be laid out.
/// The content that shall be laid out.
#[positional]
#[required]
pub body: Content,

View File

@ -25,24 +25,11 @@ pub use self::query_::*;
pub use self::state::*;
pub use self::tag::*;
use crate::foundations::{category, Category, Scope};
/// 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.
#[category]
pub static INTROSPECTION: Category;
use crate::foundations::Scope;
/// Hook up all `introspection` definitions.
pub fn define(global: &mut Scope) {
global.start_category(INTROSPECTION);
global.start_category(crate::Category::Introspection);
global.define_type::<Location>();
global.define_type::<Counter>();
global.define_type::<State>();
@ -50,4 +37,5 @@ pub fn define(global: &mut Scope) {
global.define_func::<here>();
global.define_func::<query>();
global.define_func::<locate>();
global.reset_category();
}

View File

@ -64,17 +64,11 @@ pub use self::spacing::*;
pub use self::stack::*;
pub use self::transform::*;
use crate::foundations::{category, Category, Scope};
/// Arranging elements on the page in different ways.
///
/// By combining layout functions, you can create complex and automatic layouts.
#[category]
pub static LAYOUT: Category;
use crate::foundations::Scope;
/// Hook up all `layout` definitions.
pub fn define(global: &mut Scope) {
global.start_category(LAYOUT);
global.start_category(crate::Category::Layout);
global.define_type::<Length>();
global.define_type::<Angle>();
global.define_type::<Ratio>();
@ -103,4 +97,5 @@ pub fn define(global: &mut Scope) {
global.define_elem::<HideElem>();
global.define_func::<measure>();
global.define_func::<layout>();
global.reset_category();
}

View File

@ -29,6 +29,7 @@ pub mod visualize;
use std::ops::{Deref, Range};
use serde::{Deserialize, Serialize};
use typst_syntax::{FileId, Source, Span};
use typst_utils::{LazyHash, SmallBitSet};
@ -236,31 +237,72 @@ pub enum Feature {
Html,
}
/// A group of related standard library definitions.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Category {
Foundations,
Introspection,
Layout,
DataLoading,
Math,
Model,
Symbols,
Text,
Visualize,
Pdf,
Html,
Svg,
Png,
}
impl Category {
/// The kebab-case name of the category.
pub fn name(&self) -> &'static str {
match self {
Self::Foundations => "foundations",
Self::Introspection => "introspection",
Self::Layout => "layout",
Self::DataLoading => "data-loading",
Self::Math => "math",
Self::Model => "model",
Self::Symbols => "symbols",
Self::Text => "text",
Self::Visualize => "visualize",
Self::Pdf => "pdf",
Self::Html => "html",
Self::Svg => "svg",
Self::Png => "png",
}
}
}
/// Construct the module with global definitions.
fn global(math: Module, inputs: Dict, features: &Features) -> Module {
let mut global = Scope::deduplicating();
self::foundations::define(&mut global, inputs, features);
self::model::define(&mut global);
self::text::define(&mut global);
global.reset_category();
global.define("math", math);
self::layout::define(&mut global);
self::visualize::define(&mut global);
self::introspection::define(&mut global);
self::loading::define(&mut global);
self::symbols::define(&mut global);
self::pdf::define(&mut global);
global.reset_category();
global.define("math", math);
global.define("pdf", self::pdf::module());
if features.is_enabled(Feature::Html) {
global.define("html", self::html::module());
}
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);

View File

@ -34,9 +34,6 @@ pub fn cbor(
#[scope]
impl cbor {
/// Reads structured data from CBOR bytes.
///
/// This function is deprecated. The [`cbor`] function now accepts bytes
/// directly.
#[func(title = "Decode CBOR")]
#[deprecated = "`cbor.decode` is deprecated, directly pass bytes to `cbor` instead"]
pub fn decode(

View File

@ -96,9 +96,6 @@ pub fn csv(
#[scope]
impl csv {
/// Reads structured data from a CSV string/bytes.
///
/// This function is deprecated. The [`csv`] function now accepts bytes
/// directly.
#[func(title = "Decode CSV")]
#[deprecated = "`csv.decode` is deprecated, directly pass bytes to `csv` instead"]
pub fn decode(

View File

@ -65,9 +65,6 @@ pub fn json(
#[scope]
impl json {
/// Reads structured data from a JSON string/bytes.
///
/// This function is deprecated. The [`json`] function now accepts bytes
/// directly.
#[func(title = "Decode JSON")]
#[deprecated = "`json.decode` is deprecated, directly pass bytes to `json` instead"]
pub fn decode(

View File

@ -29,19 +29,12 @@ pub use self::yaml_::*;
use crate::diag::{At, SourceResult};
use crate::foundations::OneOrMultiple;
use crate::foundations::{cast, category, Bytes, Category, Scope, Str};
use crate::foundations::{cast, Bytes, Scope, Str};
use crate::World;
/// Data loading from external files.
///
/// These functions help you with loading and embedding data, for example from
/// the results of an experiment.
#[category]
pub static DATA_LOADING: Category;
/// Hook up all `data-loading` definitions.
pub(super) fn define(global: &mut Scope) {
global.start_category(DATA_LOADING);
global.start_category(crate::Category::DataLoading);
global.define_func::<read>();
global.define_func::<csv>();
global.define_func::<json>();
@ -49,6 +42,7 @@ pub(super) fn define(global: &mut Scope) {
global.define_func::<yaml>();
global.define_func::<cbor>();
global.define_func::<xml>();
global.reset_category();
}
/// Something we can retrieve byte data from.

View File

@ -44,9 +44,6 @@ pub fn toml(
#[scope]
impl toml {
/// Reads structured data from a TOML string/bytes.
///
/// This function is deprecated. The [`toml`] function now accepts bytes
/// directly.
#[func(title = "Decode TOML")]
#[deprecated = "`toml.decode` is deprecated, directly pass bytes to `toml` instead"]
pub fn decode(

View File

@ -77,9 +77,6 @@ pub fn xml(
#[scope]
impl xml {
/// Reads structured data from an XML string/bytes.
///
/// This function is deprecated. The [`xml`] function now accepts bytes
/// directly.
#[func(title = "Decode XML")]
#[deprecated = "`xml.decode` is deprecated, directly pass bytes to `xml` instead"]
pub fn decode(

View File

@ -55,9 +55,6 @@ pub fn yaml(
#[scope]
impl yaml {
/// Reads structured data from a YAML string/bytes.
///
/// This function is deprecated. The [`yaml`] function now accepts bytes
/// directly.
#[func(title = "Decode YAML")]
#[deprecated = "`yaml.decode` is deprecated, directly pass bytes to `yaml` instead"]
pub fn decode(

View File

@ -27,119 +27,10 @@ pub use self::underover::*;
use typst_utils::singleton;
use unicode_math_class::MathClass;
use crate::foundations::{
category, elem, Category, Content, Module, NativeElement, Scope,
};
use crate::foundations::{elem, Content, Module, NativeElement, Scope};
use crate::layout::{Em, HElem};
use crate::text::TextElem;
/// 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.
#[category]
pub static MATH: Category;
// Spacings.
pub const THIN: Em = Em::new(1.0 / 6.0);
pub const MEDIUM: Em = Em::new(2.0 / 9.0);
@ -150,7 +41,7 @@ pub const WIDE: Em = Em::new(2.0);
/// Create a module with all math definitions.
pub fn module() -> Module {
let mut math = Scope::deduplicating();
math.start_category(MATH);
math.start_category(crate::Category::Math);
math.define_elem::<EquationElem>();
math.define_elem::<TextElem>();
math.define_elem::<LrElem>();

View File

@ -40,19 +40,11 @@ pub use self::strong::*;
pub use self::table::*;
pub use self::terms::*;
use crate::foundations::{category, Category, Scope};
/// 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.
#[category]
pub static MODEL: Category;
use crate::foundations::Scope;
/// Hook up all `model` definitions.
pub fn define(global: &mut Scope) {
global.start_category(MODEL);
global.start_category(crate::Category::Model);
global.define_elem::<DocumentElem>();
global.define_elem::<RefElem>();
global.define_elem::<LinkElem>();
@ -72,4 +64,5 @@ pub fn define(global: &mut Scope) {
global.define_elem::<EmphElem>();
global.define_elem::<StrongElem>();
global.define_func::<numbering>();
global.reset_category();
}

View File

@ -4,21 +4,12 @@ mod embed;
pub use self::embed::*;
use crate::foundations::{category, Category, Module, Scope};
/// PDF-specific functionality.
#[category]
pub static PDF: Category;
/// Hook up the `pdf` module.
pub(super) fn define(global: &mut Scope) {
global.start_category(PDF);
global.define("pdf", module());
}
use crate::foundations::{Module, Scope};
/// Hook up all `pdf` definitions.
pub fn module() -> Module {
let mut scope = Scope::deduplicating();
scope.define_elem::<EmbedElem>();
Module::new("pdf", scope)
let mut pdf = Scope::deduplicating();
pdf.start_category(crate::Category::Pdf);
pdf.define_elem::<EmbedElem>();
Module::new("pdf", pdf)
}

View File

@ -1,19 +1,12 @@
//! Modifiable symbols.
use crate::foundations::{category, Category, Module, Scope, Symbol, Value};
/// 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.
#[category]
pub static SYMBOLS: Category;
use crate::foundations::{Module, Scope, Symbol, Value};
/// Hook up all `symbol` definitions.
pub(super) fn define(global: &mut Scope) {
global.start_category(SYMBOLS);
global.start_category(crate::Category::Symbols);
extend_scope_from_codex_module(global, codex::ROOT);
global.reset_category();
}
/// Hook up all math `symbol` definitions, i.e., elements of the `sym` module.

View File

@ -45,9 +45,9 @@ use typst_utils::singleton;
use crate::diag::{bail, warning, HintedStrResult, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
cast, category, dict, elem, Args, Array, Cast, Category, Construct, Content, Dict,
Fold, IntoValue, NativeElement, Never, NoneValue, Packed, PlainText, Regex, Repr,
Resolve, Scope, Set, Smart, StyleChain,
cast, dict, elem, Args, Array, Cast, Construct, Content, Dict, Fold, IntoValue,
NativeElement, Never, NoneValue, Packed, PlainText, Regex, Repr, Resolve, Scope, Set,
Smart, StyleChain,
};
use crate::layout::{Abs, Axis, Dir, Em, Length, Ratio, Rel};
use crate::math::{EquationElem, MathSize};
@ -55,15 +55,9 @@ use crate::model::ParElem;
use crate::visualize::{Color, Paint, RelativeTo, Stroke};
use crate::World;
/// Text styling.
///
/// The [text function]($text) is of particular interest.
#[category]
pub static TEXT: Category;
/// Hook up all `text` definitions.
pub(super) fn define(global: &mut Scope) {
global.start_category(TEXT);
global.start_category(crate::Category::Text);
global.define_elem::<TextElem>();
global.define_elem::<LinebreakElem>();
global.define_elem::<SmartQuoteElem>();
@ -78,6 +72,7 @@ pub(super) fn define(global: &mut Scope) {
global.define_func::<lower>();
global.define_func::<upper>();
global.define_func::<lorem>();
global.reset_category();
}
/// Customizes the look and layout of text in a variety of ways.

View File

@ -50,6 +50,17 @@ pub struct ImageElem {
/// supported [formats]($image.format).
///
/// For more details about paths, see the [Paths section]($syntax/#paths).
///
/// ```example
/// #let original = read("diagram.svg")
/// #let changed = original.replace(
/// "#2B80FF", // blue
/// green.to-hex(),
/// )
///
/// #image(bytes(original))
/// #image(bytes(changed))
/// ```
#[required]
#[parse(
let source = args.expect::<Spanned<DataSource>>("source")?;
@ -156,20 +167,6 @@ pub struct ImageElem {
#[allow(clippy::too_many_arguments)]
impl ImageElem {
/// Decode a raster or vector graphic from bytes or a string.
///
/// This function is deprecated. The [`image`] function now accepts bytes
/// directly.
///
/// ```example
/// #let original = read("diagram.svg")
/// #let changed = original.replace(
/// "#2B80FF", // blue
/// green.to-hex(),
/// )
///
/// #image.decode(original)
/// #image.decode(changed)
/// ```
#[func(title = "Decode Image")]
#[deprecated = "`image.decode` is deprecated, directly pass bytes to `image` instead"]
pub fn decode(

View File

@ -24,19 +24,11 @@ pub use self::shape::*;
pub use self::stroke::*;
pub use self::tiling::*;
use crate::foundations::{category, Category, Element, Scope, Type};
/// 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.
#[category]
pub static VISUALIZE: Category;
use crate::foundations::{Element, Scope, Type};
/// Hook up all visualize definitions.
pub(super) fn define(global: &mut Scope) {
global.start_category(VISUALIZE);
global.start_category(crate::Category::Visualize);
global.define_type::<Color>();
global.define_type::<Gradient>();
global.define_type::<Tiling>();
@ -55,4 +47,5 @@ pub(super) fn define(global: &mut Scope) {
global
.define("pattern", Type::of::<Tiling>())
.deprecated("the name `pattern` is deprecated, use `tiling` instead");
global.reset_category();
}

View File

@ -21,9 +21,6 @@ use crate::visualize::{FillRule, Paint, Stroke};
/// ((50%, 0pt), (40pt, 0pt)),
/// )
/// ```
///
/// # Deprecation
/// This function is deprecated. The [`curve`] function should be used instead.
#[elem(Show)]
pub struct PathElem {
/// How to fill the path.

View File

@ -1,59 +0,0 @@
use heck::{ToKebabCase, ToTitleCase};
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Attribute, Ident, Result, Token, Type, Visibility};
use crate::util::{documentation, foundations};
/// Expand the `#[category]` macro.
pub fn category(_: TokenStream, item: syn::Item) -> Result<TokenStream> {
let syn::Item::Verbatim(stream) = item else {
bail!(item, "expected bare static");
};
let BareStatic { attrs, vis, ident, ty, .. } = syn::parse2(stream)?;
let name = ident.to_string().to_kebab_case();
let title = name.to_title_case();
let docs = documentation(&attrs);
Ok(quote! {
#(#attrs)*
#[allow(rustdoc::broken_intra_doc_links)]
#vis static #ident: #ty = {
static DATA: #foundations::CategoryData = #foundations::CategoryData {
name: #name,
title: #title,
docs: #docs,
};
#foundations::Category::from_data(&DATA)
};
})
}
/// Parse a bare `pub static CATEGORY: Category;` item.
#[allow(dead_code)]
pub struct BareStatic {
pub attrs: Vec<Attribute>,
pub vis: Visibility,
pub static_token: Token![static],
pub ident: Ident,
pub colon_token: Token![:],
pub ty: Type,
pub semi_token: Token![;],
}
impl Parse for BareStatic {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
attrs: input.call(Attribute::parse_outer)?,
vis: input.parse()?,
static_token: input.parse()?,
ident: input.parse()?,
colon_token: input.parse()?,
ty: input.parse()?,
semi_token: input.parse()?,
})
}
}

View File

@ -5,7 +5,6 @@ extern crate proc_macro;
#[macro_use]
mod util;
mod cast;
mod category;
mod elem;
mod func;
mod scope;
@ -266,15 +265,6 @@ pub fn scope(stream: BoundaryStream, item: BoundaryStream) -> BoundaryStream {
.into()
}
/// Defines a category of definitions.
#[proc_macro_attribute]
pub fn category(stream: BoundaryStream, item: BoundaryStream) -> BoundaryStream {
let item = syn::parse_macro_input!(item as syn::Item);
category::category(stream.into(), item)
.unwrap_or_else(|err| err.to_compile_error())
.into()
}
/// Implements `Reflect`, `FromValue`, and `IntoValue` for a type.
///
/// - `Reflect` makes Typst's runtime aware of the type's characteristics.

View File

@ -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 }

324
docs/changelog/0.13.0.md Normal file
View File

@ -0,0 +1,324 @@
---
title: Unreleased changes planned for 0.13.0
description: Changes slated to appear in Typst 0.13.0
---
# Unreleased
## Highlights
- There is now a distinction between [proper paragraphs]($par) and just
inline-level content. This is important for future work on accessibility and
means that [first line indent]($par.first-line-indent) can now be enabled for
all paragraphs instead of just consecutive ones.
- The [`outline`] has a better out-of-the-box look and is more customizable
- The new [`curve`] function (that supersedes the `path` function) provides a
simpler and more flexible interface for creating Bézier curves
- The `image` function now supports raw [pixel raster formats]($image.format)
for generating images from within Typst
- Functions that accept [file paths]($syntax/#paths) now also accept raw
[bytes] instead, for full flexibility
- WebAssembly [plugins]($plugin) are more flexible and automatically run
multi-threaded
- Fixed a long-standing bug where single-letter strings in math (`[$"a"$]`)
would be displayed in italics
- You can now specify which charset should be [covered]($text.font) by which
font family
- The [`pdf.embed`] function lets you embed arbitrary files in the exported
PDF
- HTML export is currently under active development. The feature is still _very_
incomplete, but already available for experimentation behind a feature flag.
## Model
- There is now a distinction between [proper paragraphs]($par) and just
inline-level content **(Breaking change)**
- All text at the root of a document is wrapped in paragraphs. Meanwhile, text
in a container (like a block) is only wrapped in a paragraph if the
container holds any block-level content. If all of the content is
inline-level, no paragraph is created.
- In the laid-out document, it's not immediately visible whether text became
part of a paragraph. However, it is still important for accessibility, HTML
export, and for properties like `first-line-indent`.
- Show rules on `par` now only affect proper paragraphs
- The `first-line-indent` and `hanging-indent` properties also only affect
proper paragraphs
- Creating a `{par[..]}` with body content that is not fully inline-level will
result in a warning
- The default show rules of various built-in elements like lists, quotes, etc.
were adjusted to ensure they produce/don't produce paragraphs as appropriate
- The [`outline`] function was fully reworked to improve its out-of-the-box
behavior **(Breaking change)**
- [Outline entries]($outline.entry) are now [blocks]($block) and are thus
affected by block spacing
- The `{auto}` indentation mode now aligns numberings and titles outline-wide
for a grid-like look
- Automatic indentation now also indents entries without a numbering
- Titles wrapping over multiple lines now have hanging indent
- The page number won't appear alone on its own line anymore
- The link now spans the full entry instead of just the title and page number
- The default spacing between outline leader dots was increased
- The [`fill`]($outline.entry.fill) parameter was moved from `outline` to
`outline.entry` and can thus be configured through show-set rules
- Removed `body` and `page` fields from outline entry
- Added `indented`, `prefix`, `inner`, `body`, and `page` methods on outline
entries to simplify writing of show rules
- Added configuration to [`par.first-line-indent`] for indenting all paragraphs
instead of just consecutive ones
- Added [`form`]($ref.form) parameter to `ref` function. Setting the form to
`{"page"}` will produce a page reference instead of a textual one.
- Added [`document.description`] field, which results in corresponding PDF and
HTML metadata
- Added [`enum.reversed`] parameter
- Added support for Greek [numbering]
- When the [`link`] function wraps around a container like a [block], it will
now generate only one link for the whole block instead of individual links for
all the visible leaf elements. This significantly reduces PDF file sizes when
combining `link` and [`repeat`].
- The [`link`] function will now only strip one prefix (like `mailto:` or
`tel:`) instead of multiple
- The link function now suppresses hyphenation via a built-in show-set rule
rather than through its default show rule
- Displaying the page counter without a specified numbering will now take the
page numbering into account
## Visualization
- Added new [`curve`] function that supersedes the [`path`] function and
provides a simpler and more flexible interface. The `path` function is now
deprecated.
- The `image` function now supports raw [pixel raster formats]($image.format).
This can be used to generate images from within Typst without the need for
encoding in an image exchange format.
- Added [`image.scaling`] parameter for configuring how an image is scaled by
PNG export and PDF viewers (smooth or pixelated)
- Added [`image.icc`] parameter for providing or overriding the ICC profile of
an image
- Renamed `pattern` to [`tiling`]. The name `pattern` remains as a deprecated
alias.
- Added [`gradient.center`], [`gradient.radius`], [`gradient.focal-center`], and
[`gradient.focal-radius`] methods
- Fixed interaction of clipping and outset on [`box`] and [`block`]
- Fixed panic with [`path`] of infinite length
- Fixed non-solid (e.g. tiling) text fills in clipped blocks
- Auto-detection of image formats from a raw buffer now has basic support for
SVGs
## Scripting
- Functions that accept [file paths]($syntax/#paths) now also accept raw
[bytes]
- [`image`], [`cbor`], [`csv`], [`json`], [`toml`], [`xml`], and [`yaml`] now
support a path string or bytes and their `.decode` variants are deprecated
- [`plugin`], [`bibliography`], [`bibliography.style`], [`cite.style`],
[`raw.theme`], and [`raw.syntaxes`] now accept bytes in addition to path
strings. These did not have `.decode` variants, so this adds new
flexibility.
- The `path` argument/field of [`image`] and [`bibliography`] was renamed to
`source` and `sources`, respectively **(Minor breaking change)**
- Improved WebAssembly [plugins]($plugin)
- The `plugin` type is replaced by a [`plugin` function]($plugin) that returns
a [module] containing normal Typst functions. This module can be used with
import syntax. **(Breaking change)**
- Plugins now automatically run in multiple threads without any changes by
plugin authors
- A new [`plugin.transition`] API is introduced which allows plugins to run
impure initialization in a way that doesn't break Typst's purity guarantees
- The variable name bound by a bare import (no renaming, no import list) is now
determined statically and dynamic imports without `{as}` renaming (e.g.
`{import "ot" + "her.typ"}`) are a hard error **(Breaking change)**
- Values of the [`arguments`] type can now be added with `+` and
[joined]($scripting/#blocks) in curly-braced code blocks
- Functions in an element function's scope can now be called with method syntax,
bringing elements and types closer (in anticipation of a future full
unification of the two). Currently, this is only useful for [`outline.entry`]
as no other element function defines methods.
- Added [`calc.norm`] function
- Added support for 32-bit floats in [`float.from-bytes`] and [`float.to-bytes`]
- The [`decimal`] constructor now also accepts decimal values
- Improved `repr` of [symbols]($symbol), [arguments], and [types]($type)
- Duplicate [symbol] variants and modifiers are now a hard error
**(Breaking change)**
## Math
- Fixed a bug where single letter strings in math (`[$"a"$]`) would be displayed
in italics
- Math function calls can now have hyphenated named arguments and support
[argument spreading]($arguments/#spreading)
- Better looking accents thanks to support for the `flac` (Flattened Accent
Forms) and `dtls` (Dotless Forms) OpenType features
- Added `lcm` [text operator]($math.op)
- The [`bold`]($math.bold) function now works with ϝ and Ϝ
- The [`italic`]($math.italic) function now works with ħ
- Fixed a bug where the extent of a math equation was wrongly affected by
internal metadata
- Fixed interaction of [`lr`]($math.lr) and [context] expressions
- Fixed weak spacing being unconditionally ignored in [`lr`]($math.lr)
- Fixed sub/superscripts sometimes being in the wrong position with
[`lr`]($math.lr)
- Fixed multi-line annotations (e.g. overbrace) changing the math baseline
- Fixed merging of attachments when the base is a nested equation
- Fixed resolving of contextual (em-based) text sizes within math
- Fixed spacing around ⊥
## Bibliography
- Prose and author-only citations now use editor names if the author names are
unavailable
- Some non-standard but widely used BibLaTeX `editortype`s like `producer`,
`writer`, `scriptwriter`, and `none` (defined by widespread style
`biblatex-chicago` to mean performers within `music` and `video` entries) are
now recognized
- CSL styles can now render affixes around the bibliography
- For BibTeX entries with `eprinttype = {pubmed}`, the PubMed ID will now be
correctly processed
- Whitespace handling for strings delimiting initialized names has been improved
- Uppercase spelling after apostrophes used as quotation marks is now possible
- Fixed bugs around the handling of CSL delimiting characters
- Fixed a problem with parsing multibyte characters in page ranges that could
prevent Hayagriva from parsing some BibTeX page ranges
- Updated CSL APA style
- Updated CSL locales for Finnish, Swiss German, Austrian German, German, and
Arabic
## Text
- Added support for specifying which charset should be [covered]($text.font) by
which font family
- Added [`all`]($smallcaps.all) parameter to `smallcaps` function that also
enables small capitals on uppercase letters
- Added basic i18n for Basque and Bulgarian
- [Justification]($par.justify) does not affect [raw] blocks anymore
- [CJK-Latin-spacing]($text.cjk-latin-spacing) does not affect [raw] text
anymore
- Fixed wrong language codes being used for Greek and Ukrainian
- Fixed default quotes for Croatian
- Fixed crash in RTL text handling
- Added support for [`raw`] syntax highlighting for a few new languages: CFML,
NSIS, and WGSL
- New font metadata exception for New Computer Modern Sans Math
- Updated bundled New Computer Modern fonts to version 7.0
## Layout
- Fixed various bugs with footnotes
- Fixed footnotes getting lost when multiple footnotes were nested within
another footnote
- Fixed endless loops with empty and overlarge footnotes
- Fixed crash with overlarge footnotes within a floating placement
- Fixed sizing of quadratic shapes ([`square`] and [`circle`])
- Fixed [`block.sticky`] not working properly at the top of a container
- Fixed crash due to consecutive weak spacing
- Fixed crash when a [block] or text have negative sizes
- Fixed unnecessary hyphenations occurring in rare scenarios due to a bad
interaction between padding and paragraph optimization
- Fixed lone [citations]($cite) in [`align`] not becoming their own paragraph
## Syntax
- Top-level closing square brackets that do not have a matching opening square
bracket are now a hard error **(Minor breaking change)**
- Adding a space between the identifier and the parentheses in a set rule is not
allowed anymore **(Minor breaking change)**
- Numbers with a unit cannot have a base prefix anymore, e.g. `0b100000pt` is
not allowed anymore. Previously, it was syntactically allowed but always
resolved to a value of zero. **(Minor breaking change)**
- Using `is` as an identifier will now warn as it might become a keyword in the
future
- Fixed minor whitespace handling bugs
- in math mode argument lists
- at the end of headings
- between a term list's term and description
- Fixed parsing of empty single line raw blocks with 3+ backticks and a language
tag
- Fixed minor bug with parentheses parsing in math
- Markup that can only appear at the start of the line (headings, lists) can now
also appear at the start of a list item
- A shebang `#!` at the very start of a file is now ignored
## PDF export
- Added `pdf.embed` function for embedding arbitrary files in the exported PDF
- Added support for PDF/A-3b export
- The PDF timestamp will now contain the timezone by default
## HTML export
**Note:** HTML export is currently under active development. The feature is
still _very_ incomplete, but already available for experimentation behind a
feature flag.
- Added HTML output support for some (but not all) of the built-in elements
- Added [`html.elem`] function for outputting an arbitrary HTML element
- Added [`html.frame`] function for integrating content that requires layout
into HTML (by embedding an SVG)
- Added [`target`] function which returns either `{"paged"}` or `{"html"}`
depending on the export target
## Tooling and Diagnostics
- Autocompletion improvements
- Added autocompletion for file paths
- Smarter autocompletion of variables: Completing `{rect(fill: |)}` will now
only show variables which contain a valid fill (either directly or nested,
e.g. a dictionary containing a valid fill)
- Different functions will now autocomplete with different brackets (round vs
square) depending on which kind is more useful
- Positional parameters which are already provided aren't autocompleted again
anymore
- Fixed variable autocompletion not considering parameters
- Added autocompletion snippets for common figure usages
- Fixed autocompletion after half-completed import item
- Fixed autocompletion for `cite` function
- Added warning when an unconditional return in a code block discards joined
content
- Fixed error message when accessing non-existent label
- Fixed handling of nested imports in IDE functionality
## Command Line Interface
- Added `--features` argument and `TYPST_FEATURES` environment variable for
opting into experimental features. The only feature so far is `html`.
- Added a live reloading HTTP server to `typst watch` when targeting HTML
- Fixed self-update not being aware about certain target architectures
- Fixed crash when piping `typst fonts` output to another command
## Symbols
- New
- `inter`, `inter.and`, `inter.big`, `inter.dot`, `inter.double`, `inter.sq`,
`inter.sq.big`, `inter.sq.double`, `integral.inter`
- `asymp`, `asymp.not`
- `mapsto`, `mapsto.long`
- `divides.not.rev`, `divides.struck`
- `interleave`, `interleave.big`, `interleave.struck`
- `eq.triple.not`, `eq.dots`, `eq.dots.down`, `eq.dots.up`
- `smt`, `smt.eq`, `lat`, `lat.eq`
- `colon.tri`, `colon.tri.op`
- `dagger.triple`, `dagger.l`, `dagger.r`, `dagger.inv`
- `hourglass.stroked`, `hourglass.filled`
- `die.six`, `die.five`, `die.four`, `die.three`, `die.two`, `die.one`
- `errorbar.square.stroked`, `errorbar.square.filled`,
`errorbar.diamond.stroked`, `errorbar.diamond.filled`,
`errorbar.circle.stroked`, `errorbar.circle.filled`
- `numero`
- `Omega.inv`
- Renamed
- `ohm.inv` to `Omega.inv`
- Changed codepoint
- `angle.l.double` from `《` to `⟪`
- `angle.r.double` from `》` to `⟫`
- `angstrom` from U+212B (`Å`) to U+00C5 (`Å`)
- Deprecated
- `sect` and all its variants in favor of `inter`
- `integral.sect` in favor of `integral.inter`
- Removed
- `degree.c` in favor of `°C` (`[$upright(°C)$]` or `[$upright(degree C)$]` in math)
- `degree.f` in favor of `°F` (`[$upright(°F)$]` or `[$upright(degree F)$]` in math)
- `kelvin` in favor of just K (`[$upright(K)$]` in math)
## Deprecations
- The [`path`] function in favor of the [`curve`] function
- The name `pattern` for tiling patterns in favor of the new name [`tiling`]
- [`image.decode`], [`cbor.decode`], [`csv.decode`], [`json.decode`],
[`toml.decode`], [`xml.decode`], [`yaml.decode`] in favor of the top-level
functions directly accepting both paths and bytes
- The `sect` and its variants in favor of `inter`, and `integral.sect` in favor
of `integral.inter`
- Fully removed type/str compatibility behavior (e.g. `{int == "integer"}`)
which was temporarily introduced in Typst 0.8 **(Breaking change)**
## Development
- The `typst::compile` function is now generic and can return either a
`PagedDocument` or an `HtmlDocument`
- `typst-timing` now supports WebAssembly targets via `web-sys` when the `wasm`
feature is enabled
- Increased minimum supported Rust version to 1.80
- Fixed linux/arm64 Docker image

View File

@ -10,6 +10,7 @@ forward. This section documents all changes to Typst since its initial public
release.
## Versions
- [Unreleased changes planned for Typst 0.13.0]($changelog/0.13.0)
- [Typst 0.12.0]($changelog/0.12.0)
- [Typst 0.11.1]($changelog/0.11.1)
- [Typst 0.11.0]($changelog/0.11.0)

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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-`.

View File

@ -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-`.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -0,0 +1,3 @@
Arranging elements on the page in different ways.
By combining layout functions, you can create complex and automatic layouts.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -0,0 +1,3 @@
Text styling.
The [text function]($text) is of particular interest.

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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
}
@ -191,6 +188,7 @@ fn changelog_pages(resolver: &dyn Resolver) -> PageModel {
let mut page = md_page(resolver, resolver.base(), load!("changelog/welcome.md"));
let base = format!("{}changelog/", resolver.base());
page.children = vec![
md_page(resolver, &base, load!("changelog/0.13.0.md")),
md_page(resolver, &base, load!("changelog/0.12.0.md")),
md_page(resolver, &base, load!("changelog/0.11.1.md")),
md_page(resolver, &base, load!("changelog/0.11.0.md")),
@ -219,14 +217,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 +243,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 +256,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 +273,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 +292,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 +316,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());
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 +357,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 +403,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 +417,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 +439,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 +522,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 +598,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 +669,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 +723,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 +743,7 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
.filter(|(other, _)| other != &variant)
.map(|(other, _)| complete(other))
.collect(),
deprecation,
});
}
}
@ -769,12 +820,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)]

View File

@ -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('-');

View File

@ -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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB