summaryrefslogtreecommitdiff
path: root/src/parse/incremental.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-04-24 17:52:02 +0200
committerLaurenz <laurmaedje@gmail.com>2022-04-24 18:00:36 +0200
commit2791f59ce2404d0483aee92b8231df95aa45b7a5 (patch)
tree13d4f86f8a3bd7c021dc43721f82b6ef23913e30 /src/parse/incremental.rs
parent89927d7de069169eeecfa091d6b77408b69fe188 (diff)
Clean up the parser a bit
Diffstat (limited to 'src/parse/incremental.rs')
-rw-r--r--src/parse/incremental.rs67
1 files changed, 37 insertions, 30 deletions
diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs
index 64fe95ab..38938c4b 100644
--- a/src/parse/incremental.rs
+++ b/src/parse/incremental.rs
@@ -8,35 +8,41 @@ use super::{
reparse_markup_elements, TokenMode,
};
+/// Refresh the given green node with as little parsing as possible.
+///
+/// Takes the new source, the range in the old source that was replaced and the
+/// length of the replacement.
+///
+/// Returns the range in the new source that was ultimately reparsed.
+pub fn reparse(
+ green: &mut Arc<GreenNode>,
+ src: &str,
+ replaced: Range<usize>,
+ replacement_len: usize,
+) -> Range<usize> {
+ Reparser { src, replaced, replacement_len }
+ .reparse_step(Arc::make_mut(green), 0, true)
+ .unwrap_or_else(|| {
+ *green = parse(src);
+ 0 .. src.len()
+ })
+}
+
/// Allows partial refreshs of the [`Green`] node tree.
///
/// This struct holds a description of a change. Its methods can be used to try
/// and apply the change to a green tree.
-pub struct Reparser<'a> {
+struct Reparser<'a> {
/// The new source code, with the change applied.
src: &'a str,
/// Which range in the old source file was changed.
- replace_range: Range<usize>,
- /// How many characters replaced the text in `replace_range`.
- replace_len: usize,
-}
-
-impl<'a> Reparser<'a> {
- /// Create a new reparser.
- pub fn new(src: &'a str, replace_range: Range<usize>, replace_len: usize) -> Self {
- Self { src, replace_range, replace_len }
- }
+ replaced: Range<usize>,
+ /// How many characters replaced the text in `replaced`.
+ replacement_len: usize,
}
impl Reparser<'_> {
- /// Find the innermost child that is incremental safe.
- pub fn reparse(&self, green: &mut Arc<GreenNode>) -> Range<usize> {
- self.reparse_step(Arc::make_mut(green), 0, true).unwrap_or_else(|| {
- *green = parse(self.src);
- 0 .. self.src.len()
- })
- }
-
+ /// Try to reparse inside the given node.
fn reparse_step(
&self,
green: &mut GreenNode,
@@ -64,19 +70,19 @@ impl Reparser<'_> {
match search {
SearchState::NoneFound => {
// The edit is contained within the span of the current element.
- if child_span.contains(&self.replace_range.start)
- && child_span.end >= self.replace_range.end
+ if child_span.contains(&self.replaced.start)
+ && child_span.end >= self.replaced.end
{
// In Markup mode, we want to consider a non-whitespace
// neighbor if the edit is on the node boundary.
- search = if child_span.end == self.replace_range.end
+ search = if child_span.end == self.replaced.end
&& child_mode == TokenMode::Markup
{
SearchState::RequireNonTrivia(pos)
} else {
SearchState::Contained(pos)
};
- } else if child_span.contains(&self.replace_range.start) {
+ } else if child_span.contains(&self.replaced.start) {
search = SearchState::Inside(pos);
} else {
// We look only for non spaces, non-semicolon and also
@@ -86,7 +92,7 @@ impl Reparser<'_> {
&& child.kind() != &NodeKind::Semicolon
&& child.kind() != &NodeKind::Text('/'.into())
&& (ahead_nontrivia.is_none()
- || self.replace_range.start > child_span.end)
+ || self.replaced.start > child_span.end)
{
ahead_nontrivia = Some((pos, at_start));
}
@@ -94,9 +100,9 @@ impl Reparser<'_> {
}
}
SearchState::Inside(start) => {
- if child_span.end == self.replace_range.end {
+ if child_span.end == self.replaced.end {
search = SearchState::RequireNonTrivia(start);
- } else if child_span.end > self.replace_range.end {
+ } else if child_span.end > self.replaced.end {
search = SearchState::SpanFound(start, pos);
}
}
@@ -172,7 +178,7 @@ impl Reparser<'_> {
if let Some((ahead, ahead_at_start)) = ahead_nontrivia {
let ahead_kind = green.children()[ahead.idx].kind();
- if start.offset == self.replace_range.start
+ if start.offset == self.replaced.start
|| ahead_kind.only_at_start()
|| ahead_kind.only_in_mode() != Some(TokenMode::Markup)
{
@@ -206,7 +212,7 @@ impl Reparser<'_> {
let superseded_start = superseded_idx.start;
let differential: isize =
- self.replace_len as isize - self.replace_range.len() as isize;
+ self.replacement_len as isize - self.replaced.len() as isize;
let newborn_end = (superseded_span.end as isize + differential) as usize;
let newborn_span = superseded_span.start .. newborn_end;
@@ -251,11 +257,12 @@ impl Reparser<'_> {
}
}
-/// The position of a green node in terms of its string offset and index within
-/// the parent node.
+/// The position of a green node.
#[derive(Clone, Copy, Debug, PartialEq)]
struct GreenPos {
+ /// The index in the parent node.
idx: usize,
+ /// The byte offset in the string.
offset: usize,
}