From e6fdca45dbc100e0597920e8330127e3b88d605d Mon Sep 17 00:00:00 2001 From: Mael Cravero Date: Thu, 26 Jan 2023 12:38:54 +0100 Subject: [PATCH] Add comment-end-token language config option Some languages lack line comments and only have block comments, in which case an end of comment token is needed to comment single lines. --- book/src/languages.md | 1 + helix-core/src/comment.rs | 39 +++++++++++++++++++++++++++++++++----- helix-core/src/syntax.rs | 1 + helix-term/src/commands.rs | 9 ++++++++- languages.toml | 7 +++++-- 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/book/src/languages.md b/book/src/languages.md index 8a8f3bb61e86..27d1148d1a2a 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -58,6 +58,7 @@ These configuration keys are available: | `auto-format` | Whether to autoformat this language when saving | | `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) | | `comment-token` | The token to use as a comment-token | +| `comment-end-token` | The token to use to end comments (in languages with no line comments) | | `indent` | The indent to use. Has sub keys `unit` (the text inserted into the document when indenting; usually set to N spaces or `"\t"` for tabs) and `tab-width` (the number of spaces rendered for a tab) | | `language-server` | The Language Server to run. See the Language Server configuration section below. | | `config` | Language Server configuration | diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 9c7e50f335b1..80b80fa65a2e 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -57,12 +57,19 @@ fn find_line_comment( } #[must_use] -pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&str>) -> Transaction { +pub fn toggle_line_comments( + doc: &Rope, + selection: &Selection, + token: Option<&str>, + end_token: Option<&str>, +) -> Transaction { let text = doc.slice(..); let token = token.unwrap_or("//"); let comment = Tendril::from(format!("{} ", token)); + let end_comment = end_token.map(|t| Tendril::from(format!(" {}", t))); + let mut lines: Vec = Vec::with_capacity(selection.len()); let mut min_next_line = 0; @@ -81,13 +88,20 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st for line in to_change { let pos = text.line_to_char(line) + min; + let end_pos = pos + text.line(line).len_chars() - min - 1 /* skip \n*/; if !commented { // comment line changes.push((pos, pos, Some(comment.clone()))); + if let Some(end_comment) = &end_comment { + changes.push((end_pos, end_pos, Some(end_comment.clone()))); + } } else { // uncomment line changes.push((pos, pos + token.len() + margin, None)); + if let Some(end_token) = &end_token { + changes.push((end_pos - end_token.len() - margin, end_pos, None)); + } } } @@ -112,14 +126,14 @@ mod test { assert_eq!(res, (false, vec![0, 2], 2, 0)); // comment - let transaction = toggle_line_comments(&doc, &selection, None); + let transaction = toggle_line_comments(&doc, &selection, None, None); transaction.apply(&mut doc); selection = selection.map(transaction.changes()); assert_eq!(doc, " // 1\n\n // 2\n // 3"); // uncomment - let transaction = toggle_line_comments(&doc, &selection, None); + let transaction = toggle_line_comments(&doc, &selection, None, None); transaction.apply(&mut doc); selection = selection.map(transaction.changes()); assert_eq!(doc, " 1\n\n 2\n 3"); @@ -130,7 +144,7 @@ mod test { // reset the selection. selection = Selection::single(0, doc.len_chars() - 1); - let transaction = toggle_line_comments(&doc, &selection, None); + let transaction = toggle_line_comments(&doc, &selection, None, None); transaction.apply(&mut doc); selection = selection.map(transaction.changes()); assert_eq!(doc, " 1\n\n 2\n 3"); @@ -141,12 +155,27 @@ mod test { // reset the selection. selection = Selection::single(0, doc.len_chars() - 1); - let transaction = toggle_line_comments(&doc, &selection, None); + let transaction = toggle_line_comments(&doc, &selection, None, None); transaction.apply(&mut doc); selection = selection.map(transaction.changes()); assert_eq!(doc, ""); assert!(selection.len() == 1); // to ignore the selection unused warning // TODO: account for uncommenting with uneven comment indentation + + // comment and uncomment with end of comment tokens + doc = Rope::from("1 2\n 3\n"); + selection = Selection::single(0, doc.len_chars() - 1); + + let transaction = toggle_line_comments(&doc, &selection, Some("/*"), Some("*/")); + transaction.apply(&mut doc); + selection = selection.map(transaction.changes()); + assert_eq!(doc, "/* 1 2 */\n/* 3 */\n"); + + let transaction = toggle_line_comments(&doc, &selection, Some("/*"), Some("*/")); + transaction.apply(&mut doc); + selection = selection.map(transaction.changes()); + assert_eq!(doc, "1 2\n 3\n"); + assert!(selection.len() == 1); // to ignore the selection unused warning } } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 1b6c1b1dab3e..fca16b56857b 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -82,6 +82,7 @@ pub struct LanguageConfiguration { pub shebangs: Vec, // interpreter(s) associated with language pub roots: Vec, // these indicate project roots <.git, Cargo.toml> pub comment_token: Option, + pub comment_end_token: Option, pub max_line_length: Option, #[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")] diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c76e9f2bdf80..84ed99fde19a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4221,7 +4221,14 @@ fn toggle_comments(cx: &mut Context) { .language_config() .and_then(|lc| lc.comment_token.as_ref()) .map(|tc| tc.as_ref()); - let transaction = comment::toggle_line_comments(doc.text(), doc.selection(view.id), token); + + let end_token = doc + .language_config() + .and_then(|lc| lc.comment_end_token.as_ref()) + .map(|tc| tc.as_ref()); + + let transaction = + comment::toggle_line_comments(doc.text(), doc.selection(view.id), token, end_token); doc.apply(&transaction, view.id); exit_select_mode(cx); diff --git a/languages.toml b/languages.toml index c34135244c46..bb0780b61ad5 100644 --- a/languages.toml +++ b/languages.toml @@ -707,7 +707,8 @@ injection-regex = "ocaml" file-types = ["ml"] shebangs = [] roots = [] -comment-token = "(**)" +comment-token = "(*" +comment-end-token = "*)" language-server = { command = "ocamllsp" } indent = { tab-width = 2, unit = " " } @@ -721,7 +722,8 @@ scope = "source.ocaml.interface" file-types = ["mli"] shebangs = [] roots = [] -comment-token = "(**)" +comment-token = "(*" +comment-end-token = "*)" language-server = { command = "ocamllsp" } indent = { tab-width = 2, unit = " " } @@ -1870,6 +1872,7 @@ scope = "source.sml" injection-regex = "sml" file-types = ["sml"] comment-token = "(*" +comment-end-token = "*)" roots = [] [[grammar]]