mirror of
https://github.com/typst/typst
synced 2025-05-15 01:25:28 +08:00
Deal with offside rule and remove RightWhitespace
This commit is contained in:
parent
12f7335ac3
commit
289122e83c
@ -5,7 +5,7 @@ use crate::syntax::{Green, GreenNode, NodeKind};
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
parse_atomic, parse_atomic_markup, parse_block, parse_comment, parse_markup,
|
parse_atomic, parse_atomic_markup, parse_block, parse_comment, parse_markup,
|
||||||
parse_markup_elements, parse_template, TokenMode,
|
parse_markup_elements, parse_template, Scanner, TokenMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The conditions that a node has to fulfill in order to be replaced.
|
/// The conditions that a node has to fulfill in order to be replaced.
|
||||||
@ -40,14 +40,13 @@ pub enum Postcondition {
|
|||||||
pub enum Precondition {
|
pub enum Precondition {
|
||||||
/// These nodes depend on being at the start of a line. Reparsing of safe
|
/// These nodes depend on being at the start of a line. Reparsing of safe
|
||||||
/// left neighbors has to check this invariant. Otherwise, this node is
|
/// left neighbors has to check this invariant. Otherwise, this node is
|
||||||
/// safe.
|
/// safe. Additionally, the indentation of the first right non-trivia,
|
||||||
|
/// non-whitespace sibling must not be greater than the current indentation.
|
||||||
AtStart,
|
AtStart,
|
||||||
/// These nodes depend on not being at the start of a line. Reparsing of
|
/// These nodes depend on not being at the start of a line. Reparsing of
|
||||||
/// safe left neighbors has to check this invariant. Otherwise, this node is
|
/// safe left neighbors has to check this invariant. Otherwise, this node is
|
||||||
/// safe.
|
/// safe.
|
||||||
NotAtStart,
|
NotAtStart,
|
||||||
/// These nodes must be followed by whitespace.
|
|
||||||
RightWhitespace,
|
|
||||||
/// No additional requirements.
|
/// No additional requirements.
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
@ -213,6 +212,8 @@ impl Reparser<'_> {
|
|||||||
&newborns,
|
&newborns,
|
||||||
mode,
|
mode,
|
||||||
post,
|
post,
|
||||||
|
replace_span.clone(),
|
||||||
|
self.src,
|
||||||
) {
|
) {
|
||||||
green.replace_child_range(children_range, newborns);
|
green.replace_child_range(children_range, newborns);
|
||||||
Some(replace_span)
|
Some(replace_span)
|
||||||
@ -230,6 +231,8 @@ fn validate(
|
|||||||
newborns: &[Green],
|
newborns: &[Green],
|
||||||
mode: TokenMode,
|
mode: TokenMode,
|
||||||
post: Postcondition,
|
post: Postcondition,
|
||||||
|
replace_span: Range<usize>,
|
||||||
|
src: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Atomic primaries must only generate one new child.
|
// Atomic primaries must only generate one new child.
|
||||||
if post == Postcondition::AtomicPrimary && newborns.len() != 1 {
|
if post == Postcondition::AtomicPrimary && newborns.len() != 1 {
|
||||||
@ -253,24 +256,38 @@ fn validate(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that a possible right-whitespace precondition of a node before the
|
// Check if there are any `AtStart` predecessors which require a certain
|
||||||
// replacement range is satisfied.
|
// indentation.
|
||||||
if children_range.start > 0
|
let s = Scanner::new(src);
|
||||||
&& prev_children[children_range.start - 1].kind().pre()
|
let mut prev_pos = replace_span.start;
|
||||||
== Precondition::RightWhitespace
|
for child in (&prev_children[.. children_range.start]).iter().rev() {
|
||||||
&& !newborns[0].kind().is_whitespace()
|
prev_pos -= child.len();
|
||||||
{
|
if !child.kind().is_trivia() {
|
||||||
return false;
|
if child.kind().pre() == Precondition::AtStart {
|
||||||
|
let left_col = s.column(prev_pos);
|
||||||
|
|
||||||
|
// Search for the first non-trivia newborn.
|
||||||
|
let mut new_pos = replace_span.start;
|
||||||
|
let mut child_col = None;
|
||||||
|
for child in newborns {
|
||||||
|
if !child.kind().is_trivia() {
|
||||||
|
child_col = Some(s.column(new_pos));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that a possible right-whitespace precondition of a new node at the
|
new_pos += child.len();
|
||||||
// end of the replacement range is satisfied.
|
}
|
||||||
if newborns.last().map(|x| x.kind().pre()) == Some(Precondition::RightWhitespace)
|
|
||||||
&& children_range.end < prev_children.len()
|
if let Some(child_col) = child_col {
|
||||||
&& !prev_children[children_range.end].kind().is_whitespace()
|
if child_col > left_col {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the at_start state behind the new children.
|
// Compute the at_start state behind the new children.
|
||||||
for child in newborns {
|
for child in newborns {
|
||||||
@ -294,6 +311,37 @@ fn validate(
|
|||||||
at_start = child.kind().is_at_start(at_start);
|
at_start = child.kind().is_at_start(at_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have to check whether the last non-trivia newborn is `AtStart` and
|
||||||
|
// verify the indent of its right neighbors in order to make sure its
|
||||||
|
// indentation requirements are fulfilled.
|
||||||
|
let mut child_pos = replace_span.end;
|
||||||
|
let mut child_col = None;
|
||||||
|
for child in newborns.iter().rev() {
|
||||||
|
child_pos -= child.len();
|
||||||
|
|
||||||
|
if !child.kind().is_trivia() {
|
||||||
|
if child.kind().pre() == Precondition::AtStart {
|
||||||
|
child_col = Some(s.column(child_pos));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(child_col) = child_col {
|
||||||
|
let mut right_pos = replace_span.end;
|
||||||
|
for child in &prev_children[children_range.end ..] {
|
||||||
|
if !child.kind().is_trivia() {
|
||||||
|
if s.column(right_pos) > child_col {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
right_pos += child.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +517,6 @@ impl NodeKind {
|
|||||||
match self {
|
match self {
|
||||||
Self::Heading | Self::Enum | Self::List => Precondition::AtStart,
|
Self::Heading | Self::Enum | Self::List => Precondition::AtStart,
|
||||||
Self::TextInLine(_) => Precondition::NotAtStart,
|
Self::TextInLine(_) => Precondition::NotAtStart,
|
||||||
Self::Linebreak => Precondition::RightWhitespace,
|
|
||||||
_ => Precondition::None,
|
_ => Precondition::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -515,7 +562,8 @@ mod tests {
|
|||||||
test("a your thing a", 6 .. 7, "a", 2 .. 12);
|
test("a your thing a", 6 .. 7, "a", 2 .. 12);
|
||||||
test("{call(); abc}", 7 .. 7, "[]", 0 .. 15);
|
test("{call(); abc}", 7 .. 7, "[]", 0 .. 15);
|
||||||
test("#call() abc", 7 .. 7, "[]", 0 .. 10);
|
test("#call() abc", 7 .. 7, "[]", 0 .. 10);
|
||||||
// test("hi\n- item\n- item 2\n - item 3", 10 .. 10, " ", 9 .. 33);
|
test("hi[\n- item\n- item 2\n - item 3]", 11 .. 11, " ", 2 .. 35);
|
||||||
|
test("hi\n- item\nno item\n - item 3", 10 .. 10, "- ", 0 .. 32);
|
||||||
test("#grid(columns: (auto, 1fr, 40%), [*plonk*], rect(width: 100%, height: 1pt, fill: conifer), [thing])", 16 .. 20, "none", 16 .. 20);
|
test("#grid(columns: (auto, 1fr, 40%), [*plonk*], rect(width: 100%, height: 1pt, fill: conifer), [thing])", 16 .. 20, "none", 16 .. 20);
|
||||||
test("#grid(columns: (auto, 1fr, 40%), [*plonk*], rect(width: 100%, height: 1pt, fill: conifer), [thing])", 33 .. 42, "[_gronk_]", 33 .. 42);
|
test("#grid(columns: (auto, 1fr, 40%), [*plonk*], rect(width: 100%, height: 1pt, fill: conifer), [thing])", 33 .. 42, "[_gronk_]", 33 .. 42);
|
||||||
test("#grid(columns: (auto, 1fr, 40%), [*plonk*], rect(width: 100%, height: 1pt, fill: conifer), [thing])", 34 .. 41, "_bar_", 34 .. 39);
|
test("#grid(columns: (auto, 1fr, 40%), [*plonk*], rect(width: 100%, height: 1pt, fill: conifer), [thing])", 34 .. 41, "_bar_", 34 .. 39);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user