1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use std::any::Any;
use comemo::Tracked;
use crate::diag::{HintedStrResult, SourceResult};
use crate::engine::Engine;
use crate::foundations::{Cast, Content, Context, StyleChain, elem, func};
use crate::introspection::Introspector;
/// A compilation output for a particular target.
///
/// Has a 1-1 relationship with the variants of [`Target`].
pub trait Output: Any {
/// The target associated with the output.
fn target() -> Target
where
Self: Sized;
/// Creates the output.
fn create(
engine: &mut Engine,
content: &Content,
styles: StyleChain,
) -> SourceResult<Self>
where
Self: Sized;
/// Get the output's introspector.
fn introspector(&self) -> &dyn Introspector;
}
/// A trait for accepting an arbitrary kind of output as an argument.
///
/// Can be used to accept a reference to
/// - any kind of sized type that implements [`Output`], or
/// - the trait object [`&dyn Output`].
///
/// Should be used as `impl AsOutput` rather than `&impl AsOutput`.
///
/// # Why is this needed?
/// Unfortunately, `&impl Output` can't be turned into `&dyn Output` in a
/// generic function. Directly accepting `&dyn Output` is of course also
/// possible, but is less convenient, especially in cases where the document is
/// optional.
///
/// See also
/// <https://users.rust-lang.org/t/converting-from-generic-unsized-parameter-to-trait-object/72376>
pub trait AsOutput {
/// Turns the reference into the trait object.
fn as_output(&self) -> &dyn Output;
}
impl AsOutput for &dyn Output {
fn as_output(&self) -> &dyn Output {
*self
}
}
impl<T: Output> AsOutput for &T {
fn as_output(&self) -> &dyn Output {
*self
}
}
/// The compilation target.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum Target {
/// The target that is used for paged, fully laid-out content.
#[default]
Paged,
/// The target that is used for HTML export.
Html,
/// The target for _bundle_ export. This export target can produce multiple
/// [documents]($document) and [assets]($asset) from a single Typst project.
Bundle,
}
impl Target {
/// Whether this is the HTML target.
pub fn is_html(self) -> bool {
self == Self::Html
}
}
/// This element exists solely to host the `target` style chain field. It is
/// never constructed and not visible to users.
#[elem]
pub struct TargetElem {
/// The compilation target.
pub target: Target,
}
/// Returns the current export target.
///
/// This function returns
/// - `{"paged"}` in @pdf[PDF], @reference:png[PNG], and
/// @reference:svg[SVG] export, or within an @html.frame[HTML frame]
/// - `{"html"}` in @html[HTML] export
/// - `{"bundle"}` in @reference:bundle[Bundle] export
///
/// = When to use it <when-to-use-it>
/// This function allows you to format your document properly across the paged,
/// HTML, and multi file 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 different export targets.
///
/// = Varying targets <varying-targets>
/// This function is @reference:context[contextual] 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>
/// ```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(context.styles()?.get(TargetElem::target))
}