1use crate::SyntaxMode;
2
3#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
7#[repr(u8)]
8pub enum SyntaxKind {
9 End,
11 Error,
13
14 Shebang,
16 LineComment,
18 BlockComment,
20
21 Markup,
23 Text,
25 Space,
28 Linebreak,
30 Parbreak,
32 Escape,
34 Shorthand,
37 SmartQuote,
39 Strong,
41 Emph,
43 Raw,
45 RawLang,
47 RawDelim,
49 RawTrimmed,
51 Link,
53 Label,
55 Ref,
57 RefMarker,
59 Heading,
61 HeadingMarker,
63 ListItem,
65 ListMarker,
67 EnumItem,
69 EnumMarker,
71 TermItem,
73 TermMarker,
75
76 Equation,
78 Math,
80 MathText,
82 MathIdent,
84 MathFieldAccess,
86 MathShorthand,
88 MathAlignPoint,
90 MathCall,
92 MathArgs,
94 MathDelimited,
96 MathAttach,
98 MathPrimes,
100 MathFrac,
102 MathRoot,
104
105 Hash,
107 LeftBrace,
109 RightBrace,
111 LeftBracket,
113 RightBracket,
115 LeftParen,
118 RightParen,
121 Comma,
123 Semicolon,
125 Colon,
128 Star,
131 Underscore,
133 Dollar,
135 Plus,
137 Minus,
139 Slash,
141 Hat,
143 Dot,
145 Eq,
147 EqEq,
149 ExclEq,
151 Lt,
153 LtEq,
155 Gt,
157 GtEq,
159 PlusEq,
161 HyphEq,
163 StarEq,
165 SlashEq,
167 Dots,
169 Arrow,
171 Root,
173 Bang,
175
176 Not,
178 And,
180 Or,
182 None,
184 Auto,
186 Let,
188 Set,
190 Show,
192 Context,
194 If,
196 Else,
198 For,
200 In,
202 While,
204 Break,
206 Continue,
208 Return,
210 Import,
212 Include,
214 As,
216
217 Code,
219 Ident,
221 Bool,
223 Int,
225 Float,
227 Numeric,
229 Str,
231 CodeBlock,
233 ContentBlock,
235 Parenthesized,
237 Array,
239 Dict,
241 Named,
243 Keyed,
245 Unary,
247 Binary,
249 FieldAccess,
251 FuncCall,
253 Args,
255 Spread,
257 Closure,
259 Params,
261 LetBinding,
263 SetRule,
265 ShowRule,
267 Contextual,
269 Conditional,
271 WhileLoop,
273 ForLoop,
275 ModuleImport,
277 ImportItems,
279 ImportItemPath,
281 RenamedImportItem,
283 ModuleInclude,
285 LoopBreak,
287 LoopContinue,
289 FuncReturn,
291 Destructuring,
293 DestructAssignment,
295}
296
297impl SyntaxKind {
298 pub fn is_grouping(self) -> bool {
300 matches!(
301 self,
302 Self::LeftBracket
303 | Self::LeftBrace
304 | Self::LeftParen
305 | Self::RightBracket
306 | Self::RightBrace
307 | Self::RightParen
308 )
309 }
310
311 pub fn is_terminator(self) -> bool {
313 matches!(
314 self,
315 Self::End
316 | Self::Semicolon
317 | Self::RightBrace
318 | Self::RightParen
319 | Self::RightBracket
320 )
321 }
322
323 pub fn is_block(self) -> bool {
325 matches!(self, Self::CodeBlock | Self::ContentBlock)
326 }
327
328 pub fn is_stmt(self) -> bool {
330 matches!(
331 self,
332 Self::LetBinding
333 | Self::SetRule
334 | Self::ShowRule
335 | Self::ModuleImport
336 | Self::ModuleInclude
337 )
338 }
339
340 pub fn is_keyword(self) -> bool {
342 matches!(
343 self,
344 Self::Not
345 | Self::And
346 | Self::Or
347 | Self::None
348 | Self::Auto
349 | Self::Let
350 | Self::Set
351 | Self::Show
352 | Self::Context
353 | Self::If
354 | Self::Else
355 | Self::For
356 | Self::In
357 | Self::While
358 | Self::Break
359 | Self::Continue
360 | Self::Return
361 | Self::Import
362 | Self::Include
363 | Self::As
364 )
365 }
366
367 pub fn is_trivia(self) -> bool {
370 matches!(
371 self,
372 Self::Shebang
373 | Self::LineComment
374 | Self::BlockComment
375 | Self::Space
376 | Self::Parbreak
377 )
378 }
379
380 pub const fn is_error(self) -> bool {
382 matches!(self, Self::Error)
383 }
384
385 pub fn name(self) -> &'static str {
387 match self {
388 Self::End => "end of tokens",
389 Self::Error => "syntax error",
390 Self::Shebang => "shebang",
391 Self::LineComment => "line comment",
392 Self::BlockComment => "block comment",
393 Self::Markup => "markup",
394 Self::Text => "text",
395 Self::Space => "space",
396 Self::Linebreak => "line break",
397 Self::Parbreak => "paragraph break",
398 Self::Escape => "escape sequence",
399 Self::Shorthand => "shorthand",
400 Self::SmartQuote => "smart quote",
401 Self::Strong => "strong content",
402 Self::Emph => "emphasized content",
403 Self::Raw => "raw block",
404 Self::RawLang => "raw language tag",
405 Self::RawTrimmed => "raw trimmed",
406 Self::RawDelim => "raw delimiter",
407 Self::Link => "link",
408 Self::Label => "label",
409 Self::Ref => "reference",
410 Self::RefMarker => "reference marker",
411 Self::Heading => "heading",
412 Self::HeadingMarker => "heading marker",
413 Self::ListItem => "list item",
414 Self::ListMarker => "list marker",
415 Self::EnumItem => "enum item",
416 Self::EnumMarker => "enum marker",
417 Self::TermItem => "term list item",
418 Self::TermMarker => "term marker",
419 Self::Equation => "equation",
420 Self::Math => "math",
421 Self::MathText => "math text",
422 Self::MathIdent => "math identifier",
423 Self::MathFieldAccess => "math field access",
424 Self::MathShorthand => "math shorthand",
425 Self::MathAlignPoint => "math alignment point",
426 Self::MathCall => "math function call",
427 Self::MathArgs => "math call arguments",
428 Self::MathDelimited => "delimited math",
429 Self::MathAttach => "math attachments",
430 Self::MathFrac => "math fraction",
431 Self::MathRoot => "math root",
432 Self::MathPrimes => "math primes",
433 Self::Hash => "hash",
434 Self::LeftBrace => "opening brace",
435 Self::RightBrace => "closing brace",
436 Self::LeftBracket => "opening bracket",
437 Self::RightBracket => "closing bracket",
438 Self::LeftParen => "opening paren",
439 Self::RightParen => "closing paren",
440 Self::Comma => "comma",
441 Self::Semicolon => "semicolon",
442 Self::Colon => "colon",
443 Self::Star => "star",
444 Self::Underscore => "underscore",
445 Self::Dollar => "dollar sign",
446 Self::Plus => "plus",
447 Self::Minus => "minus",
448 Self::Slash => "slash",
449 Self::Hat => "hat",
450 Self::Dot => "dot",
451 Self::Eq => "equals sign",
452 Self::EqEq => "equality operator",
453 Self::ExclEq => "inequality operator",
454 Self::Lt => "less-than operator",
455 Self::LtEq => "less-than or equal operator",
456 Self::Gt => "greater-than operator",
457 Self::GtEq => "greater-than or equal operator",
458 Self::PlusEq => "add-assign operator",
459 Self::HyphEq => "subtract-assign operator",
460 Self::StarEq => "multiply-assign operator",
461 Self::SlashEq => "divide-assign operator",
462 Self::Dots => "dots",
463 Self::Arrow => "arrow",
464 Self::Root => "root",
465 Self::Bang => "exclamation mark",
466 Self::Not => "operator `not`",
467 Self::And => "operator `and`",
468 Self::Or => "operator `or`",
469 Self::None => "`none`",
470 Self::Auto => "`auto`",
471 Self::Let => "keyword `let`",
472 Self::Set => "keyword `set`",
473 Self::Show => "keyword `show`",
474 Self::Context => "keyword `context`",
475 Self::If => "keyword `if`",
476 Self::Else => "keyword `else`",
477 Self::For => "keyword `for`",
478 Self::In => "keyword `in`",
479 Self::While => "keyword `while`",
480 Self::Break => "keyword `break`",
481 Self::Continue => "keyword `continue`",
482 Self::Return => "keyword `return`",
483 Self::Import => "keyword `import`",
484 Self::Include => "keyword `include`",
485 Self::As => "keyword `as`",
486 Self::Code => "code",
487 Self::Ident => "identifier",
488 Self::Bool => "boolean",
489 Self::Int => "integer",
490 Self::Float => "float",
491 Self::Numeric => "numeric value",
492 Self::Str => "string",
493 Self::CodeBlock => "code block",
494 Self::ContentBlock => "content block",
495 Self::Parenthesized => "group",
496 Self::Array => "array",
497 Self::Dict => "dictionary",
498 Self::Named => "named pair",
499 Self::Keyed => "keyed pair",
500 Self::Unary => "unary expression",
501 Self::Binary => "binary expression",
502 Self::FieldAccess => "field access",
503 Self::FuncCall => "function call",
504 Self::Args => "call arguments",
505 Self::Spread => "spread",
506 Self::Closure => "closure",
507 Self::Params => "closure parameters",
508 Self::LetBinding => "`let` expression",
509 Self::SetRule => "`set` expression",
510 Self::ShowRule => "`show` expression",
511 Self::Contextual => "`context` expression",
512 Self::Conditional => "`if` expression",
513 Self::WhileLoop => "while-loop expression",
514 Self::ForLoop => "for-loop expression",
515 Self::ModuleImport => "`import` expression",
516 Self::ImportItems => "import items",
517 Self::ImportItemPath => "imported item path",
518 Self::RenamedImportItem => "renamed import item",
519 Self::ModuleInclude => "`include` expression",
520 Self::LoopBreak => "`break` expression",
521 Self::LoopContinue => "`continue` expression",
522 Self::FuncReturn => "`return` expression",
523 Self::Destructuring => "destructuring pattern",
524 Self::DestructAssignment => "destructuring assignment expression",
525 }
526 }
527}
528
529#[derive(Debug, Clone, Copy, PartialEq, Eq)]
532pub(crate) enum ModeAfter {
533 Known(SyntaxMode),
535 Parent,
537 None,
540 Text,
542 RawDelim,
545 Dollar,
548 Space,
555 Embeddable,
563}
564
565impl SyntaxKind {
566 pub(crate) fn mode_after(self) -> ModeAfter {
571 use ModeAfter::*;
572 use SyntaxMode::{Code, Markup, Math};
573
574 match self {
581 Self::End => None, Self::Error => Parent, Self::Shebang => None, Self::LineComment => None, Self::BlockComment => None, Self::Markup => Known(Markup),
589 Self::Text => Text, Self::Space => Space, Self::Linebreak => Parent, Self::Parbreak => Known(Markup),
593 Self::Escape => Parent, Self::Shorthand => Known(Markup),
595 Self::SmartQuote => Known(Markup),
596 Self::Strong => Known(Markup),
597 Self::Emph => Known(Markup),
598 Self::Raw => Embeddable, Self::RawLang => None, Self::RawDelim => RawDelim, Self::RawTrimmed => None, Self::Link => Known(Markup),
603 Self::Label => Embeddable, Self::Ref => Known(Markup),
605 Self::RefMarker => Known(Markup),
606 Self::Heading => Known(Markup),
607 Self::HeadingMarker => Known(Markup),
608 Self::ListItem => Known(Markup),
609 Self::ListMarker => Known(Markup),
610 Self::EnumItem => Known(Markup),
611 Self::EnumMarker => Known(Markup),
612 Self::TermItem => Known(Markup),
613 Self::TermMarker => Known(Markup),
614
615 Self::Equation => Embeddable, Self::Math => Known(Math),
617 Self::MathText => Known(Math),
618 Self::MathIdent => Known(Math),
619 Self::MathFieldAccess => Known(Math),
620 Self::MathShorthand => Known(Math),
621 Self::MathAlignPoint => Known(Math),
622 Self::MathCall => Known(Math),
623 Self::MathArgs => Known(Math),
624 Self::MathDelimited => Known(Math),
625 Self::MathAttach => Known(Math),
626 Self::MathPrimes => Known(Math),
627 Self::MathFrac => Known(Math),
628 Self::MathRoot => Known(Math),
629
630 Self::Hash => Known(Code),
631 Self::LeftBrace => Known(Code),
632 Self::RightBrace => Known(Code),
633 Self::LeftBracket => Known(Markup),
634 Self::RightBracket => Parent, Self::LeftParen => Parent, Self::RightParen => Parent, Self::Comma => Parent, Self::Semicolon => Parent, Self::Colon => Parent, Self::Star => Parent, Self::Underscore => Parent, Self::Dollar => Dollar, Self::Plus => Known(Code),
644 Self::Minus => Known(Code),
645 Self::Slash => Parent, Self::Hat => Known(Math),
647 Self::Dot => Parent, Self::Eq => Known(Code),
649 Self::EqEq => Known(Code),
650 Self::ExclEq => Known(Code),
651 Self::Lt => Known(Code),
652 Self::LtEq => Known(Code),
653 Self::Gt => Known(Code),
654 Self::GtEq => Known(Code),
655 Self::PlusEq => Known(Code),
656 Self::HyphEq => Known(Code),
657 Self::StarEq => Known(Code),
658 Self::SlashEq => Known(Code),
659 Self::Dots => Parent, Self::Arrow => Known(Code),
661 Self::Root => Known(Math),
662 Self::Bang => Known(Math),
663
664 Self::Not => Known(Code),
665 Self::And => Known(Code),
666 Self::Or => Known(Code),
667 Self::None => Known(Code),
668 Self::Auto => Known(Code),
669 Self::Let => Known(Code),
670 Self::Set => Known(Code),
671 Self::Show => Known(Code),
672 Self::Context => Known(Code),
673 Self::If => Known(Code),
674 Self::Else => Known(Code),
675 Self::For => Known(Code),
676 Self::In => Known(Code),
677 Self::While => Known(Code),
678 Self::Break => Known(Code),
679 Self::Continue => Known(Code),
680 Self::Return => Known(Code),
681 Self::Import => Known(Code),
682 Self::Include => Known(Code),
683 Self::As => Known(Code),
684
685 Self::Code => Known(Code),
686 Self::Ident => Embeddable, Self::Bool => Known(Code),
688 Self::Int => Known(Code),
689 Self::Float => Known(Code),
690 Self::Numeric => Known(Code),
691 Self::Str => Embeddable, Self::CodeBlock => Known(Code),
693 Self::ContentBlock => Embeddable, Self::Parenthesized => Known(Code),
695 Self::Array => Known(Code),
696 Self::Dict => Known(Code),
697 Self::Named => Parent, Self::Keyed => Known(Code),
699 Self::Unary => Known(Code),
700 Self::Binary => Known(Code),
701 Self::FieldAccess => Known(Code),
702 Self::FuncCall => Known(Code),
703 Self::Args => Known(Code),
704 Self::Spread => Parent, Self::Closure => Known(Code),
706 Self::Params => Known(Code),
707 Self::LetBinding => Known(Code),
708 Self::SetRule => Known(Code),
709 Self::ShowRule => Known(Code),
710 Self::Contextual => Known(Code),
711 Self::Conditional => Known(Code),
712 Self::WhileLoop => Known(Code),
713 Self::ForLoop => Known(Code),
714 Self::ModuleImport => Known(Code),
715 Self::ImportItems => Known(Code),
716 Self::ImportItemPath => Known(Code),
717 Self::RenamedImportItem => Known(Code),
718 Self::ModuleInclude => Known(Code),
719 Self::LoopBreak => Known(Code),
720 Self::LoopContinue => Known(Code),
721 Self::FuncReturn => Known(Code),
722 Self::Destructuring => Known(Code),
723 Self::DestructAssignment => Known(Code),
724 }
725 }
726}
727
728#[cfg(test)]
729mod test {
730 use super::*;
731 use crate::{LinkedNode, Side, Source};
732
733 #[track_caller]
734 fn test_mode(
735 text: &str,
736 cursors: impl IntoIterator<Item = usize>,
737 expected: Option<SyntaxMode>,
738 ) {
739 let source = Source::detached(text);
740 let root = LinkedNode::new(source.root());
741 for cursor in cursors {
742 let leaf = root.leaf_at(cursor, Side::After).unwrap();
743 let c = source.text()[cursor..].chars().next().unwrap();
744 assert_eq!(leaf.mode_after(), expected, "different at '{c}' index {cursor}");
745 }
746 }
747
748 #[test]
749 fn test_mode_after() {
750 use SyntaxMode::{Code, Markup, Math};
751
752 test_mode("#! typ", [0, 1, 2, 3], None);
754 test_mode("#! typ\n", [6], Some(Markup));
755 test_mode("// xxx", [0, 1, 2, 3], None);
756 test_mode("\n// xxx\n", [0, 7], Some(Markup));
757 test_mode("/* xxx */", [0, 1, 2, 3, 4, 7, 8], None);
758
759 test_mode("*/", [0, 1], Some(Markup));
761 test_mode("#{*/}", [2, 3], Some(Code));
762 test_mode("$*/$", [1, 2], Some(Math));
763
764 test_mode("https://typst.org", [0], Some(Markup));
766 test_mode("a\\bcd", [0, 1, 2, 3], Some(Markup));
767 test_mode("a c\n\n d\\\nef", [1, 5, 9], Some(Markup));
768 test_mode("\\u{41}", [0, 1, 2, 3, 5], Some(Markup));
769 test_mode("\"abc\"", [0, 1, 4], Some(Markup));
770 test_mode("a-?b", [1, 2], Some(Markup));
771 test_mode("_*abcd*_", [0, 1, 6, 7], Some(Markup));
772 test_mode("<label>", [0, 1], Some(Markup));
773 test_mode("@label[x @y]", [0, 1, 6, 7, 8, 9, 11], Some(Markup));
774 test_mode("= marker", [0, 1, 2], Some(Markup));
775 test_mode("- marker", [0, 1, 2], Some(Markup));
776 test_mode("+ marker", [0, 1, 2], Some(Markup));
777 test_mode("/ marker: y", [0, 1, 2, 8, 9, 10], Some(Markup));
778
779 test_mode("#{x;1}", [0, 1, 2, 3, 4], Some(Code));
781 test_mode("#(x)", [1, 2, 3], Some(Code));
782 test_mode("#(1,2,)", [1, 2, 3, 5, 6], Some(Code));
783 test_mode("#(a:1,\"b\":2)", [1, 2, 3, 4, 5, 6, 7, 8, 9, 11], Some(Code));
784 test_mode("#{-x}", [2], Some(Code));
785 test_mode("#{a / b}", [4], Some(Code));
786 test_mode("#a.b", [1, 2, 3], Some(Code));
787 test_mode("#$$.at()", [2, 3], Some(Code));
788 test_mode("#[].at()", [2, 3], Some(Code));
789 test_mode("#f(x, ..y)", [2, 4, 6], Some(Code));
790 test_mode("#{(x) => {}}", [3, 6], Some(Code));
791 test_mode("#let x = 1", [1, 7], Some(Code));
792 test_mode("#let x;", [6], Some(Markup)); test_mode("#set text()", [1, 4], Some(Code));
794 test_mode("#show text : it => it", [1, 11], Some(Code));
795 test_mode("#context 1", [1, 8], Some(Code));
796 test_mode("#while true {break;continue;}", [1, 13, 19], Some(Code));
797 test_mode("#for a in b {}", [1, 7], Some(Code));
798 test_mode("#if true {} else {}", [1, 12], Some(Code));
799 test_mode("#import \"lib.typ\" : a, b as d, e.f", [2, 8, 21, 25, 32], Some(Code));
800 test_mode("#include \"lib.typ\"", [1], Some(Code));
801 test_mode("#let f() = { return 1 }", [13], Some(Code));
802 test_mode("#{(x, _, ..y) = (1, 2, ..z)}", [2, 14], Some(Code));
803 test_mode("= #1.1", [2, 3], Some(Code));
804
805 test_mode("$$", [0], Some(Math)); test_mode("$$", [1], Some(Markup)); test_mode("#$$", [2], Some(Code)); test_mode("$ a b $", [1, 3, 5], Some(Math)); test_mode("$\na\nb\n$", [1, 3, 5], Some(Math)); test_mode("$arrow$", [1], Some(Math));
812 test_mode("$123.32$", [1, 2, 4, 5], Some(Math));
813 test_mode("$+12 * y!", [1, 5, 8], Some(Math));
814 test_mode("$1/2$", [2], Some(Math));
815 test_mode("$f''$", [2], Some(Math));
816 test_mode("$f_(x)^y$", [2, 3, 6, 7], Some(Math));
817 test_mode("$a>=b$", [2], Some(Math));
818 test_mode("$√x$", [1, 4], Some(Math));
819 test_mode("$&x$", [1], Some(Math));
820 test_mode("$\\#\\u{41}$", [1, 2, 3, 4, 5, 6], Some(Math));
821 test_mode("$ff(x, sin(y), abs(z))$", [3, 4, 5, 7, 10, 15, 18], Some(Math));
822 test_mode("$ff(..args, named: key)$", [4, 6, 16, 17], Some(Math));
823 test_mode("$arrow.r$", [6], Some(Math));
824
825 test_mode("`r`", [0, 1], None);
827 test_mode("`r`", [2], Some(Markup));
828 test_mode("` \n r\n `", [1, 2, 3, 4, 5, 6], None);
829 test_mode("#`r`", [1, 2], None);
830 test_mode("#`r`", [3], Some(Code));
831 test_mode("```l r\n```", [7], Some(Markup));
832 test_mode("```l r\n```", [0, 3, 4, 5, 6], None);
833 test_mode("#```l r\n```", [8], Some(Code));
834 test_mode("#```l r\n```", [1, 4, 5, 6, 7], None);
835
836 test_mode("#<l>", [1, 2, 3], Some(Code));
838 test_mode("$#pa$", [2, 3], Some(Code));
839 test_mode("$#{x}$", [2], Some(Code));
840 test_mode("$#[x]$", [1, 4], Some(Code));
841 test_mode("$#[x]$", [2, 3], Some(Markup));
842 test_mode("$#f(x, ..args, named: key)$", [3, 4, 5, 7, 9, 19, 20], Some(Code));
843 test_mode("$#context 1$", [9, 10], Some(Code));
844 test_mode("$#context $", [9], Some(Code));
845 test_mode("$#std.align$", [2, 5, 6], Some(Code));
846 test_mode("$ff(named: #ident)$", [12], Some(Code));
847 test_mode("$ #$x$; $", [0, 1, 3, 4, 6, 7], Some(Math));
848 test_mode("$ #$x$; $", [8], Some(Markup));
849 test_mode("$ #$x$; $", [2, 5], Some(Code));
850 test_mode("#[$x$]", [2, 3], Some(Math));
851 test_mode("#[$x$]", [1, 4], Some(Markup));
852 }
853}