summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst-syntax/src/highlight.rs1
-rw-r--r--crates/typst-syntax/src/kind.rs9
-rw-r--r--crates/typst-syntax/src/lexer.rs6
-rw-r--r--crates/typst-syntax/src/parser.rs2
-rw-r--r--tests/suite/syntax/shebang.typ7
5 files changed, 24 insertions, 1 deletions
diff --git a/crates/typst-syntax/src/highlight.rs b/crates/typst-syntax/src/highlight.rs
index de8ed65c..c59a0338 100644
--- a/crates/typst-syntax/src/highlight.rs
+++ b/crates/typst-syntax/src/highlight.rs
@@ -287,6 +287,7 @@ pub fn highlight(node: &LinkedNode) -> Option<Tag> {
SyntaxKind::Destructuring => None,
SyntaxKind::DestructAssignment => None,
+ SyntaxKind::Shebang => Some(Tag::Comment),
SyntaxKind::LineComment => Some(Tag::Comment),
SyntaxKind::BlockComment => Some(Tag::Comment),
SyntaxKind::Error => Some(Tag::Error),
diff --git a/crates/typst-syntax/src/kind.rs b/crates/typst-syntax/src/kind.rs
index 0a7c160b..b4a97a3e 100644
--- a/crates/typst-syntax/src/kind.rs
+++ b/crates/typst-syntax/src/kind.rs
@@ -9,6 +9,8 @@ pub enum SyntaxKind {
/// An invalid sequence of characters.
Error,
+ /// A shebang: `#! ...`
+ Shebang,
/// A line comment: `// ...`.
LineComment,
/// A block comment: `/* ... */`.
@@ -357,7 +359,11 @@ impl SyntaxKind {
pub fn is_trivia(self) -> bool {
matches!(
self,
- Self::LineComment | Self::BlockComment | Self::Space | Self::Parbreak
+ Self::Shebang
+ | Self::LineComment
+ | Self::BlockComment
+ | Self::Space
+ | Self::Parbreak
)
}
@@ -371,6 +377,7 @@ impl SyntaxKind {
match self {
Self::End => "end of tokens",
Self::Error => "syntax error",
+ Self::Shebang => "shebang",
Self::LineComment => "line comment",
Self::BlockComment => "block comment",
Self::Markup => "markup",
diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs
index 6b5d2816..17401044 100644
--- a/crates/typst-syntax/src/lexer.rs
+++ b/crates/typst-syntax/src/lexer.rs
@@ -103,6 +103,7 @@ impl Lexer<'_> {
self.newline = false;
let kind = match self.s.eat() {
Some(c) if is_space(c, self.mode) => self.whitespace(start, c),
+ Some('#') if start == 0 && self.s.eat_if('!') => self.shebang(),
Some('/') if self.s.eat_if('/') => self.line_comment(),
Some('/') if self.s.eat_if('*') => self.block_comment(),
Some('*') if self.s.eat_if('/') => {
@@ -151,6 +152,11 @@ impl Lexer<'_> {
}
}
+ fn shebang(&mut self) -> SyntaxKind {
+ self.s.eat_until(is_newline);
+ SyntaxKind::Shebang
+ }
+
fn line_comment(&mut self) -> SyntaxKind {
self.s.eat_until(is_newline);
SyntaxKind::LineComment
diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs
index 5b9e66e2..5de71caf 100644
--- a/crates/typst-syntax/src/parser.rs
+++ b/crates/typst-syntax/src/parser.rs
@@ -93,6 +93,8 @@ fn markup_expr(p: &mut Parser, at_start: bool, nesting: &mut usize) {
p.hint("try using a backslash escape: \\]");
}
+ SyntaxKind::Shebang => p.eat(),
+
SyntaxKind::Text
| SyntaxKind::Linebreak
| SyntaxKind::Escape
diff --git a/tests/suite/syntax/shebang.typ b/tests/suite/syntax/shebang.typ
new file mode 100644
index 00000000..c2eb2e43
--- /dev/null
+++ b/tests/suite/syntax/shebang.typ
@@ -0,0 +1,7 @@
+// Test shebang support.
+
+--- shebang ---
+#!typst compile
+
+// Error: 2-3 the character `!` is not valid in code
+#!not-a-shebang