Repository: tamasfe/taplo (Rust)

Issue:
Smarter "align_comments" when there's only 1 comment?
:wave: Howdy!

We've added support for Taplo to https://github.com/pantsbuild/pants, and are not integrating it into the repo itself.

One thing I noticed was I like the idea of "align_comments" (:+1:) but I wished that if there was 1 (and only 1) comment, it didn't apply.

E.g.
```toml
foo = [
    "hello world",
    "a",                # I'm way over here
    "b",
]
```
would be:
```toml
foo = [
    "hello world",
    "a",  # I'm way over here
    "b",
]
```

but adding a new comment would result in
```toml
foo = [
    "hello world",
    "a",                # I'm way over here
    "b",                # me too
]
```


This, of course, would be hidden behind a toggle.

Thanks again (I'm also looking forward to integrating Taplo into our eventual Pants LSP for handling our config file, so thanks for the LSP side of things too :raised_hands: )


Discussion:
Hi @thejcannon and thanks for the suggestion!

Given the project is currently under-staffed (see #403) and this feature is rather low priority at the moment, I would not expect a PR in the next months about this. However, if you are ready to write the PR yourself, I would be happy to review it.
I took a stab at it :smile: 



Patch:
diff --git a/crates/taplo/src/formatter/mod.rs b/crates/taplo/src/formatter/mod.rs
index 49c2bef7f..f131b67c6 100644
--- a/crates/taplo/src/formatter/mod.rs
+++ b/crates/taplo/src/formatter/mod.rs
@@ -51,6 +51,10 @@ create_options!(
         /// This applies to comments that are after entries or array items.
         pub align_comments: bool,
 
+        /// If `align_comments` is true, apply the alignment in cases where
+        /// there's only one comment.
+        pub align_single_comments: bool,
+
         /// Put trailing commas for multiline
         /// arrays.
         pub array_trailing_comma: bool,
@@ -145,6 +149,7 @@ impl Default for Options {
         Options {
             align_entries: false,
             align_comments: true,
+            align_single_comments: true,
             array_trailing_comma: true,
             array_auto_expand: true,
             array_auto_collapse: true,
@@ -177,6 +182,10 @@ impl Options {
     fn newlines(&self, count: usize) -> impl Iterator<Item = &'static str> {
         repeat(self.newline()).take(usize::min(count, self.allowed_blank_lines + 1))
     }
+
+    fn should_align_comments(&self, comment_count: usize) -> bool {
+        (comment_count != 1 || self.align_single_comments) && self.align_comments
+    }
 }
 
 #[derive(Debug, Clone)]
@@ -697,6 +706,7 @@ fn add_entries(
         }
     }
 
+    let mut comment_count = 0;
     // Transform the entries into generic rows that can be aligned.
     let rows = entry_group
         .drain(0..)
@@ -709,18 +719,20 @@ fn add_entries(
             row.push(e.value);
             if let Some(c) = e.comment {
                 row.push(c);
+                comment_count += 1;
             }
 
             row
         })
         .collect::<Vec<_>>();
 
+    let align_comments = options.should_align_comments(comment_count);
     *formatted += &format_rows(
-        if !options.align_entries && !options.align_comments {
+        if !options.align_entries && !align_comments {
             0..0
-        } else if !options.align_entries && options.align_comments {
+        } else if !options.align_entries && align_comments {
             3..usize::MAX
-        } else if options.align_entries && !options.align_comments {
+        } else if options.align_entries && !align_comments {
             0..3
         } else {
             0..usize::MAX
@@ -972,6 +984,7 @@ fn format_array(node: SyntaxNode, options: &Options, context: &Context) -> impl
             return were_values;
         }
 
+        let mut comment_count = 0;
         let rows = value_group
             .drain(0..)
             .map(|(value, comment)| {
@@ -981,18 +994,16 @@ fn format_array(node: SyntaxNode, options: &Options, context: &Context) -> impl
                 row.push(value);
                 if let Some(c) = comment {
                     row.push(c);
+                    comment_count += 1;
                 }
 
                 row
             })
             .collect::<Vec<_>>();
 
+        let align_comments = options.should_align_comments(comment_count);
         *formatted += &format_rows(
-            if options.align_comments {
-                0..usize::MAX
-            } else {
-                0..0
-            },
+            if align_comments { 0..usize::MAX } else { 0..0 },
             1..usize::MAX,
             &rows,
             options.newline(),


Test patch:
diff --git a/crates/taplo/src/tests/formatter.rs b/crates/taplo/src/tests/formatter.rs
index 9a6b288d9..3337fcc1b 100644
--- a/crates/taplo/src/tests/formatter.rs
+++ b/crates/taplo/src/tests/formatter.rs
@@ -1024,3 +1024,87 @@ foo = [
 
     assert_format!(expected, &formatted);
 }
+
+#[test]
+fn test_single_comment_no_alignment() {
+    let src = r#"
+entry1 = "string"  # trailing comment
+entry2 = "longer_string"
+
+my_array = [
+  #Items
+  "abc",
+  "b", # Some comment
+  "caa",
+ # comment
+  # Other stuff
+]
+"#;
+
+    let expected = r#"
+entry1 = "string" # trailing comment
+entry2 = "longer_string"
+
+my_array = [
+  #Items
+  "abc",
+  "b", # Some comment
+  "caa",
+  # comment
+  # Other stuff
+]
+"#;
+
+    let formatted = crate::formatter::format(
+        src,
+        formatter::Options {
+            align_comments: true,
+            align_single_comments: false,
+            ..Default::default()
+        },
+    );
+
+    assert_format!(expected, &formatted);
+}
+
+#[test]
+fn test_single_comment_alignment() {
+    let src = r#"
+entry1 = "string"  # trailing comment
+entry2 = "longer_string"
+
+my_array = [
+  #Items
+  "abc",
+  "b", # Some comment
+  "caa",
+ # comment
+  # Other stuff
+]
+"#;
+
+    let expected = r#"
+entry1 = "string"        # trailing comment
+entry2 = "longer_string"
+
+my_array = [
+  #Items
+  "abc",
+  "b",   # Some comment
+  "caa",
+  # comment
+  # Other stuff
+]
+"#;
+
+    let formatted = crate::formatter::format(
+        src,
+        formatter::Options {
+            align_comments: true,
+            align_single_comments: true,
+            ..Default::default()
+        },
+    );
+
+    assert_format!(expected, &formatted);
+}