Skip to content

Commit

Permalink
TODO: anchor comments
Browse files Browse the repository at this point in the history
  • Loading branch information
nbacquey authored and Erin van der Veen committed Aug 22, 2023
1 parent 86969e1 commit f5da50b
Showing 1 changed file with 81 additions and 2 deletions.
83 changes: 81 additions & 2 deletions topiary/src/tree_sitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashSet;
use serde::Serialize;
use tree_sitter_facade::{
InputEdit, Language, Node, Parser, Point, Query, QueryCapture, QueryCursor, QueryPredicate,
Tree,
Tree, TreeCursor,
};

use crate::{
Expand Down Expand Up @@ -242,14 +242,85 @@ fn find_comments<'a>(node: Node<'a>, comments: &mut Vec<Node<'a>>) -> () {
}
}

fn anchor(comment: Node, stream: &mut CommentStream) -> () {}
enum Anchor<T> {
AnchorBefore(T),
AnchorAfter(T),
}

fn next_non_comment<'a>(node: &'a Node<'a>) -> Option<Node<'a>> {
let temp_node = node;
while let Some(temp_node) = temp_node.next_sibling() {
if !is_comment(&temp_node) {
return Some(temp_node);
}
}
None
}

fn previous_non_comment<'a>(node: &'a Node<'a>) -> Option<Node<'a>> {
let temp_node = node;
while let Some(temp_node) = temp_node.prev_sibling() {
if !is_comment(&temp_node) {
return Some(temp_node);
}
}
None
}

// Use the following heuristics to find a comment's anchor:
// If the comment is only prefixed by blank symbols on its line, then the anchor is the
// next non-comment sibling node.
// Otherwise, the anchor is the previous non-comment sibling node.
// If there is no such node, we anchor to the first non-comment sibling node
// in the other direction.
fn find_anchor<'a>(node: &'a Node, input: &str) -> FormatterResult<Anchor<Node<'a>>> {
let point = node.start_position();
let mut lines = input.lines();
let prefix = lines
.nth(point.row() as usize)
.map(|line| &line[..point.column() as usize])
.ok_or_else(|| {
FormatterError::Internal(
format!(
"Trying to access nonexistent line {} in text:\n{}",
point.row(),
input,
),
None,
)
})?;
if prefix.trim_start() == "" {
if let Some(anchor) = next_non_comment(&node) {
return Ok(Anchor::AnchorAfter(anchor));
} else if let Some(anchor) = previous_non_comment(&node) {
return Ok(Anchor::AnchorBefore(anchor));
} else {
return Err(FormatterError::Internal(
format!("Could find no anchor for comment {node:?}",),
None,
));
}
} else {
if let Some(anchor) = previous_non_comment(&node) {
return Ok(Anchor::AnchorBefore(anchor));
} else if let Some(anchor) = next_non_comment(&node) {
return Ok(Anchor::AnchorAfter(anchor));
} else {
return Err(FormatterError::Internal(
format!("Could find no anchor for comment {node:?}",),
None,
));
}
}
}

// TODO: store comments instead of discarding them
fn extract_comments<'a>(
tree: Tree,
input: &str,
grammar: &Language,
) -> FormatterResult<(Tree, String)> {
// let mut comment_stream: CommentStream = CommentStream::new();
let mut comments: Vec<Node> = Vec::new();
let mut new_input: String = input.to_string();
let mut new_tree: Tree = tree;
Expand All @@ -258,6 +329,14 @@ fn extract_comments<'a>(
comments.reverse();
let mut edits: Vec<InputEdit> = Vec::new();
for node in comments {
match find_anchor(&node, input)? {
Anchor::AnchorBefore(anchor) => {
log::debug!("Anchor precedes comment {node:?}:\n{anchor:?}")
}
Anchor::AnchorAfter(anchor) => {
log::debug!("Anchor follows comment {node:?}:\n{anchor:?}")
}
}
new_input.replace_range((node.start_byte() as usize)..(node.end_byte() as usize), "");
let edit = InputEdit::new(
node.start_byte(),
Expand Down

0 comments on commit f5da50b

Please sign in to comment.