mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Fix newline parsing behaviour in markup
This commit is contained in:
parent
14d28dbf4e
commit
e39be71a54
@ -571,13 +571,13 @@ fn code(p: &mut Parser, stop: impl FnMut(&Parser) -> bool) {
|
|||||||
|
|
||||||
fn code_exprs(p: &mut Parser, mut stop: impl FnMut(&Parser) -> bool) {
|
fn code_exprs(p: &mut Parser, mut stop: impl FnMut(&Parser) -> bool) {
|
||||||
while !p.eof() && !stop(p) {
|
while !p.eof() && !stop(p) {
|
||||||
p.stop_at_newline(true);
|
p.enter_newline_mode(NewlineMode::Contextual);
|
||||||
let prev = p.prev_end();
|
let prev = p.prev_end();
|
||||||
code_expr(p);
|
code_expr(p);
|
||||||
if p.progress(prev) && !p.eof() && !stop(p) && !p.eat_if(SyntaxKind::Semicolon) {
|
if p.progress(prev) && !p.eof() && !stop(p) && !p.eat_if(SyntaxKind::Semicolon) {
|
||||||
p.expected("semicolon or line break");
|
p.expected("semicolon or line break");
|
||||||
}
|
}
|
||||||
p.unstop();
|
p.exit_newline_mode();
|
||||||
if !p.progress(prev) && !p.eof() {
|
if !p.progress(prev) && !p.eof() {
|
||||||
p.unexpected();
|
p.unexpected();
|
||||||
}
|
}
|
||||||
@ -593,7 +593,7 @@ fn code_expr_or_pattern(p: &mut Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn embedded_code_expr(p: &mut Parser) {
|
fn embedded_code_expr(p: &mut Parser) {
|
||||||
p.stop_at_newline(true);
|
p.enter_newline_mode(NewlineMode::Stop);
|
||||||
p.enter(LexMode::Code);
|
p.enter(LexMode::Code);
|
||||||
p.assert(SyntaxKind::Hashtag);
|
p.assert(SyntaxKind::Hashtag);
|
||||||
p.unskip();
|
p.unskip();
|
||||||
@ -611,12 +611,8 @@ fn embedded_code_expr(p: &mut Parser) {
|
|||||||
code_expr_prec(p, true, 0, false);
|
code_expr_prec(p, true, 0, false);
|
||||||
|
|
||||||
// Consume error for things like `#12p` or `#"abc\"`.#
|
// Consume error for things like `#12p` or `#"abc\"`.#
|
||||||
if !p.progress(prev) {
|
if !p.progress(prev) && !p.current().is_trivia() && !p.eof() {
|
||||||
if p.current().is_trivia() {
|
p.unexpected();
|
||||||
// p.unskip();
|
|
||||||
} else if !p.eof() {
|
|
||||||
p.unexpected();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let semi =
|
let semi =
|
||||||
@ -627,7 +623,7 @@ fn embedded_code_expr(p: &mut Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.exit();
|
p.exit();
|
||||||
p.unstop();
|
p.exit_newline_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn code_expr_prec(
|
fn code_expr_prec(
|
||||||
@ -772,7 +768,7 @@ pub(super) fn reparse_block(text: &str, range: Range<usize>) -> Option<SyntaxNod
|
|||||||
fn code_block(p: &mut Parser) {
|
fn code_block(p: &mut Parser) {
|
||||||
let m = p.marker();
|
let m = p.marker();
|
||||||
p.enter(LexMode::Code);
|
p.enter(LexMode::Code);
|
||||||
p.stop_at_newline(false);
|
p.enter_newline_mode(NewlineMode::Continue);
|
||||||
p.assert(SyntaxKind::LeftBrace);
|
p.assert(SyntaxKind::LeftBrace);
|
||||||
code(p, |p| {
|
code(p, |p| {
|
||||||
p.at(SyntaxKind::RightBrace)
|
p.at(SyntaxKind::RightBrace)
|
||||||
@ -781,7 +777,7 @@ fn code_block(p: &mut Parser) {
|
|||||||
});
|
});
|
||||||
p.expect_closing_delimiter(m, SyntaxKind::RightBrace);
|
p.expect_closing_delimiter(m, SyntaxKind::RightBrace);
|
||||||
p.exit();
|
p.exit();
|
||||||
p.unstop();
|
p.exit_newline_mode();
|
||||||
p.wrap(m, SyntaxKind::CodeBlock);
|
p.wrap(m, SyntaxKind::CodeBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,7 +848,7 @@ fn invalidate_destructuring(p: &mut Parser, m: Marker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind {
|
fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind {
|
||||||
p.stop_at_newline(false);
|
p.enter_newline_mode(NewlineMode::Continue);
|
||||||
|
|
||||||
let m = p.marker();
|
let m = p.marker();
|
||||||
p.assert(SyntaxKind::LeftParen);
|
p.assert(SyntaxKind::LeftParen);
|
||||||
@ -901,7 +897,7 @@ fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.expect_closing_delimiter(m, SyntaxKind::RightParen);
|
p.expect_closing_delimiter(m, SyntaxKind::RightParen);
|
||||||
p.unstop();
|
p.exit_newline_mode();
|
||||||
|
|
||||||
if parenthesized && count == 1 {
|
if parenthesized && count == 1 {
|
||||||
SyntaxKind::Parenthesized
|
SyntaxKind::Parenthesized
|
||||||
@ -1442,10 +1438,20 @@ struct Parser<'s> {
|
|||||||
current: SyntaxKind,
|
current: SyntaxKind,
|
||||||
modes: Vec<LexMode>,
|
modes: Vec<LexMode>,
|
||||||
nodes: Vec<SyntaxNode>,
|
nodes: Vec<SyntaxNode>,
|
||||||
stop_at_newline: Vec<bool>,
|
newline_modes: Vec<NewlineMode>,
|
||||||
balanced: bool,
|
balanced: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How to proceed with parsing when seeing a newline.
|
||||||
|
enum NewlineMode {
|
||||||
|
/// Stop always.
|
||||||
|
Stop,
|
||||||
|
/// Proceed if there is no continuation with `else` or `.`
|
||||||
|
Contextual,
|
||||||
|
/// Just proceed like with normal whitespace.
|
||||||
|
Continue,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
struct Marker(usize);
|
struct Marker(usize);
|
||||||
|
|
||||||
@ -1462,7 +1468,7 @@ impl<'s> Parser<'s> {
|
|||||||
current,
|
current,
|
||||||
modes: vec![],
|
modes: vec![],
|
||||||
nodes: vec![],
|
nodes: vec![],
|
||||||
stop_at_newline: vec![],
|
newline_modes: vec![],
|
||||||
balanced: true,
|
balanced: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1597,13 +1603,13 @@ impl<'s> Parser<'s> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop_at_newline(&mut self, stop: bool) {
|
fn enter_newline_mode(&mut self, stop: NewlineMode) {
|
||||||
self.stop_at_newline.push(stop);
|
self.newline_modes.push(stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unstop(&mut self) {
|
fn exit_newline_mode(&mut self) {
|
||||||
self.unskip();
|
self.unskip();
|
||||||
self.stop_at_newline.pop();
|
self.newline_modes.pop();
|
||||||
self.lexer.jump(self.prev_end);
|
self.lexer.jump(self.prev_end);
|
||||||
self.lex();
|
self.lex();
|
||||||
self.skip();
|
self.skip();
|
||||||
@ -1654,8 +1660,15 @@ impl<'s> Parser<'s> {
|
|||||||
self.current = self.lexer.next();
|
self.current = self.lexer.next();
|
||||||
if self.lexer.mode() == LexMode::Code
|
if self.lexer.mode() == LexMode::Code
|
||||||
&& self.lexer.newline()
|
&& self.lexer.newline()
|
||||||
&& self.stop_at_newline.last().copied().unwrap_or(false)
|
&& match self.newline_modes.last() {
|
||||||
&& !matches!(self.lexer.clone().next(), SyntaxKind::Else | SyntaxKind::Dot)
|
Some(NewlineMode::Continue) => false,
|
||||||
|
Some(NewlineMode::Contextual) => !matches!(
|
||||||
|
self.lexer.clone().next(),
|
||||||
|
SyntaxKind::Else | SyntaxKind::Dot
|
||||||
|
),
|
||||||
|
Some(NewlineMode::Stop) => true,
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
{
|
{
|
||||||
self.current = SyntaxKind::Eof;
|
self.current = SyntaxKind::Eof;
|
||||||
}
|
}
|
||||||
|
BIN
tests/ref/bugs/newline-mode.png
Normal file
BIN
tests/ref/bugs/newline-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
24
tests/typ/bugs/newline-mode.typ
Normal file
24
tests/typ/bugs/newline-mode.typ
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Test newline continuations.
|
||||||
|
|
||||||
|
---
|
||||||
|
#{
|
||||||
|
"hello"
|
||||||
|
.clusters()
|
||||||
|
if false {
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
("1", "2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
#"hello"
|
||||||
|
.codepoints()
|
||||||
|
|
||||||
|
#if false {
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
("1", "2")
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user