difftreelog
feat(fmt) preserve comments at root of source code
in: master
3 files changed
cmds/jrsonnet-fmt/src/children.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/children.rs
+++ b/cmds/jrsonnet-fmt/src/children.rs
@@ -1,3 +1,5 @@
+// TODO: Return errors as trivia
+
use std::{fmt::Debug, marker::PhantomData, mem};
use jrsonnet_rowan_parser::{
@@ -9,9 +11,52 @@
pub type ChildTrivia = Vec<Trivia>;
-pub struct ChildIterator<I, T> {
- inner: I,
- _marker: PhantomData<T>,
+/// Node should have no non-trivia tokens before element
+pub fn trivia_before(node: SyntaxNode, end: Option<&SyntaxElement>) -> ChildTrivia {
+ let mut out = Vec::new();
+ for item in node.children_with_tokens() {
+ if Some(&item) == end {
+ break;
+ }
+
+ if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
+ out.push(trivia);
+ } else if end.is_none() {
+ break;
+ } else {
+ assert!(
+ TS![, ;].contains(item.kind()) || item.kind() == ERROR,
+ "silently eaten token: {:?}",
+ item.kind()
+ )
+ }
+ }
+ out
+}
+/// Node should have no non-trivia tokens after element
+pub fn trivia_after(node: SyntaxNode, start: Option<&SyntaxElement>) -> ChildTrivia {
+ if start.is_none() {
+ return Vec::new();
+ }
+ let mut iter = node.children_with_tokens().peekable();
+ while iter.peek() != start {
+ // println!("Skipped {}");
+ dbg!(&iter.next());
+ }
+ dbg!(&iter.next());
+ let mut out = Vec::new();
+ for item in iter {
+ if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
+ out.push(trivia);
+ } else {
+ assert!(
+ TS![, ;].contains(item.kind()) || item.kind() == ERROR,
+ "silently eaten token: {:?}",
+ item.kind()
+ )
+ }
+ }
+ out
}
pub fn children_between<T: AstNode + Debug>(
@@ -20,9 +65,10 @@
end: Option<&SyntaxElement>,
) -> (Vec<Child<T>>, ChildTrivia) {
let mut iter = node.children_with_tokens().peekable();
- while iter.peek() == start {
+ while iter.peek() != start {
iter.next();
}
+ iter.next();
children(
iter.take_while(|i| Some(i) != end),
start.is_none() || end.is_none(),
@@ -31,7 +77,7 @@
pub fn should_start_with_newline(tt: &ChildTrivia) -> bool {
// First for previous item end
- count_newlines_before(&tt) >= 2
+ count_newlines_before(tt) >= 2
}
fn count_newlines_before(tt: &ChildTrivia) -> usize {
cmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/main.rs
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -1,6 +1,6 @@
use std::any::type_name;
-use children::children_between;
+use children::{children_between, trivia_before};
use dprint_core::formatting::{PrintItems, PrintOptions};
use jrsonnet_rowan_parser::{
nodes::{
@@ -13,7 +13,7 @@
};
use crate::{
- children::should_start_with_newline,
+ children::{should_start_with_newline, trivia_after},
comments::{format_comments, CommentLocation},
};
@@ -463,8 +463,25 @@
impl Printable for SourceFile {
fn print(&self) -> PrintItems {
- assert!(self.expr().is_some());
- self.expr().print()
+ let mut pi = p!(new:);
+ let before = trivia_before(
+ self.syntax().clone(),
+ self.expr()
+ .map(|e| e.syntax().clone())
+ .map(Into::into)
+ .as_ref(),
+ );
+ let after = trivia_after(
+ self.syntax().clone(),
+ self.expr()
+ .map(|e| e.syntax().clone())
+ .map(Into::into)
+ .as_ref(),
+ );
+ p!(pi: items(format_comments(&before, CommentLocation::AboveItem)));
+ p!(pi: {self.expr()} nl);
+ p!(pi: items(format_comments(&after, CommentLocation::EndOfItems)));
+ pi
}
}
@@ -574,6 +591,7 @@
} + Template
+ // Comment after everything
"#,
);
crates/jrsonnet-rowan-parser/src/event.rsdiffbeforeafterboth1use std::mem;23use rowan::{GreenNodeBuilder, Language};45use crate::{6 lex::Lexeme,7 nodes::Trivia,8 parser::{Parse, SyntaxError},9 AstToken, JsonnetLanguage, SyntaxKind,10};1112#[derive(Clone, Debug, PartialEq, Eq)]13pub enum Event {14 /// Used for unfinished markers15 Pending,16 /// After marker is completed, Pending event is replaced with Start17 Start {18 kind: SyntaxKind,19 /// If marker is preceded or wrapped - instead of reordering events, we20 /// insert start event in the end of events Vec instead, and store relative offset to this event here21 forward_parent: Option<usize>,22 },23 /// Eat token24 Token {25 kind: SyntaxKind,26 },27 /// Push token, but do not eat anything,28 VirtualToken {29 kind: SyntaxKind,30 },31 /// Position of finished node32 Finish {33 /// Same as forward_parent of Start, but for wrapping34 wrapper: Option<usize>,35 },36 Error(SyntaxError),37 /// Used for dropped markers and other things38 Noop,39}4041pub(super) struct Sink<'i> {42 pub builder: GreenNodeBuilder<'static>,43 lexemes: &'i [Lexeme<'i>],44 offset: usize,45 events: Vec<Event>,46 pub errors: Vec<SyntaxError>,47}4849impl<'i> Sink<'i> {50 pub(super) fn new(events: Vec<Event>, lexemes: &'i [Lexeme<'i>]) -> Self {51 Self {52 builder: GreenNodeBuilder::new(),53 lexemes,54 offset: 0,55 events,56 errors: vec![],57 }58 }5960 pub(super) fn finish(mut self) -> Parse {61 let mut eat_start_whitespace = false;62 let mut depth = 0;63 for idx in 0..self.events.len() {64 match mem::replace(&mut self.events[idx], Event::Noop) {65 Event::Start {66 kind,67 forward_parent,68 } => {69 if depth != 0 {70 self.skip_whitespace();71 }72 let mut kinds = vec![kind];7374 let mut idx = idx;75 let mut forward_parent = forward_parent;7677 // Walk through the forward parent of the forward parent, and the forward parent78 // of that, and of that, etc. until we reach a StartNode event without a forward79 // parent.80 while let Some(fp) = forward_parent {81 idx += fp;8283 forward_parent = if let Event::Start {84 kind,85 forward_parent,86 } = mem::replace(&mut self.events[idx], Event::Noop)87 {88 kinds.push(kind);89 forward_parent90 } else {91 unreachable!()92 };93 }9495 for kind in kinds.into_iter().rev() {96 self.builder.start_node(JsonnetLanguage::kind_to_raw(kind));97 depth += 1;98 if depth == 1 {99 self.skip_whitespace();100 }101 }102103 eat_start_whitespace = false;104 }105 Event::Token { kind } => {106 if eat_start_whitespace {107 self.skip_whitespace();108 }109 self.token(kind);110 eat_start_whitespace = true;111 }112 Event::VirtualToken { kind } => {113 if eat_start_whitespace {114 self.skip_whitespace();115 }116 self.virtual_token(kind);117 eat_start_whitespace = false;118 }119 Event::Finish { wrapper } => {120 self.builder.finish_node();121 depth -= 1;122 let mut idx = idx;123 let mut wrapper = wrapper;124 while let Some(w) = wrapper {125 idx += w;126 wrapper = if let Event::Finish { wrapper } =127 mem::replace(&mut self.events[idx], Event::Noop)128 {129 self.builder.finish_node();130 depth -= 1;131 wrapper132 } else {133 unreachable!()134 }135 }136 eat_start_whitespace = true;137 }138 Event::Pending => panic!("pending event should not appear in finished events"),139 Event::Noop => {}140 Event::Error(e) => {141 self.errors.push(e);142 }143 }144 }145146 Parse {147 green_node: self.builder.finish(),148 errors: self.errors,149 }150 }151 fn virtual_token(&mut self, kind: SyntaxKind) {152 self.builder.token(JsonnetLanguage::kind_to_raw(kind), "")153 }154 fn token(&mut self, kind: SyntaxKind) {155 let lexeme = self.lexemes[self.offset];156 self.builder157 .token(JsonnetLanguage::kind_to_raw(kind), lexeme.text);158 self.offset += 1;159 }160 fn skip_whitespace(&mut self) {161 while let Some(lexeme) = self.lexemes.get(self.offset) {162 if !Trivia::can_cast(lexeme.kind) {163 break;164 }165166 self.token(lexeme.kind);167 }168 }169}