diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-10-28 23:35:13 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-10-29 00:52:15 +0200 |
| commit | 29130a26f83f28ae37be1ff4f57877e765d27285 (patch) | |
| tree | 5abc020ae1be4fa2681ca1b977ee7ce398b3a9bb /crates/typst-syntax | |
| parent | 4c75adbb047cba73b052c2fafa9155e2e4026610 (diff) | |
Linebreaking for links
Diffstat (limited to 'crates/typst-syntax')
| -rw-r--r-- | crates/typst-syntax/src/lexer.rs | 70 | ||||
| -rw-r--r-- | crates/typst-syntax/src/lib.rs | 2 |
2 files changed, 41 insertions, 31 deletions
diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs index 18622154..a909dfa0 100644 --- a/crates/typst-syntax/src/lexer.rs +++ b/crates/typst-syntax/src/lexer.rs @@ -253,43 +253,16 @@ impl Lexer<'_> { } fn link(&mut self) -> SyntaxKind { - let mut brackets = Vec::new(); - - #[rustfmt::skip] - self.s.eat_while(|c: char| { - match c { - | '0' ..= '9' - | 'a' ..= 'z' - | 'A' ..= 'Z' - | '!' | '#' | '$' | '%' | '&' | '*' | '+' - | ',' | '-' | '.' | '/' | ':' | ';' | '=' - | '?' | '@' | '_' | '~' | '\'' => true, - '[' => { - brackets.push(SyntaxKind::LeftBracket); - true - } - '(' => { - brackets.push(SyntaxKind::LeftParen); - true - } - ']' => brackets.pop() == Some(SyntaxKind::LeftBracket), - ')' => brackets.pop() == Some(SyntaxKind::LeftParen), - _ => false, - } - }); + let (link, balanced) = link_prefix(self.s.after()); + self.s.jump(self.s.cursor() + link.len()); - if !brackets.is_empty() { + if !balanced { return self.error( "automatic links cannot contain unbalanced brackets, \ use the `link` function instead", ); } - // Don't include the trailing characters likely to be part of text. - while matches!(self.s.scout(-1), Some('!' | ',' | '.' | ':' | ';' | '?' | '\'')) { - self.s.uneat(); - } - SyntaxKind::Link } @@ -662,6 +635,43 @@ pub fn is_newline(character: char) -> bool { ) } +/// Extracts a prefix of the text that is a link and also returns whether the +/// parentheses and brackets in the link were balanced. +pub fn link_prefix(text: &str) -> (&str, bool) { + let mut s = unscanny::Scanner::new(text); + let mut brackets = Vec::new(); + + #[rustfmt::skip] + s.eat_while(|c: char| { + match c { + | '0' ..= '9' + | 'a' ..= 'z' + | 'A' ..= 'Z' + | '!' | '#' | '$' | '%' | '&' | '*' | '+' + | ',' | '-' | '.' | '/' | ':' | ';' | '=' + | '?' | '@' | '_' | '~' | '\'' => true, + '[' => { + brackets.push(b'['); + true + } + '(' => { + brackets.push(b'('); + true + } + ']' => brackets.pop() == Some(b'['), + ')' => brackets.pop() == Some(b'('), + _ => false, + } + }); + + // Don't include the trailing characters likely to be part of text. + while matches!(s.scout(-1), Some('!' | ',' | '.' | ':' | ';' | '?' | '\'')) { + s.uneat(); + } + + (s.before(), brackets.is_empty()) +} + /// Split text at newlines. pub(super) fn split_newlines(text: &str) -> Vec<&str> { let mut s = Scanner::new(text); diff --git a/crates/typst-syntax/src/lib.rs b/crates/typst-syntax/src/lib.rs index 4ee37096..5cf740e7 100644 --- a/crates/typst-syntax/src/lib.rs +++ b/crates/typst-syntax/src/lib.rs @@ -15,7 +15,7 @@ mod span; pub use self::file::{FileId, PackageSpec, PackageVersion, VirtualPath}; pub use self::highlight::{highlight, highlight_html, Tag}; pub use self::kind::SyntaxKind; -pub use self::lexer::{is_id_continue, is_id_start, is_ident, is_newline}; +pub use self::lexer::{is_id_continue, is_id_start, is_ident, is_newline, link_prefix}; pub use self::node::{LinkedChildren, LinkedNode, SyntaxError, SyntaxNode}; pub use self::parser::{parse, parse_code, parse_math}; pub use self::source::Source; |
