diff --git a/topiary-core/src/comments.rs b/topiary-core/src/comments.rs index a97c71fc..fefccecd 100644 --- a/topiary-core/src/comments.rs +++ b/topiary-core/src/comments.rs @@ -63,10 +63,10 @@ fn is_comment(node: &Node) -> bool { node.is_extra() && node.kind().to_string().contains("comment") } -fn find_comments<'a>(node: Node<'a>, input: &str, comments: &'a mut Vec<(Node<'a>, Commented)>) -> FormatterResult<()> { +fn find_comments<'a>(node: Node<'a>, input: &str, comments: & mut Vec>) -> FormatterResult<()> { if is_comment(&node) { - let commented_section = find_anchor(&node, input)?; - comments.push((node, commented_section)); + let commented = find_anchor(&node, input)?; + comments.push(AnchoredComment{comment: node, commented}); Ok(()) } else { let mut walker = node.walk(); @@ -79,6 +79,7 @@ fn find_comments<'a>(node: Node<'a>, input: &str, comments: &'a mut Vec<(Node<'a /// The section of code to which a comment refers. We also remember whether the comment /// is positioned before or after the section. +#[derive(Debug)] pub enum Commented { /// The code section is before the comment, as in: /// ``` @@ -100,6 +101,19 @@ pub enum Commented { CommentedAfter(InputSection), } +impl Diff for Commented { + fn substract(self: &mut Self, other: &InputSection) -> FormatterResult<()> { + match self { + Commented::CommentedBefore(section) => { + section.substract(other) + }, + Commented::CommentedAfter(section) => { + section.substract(other) + }, + } + } +} + fn next_non_comment<'tree>(node: Node<'tree>) -> Option> { let mut temp_node: Node<'tree> = node; loop { @@ -170,9 +184,9 @@ fn find_anchor<'tree>( })?; if prefix.trim_start() == "" { if let Some(anchor) = next_non_comment(node.clone()) { - return Ok(Commented::CommentedAfter(anchor.into())); + return Ok(Commented::CommentedAfter((&anchor).into())); } else if let Some(anchor) = previous_non_comment(node.clone()) { - return Ok(Commented::CommentedBefore(anchor.into())); + return Ok(Commented::CommentedBefore((&anchor).into())); } else { return Err(FormatterError::Internal( format!("Could find no anchor for comment {node:?}",), @@ -193,10 +207,15 @@ fn find_anchor<'tree>( } } -pub struct SeparatedInput<'a> { +struct AnchoredComment<'a>{ + comment: Node<'a>, + commented: Commented, +} + +pub struct SeparatedInput<'a>{ pub input_tree: Tree, pub input_string: String, - pub comments: Vec<(&'a Node<'a>, Commented)>, + pub comments: Vec>, } // TODO: store comments instead of discarding them @@ -204,37 +223,40 @@ pub fn extract_comments<'a>( tree: Tree, input: &str, grammar: &Language, -) -> FormatterResult<(Tree, String)> { - let mut comments: Vec<(Node, Commented)> = Vec::new(); +) -> FormatterResult<(Tree, String, Vec>)> { + let mut anchors: Vec = Vec::new(); let mut new_input: String = input.to_string(); let mut new_tree: Tree = tree; - find_comments(new_tree.root_node(), input, &mut comments); - comments.sort_by_key(|(node, _)| node.start_byte()); - comments.reverse(); + find_comments(new_tree.root_node(), input, &mut anchors)?; + anchors.sort_by_key(|AnchoredComment { comment, .. }| comment.start_byte()); let mut edits: Vec = Vec::new(); - for (node, anchor) in comments { - match anchor { - Commented::CommentedBefore(anchor) => { - log::warn!("Commented section precedes comment {:?}:\n{anchor:?}", &node) - } - Commented::CommentedAfter(anchor) => { - log::warn!("Commented section follows comment {:?}:\n{anchor:?}", &node) - } - } - new_input.replace_range((node.start_byte() as usize)..(node.end_byte() as usize), ""); + // for each (comment, anchor) pair in reverse order, we: + // 1) remove the comment from the input, + // 2) register an InputEdit to modify the tree, + // 3) edit the following anchors to account for the removed comment. + for index in (0..anchors.len()).rev() { + let AnchoredComment{comment, ..} = &anchors[index]; + // 1) + new_input.replace_range((comment.start_byte() as usize)..(comment.end_byte() as usize), ""); + // 2) let edit = InputEdit::new( - node.start_byte(), - node.end_byte(), - node.start_byte(), - &node.start_position(), - &node.end_position(), - &node.start_position(), + comment.start_byte(), + comment.end_byte(), + comment.start_byte(), + &comment.start_position(), + &comment.end_position(), + &comment.start_position(), ); edits.push(edit); + // 3) + for following_index in index..anchors.len() { + let AnchoredComment { commented: mut following_anchor, .. } = &anchors[following_index]; + following_anchor.substract(&comment.into()); + } } for edit in edits { new_tree.edit(&edit); } new_tree = reparse(new_tree, new_input.as_str(), grammar)?; - Ok((new_tree, new_input)) -} \ No newline at end of file + Ok((new_tree, new_input, anchors)) +} diff --git a/topiary-core/src/types.rs b/topiary-core/src/types.rs index af163c1b..f7e97c18 100644 --- a/topiary-core/src/types.rs +++ b/topiary-core/src/types.rs @@ -38,8 +38,8 @@ pub struct InputSection { pub end: Position, } -impl From> for InputSection { - fn from(value: Node) -> Self { +impl From<&Node<'_>> for InputSection { + fn from(value: &Node) -> Self { InputSection { start: value.start_position().into(), end: value.end_position().into(),