Interpret two backticks as single-backtick block

This commit is contained in:
Laurenz 2021-01-30 15:24:11 +01:00
parent fe7ea53800
commit 67047047e8
5 changed files with 54 additions and 42 deletions

View File

@ -227,6 +227,11 @@ impl<'s> Tokens<'s> {
backticks += 1; backticks += 1;
} }
// Special case for empty inline block.
if backticks == 2 {
return Token::Raw(TokenRaw { text: "", backticks: 1, terminated: true });
}
let start = self.s.index(); let start = self.s.index();
let mut found = 0; let mut found = 0;
@ -723,21 +728,25 @@ mod tests {
#[test] #[test]
fn test_tokenize_raw_blocks() { fn test_tokenize_raw_blocks() {
let empty = Raw("", 1, true);
// Test basic raw block. // Test basic raw block.
t!(Markup: "``" => empty);
t!(Markup: "`raw`" => Raw("raw", 1, true)); t!(Markup: "`raw`" => Raw("raw", 1, true));
t!(Markup[""]: "`]" => Raw("]", 1, false)); t!(Markup[""]: "`]" => Raw("]", 1, false));
// Test special symbols in raw block. // Test special symbols in raw block.
t!(Markup: "`[func]`" => Raw("[func]", 1, true)); t!(Markup: "`[brackets]`" => Raw("[brackets]", 1, true));
t!(Markup[""]: r"`\`` " => Raw(r"\", 1, true), Raw(" ", 1, false)); t!(Markup[""]: r"`\`` " => Raw(r"\", 1, true), Raw(" ", 1, false));
// Test more backticks.
t!(Markup: "````🚀````" => Raw("🚀", 4, true));
t!(Markup[""]: "````👩‍🚀``noend" => Raw("👩‍🚀``noend", 4, false));
t!(Markup[""]: "````raw``````new" => Raw("raw", 4, true), Raw("new", 2, false));
// Test separated closing backticks. // Test separated closing backticks.
t!(Markup: "```not `y`e`t```" => Raw("not `y`e`t", 3, true)); t!(Markup: "```not `y`e`t```" => Raw("not `y`e`t", 3, true));
// Test more backticks.
t!(Markup: "``nope``" => empty, Text("nope"), empty);
t!(Markup: "````🚀````" => Raw("🚀", 4, true));
t!(Markup[""]: "`````👩‍🚀````noend" => Raw("👩‍🚀````noend", 5, false));
t!(Markup[""]: "````raw``````" => Raw("raw", 4, true), empty);
} }
#[test] #[test]

View File

@ -63,9 +63,10 @@ mod tests {
roundtrip("= *Ok*"); roundtrip("= *Ok*");
// Raw. // Raw.
roundtrip("``");
roundtrip("`lang 1`"); roundtrip("`lang 1`");
test("`` hi``", "`hi`"); test("``` hi```", "`hi`");
test("`` ` ``", "```"); test("``` ` ```", "```");
} }
#[test] #[test]

View File

@ -66,11 +66,11 @@ impl Pretty for NodeHeading {
/// A raw block with optional syntax highlighting: `` `raw` ``. /// A raw block with optional syntax highlighting: `` `raw` ``.
/// ///
/// Raw blocks start with an arbitrary number of backticks and end with the same /// Raw blocks start with 1 or 3+ backticks and end with the same number of
/// number of backticks. If you want to include a sequence of backticks in a raw /// backticks. If you want to include a sequence of backticks in a raw block,
/// block, simply surround the block with more backticks. /// simply surround the block with more backticks.
/// ///
/// When using at least two backticks, an optional language tag may follow /// When using at least three backticks, an optional language tag may follow
/// directly after the backticks. This tag defines which language to /// directly after the backticks. This tag defines which language to
/// syntax-highlight the text in. Apart from the language tag and some /// syntax-highlight the text in. Apart from the language tag and some
/// whitespace trimming discussed below, everything inside a raw block is /// whitespace trimming discussed below, everything inside a raw block is
@ -82,22 +82,21 @@ impl Pretty for NodeHeading {
/// `raw` /// `raw`
/// ``` /// ```
/// - An optional language tag may follow directly at the start when the block /// - An optional language tag may follow directly at the start when the block
/// is surrounded by at least two backticks. /// is surrounded by at least three backticks.
/// ```typst /// ````typst
/// ``rust println!("hello!")``; /// ```rust println!("hello!")```;
/// ``` /// ````
/// - Blocks can span multiple lines. Two backticks suffice to be able to /// - Blocks can span multiple lines.
/// specify the language tag, but three are fine, too. /// ````typst
/// ```typst /// ```rust
/// ``rust
/// loop { /// loop {
/// find_yak().shave(); /// 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 /// - Start with a space to omit the language tag (the space will be trimmed
/// text. /// from the output) and use more backticks to allow backticks in the raw
/// text.
/// `````typst /// `````typst
/// ```` This contains ```backticks``` and has no leading & trailing spaces. ```` /// ```` This contains ```backticks``` and has no leading & trailing spaces. ````
/// ````` /// `````
@ -107,24 +106,22 @@ impl Pretty for NodeHeading {
/// given, a few things would become problematic or even impossible: /// given, a few things would become problematic or even impossible:
/// - Typical multiline code blocks (like in the example above) would have an /// - Typical multiline code blocks (like in the example above) would have an
/// additional newline before and after the code. /// additional newline before and after the code.
/// - Raw text wrapped in more than one backtick could not exist without /// - The first word of text wrapped in more than three backticks would always
/// leading whitespace since the first word would be interpreted as a /// be interpreted as a language tag which means that text without leading
/// language tag. /// space would be impossible.
/// - A single backtick without surrounding spaces could not exist as raw text /// - A single backtick without surrounding spaces could not exist as raw text
/// since it would be interpreted as belonging to the opening or closing /// since it would be interpreted as belonging to the opening or closing
/// backticks. /// backticks.
/// ///
/// To fix these problems, we trim text in multi-backtick blocks as follows: /// To fix these problems, we trim blocks with 3+ backticks as follows:
/// - We trim a single space or a sequence of whitespace followed by a newline /// - A single space or a sequence of whitespace followed by a newline at the start.
/// at the start. /// - A single space or a newline followed by a sequence of whitespace at the end.
/// - 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 /// With these rules, a single raw backtick can be produced by the sequence
/// ``` `` ` `` ```, ``` `` unhighlighted text `` ``` has no surrounding /// ```` ``` ` ``` ````, ```` ``` unhighlighted text ``` ```` has no
/// spaces and multiline code blocks don't have extra empty lines. Note that /// surrounding spaces and multiline code blocks don't have extra empty lines.
/// you can always force leading or trailing whitespace simply by adding more /// Note that you can always force leading or trailing whitespace simply by
/// spaces. /// adding more spaces.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct NodeRaw { pub struct NodeRaw {
/// An optional identifier specifying the language to syntax-highlight in. /// An optional identifier specifying the language to syntax-highlight in.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,22 +1,27 @@
#[font 8pt] #[font 8pt]
// No extra space.
`A``B`
// Typst syntax inside. // Typst syntax inside.
`#let x = 1``[f 1]` `#let x = 1` \
`#[f 1]`
// Space between "rust" and "let" is trimmed. // Space between "rust" and "let" is trimmed.
The keyword ``rust let``. The keyword ```rust let```.
// Trimming depends on number backticks. // Trimming depends on number backticks.
<``> \
<` untrimmed `> \ <` untrimmed `> \
<`` trimmed ``> <``` trimmed ```>
// Multiline trimming. // Multiline trimming.
``py ```py
import this import this
def say_hi(): def say_hi():
print("Hi!") print("Hi!")
`` ```
// Lots of backticks inside. // Lots of backticks inside.
```` ````