//! The syntax tree. use super::span::{SpanVec, Spanned}; use super::{Expr, Ident}; /// A collection of nodes which form a tree together with the nodes' children. pub type SynTree = SpanVec; /// A syntax node, which encompasses a single logical entity of parsed source /// code. #[derive(Debug, Clone, PartialEq)] pub enum SynNode { /// Whitespace containing less than two newlines. Spacing, /// A forced line break. Linebreak, /// A paragraph break. Parbreak, /// Italics were enabled / disabled. ToggleItalic, /// Bolder was enabled / disabled. ToggleBolder, /// Plain text. Text(String), /// An optionally syntax-highlighted raw block. Raw(NodeRaw), /// A section heading. Heading(NodeHeading), /// An expression. Expr(Expr), } /// A raw block, rendered in monospace with optional syntax highlighting. /// /// 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, /// 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, /// 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, } /// A section heading. #[derive(Debug, Clone, PartialEq)] pub struct NodeHeading { /// The section depth (how many hashtags minus 1). pub level: Spanned, /// The contents of the heading. pub contents: SynTree, }