summaryrefslogtreecommitdiff
path: root/crates/typst-syntax/src/lexer.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-10-28 23:35:13 +0200
committerLaurenz <laurmaedje@gmail.com>2023-10-29 00:52:15 +0200
commit29130a26f83f28ae37be1ff4f57877e765d27285 (patch)
tree5abc020ae1be4fa2681ca1b977ee7ce398b3a9bb /crates/typst-syntax/src/lexer.rs
parent4c75adbb047cba73b052c2fafa9155e2e4026610 (diff)
Linebreaking for links
Diffstat (limited to 'crates/typst-syntax/src/lexer.rs')
-rw-r--r--crates/typst-syntax/src/lexer.rs70
1 files changed, 40 insertions, 30 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);