summaryrefslogtreecommitdiff
path: root/src/library/markup.rs
blob: d7d750ea1523a7f046008b4fa28f6df01b1fec38 (plain) (blame)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use super::*;
use crate::syntax::{HeadingNode, RawNode};

/// `linebreak`: Start a new line.
///
/// # Syntax
/// This function has dedicated syntax:
/// ```typst
/// This line ends here, \
/// And a new one begins.
/// ```
///
/// # Return value
/// A template that inserts a line break.
pub fn linebreak(_: &mut EvalContext, _: &mut FuncArgs) -> Value {
    Value::template(Node::LINEBREAK, move |ctx| {
        ctx.push_linebreak();
    })
}

/// `parbreak`: Start a new paragraph.
///
/// # Return value
/// A template that inserts a paragraph break.
pub fn parbreak(_: &mut EvalContext, _: &mut FuncArgs) -> Value {
    Value::template(Node::PARBREAK, move |ctx| {
        ctx.push_parbreak();
    })
}

/// `strong`: Strong text.
///
/// # Syntax
/// This function has dedicated syntax.
/// ```typst
/// This is *important*!
/// ```
///
/// # Positional parameters
/// - Body: optional, of type `template`.
///
/// # Return value
/// A template that flips the boldness of text. The effect is scoped to the
/// body if present.
pub fn strong(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
    let body = args.find::<TemplateValue>(ctx);
    Value::template(Node::STRONG, move |ctx| {
        let snapshot = ctx.state.clone();
        ctx.state.font.strong ^= true;

        if let Some(body) = &body {
            body.exec(ctx);
            ctx.state = snapshot;
        }
    })
}

/// `emph`: Emphasized text.
///
/// # Syntax
/// This function has dedicated syntax.
/// ```typst
/// I would have _never_ thought so!
/// ```
///
/// # Positional parameters
/// - Body: optional, of type `template`.
///
/// # Return value
/// A template that flips whether text is set in italics. The effect is scoped
/// to the body if present.
pub fn emph(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
    let body = args.find::<TemplateValue>(ctx);
    Value::template(Node::EMPH, move |ctx| {
        let snapshot = ctx.state.clone();
        ctx.state.font.emph ^= true;

        if let Some(body) = &body {
            body.exec(ctx);
            ctx.state = snapshot;
        }
    })
}

/// `heading`: A section heading.
///
/// # Syntax
/// This function has dedicated syntax.
/// ```typst
/// = Section
/// ...
///
/// == Subsection
/// ...
/// ```
///
/// # Positional parameters
/// - Body, of type `template`.
///
/// # Named parameters
/// - Section depth: `level`, of type `integer` between 1 and 6.
///
/// # Return value
/// A template that sets the body as a section heading, that is, large and in
/// bold.
pub fn heading(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
    let level = args.get(ctx, HeadingNode::LEVEL).unwrap_or(1);
    let body = args
        .require::<TemplateValue>(ctx, HeadingNode::BODY)
        .unwrap_or_default();

    Value::template(Node::HEADING, move |ctx| {
        let snapshot = ctx.state.clone();
        let upscale = 1.6 - 0.1 * level as f64;
        ctx.state.font.scale *= upscale;
        ctx.state.font.strong = true;

        body.exec(ctx);
        ctx.state = snapshot;

        ctx.push_parbreak();
    })
}

/// `raw`: Raw text.
///
/// # Syntax
/// This function has dedicated syntax:
/// - For inline-level raw text:
///   ```typst
///   `...`
///   ```
/// - For block-level raw text:
///   ````typst
///   ```rust
///   println!("Hello World!");
///   ```
///   ````
///
/// # Positional parameters
/// - Text, of type `string`.
///
/// # Named parameters
/// - Language for syntax highlighting: `lang`, of type `string`.
/// - Whether the item is block level (split in its own paragraph): `block`, of
///   type `boolean`.
///
/// # Return value
/// A template that sets the text raw, that is, in monospace and optionally with
/// syntax highlighting.
pub fn raw(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
    let text = args.require::<String>(ctx, RawNode::TEXT).unwrap_or_default();
    let _lang = args.get::<String>(ctx, RawNode::LANG);
    let block = args.get(ctx, RawNode::BLOCK).unwrap_or(false);

    Value::template(Node::RAW, move |ctx| {
        if block {
            ctx.push_parbreak();
        }

        let snapshot = ctx.state.clone();
        ctx.set_monospace();
        ctx.push_text(&text);
        ctx.state = snapshot;

        if block {
            ctx.push_parbreak();
        }
    })
}