Documentation for citation, bibliography, and content

This commit is contained in:
Laurenz 2023-03-20 21:56:32 +01:00
parent 22bf0117a0
commit 2d16f9434f
17 changed files with 268 additions and 86 deletions

View File

@ -1,4 +1,4 @@
@article{stupid,
@article{netwok,
title={At-scale impact of the {Net Wok}: A culinarically holistic investigation of distributed dumplings},
author={Astley, Rick and Morris, Linda},
journal={Armenian Journal of Proceedings},
@ -26,7 +26,7 @@
author={Leeson, Peter T.},
}
@misc{cannonfodder,
@misc{distress,
title={An Insight into Bibliographical Distress},
author={Aldrin, Buzz}
}

View File

@ -95,10 +95,17 @@ visualize: |
be in the future.
meta: |
Document structuring and metadata setup.
Document structuring, introspection, and metadata configuration.
Here, you can find functions to structure your document and configure its
metadata.
Here, you can find functions to structure your document and interact with that
structure. This includes section headings and figures, bibliography
management, cross-referencing and more.
Moreover, 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. And 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.
symbols: |
These two modules give names to symbols and emoji to make them easy to insert
@ -114,6 +121,8 @@ sym: |
[formulas]($category/math), these symbols can be used without the `#sym.`
prefix.
The `d` in an integral's `dx` can be written as `[$dif x$]`.
emoji: |
Named emoji.

View File

@ -178,8 +178,7 @@ can be either:
- a [dictionary]($type/dictionary) that has the specified key,
- a [symbols]($type/symbol) that has the specified modifier,
- a [module]($type/module) containing the specified definition,
- [content]($type/content) that exposes the specified field. Most elements
expose some or all of the non-settable arguments passed to them as fields.
- [content]($type/content) that has the specified field.
```example
#let dict = (greet: "Hello")

View File

@ -13,15 +13,17 @@ of elements.
## Set rules { #set-rules }
With set rules, you can customize the appearance of elements. They are written
as a [function call]($type/function) to the respective function preceded by the
`{set}` keyword (or `[#set]` in markup). Only settable parameters must be
provided as arguments. Refer to each function's documentation for a list of
settable parameters. In the example below, we use two set rules to change the
[font family]($func/text.family) and
[heading numbering]($func/heading.numbering) style.
`{set}` keyword (or `[#set]` in markup). Only optional parameters of that
function can be provided to the set rule. Refer to each function's documentation
to see which parameters are optional. In the example below, we use two set rules
to change the [font family]($func/text.family) and
[heading numbering]($func/heading.numbering).
```example
#set text(font: "New Computer Modern")
#set heading(numbering: "I.")
#set text(
font: "New Computer Modern"
)
= Introduction
With set rules, you can style
@ -35,9 +37,10 @@ your document. Below, we use a content block to scope the list styling to one
particular list.
```example
This list is affected:
#[#set list(marker: [--])
- Dash]
This list is affected: #[
#set list(marker: [--])
- Dash
]
This one is not:
- Bullet
@ -87,8 +90,7 @@ fantasy encyclopedia.
#set align(center)
#set text(font: "Inria Serif")
\~ #emph(it.body)
#(counter(heading)
.display(it.numbering)) \~
#counter(heading).display() \~
]
= Dragon

View File

@ -379,18 +379,16 @@ the resulting parts.
- returns: array
# Content
Representation of text, elements, and more.
Representation of document content.
This type is at the heart of Typst. All markup you write and most
[functions]($type/function) you call produce content values. You
can create a content value by enclosing markup in square brackets. This is also
how you pass content to functions. Typst does not allow you to peek into
content, but you can affect its appearance in various ways using set and show
rules. See the chapter on [styling]($styling) for more details.
[functions]($type/function) you call produce content values. You can create a
content value by enclosing markup in square brackets. This is also how you pass
content to functions.
```example
#type([*Hello!*]) \
#strong[Hello!]
Type of *Hello!* is
#type([*Hello!*])
```
Content can be added with the `+` operator,
@ -398,21 +396,62 @@ Content can be added with the `+` operator,
integers. Wherever content is expected, you can also pass a
[string]($type/string) or `{none}`.
### Reactivity
Content is reactive to the styles that are active where it is inserted.
When you write a set or show rule, content that was _created_ before the show
rule is stilled affected by the show rule if it is _inserted_ after the show
rule.
## Representation
Content consists of elements with fields. When constructing an element with
its _element function,_ you provide these fields as arguments and when you have
a content value, you can access its fields with
[field access syntax]($scripting/#field-access).
```example
// Content is created here.
#let mytext = [= A heading]
Some fields are required: These must be provided when constructing an element
and as a consequence, they are always available through field access on content
of that type. Required fields are marked as such in the documentation.
// But still affected by the
// styles that are active here.
#show heading: set text(green)
#mytext
```
Most fields are optional: Like required fields, they can be passed to the
element function to configure them for a single element. However, these can also
be configured with [set rules]($styling/#set-rules) to apply them to all
elements within a scope. Optional fields are only available with field access
syntax when they are were explicitly passed to the element function, not when
they result from a set rule.
Each element has a default appearance. However, you can also completely
customize its appearance with a [show rule]($styling/#show-rules). The show rule
is passed the element. It can access the element's field and produce arbitrary
content from it.
In the web app, you can hover over a content variable to see exactly which
elements the content is composed of and what fields they have. Alternatively,
you can inspect the output of the [`repr`]($func/repr) function.
## Methods
### func()
The content's element function. This function can be used to create the element
contained in this content. It can be used in set and show rules for the element.
Can be compared with global functions to check whether you have a specific
kind of element.
- returns: function
### has()
Whether the content has the specified field.
- field: string (positional, required)
The field to look for.
- returns: boolean
### at()
Access the specified field on the content.
- field: string (positional, required)
The field to access.
- returns: any
### location()
The location of the content. This is only available on content returned by
[query]($func/query), for other content it will fail with an error. The
resulting location can be used with [counters]($func/counter),
[state]($func/state) and [queries]($func/query).
- returns: location
# Array
A sequence of values.

View File

@ -318,7 +318,7 @@ impl PageElem {
Numbering::Func(_) => true,
};
Counter::new(CounterKey::Page)
.display(numbering, both)
.display(Some(numbering), both)
.aligned(self.number_align(styles))
})
});

View File

@ -158,7 +158,7 @@ pub struct EquationElem {
}
impl Synthesize for EquationElem {
fn synthesize(&mut self, _: &Vt, styles: StyleChain) {
fn synthesize(&mut self, styles: StyleChain) {
self.push_block(self.block(styles));
self.push_numbering(self.numbering(styles));
}
@ -216,7 +216,7 @@ impl Layout for EquationElem {
if let Some(numbering) = self.numbering(styles) {
let pod = Regions::one(regions.base(), Axes::splat(false));
let counter = Counter::of(Self::func())
.display(numbering, false)
.display(Some(numbering), false)
.layout(vt, styles, pod)?
.into_frame();

View File

@ -16,6 +16,31 @@ use crate::text::TextElem;
/// A bibliography / reference listing.
///
/// You can create a new bibliography by calling this function with a path
/// to a bibliography file in either one of two formats:
///
/// - A Hayagriva `.yml` file. Hayagriva is a new bibliography file format
/// designed for use with Typst. Visit its
/// [documentation](https://github.com/typst/hayagriva/blob/main/docs/file-format.md)
/// for more details.
/// - A BibLaTeX `.bib` file.
///
/// As soon as you add a bibliography somewhere in your document, you can start
/// citing things with reference syntax (`[@key]`) or explicit calls to the
/// [citation]($func/cite) function (`[#cite("key")]`). The bibliography will
/// only show entries for works that were referenced in the document.
///
/// # Example
/// ```example
/// This was already noted by
/// pirates long ago. @arrgh
///
/// Multiple sources say ...
/// #cite("arrgh", "netwok").
///
/// #bibliography("works.bib")
/// ```
///
/// Display: Bibliography
/// Category: meta
#[element(Locatable, Synthesize, Show, LocalName)]
@ -90,7 +115,7 @@ impl BibliographyElem {
}
impl Synthesize for BibliographyElem {
fn synthesize(&mut self, _: &Vt, styles: StyleChain) {
fn synthesize(&mut self, styles: StyleChain) {
self.push_style(self.style(styles));
}
}
@ -192,21 +217,64 @@ impl BibliographyStyle {
}
}
/// A citation of another work.
/// Cite a work from the bibliography.
///
/// Before you starting citing, you need to add a
/// [bibliography]($func/bibliography) somewhere in your document.
///
/// # Example
/// ```example
/// This was already noted by
/// pirates long ago. @arrgh
///
/// Multiple sources say ...
/// #cite("arrgh", "netwok").
///
/// #bibliography("works.bib")
/// ```
///
/// # Syntax
/// This function indirectly has dedicated syntax. [References]($func/ref)
/// can be used to cite works from the bibliography. The label then
/// corresponds to the citation key.
///
/// Display: Citation
/// Category: meta
#[element(Locatable, Synthesize, Show)]
pub struct CiteElem {
/// The citation key.
/// The citation keys that identify the elements that shall be cited in
/// the bibliography.
///
/// Reference syntax supports only a single key.
#[variadic]
pub keys: Vec<EcoString>,
/// A supplement for the citation such as page or chapter number.
///
/// In reference syntax, the supplement can be added in square brackets:
///
/// ```example
/// This has been proven over and
/// over again. @distress[p.~7]
///
/// #bibliography("works.bib")
/// ```
#[positional]
pub supplement: Option<Content>,
/// Whether the citation should include brackets.
///
/// ```example
/// #set cite(brackets: false)
///
/// @netwok follow these methods
/// in their work ...
///
/// #bibliography(
/// "works.bib",
/// style: "author-date",
/// )
/// ```
#[default(true)]
pub brackets: bool,
@ -214,11 +282,19 @@ pub struct CiteElem {
///
/// When set to `{auto}`, automatically picks the preferred citation style
/// for the bibliography's style.
///
/// ```example
/// #set cite(style: "alphanumerical")
/// Alphanumerical references.
/// @netwok
///
/// #bibliography("works.bib")
/// ```
pub style: Smart<CitationStyle>,
}
impl Synthesize for CiteElem {
fn synthesize(&mut self, _: &Vt, styles: StyleChain) {
fn synthesize(&mut self, styles: StyleChain) {
self.push_supplement(self.supplement(styles));
self.push_brackets(self.brackets(styles));
self.push_style(self.style(styles));
@ -243,6 +319,11 @@ impl Show for CiteElem {
}
}
cast_from_value! {
CiteElem,
v: Content => v.to::<Self>().cloned().ok_or("expected citation")?,
}
/// A citation style.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum CitationStyle {
@ -261,6 +342,12 @@ pub enum CitationStyle {
Keys,
}
impl CitationStyle {
fn is_short(self) -> bool {
matches!(self, Self::Numerical | Self::Alphanumerical | Self::Keys)
}
}
/// Fully formatted citations and references.
#[derive(Default)]
struct Works {
@ -280,7 +367,7 @@ impl Works {
]))
.into_iter()
.map(|elem| match elem.to::<RefElem>() {
Some(reference) => reference.to_citation(StyleChain::default()),
Some(reference) => reference.citation().unwrap(),
_ => elem.to::<CiteElem>().unwrap().clone(),
})
.collect();
@ -371,6 +458,10 @@ fn create(
)
.display;
if style.is_short() {
display.value = display.value.replace(' ', "\u{a0}");
}
if brackets && len == 1 {
display = display.with_default_brackets(&*citation_style);
}

View File

@ -5,8 +5,9 @@ use ecow::{eco_vec, EcoVec};
use smallvec::{smallvec, SmallVec};
use typst::eval::Tracer;
use super::{Numbering, NumberingPattern};
use super::{FigureElem, HeadingElem, Numbering, NumberingPattern};
use crate::layout::PageElem;
use crate::math::EquationElem;
use crate::prelude::*;
/// Count through pages, elements, and more.
@ -165,7 +166,7 @@ use crate::prelude::*;
/// which one doesn't matter. After the heading follow two calls to `step()`,
/// so the final value is `{(6,)}`.
///
/// ## Different kinds of state
/// ## Other kinds of state
/// The `counter` function is closely related to [state]($func/state) function.
/// Read its documentation for more details on state management in Typst and
/// why it doesn't just use normal variables for counters.
@ -181,6 +182,9 @@ use crate::prelude::*;
/// varies, e.g. for the heading argument, you can use an
/// [argument sink]($type/arguments).
///
/// If this is omitted, displays the counter with the numbering style for the
/// counted element or with the pattern `{"1.1"}` if no such style exists.
///
/// - returns: content
///
/// ### step()
@ -275,14 +279,10 @@ impl Counter {
mut args: Args,
span: Span,
) -> SourceResult<Value> {
let pattern = |s| NumberingPattern::from_str(s).unwrap().into();
let value = match method {
"display" => self
.display(
args.eat()?.unwrap_or_else(|| pattern("1.1")),
args.named("both")?.unwrap_or(false),
)
.into(),
"display" => {
self.display(args.eat()?, args.named("both")?.unwrap_or(false)).into()
}
"step" => self
.update(CounterUpdate::Step(
args.named("level")?.unwrap_or(NonZeroUsize::ONE),
@ -298,7 +298,7 @@ impl Counter {
}
/// Display the current value of the counter.
pub fn display(self, numbering: Numbering, both: bool) -> Content {
pub fn display(self, numbering: Option<Numbering>, both: bool) -> Content {
DisplayElem::new(self, numbering, both).pack()
}
@ -574,7 +574,7 @@ struct DisplayElem {
/// The numbering to display the counter with.
#[required]
numbering: Numbering,
numbering: Option<Numbering>,
/// Whether to display both the current and final value.
#[required]
@ -582,10 +582,28 @@ struct DisplayElem {
}
impl Show for DisplayElem {
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
let location = self.0.location().unwrap();
let counter = self.counter();
let numbering = self.numbering();
let numbering = self
.numbering()
.or_else(|| {
let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else {
return None;
};
if func == HeadingElem::func() {
HeadingElem::numbering_in(styles)
} else if func == FigureElem::func() {
FigureElem::numbering_in(styles)
} else if func == EquationElem::func() {
EquationElem::numbering_in(styles)
} else {
None
}
})
.unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into());
let state = if self.both() {
counter.both(vt, location)?
} else {

View File

@ -10,7 +10,7 @@ use crate::text::TextElem;
/// ## Example
/// ```example
/// = Pipeline
/// @fig-lab shows the central step of
/// @lab shows the central step of
/// our molecular testing pipeline.
///
/// #figure(
@ -18,7 +18,7 @@ use crate::text::TextElem;
/// caption: [
/// The molecular testing pipeline.
/// ],
/// ) <fig-lab>
/// ) <lab>
/// ```
///
/// Display: Figure
@ -43,7 +43,7 @@ pub struct FigureElem {
}
impl Synthesize for FigureElem {
fn synthesize(&mut self, _: &Vt, styles: StyleChain) {
fn synthesize(&mut self, styles: StyleChain) {
self.push_numbering(self.numbering(styles));
}
}
@ -57,7 +57,7 @@ impl Show for FigureElem {
let name = self.local_name(TextElem::lang_in(styles));
caption = TextElem::packed(eco_format!("{name}\u{a0}"))
+ Counter::of(Self::func())
.display(numbering, false)
.display(Some(numbering), false)
.spanned(self.span())
+ TextElem::packed(": ")
+ caption;

View File

@ -80,7 +80,7 @@ pub struct HeadingElem {
}
impl Synthesize for HeadingElem {
fn synthesize(&mut self, _: &Vt, styles: StyleChain) {
fn synthesize(&mut self, styles: StyleChain) {
self.push_level(self.level(styles));
self.push_numbering(self.numbering(styles));
self.push_outlined(self.outlined(styles));
@ -92,7 +92,7 @@ impl Show for HeadingElem {
let mut realized = self.body();
if let Some(numbering) = self.numbering(styles) {
realized = Counter::of(Self::func())
.display(numbering, false)
.display(Some(numbering), false)
.spanned(self.span())
+ HElem::new(Em::new(0.3).into()).with_weak(true).pack()
+ realized;

View File

@ -1,7 +1,7 @@
use crate::prelude::*;
use crate::text::{Hyphenate, TextElem};
/// Link to a URL or another location in the document.
/// Link to a URL or a location in the document.
///
/// The link function makes its positional `body` argument clickable and links
/// it to the destination specified by the `dest` argument. By default, links

View File

@ -2,30 +2,37 @@ use super::{BibliographyElem, CiteElem, Counter, LocalName, Numbering};
use crate::prelude::*;
use crate::text::TextElem;
/// A reference to a label.
/// A reference to a label or bibliography.
///
/// The reference function produces a textual reference to a label. For example,
/// a reference to a heading will yield an appropriate string such as "Section
/// 1" for a reference to the first heading. The references are also links to
/// the respective element.
///
/// Reference syntax can also be used to [cite]($func/cite) from a bibliography.
///
/// # Example
/// ```example
/// #set heading(numbering: "1.")
/// #set math.equation(numbering: "(1)")
///
/// = Introduction <intro>
/// Recent developments in typesetting
/// software have rekindled hope in
/// previously frustrated researchers.
/// Recent developments in
/// typesetting software have
/// rekindled hope in previously
/// frustrated researchers. @distress
/// As shown in @results, we ...
///
/// = Results <results>
/// We evaluate our method in a
/// series of tests. @perf discusses
/// the performance aspects of ...
/// We discuss our approach in
/// comparison with others.
///
/// == Performance <perf>
/// As described in @intro, we ...
/// @slow demonstrates what slow
/// software looks like.
/// $ O(n) = 2^n $ <slow>
///
/// #bibliography("works.bib")
/// ```
///
/// ## Syntax
@ -33,9 +40,12 @@ use crate::text::TextElem;
/// created by typing an `@` followed by the name of the label (e.g.
/// `[= Introduction <intro>]` can be referenced by typing `[@intro]`).
///
/// To customize the supplement, add content in square brackets after the
/// reference: `[@intro[Chapter]]`.
///
/// Display: Reference
/// Category: meta
#[element(Locatable, Show)]
#[element(Synthesize, Locatable, Show)]
pub struct RefElem {
/// The target label that should be referenced.
#[required]
@ -58,9 +68,22 @@ pub struct RefElem {
///
/// = Introduction <intro>
/// In @intro, we see how to turn
/// Sections into Chapters.
/// Sections into Chapters. And
/// in @intro[Part], it is done
/// manually.
/// ```
pub supplement: Smart<Option<Supplement>>,
/// A synthesized citation.
#[synthesized]
pub citation: Option<CiteElem>,
}
impl Synthesize for RefElem {
fn synthesize(&mut self, styles: StyleChain) {
let citation = self.to_citation(styles);
self.push_citation(Some(citation));
}
}
impl Show for RefElem {
@ -77,7 +100,7 @@ impl Show for RefElem {
bail!(self.span(), "label occurs in the document and its bibliography");
}
return self.to_citation(styles).show(vt, styles);
return Ok(self.to_citation(styles).pack());
}
let [elem] = matches.as_slice() else {
@ -126,11 +149,12 @@ impl RefElem {
/// Turn the rference into a citation.
pub fn to_citation(&self, styles: StyleChain) -> CiteElem {
let mut elem = CiteElem::new(vec![self.target().0]);
elem.0.set_location(self.0.location().unwrap());
elem.synthesize(styles);
elem.push_supplement(match self.supplement(styles) {
Smart::Custom(Some(Supplement::Content(content))) => Some(content),
_ => None,
});
elem.0.set_location(self.0.location().unwrap());
elem
}
}

View File

@ -121,7 +121,7 @@ impl RawElem {
}
impl Synthesize for RawElem {
fn synthesize(&mut self, _: &Vt, styles: StyleChain) {
fn synthesize(&mut self, styles: StyleChain) {
self.push_lang(self.lang(styles));
}
}

View File

@ -42,7 +42,7 @@ pub fn realize(
}
if let Some(elem) = elem.with_mut::<dyn Synthesize>() {
elem.synthesize(vt, styles);
elem.synthesize(styles);
}
elem.mark_prepared();
@ -165,7 +165,7 @@ pub trait Locatable {}
/// rule.
pub trait Synthesize {
/// Prepare the element for show rule application.
fn synthesize(&mut self, vt: &Vt, styles: StyleChain);
fn synthesize(&mut self, styles: StyleChain);
}
/// The base recipe for an element.

View File

@ -14,7 +14,7 @@
---
#set page(width: 200pt)
= Details
See also #cite("arrgh", "cannonfodder", [p. 22]), @arrgh[p. 4], and @cannonfodder[p. 5].
See also #cite("arrgh", "distress", [p. 22]), @arrgh[p. 4], and @distress[p. 5].
#bibliography("/works.bib")
---
@ -22,7 +22,8 @@ See also #cite("arrgh", "cannonfodder", [p. 22]), @arrgh[p. 4], and @cannonfodde
#set page(width: 200pt)
#bibliography("/works.bib", title: [Works to be cited], style: "author-date")
#line(length: 100%)
As described by #cite("stupid", brackets: false),
#[#set cite(brackets: false)
As described by @netwok],
the net-work is a creature of its own.
This is close to piratery! @arrgh
And quark! @quark

View File

@ -31,8 +31,7 @@ Second: #mine.display("I")
#counter(heading).step()
= Alpha
In #counter(heading).display().
In #counter(heading).display()
== Beta
#set heading(numbering: none)