summaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/incremental.rs92
1 files changed, 70 insertions, 22 deletions
diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs
index cc100a4c..0e2d196c 100644
--- a/src/parse/incremental.rs
+++ b/src/parse/incremental.rs
@@ -5,7 +5,7 @@ use crate::syntax::{Green, GreenNode, NodeKind};
use super::{
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.
@@ -40,14 +40,13 @@ pub enum Postcondition {
pub enum Precondition {
/// 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
- /// safe.
+ /// safe. Additionally, the indentation of the first right non-trivia,
+ /// non-whitespace sibling must not be greater than the current indentation.
AtStart,
/// 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.
NotAtStart,
- /// These nodes must be followed by whitespace.
- RightWhitespace,
/// No additional requirements.
None,
}
@@ -213,6 +212,8 @@ impl Reparser<'_> {
&newborns,
mode,
post,
+ replace_span.clone(),
+ self.src,
) {
green.replace_child_range(children_range, newborns);
Some(replace_span)
@@ -230,6 +231,8 @@ fn validate(
newborns: &[Green],
mode: TokenMode,
post: Postcondition,
+ replace_span: Range<usize>,
+ src: &str,
) -> bool {
// Atomic primaries must only generate one new child.
if post == Postcondition::AtomicPrimary && newborns.len() != 1 {
@@ -253,23 +256,37 @@ fn validate(
return true;
}
- // Ensure that a possible right-whitespace precondition of a node before the
- // replacement range is satisfied.
- if children_range.start > 0
- && prev_children[children_range.start - 1].kind().pre()
- == Precondition::RightWhitespace
- && !newborns[0].kind().is_whitespace()
- {
- return false;
- }
+ // Check if there are any `AtStart` predecessors which require a certain
+ // indentation.
+ let s = Scanner::new(src);
+ let mut prev_pos = replace_span.start;
+ for child in (&prev_children[.. children_range.start]).iter().rev() {
+ prev_pos -= child.len();
+ if !child.kind().is_trivia() {
+ 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;
+ }
+
+ new_pos += child.len();
+ }
- // Ensure that a possible right-whitespace precondition of a new node at the
- // end of the replacement range is satisfied.
- if newborns.last().map(|x| x.kind().pre()) == Some(Precondition::RightWhitespace)
- && children_range.end < prev_children.len()
- && !prev_children[children_range.end].kind().is_whitespace()
- {
- return false;
+ if let Some(child_col) = child_col {
+ if child_col > left_col {
+ return false;
+ }
+ }
+ }
+
+ break;
+ }
}
// Compute the at_start state behind the new children.
@@ -294,6 +311,37 @@ fn validate(
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
}
@@ -469,7 +517,6 @@ impl NodeKind {
match self {
Self::Heading | Self::Enum | Self::List => Precondition::AtStart,
Self::TextInLine(_) => Precondition::NotAtStart,
- Self::Linebreak => Precondition::RightWhitespace,
_ => Precondition::None,
}
}
@@ -515,7 +562,8 @@ mod tests {
test("a your thing a", 6 .. 7, "a", 2 .. 12);
test("{call(); abc}", 7 .. 7, "[]", 0 .. 15);
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])", 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);