mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Turn reparsing methods into free functions
This commit is contained in:
parent
c81e2a5f56
commit
e03f32ca34
@ -20,8 +20,8 @@ pub fn reparse(
|
|||||||
replacement_len: usize,
|
replacement_len: usize,
|
||||||
) -> Range<usize> {
|
) -> Range<usize> {
|
||||||
if let SyntaxNode::Inner(inner) = root {
|
if let SyntaxNode::Inner(inner) = root {
|
||||||
let reparser = Reparser { src, replaced, replacement_len };
|
let change = Change { src, replaced, replacement_len };
|
||||||
if let Some(range) = reparser.reparse_step(Arc::make_mut(inner), 0, true, true) {
|
if let Some(range) = try_reparse(&change, Arc::make_mut(inner), 0, true, true) {
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,23 +32,9 @@ pub fn reparse(
|
|||||||
0 .. src.len()
|
0 .. src.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows partial refreshs of the syntax tree.
|
|
||||||
///
|
|
||||||
/// This struct holds a description of a change. Its methods can be used to try
|
|
||||||
/// and apply the change to a syntax tree.
|
|
||||||
struct Reparser<'a> {
|
|
||||||
/// The new source code, with the change applied.
|
|
||||||
src: &'a str,
|
|
||||||
/// Which range in the old source file was changed.
|
|
||||||
replaced: Range<usize>,
|
|
||||||
/// How many characters replaced the text in `replaced`.
|
|
||||||
replacement_len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reparser<'_> {
|
|
||||||
/// Try to reparse inside the given node.
|
/// Try to reparse inside the given node.
|
||||||
fn reparse_step(
|
fn try_reparse(
|
||||||
&self,
|
change: &Change,
|
||||||
node: &mut InnerNode,
|
node: &mut InnerNode,
|
||||||
mut offset: usize,
|
mut offset: usize,
|
||||||
outermost: bool,
|
outermost: bool,
|
||||||
@ -76,20 +62,20 @@ impl Reparser<'_> {
|
|||||||
match search {
|
match search {
|
||||||
SearchState::NoneFound => {
|
SearchState::NoneFound => {
|
||||||
// The edit is contained within the span of the current element.
|
// The edit is contained within the span of the current element.
|
||||||
if child_span.contains(&self.replaced.start)
|
if child_span.contains(&change.replaced.start)
|
||||||
&& child_span.end >= self.replaced.end
|
&& child_span.end >= change.replaced.end
|
||||||
{
|
{
|
||||||
// In Markup mode, we want to consider a non-whitespace
|
// In Markup mode, we want to consider a non-whitespace
|
||||||
// neighbor if the edit is on the node boundary.
|
// neighbor if the edit is on the node boundary.
|
||||||
search = if is_markup && child_span.end == self.replaced.end {
|
search = if is_markup && child_span.end == change.replaced.end {
|
||||||
SearchState::RequireNonTrivia(pos)
|
SearchState::RequireNonTrivia(pos)
|
||||||
} else {
|
} else {
|
||||||
SearchState::Contained(pos)
|
SearchState::Contained(pos)
|
||||||
};
|
};
|
||||||
} else if child_span.contains(&self.replaced.start) {
|
} else if child_span.contains(&change.replaced.start) {
|
||||||
search = SearchState::Inside(pos);
|
search = SearchState::Inside(pos);
|
||||||
} else if child_span.end == self.replaced.start
|
} else if child_span.end == change.replaced.start
|
||||||
&& self.replaced.start == self.replaced.end
|
&& change.replaced.start == change.replaced.end
|
||||||
&& child_outermost
|
&& child_outermost
|
||||||
{
|
{
|
||||||
search = SearchState::SpanFound(pos, pos);
|
search = SearchState::SpanFound(pos, pos);
|
||||||
@ -107,23 +93,20 @@ impl Reparser<'_> {
|
|||||||
if !child.kind().is_space()
|
if !child.kind().is_space()
|
||||||
&& child.kind() != &NodeKind::Semicolon
|
&& child.kind() != &NodeKind::Semicolon
|
||||||
&& child.kind() != &NodeKind::Text('/'.into())
|
&& child.kind() != &NodeKind::Text('/'.into())
|
||||||
&& (ahead.is_none() || self.replaced.start > child_span.end)
|
&& (ahead.is_none() || change.replaced.start > child_span.end)
|
||||||
&& !ahead.map_or(false, Ahead::is_compulsory)
|
&& !ahead.map_or(false, Ahead::is_compulsory)
|
||||||
{
|
{
|
||||||
ahead = Some(Ahead::new(
|
ahead =
|
||||||
pos,
|
Some(Ahead::new(pos, at_start, child.kind().is_bounded()));
|
||||||
at_start,
|
|
||||||
child.kind().is_bounded(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
at_start = child.kind().is_at_start(at_start);
|
at_start = child.kind().is_at_start(at_start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SearchState::Inside(start) => {
|
SearchState::Inside(start) => {
|
||||||
if child_span.end == self.replaced.end {
|
if child_span.end == change.replaced.end {
|
||||||
search = SearchState::RequireNonTrivia(start);
|
search = SearchState::RequireNonTrivia(start);
|
||||||
} else if child_span.end > self.replaced.end {
|
} else if child_span.end > change.replaced.end {
|
||||||
search = SearchState::SpanFound(start, pos);
|
search = SearchState::SpanFound(start, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +143,8 @@ impl Reparser<'_> {
|
|||||||
let prev_descendants = child.descendants();
|
let prev_descendants = child.descendants();
|
||||||
|
|
||||||
if let Some(range) = match child {
|
if let Some(range) = match child {
|
||||||
SyntaxNode::Inner(node) => self.reparse_step(
|
SyntaxNode::Inner(node) => try_reparse(
|
||||||
|
change,
|
||||||
Arc::make_mut(node),
|
Arc::make_mut(node),
|
||||||
pos.offset,
|
pos.offset,
|
||||||
child_outermost,
|
child_outermost,
|
||||||
@ -184,7 +168,8 @@ impl Reparser<'_> {
|
|||||||
// Return if the element was reparsable on its own, otherwise try to
|
// Return if the element was reparsable on its own, otherwise try to
|
||||||
// treat it as a markup element.
|
// treat it as a markup element.
|
||||||
if let Some(func) = func {
|
if let Some(func) = func {
|
||||||
if let Some(result) = self.replace(
|
if let Some(result) = replace(
|
||||||
|
change,
|
||||||
node,
|
node,
|
||||||
func,
|
func,
|
||||||
pos.idx .. pos.idx + 1,
|
pos.idx .. pos.idx + 1,
|
||||||
@ -205,7 +190,7 @@ impl Reparser<'_> {
|
|||||||
|
|
||||||
let (mut start, end) = search.done()?;
|
let (mut start, end) = search.done()?;
|
||||||
if let Some(ahead) = ahead {
|
if let Some(ahead) = ahead {
|
||||||
if start.offset == self.replaced.start || ahead.is_compulsory() {
|
if start.offset == change.replaced.start || ahead.is_compulsory() {
|
||||||
start = ahead.pos;
|
start = ahead.pos;
|
||||||
at_start = ahead.at_start;
|
at_start = ahead.at_start;
|
||||||
}
|
}
|
||||||
@ -216,7 +201,8 @@ impl Reparser<'_> {
|
|||||||
let superseded_span =
|
let superseded_span =
|
||||||
start.offset .. end.offset + node.children().as_slice()[end.idx].len();
|
start.offset .. end.offset + node.children().as_slice()[end.idx].len();
|
||||||
|
|
||||||
self.replace(
|
replace(
|
||||||
|
change,
|
||||||
node,
|
node,
|
||||||
ReparseMode::MarkupElements { at_start, min_indent },
|
ReparseMode::MarkupElements { at_start, min_indent },
|
||||||
start.idx .. end.idx + 1,
|
start.idx .. end.idx + 1,
|
||||||
@ -225,8 +211,9 @@ impl Reparser<'_> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reparse the superseded nodes and replace them.
|
||||||
fn replace(
|
fn replace(
|
||||||
&self,
|
change: &Change,
|
||||||
node: &mut InnerNode,
|
node: &mut InnerNode,
|
||||||
mode: ReparseMode,
|
mode: ReparseMode,
|
||||||
superseded_idx: Range<usize>,
|
superseded_idx: Range<usize>,
|
||||||
@ -236,40 +223,38 @@ impl Reparser<'_> {
|
|||||||
let superseded_start = superseded_idx.start;
|
let superseded_start = superseded_idx.start;
|
||||||
|
|
||||||
let differential: isize =
|
let differential: isize =
|
||||||
self.replacement_len as isize - self.replaced.len() as isize;
|
change.replacement_len as isize - change.replaced.len() as isize;
|
||||||
let newborn_end = (superseded_span.end as isize + differential) as usize;
|
let newborn_end = (superseded_span.end as isize + differential) as usize;
|
||||||
let newborn_span = superseded_span.start .. newborn_end;
|
let newborn_span = superseded_span.start .. newborn_end;
|
||||||
|
|
||||||
let mut prefix = "";
|
let mut prefix = "";
|
||||||
for (i, c) in self.src[.. newborn_span.start].char_indices().rev() {
|
for (i, c) in change.src[.. newborn_span.start].char_indices().rev() {
|
||||||
if is_newline(c) {
|
if is_newline(c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prefix = &self.src[i .. newborn_span.start];
|
prefix = &change.src[i .. newborn_span.start];
|
||||||
}
|
}
|
||||||
|
|
||||||
let (newborns, terminated, amount) = match mode {
|
let (newborns, terminated, amount) = match mode {
|
||||||
ReparseMode::Code => reparse_code_block(
|
ReparseMode::Code => reparse_code_block(
|
||||||
&prefix,
|
&prefix,
|
||||||
&self.src[newborn_span.start ..],
|
&change.src[newborn_span.start ..],
|
||||||
newborn_span.len(),
|
newborn_span.len(),
|
||||||
),
|
),
|
||||||
ReparseMode::Content => reparse_content_block(
|
ReparseMode::Content => reparse_content_block(
|
||||||
&prefix,
|
&prefix,
|
||||||
&self.src[newborn_span.start ..],
|
&change.src[newborn_span.start ..],
|
||||||
newborn_span.len(),
|
newborn_span.len(),
|
||||||
),
|
),
|
||||||
ReparseMode::MarkupElements { at_start, min_indent } => {
|
ReparseMode::MarkupElements { at_start, min_indent } => reparse_markup_elements(
|
||||||
reparse_markup_elements(
|
|
||||||
&prefix,
|
&prefix,
|
||||||
&self.src[newborn_span.start ..],
|
&change.src[newborn_span.start ..],
|
||||||
newborn_span.len(),
|
newborn_span.len(),
|
||||||
differential,
|
differential,
|
||||||
&node.children().as_slice()[superseded_start ..],
|
&node.children().as_slice()[superseded_start ..],
|
||||||
at_start,
|
at_start,
|
||||||
min_indent,
|
min_indent,
|
||||||
)
|
),
|
||||||
}
|
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
// Do not accept unclosed nodes if the old node wasn't at the right edge
|
// Do not accept unclosed nodes if the old node wasn't at the right edge
|
||||||
@ -283,15 +268,15 @@ impl Reparser<'_> {
|
|||||||
|
|
||||||
Some(newborn_span)
|
Some(newborn_span)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// The position of a syntax node.
|
/// A description of a change.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
struct Change<'a> {
|
||||||
struct NodePos {
|
/// The new source code, with the change applied.
|
||||||
/// The index in the parent node.
|
src: &'a str,
|
||||||
idx: usize,
|
/// Which range in the old source file was changed.
|
||||||
/// The byte offset in the string.
|
replaced: Range<usize>,
|
||||||
offset: usize,
|
/// How many characters replaced the text in `replaced`.
|
||||||
|
replacement_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encodes the state machine of the search for the nodes are pending for
|
/// Encodes the state machine of the search for the nodes are pending for
|
||||||
@ -332,6 +317,15 @@ impl SearchState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The position of a syntax node.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
struct NodePos {
|
||||||
|
/// The index in the parent node.
|
||||||
|
idx: usize,
|
||||||
|
/// The byte offset in the string.
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
/// An ahead node with an index and whether it is `at_start`.
|
/// An ahead node with an index and whether it is `at_start`.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
struct Ahead {
|
struct Ahead {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user