summaryrefslogtreecommitdiff
path: root/src/syntax/node.rs
blob: b7691a70e0b9277ac7304d764537c02e81ac3849 (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
//! Syntax tree nodes.

use super::*;

/// A syntax node, which encompasses a single logical entity of parsed source
/// code.
#[derive(Debug, Clone, PartialEq)]
pub enum SynNode {
    /// Plain text.
    Text(String),

    /// Whitespace containing less than two newlines.
    Space,
    /// A forced line break.
    Linebreak,
    /// A paragraph break.
    Parbreak,

    /// Strong text was enabled / disabled.
    Strong,
    /// Emphasized text was enabled / disabled.
    Emph,

    /// A section heading.
    Heading(NodeHeading),
    /// An optionally syntax-highlighted raw block.
    Raw(NodeRaw),

    /// An expression.
    Expr(Expr),
}

/// A section heading: `# ...`.
#[derive(Debug, Clone, PartialEq)]
pub struct NodeHeading {
    /// The section depth (numer of hashtags minus 1).
    pub level: Spanned<u8>,
    /// The contents of the heading.
    pub contents: SynTree,
}

/// A raw block with optional syntax highlighting: `` `raw` ``.
///
/// Raw blocks start with an arbitrary number of backticks and end with the same
/// number of backticks. If you want to include a sequence of backticks in a raw
/// block, simply surround the block with more backticks.
///
/// When using at least two backticks, an optional language tag may follow
/// directly after the backticks. This tag defines which language to
/// syntax-highlight the text in. Apart from the language tag and some
/// whitespace trimming discussed below, everything inside a raw block is
/// rendered verbatim, in particular, there are no escape sequences.
///
/// # Examples
/// - Raw text is surrounded by backticks.
///   ```typst
///   `raw`
///   ```
/// - An optional language tag may follow directly at the start when the block
///   is surrounded by at least two backticks.
///   ```typst
///   ``rust println!("hello!")``;
///   ```
/// - Blocks can span multiple lines. Two backticks suffice to be able to
///   specify the language tag, but three are fine, too.
///   ```typst
///   ``rust
///   loop {
///      find_yak().shave();
///   }
///   ``
///   ```
/// - Start with a space to omit the language tag (the space will be trimmed
///   from the output) and use more backticks to allow backticks in the raw
///   text.
///   `````typst
///   ```` This contains ```backticks``` and has no leading & trailing spaces. ````
///   `````
///
///   # Trimming
///   If we would always render the raw text between the backticks exactly as
///   given, a few things would become problematic or even impossible:
///   - Typical multiline code blocks (like in the example above) would have an
///     additional newline before and after the code.
///   - Raw text wrapped in more than one backtick could not exist without
///     leading whitespace since the first word would be interpreted as a
///     language tag.
///   - A single backtick without surrounding spaces could not exist as raw text
///     since it would be interpreted as belonging to the opening or closing
///     backticks.
///
///   To fix these problems, we trim text in multi-backtick blocks as follows:
///   - We trim a single space or a sequence of whitespace followed by a newline
///     at the start.
///   - We trim a single space or a newline followed by a sequence of whitespace
///     at the end.
///
///   With these rules, a single raw backtick can be produced by the sequence
///   ``` `` ` `` ```, ``` `` unhighlighted text `` ``` has no surrounding
///   spaces and multiline code blocks don't have extra empty lines. Note that
///   you can always force leading or trailing whitespace simply by adding more
///   spaces.
#[derive(Debug, Clone, PartialEq)]
pub struct NodeRaw {
    /// An optional identifier specifying the language to syntax-highlight in.
    pub lang: Option<Ident>,
    /// The lines of raw text, determined as the raw string between the
    /// backticks trimmed according to the above rules and split at newlines.
    pub lines: Vec<String>,
    /// Whether the element can be layouted inline.
    ///
    /// - When true, it will be layouted integrated within the surrounding
    ///   paragraph.
    /// - When false, it will be separated into its own paragraph.
    ///
    /// Single-backtick blocks are always inline-level. Multi-backtick blocks
    /// are inline-level when they contain no newlines.
    pub inline: bool,
}