git.delta.rocks / jrsonnet / refs/commits / dacee201fa00

difftreelog

feat(fmt) preserve comments in locals

Yaroslav Bolyukin2022-06-22parent: #016538a.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
@@ -40,10 +40,9 @@
 	}
 	let mut iter = node.children_with_tokens().peekable();
 	while iter.peek() != start {
-		// println!("Skipped {}");
-		dbg!(&iter.next());
+		iter.next();
 	}
-	dbg!(&iter.next());
+	iter.next();
 	let mut out = Vec::new();
 	for item in iter {
 		if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
@@ -59,6 +58,36 @@
 	out
 }
 
+pub fn trivia_between(
+	node: SyntaxNode,
+	start: Option<&SyntaxElement>,
+	end: Option<&SyntaxElement>,
+) -> ChildTrivia {
+	let mut iter = node.children_with_tokens().peekable();
+	while iter.peek() != start {
+		iter.next();
+	}
+	iter.next();
+
+	let loose = start.is_none() || end.is_none();
+
+	let mut out = Vec::new();
+	for item in iter.take_while(|i| Some(i) != end) {
+		if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
+			out.push(trivia);
+		} else if loose {
+			break;
+		} else {
+			assert!(
+				TS![, ;].contains(item.kind()) || item.kind() == ERROR,
+				"silently eaten token: {:?}",
+				item.kind()
+			)
+		}
+	}
+	out
+}
+
 pub fn children_between<T: AstNode + Debug>(
 	node: SyntaxNode,
 	start: Option<&SyntaxElement>,
modifiedcmds/jrsonnet-fmt/src/comments.rsdiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/src/comments.rs
+++ b/cmds/jrsonnet-fmt/src/comments.rs
@@ -12,6 +12,7 @@
 	EndOfItems,
 }
 
+#[must_use]
 pub fn format_comments(comments: &ChildTrivia, loc: CommentLocation) -> PrintItems {
 	let mut pi = p!(new:);
 
modifiedcmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth
13};13};
1414
15use crate::{15use crate::{
16 children::{should_start_with_newline, trivia_after},16 children::{should_start_with_newline, trivia_after, trivia_between},
17 comments::{format_comments, CommentLocation},17 comments::{format_comments, CommentLocation},
18};18};
1919
436 }436 }
437 Expr::ExprVar(n) => p!(new: {n.name()}),437 Expr::ExprVar(n) => p!(new: {n.name()}),
438 Expr::ExprLocal(l) => {438 Expr::ExprLocal(l) => {
439 let mut pi = p!(new: str("local") >i nl);439 let mut pi = p!(new:);
440 let (binds, end_comments) = children_between::<Bind>(
441 l.syntax().clone(),
442 l.local_kw_token().map(Into::into).as_ref(),
443 l.semi_token().map(Into::into).as_ref(),
444 );
445 if binds.len() == 1 {
446 let bind = &binds[0];
447 p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));
448 p!(pi: str("local ") {bind.value});
449 // TODO: keep end_comments, child.inline_trivia somehow, force multiple locals formatting in case of presence?
450 } else {
451 p!(pi: str("local") >i nl);
440 for bind in l.binds() {452 for bind in binds {
453 if bind.needs_newline_above() {
454 p!(pi: nl);
455 }
456 p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));
441 p!(pi: {bind} str(",") nl);457 p!(pi: {bind.value} str(";"));
442 }458 p!(pi: items(format_comments(&bind.inline_trivia, CommentLocation::ItemInline)) nl);
459 }
460 // TODO: needs_newline_above end_comments
461 p!(pi: items(format_comments(&end_comments, CommentLocation::EndOfItems)));
462 p!(pi: <i);
463 }
464 p!(pi: str(";") nl);
465
466 let expr_comments = trivia_between(
467 l.syntax().clone(),
468 l.semi_token().map(Into::into).as_ref(),
469 l.expr()
470 .map(|e| e.syntax().clone())
471 .map(Into::into)
472 .as_ref(),
473 );
474 p!(pi: items(format_comments(&expr_comments, CommentLocation::AboveItem)));
475
476 // TODO: needs_newline_above expr
443 p!(pi: <i str(";") nl {l.expr()});477 p!(pi: {l.expr()});
444 pi478 pi
445 }479 }
446 Expr::ExprIfThenElse(ite) => {480 Expr::ExprIfThenElse(ite) => {
487521
488fn main() {522fn main() {
489 let (parsed, _errors) = jrsonnet_rowan_parser::parse(523 let (parsed, _errors) = jrsonnet_rowan_parser::parse(
490 r#"524 r#"
491525
492526
493 # Edit me!527 # Edit me!
494 local b = import "b.libsonnet"; # comment528 local b = import "b.libsonnet"; # comment
495 local a = import "a.libsonnet";529 local a = import "a.libsonnet";
496530
497 local f(x,y)=x+y;531 local f(x,y)=x+y;
498532
499 local {a: [b, ..., c], d, ...e} = null;533 local {a: [b, ..., c], d, ...e} = null;
500534
501 local ass = assert false : false; false;535 local ass = assert false : false; false;
502536
503 local fn = function(a, b, c = 3) 4;537 local fn = function(a, b, c = 3) 4;
504538
505 local comp = [a for b in c if d == e];539 local comp = [a for b in c if d == e];
506 local ocomp = {[k]: 1 for k in v};540 local ocomp = {[k]: 1 for k in v};
507541
508 local ? = skip;542 local ? = skip;
509543
510 local intr = $intrinsic(test);544 local intr = $intrinsic(test);
511 local intrId = $intrinsicId;545 local intrId = $intrinsicId;
512 local intrThisFile = $intrinsicThisFile;546 local intrThisFile = $intrinsicThisFile;
513547
514 local ie = a[expr];548 local ie = a[expr];
515549
516 local unary = !a;550 local unary = !a;
517551
518 local Template = {z: "foo"};552 local
553 // I am comment
554 singleLocalWithItemComment = 1,
555 ;
556
557 // Comment between local and expression
558
559 local
560 a = 1, // Inline
561 // Comment above b
562 b = 4,
563
564 // c needs some space
565 c = 5,
566
567 // Comment after everything
568 ;
569
570
571 local Template = {z: "foo"};
519572
520 {573 {
521 local574 local
522575
523 h = 3,576 h = 3,
524 assert self.a == 1577 assert self.a == 1
525578
526 : "error",579 : "error",
527 "f": ((((((3)))))) ,580 "f": ((((((3)))))) ,
528 "g g":581 "g g":
529 f(4,2),582 f(4,2),
530 arr: [[583 arr: [[
531 1, 2,584 1, 2,
532 ],585 ],
533 3,586 3,
534 {587 {
535 b: {588 b: {
536 c: {589 c: {
537 k: [16]590 k: [16]
538 }591 }
539 }592 }
540 }593 }
541 ],594 ],
542 m: a[1::],595 m: a[1::],
543 m: b[::],596 m: b[::],
544597
545 comments: {598 comments: {
546 _: '',599 _: '',
547 // Plain comment600 // Plain comment
548 a: '',601 a: '',
549602
550 # Plain comment with empty line before603 # Plain comment with empty line before
551 b: '',604 b: '',
552 /*Single-line multiline comment605 /*Single-line multiline comment
553606
554 */607 */
555 c: '',608 c: '',
556609
557 /**Single-line multiline doc comment610 /**Single-line multiline doc comment
558611
559 */612 */
560 c: '',613 c: '',
561614
562 /**multiline doc comment615 /**multiline doc comment
563 s616 s
564 */617 */
565 c: '',618 c: '',
566619
567 /*620 /*
568621
569 Multi-line622 Multi-line
570623
571 comment624 comment
572 */625 */
573 d: '',626 d: '',
574627
575 e: '', // Inline comment628 e: '', // Inline comment
576629
577 k: '',630 k: '',
578631
579 // Text after everything632 // Text after everything
580 },633 },
581 comments2: {634 comments2: {
582 k: '',635 k: '',
583 // Text after everything, but no newline above636 // Text after everything, but no newline above
584 },637 },
585 k: if a == b then638 k: if a == b then
586639
587640
588 2641 2
589642
590 else Template {}643 else Template {}
591 } + Template644 } + Template
592645
593646
594 // Comment after everything647 // Comment after everything
595"#,648"#,
596 );649 );
597650
598 // dbg!(errors);651 // dbg!(errors);