summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstuebinm2024-04-12 17:04:55 +0200
committerstuebinm2024-04-12 17:04:55 +0200
commit9e32c201789e4d0a119c4d486138f2f5edd1e168 (patch)
tree857fdb6a71376945267ef360ba72d10c6983e0db
parent422dbd5209fddac75412d8e7de0137f732c7dbc4 (diff)
rework handling of whitespace around deletions
-rw-r--r--src/main.rs138
1 files changed, 75 insertions, 63 deletions
diff --git a/src/main.rs b/src/main.rs
index 2bc44ab..89ed1a5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
use std::{path::PathBuf, fs, process::exit};
use pipeline::{Change, ChangeKind};
-use rowan::{ast::AstNode, TextSize, NodeOrToken};
+use rnix::SyntaxNode;
+use rowan::{ast::AstNode, TextSize, NodeOrToken, TextRange};
use clap::{arg, Parser};
#[allow(dead_code)]
@@ -115,77 +116,88 @@ fn apply_changes(content: &str, mut changes: Vec<Change>, debug: bool) -> String
ncontent
}
-#[allow(unused)]
-fn surrounding_whitespace(node: &rnix::SyntaxNode) -> (usize, usize) {
- let before = node
- .prev_sibling_or_token()
- .filter(|n| n.kind() == rnix::SyntaxKind::TOKEN_WHITESPACE)
- .map(|n| n.text_range().start().into())
- .unwrap_or_else(|| node.text_range().start().into());
- let after = node
- .next_sibling_or_token()
- .filter(|n| n.kind() == rnix::SyntaxKind::TOKEN_WHITESPACE)
- .map(|n| n.text_range().end().into())
- .unwrap_or_else(|| node.text_range().end().into());
-
- (before, after)
+
+
+// TODO: does rnix really not have an alias for this?
+type NixNodeOrToken = NodeOrToken<rowan::SyntaxNode<rnix::NixLanguage>, rowan::SyntaxToken<rnix::NixLanguage>>;
+
+/// eat all tokens of the given kind (backwards or forwards)
+fn eat_kind(node: &NixNodeOrToken, kind: rnix::SyntaxKind, backwards: bool) -> NixNodeOrToken {
+ let mut span = node.clone();
+
+ loop {
+ span = match if backwards { span.prev_sibling_or_token() } else { span.next_sibling_or_token() } {
+ Some(NodeOrToken::Token(t))
+ if t.kind() == kind
+ => NodeOrToken::Token(t),
+ _ => break
+ };
+ }
+ span
}
-fn remove_node(span: &rnix::SyntaxNode) -> (usize, usize) {
-
- // TODO: how to remove brackets around the node?
-
- fn eat_to_bracket(node: &rnix::SyntaxNode, backwards: bool) -> (TextSize, usize) {
- let mut span = NodeOrToken::Node(node.clone());
- let mut bracket = span.clone();
- let mut brackets = 0;
- loop {
- match if backwards { span.prev_sibling_or_token() } else { span.next_sibling_or_token() } {
- Some(NodeOrToken::Token(t)) => match t.kind() {
- rnix::SyntaxKind::TOKEN_WHITESPACE => span = NodeOrToken::Token(t),
- rnix::SyntaxKind::TOKEN_L_PAREN if backwards => {
- span = NodeOrToken::Token(t);
- bracket = span.clone();
- brackets += 1;
- },
- rnix::SyntaxKind::TOKEN_R_PAREN if !backwards => {
- span = NodeOrToken::Token(t);
- bracket = span.clone();
- brackets += 1;
- },
- _ => break,
- },
- _ => break,
- }
+/// eat whitespace outwards both ways
+fn eat_whitespace(begin: &NixNodeOrToken, end: &NixNodeOrToken)
+ -> (NixNodeOrToken, NixNodeOrToken) {
+ let begin = eat_kind(begin, rnix::SyntaxKind::TOKEN_WHITESPACE, true);
+ let end = eat_kind(end, rnix::SyntaxKind::TOKEN_WHITESPACE, false);
+ (begin, end)
+}
+
+/// for a node, get all the "syntactic noise" which surrounds it
+/// (i.e. brackets, whitespace, etc.) which should be removed if
+/// the node itself is removed, except the final bit of whitespace
+/// potentially separating it from neighbouring nodes, which should
+/// be handled separately to keep formatting nice
+fn surrounding_noise(node: &rnix::SyntaxNode) -> (NixNodeOrToken, NixNodeOrToken) {
+
+ fn eat_matching_parens(begin: &NixNodeOrToken, end: &NixNodeOrToken)
+ -> Option<(NixNodeOrToken, NixNodeOrToken)> {
+ match (begin.prev_sibling_or_token(), end.next_sibling_or_token()) {
+ (Some(begin), Some(end))
+ if begin.kind() == rnix::SyntaxKind::TOKEN_L_PAREN
+ && end.kind() == rnix::SyntaxKind::TOKEN_R_PAREN
+ => Some((begin, end)),
+ _ => None
}
- (if backwards { bracket.text_range().start() } else { bracket.text_range().end() }, brackets)
}
- let (before, after) = match (eat_to_bracket(span, true), eat_to_bracket(span, false)) {
- ((before, n1), (after, n2)) if n1 == n2 && n1 != 0 => (before.into(), after.into()),
- _ => match (span.prev_sibling_or_token(), span.next_sibling_or_token()) {
- (Some(prev), Some(next))
- if prev.kind() == rnix::SyntaxKind::TOKEN_WHITESPACE
- && next.kind() == rnix::SyntaxKind::TOKEN_WHITESPACE
- => {
- if prev.to_string().lines().count() < next.to_string().lines().count() {
- (Into::<usize>::into(span.text_range().start() - prev.text_range().len()) + previous_indentation(&span).unwrap_or(0)
- , Into::<usize>::into(span.text_range().end()) + next_indentation(&span).unwrap_or(0))
- } else {
- (Into::<usize>::into(span.text_range().start()) - previous_indentation(&span).unwrap_or(0),
- Into::<usize>::into(span.text_range().end() + next.text_range().len()) - next_indentation(&span).unwrap_or(0))
- }
- }
- _ => (span.text_range().start().into(), span.text_range().end().into())
+ let (mut begin, mut end): (NixNodeOrToken, NixNodeOrToken) =
+ (NodeOrToken::Node(node.clone()), NodeOrToken::Node(node.clone()));
+
+ loop {
+ let (a, b) = eat_whitespace(&begin, &end);
+ if let Some(res) = eat_matching_parens(&a, &b) {
+ (begin, end) = res;
+ } else {
+ break
}
- };
+ }
+
+ (begin, end)
+}
- (before, after)
- // ( Into::<usize>::into(span.text_range().start()) - before
- // , Into::<usize>::into(span.text_range().end()) + after
- // )
+fn remove_node(node: &rnix::SyntaxNode) -> (usize, usize) {
+ let (before, after) = surrounding_noise(node);
+
+ let (prev, next) =
+ eat_whitespace(&before, &after);
+
+ if prev.kind() == rnix::SyntaxKind::TOKEN_WHITESPACE
+ && next.kind() == rnix::SyntaxKind::TOKEN_WHITESPACE {
+ if prev.to_string().lines().count() < next.to_string().lines().count() {
+ (Into::<usize>::into(node.text_range().start() - prev.text_range().len()) + previous_indentation(&node).unwrap_or(0)
+ , Into::<usize>::into(node.text_range().end()) + next_indentation(&node).unwrap_or(0))
+ } else {
+ (Into::<usize>::into(node.text_range().start()) - previous_indentation(&node).unwrap_or(0),
+ Into::<usize>::into(node.text_range().end() + next.text_range().len()) - next_indentation(&node).unwrap_or(0))
+ }
+ }
+ else {
+ (prev.text_range().start().into(), next.text_range().end().into())
+ }
}