git.delta.rocks / jrsonnet / refs/commits / 016538aa1e6d

difftreelog

feat(fmt) preserve comments at root of source code

Yaroslav Bolyukin2022-06-22parent: #014057b.patch.diff
in: master

3 files changed

modifiedcmds/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 {
modifiedcmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth
1use std::any::type_name;1use std::any::type_name;
22
3use children::children_between;3use children::{children_between, trivia_before};
4use dprint_core::formatting::{PrintItems, PrintOptions};4use dprint_core::formatting::{PrintItems, PrintOptions};
5use jrsonnet_rowan_parser::{5use jrsonnet_rowan_parser::{
6 nodes::{6 nodes::{
13};13};
1414
15use crate::{15use crate::{
16 children::should_start_with_newline,16 children::{should_start_with_newline, trivia_after},
17 comments::{format_comments, CommentLocation},17 comments::{format_comments, CommentLocation},
18};18};
1919
463463
464impl Printable for SourceFile {464impl Printable for SourceFile {
465 fn print(&self) -> PrintItems {465 fn print(&self) -> PrintItems {
466 let mut pi = p!(new:);
466 assert!(self.expr().is_some());467 let before = trivia_before(
468 self.syntax().clone(),
469 self.expr()
470 .map(|e| e.syntax().clone())
471 .map(Into::into)
472 .as_ref(),
473 );
474 let after = trivia_after(
475 self.syntax().clone(),
467 self.expr().print()476 self.expr()
477 .map(|e| e.syntax().clone())
478 .map(Into::into)
479 .as_ref(),
480 );
481 p!(pi: items(format_comments(&before, CommentLocation::AboveItem)));
482 p!(pi: {self.expr()} nl);
483 p!(pi: items(format_comments(&after, CommentLocation::EndOfItems)));
484 pi
468 }485 }
469}486}
470487
471fn main() {488fn main() {
472 let (parsed, _errors) = jrsonnet_rowan_parser::parse(489 let (parsed, _errors) = jrsonnet_rowan_parser::parse(
473 r#"490 r#"
474491
475492
476 # Edit me!493 # Edit me!
477 local b = import "b.libsonnet"; # comment494 local b = import "b.libsonnet"; # comment
478 local a = import "a.libsonnet";495 local a = import "a.libsonnet";
479496
480 local f(x,y)=x+y;497 local f(x,y)=x+y;
481498
482 local {a: [b, ..., c], d, ...e} = null;499 local {a: [b, ..., c], d, ...e} = null;
483500
484 local ass = assert false : false; false;501 local ass = assert false : false; false;
485502
486 local fn = function(a, b, c = 3) 4;503 local fn = function(a, b, c = 3) 4;
487504
488 local comp = [a for b in c if d == e];505 local comp = [a for b in c if d == e];
489 local ocomp = {[k]: 1 for k in v};506 local ocomp = {[k]: 1 for k in v};
490507
491 local ? = skip;508 local ? = skip;
492509
493 local intr = $intrinsic(test);510 local intr = $intrinsic(test);
494 local intrId = $intrinsicId;511 local intrId = $intrinsicId;
495 local intrThisFile = $intrinsicThisFile;512 local intrThisFile = $intrinsicThisFile;
496513
497 local ie = a[expr];514 local ie = a[expr];
498515
499 local unary = !a;516 local unary = !a;
500517
501 local Template = {z: "foo"};518 local Template = {z: "foo"};
502519
503 {520 {
504 local521 local
505522
506 h = 3,523 h = 3,
507 assert self.a == 1524 assert self.a == 1
508525
509 : "error",526 : "error",
510 "f": ((((((3)))))) ,527 "f": ((((((3)))))) ,
511 "g g":528 "g g":
512 f(4,2),529 f(4,2),
513 arr: [[530 arr: [[
514 1, 2,531 1, 2,
515 ],532 ],
516 3,533 3,
517 {534 {
518 b: {535 b: {
519 c: {536 c: {
520 k: [16]537 k: [16]
521 }538 }
522 }539 }
523 }540 }
524 ],541 ],
525 m: a[1::],542 m: a[1::],
526 m: b[::],543 m: b[::],
527544
528 comments: {545 comments: {
529 _: '',546 _: '',
530 // Plain comment547 // Plain comment
531 a: '',548 a: '',
532549
533 # Plain comment with empty line before550 # Plain comment with empty line before
534 b: '',551 b: '',
535 /*Single-line multiline comment552 /*Single-line multiline comment
536553
537 */554 */
538 c: '',555 c: '',
539556
540 /**Single-line multiline doc comment557 /**Single-line multiline doc comment
541558
542 */559 */
543 c: '',560 c: '',
544561
545 /**multiline doc comment562 /**multiline doc comment
546 s563 s
547 */564 */
548 c: '',565 c: '',
549566
550 /*567 /*
551568
552 Multi-line569 Multi-line
553570
554 comment571 comment
555 */572 */
556 d: '',573 d: '',
557574
558 e: '', // Inline comment575 e: '', // Inline comment
559576
560 k: '',577 k: '',
561578
562 // Text after everything579 // Text after everything
563 },580 },
564 comments2: {581 comments2: {
565 k: '',582 k: '',
566 // Text after everything, but no newline above583 // Text after everything, but no newline above
567 },584 },
568 k: if a == b then585 k: if a == b then
569586
570587
571 2588 2
572589
573 else Template {}590 else Template {}
574 } + Template591 } + Template
575592
576593
594 // Comment after everything
577"#,595"#,
578 );596 );
579597
580 // dbg!(errors);598 // dbg!(errors);
modifiedcrates/jrsonnet-rowan-parser/src/event.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/event.rs
+++ b/crates/jrsonnet-rowan-parser/src/event.rs
@@ -117,6 +117,9 @@
 					eat_start_whitespace = false;
 				}
 				Event::Finish { wrapper } => {
+					if depth == 1 {
+						self.skip_whitespace();
+					}
 					self.builder.finish_node();
 					depth -= 1;
 					let mut idx = idx;
@@ -126,6 +129,9 @@
 						wrapper = if let Event::Finish { wrapper } =
 							mem::replace(&mut self.events[idx], Event::Noop)
 						{
+							if depth == 1 {
+								self.skip_whitespace();
+							}
 							self.builder.finish_node();
 							depth -= 1;
 							wrapper