From 3844eb7fe2a98e6e13e530ec3c832c67feb52000 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 10:07:28 -0500 Subject: [PATCH 01/59] Add `continue_comment` function --- helix-core/src/comment.rs | 40 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 9c7e50f335b1..89b0943039c9 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -1,8 +1,12 @@ -//! This module contains the functionality toggle comments on lines over the selection -//! using the comment character defined in the user's `languages.toml` +//! This module contains the functionality for the following comment-related features +//! using the comment character defined in the user's `languages.toml`: +//! * toggle comments on lines over the selection +//! * continue comment when opening a new line use crate::{ - find_first_non_whitespace_char, Change, Rope, RopeSlice, Selection, Tendril, Transaction, + find_first_non_whitespace_char, + syntax::{CapturedNode, LanguageConfiguration}, + Change, Rope, RopeSlice, Selection, Tendril, Transaction, }; use std::borrow::Cow; @@ -94,6 +98,36 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st Transaction::change(doc, changes.into_iter()) } +/// Return the comment token of the current line if it is commented. +/// Return None otherwise. +pub fn continue_comment<'a>(doc: &Rope, line: usize, tokens: &'a [String]) -> Option<&'a str> { + // TODO: don't continue shebangs + if tokens.is_empty() { + return None; + } + + let mut result = None; + let line_slice = doc.line(line); + + if let Some(pos) = find_first_non_whitespace_char(line_slice) { + let len = line_slice.len_chars(); + + for token in tokens { + // line can be shorter than pos + token length + let fragment = Cow::from(line_slice.slice(pos..std::cmp::min(pos + token.len(), len))); + + if fragment == *token { + // We don't necessarily want to break upon finding the first matching comment token + // Instead, we check against all of the comment tokens and end up returning the longest + // comment token that matches + result = Some(token.as_str()); + } + } + } + + result +} + #[cfg(test)] mod test { use super::*; From 3d31e661aa0f56cc1b65191964b4966e0cd7ca40 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 10:40:08 -0500 Subject: [PATCH 02/59] Add test for `get_comment_token` fn --- helix-core/src/comment.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 89b0943039c9..4df484f6dd19 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -4,9 +4,7 @@ //! * continue comment when opening a new line use crate::{ - find_first_non_whitespace_char, - syntax::{CapturedNode, LanguageConfiguration}, - Change, Rope, RopeSlice, Selection, Tendril, Transaction, + find_first_non_whitespace_char, Change, Rope, RopeSlice, Selection, Tendril, Transaction, }; use std::borrow::Cow; @@ -100,7 +98,7 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st /// Return the comment token of the current line if it is commented. /// Return None otherwise. -pub fn continue_comment<'a>(doc: &Rope, line: usize, tokens: &'a [String]) -> Option<&'a str> { +pub fn get_comment_token<'a>(doc: &Rope, line: usize, tokens: &'a [String]) -> Option<&'a str> { // TODO: don't continue shebangs if tokens.is_empty() { return None; @@ -133,7 +131,7 @@ mod test { use super::*; #[test] - fn test_find_line_comment() { + fn test_toggle_line_comments() { // four lines, two space indented, except for line 1 which is blank. let mut doc = Rope::from(" 1\n\n 2\n 3"); // select whole document @@ -183,4 +181,16 @@ mod test { // TODO: account for uncommenting with uneven comment indentation } + + #[test] + fn test_get_comment_token() { + let doc = Rope::from("# 1\n // 2 \n///3\n/// 4\n//! 5"); + let tokens = vec![String::from("//"), String::from("///"), String::from("//!")]; + + assert_eq!(get_comment_token(&doc, 0, &tokens), None); + assert_eq!(get_comment_token(&doc, 1, &tokens), Some("//")); + assert_eq!(get_comment_token(&doc, 2, &tokens), None); + assert_eq!(get_comment_token(&doc, 3, &tokens), Some("///")); + assert_eq!(get_comment_token(&doc, 4, &tokens), Some("//!")); + } } From 129ecae997460307b9e3b7e9e961d87d27651774 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 10:48:37 -0500 Subject: [PATCH 03/59] Fix incorrect assertion --- helix-core/src/comment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 4df484f6dd19..f42442de489e 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -189,7 +189,7 @@ mod test { assert_eq!(get_comment_token(&doc, 0, &tokens), None); assert_eq!(get_comment_token(&doc, 1, &tokens), Some("//")); - assert_eq!(get_comment_token(&doc, 2, &tokens), None); + assert_eq!(get_comment_token(&doc, 2, &tokens), Some("///")); assert_eq!(get_comment_token(&doc, 3, &tokens), Some("///")); assert_eq!(get_comment_token(&doc, 4, &tokens), Some("//!")); } From 24496229a813aff733a707144d9843c6005fcac2 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 11:21:11 -0500 Subject: [PATCH 04/59] Wire up continue comment functionality --- helix-core/src/comment.rs | 18 +++++++++++------- helix-core/src/syntax.rs | 4 +++- helix-term/src/commands.rs | 26 +++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index f42442de489e..d4e365dbe98e 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -98,7 +98,11 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st /// Return the comment token of the current line if it is commented. /// Return None otherwise. -pub fn get_comment_token<'a>(doc: &Rope, line: usize, tokens: &'a [String]) -> Option<&'a str> { +pub fn continue_single_comment<'a>( + doc: &Rope, + line: usize, + tokens: &'a [String], +) -> Option<&'a str> { // TODO: don't continue shebangs if tokens.is_empty() { return None; @@ -183,14 +187,14 @@ mod test { } #[test] - fn test_get_comment_token() { + fn test_continue_single_comment() { let doc = Rope::from("# 1\n // 2 \n///3\n/// 4\n//! 5"); let tokens = vec![String::from("//"), String::from("///"), String::from("//!")]; - assert_eq!(get_comment_token(&doc, 0, &tokens), None); - assert_eq!(get_comment_token(&doc, 1, &tokens), Some("//")); - assert_eq!(get_comment_token(&doc, 2, &tokens), Some("///")); - assert_eq!(get_comment_token(&doc, 3, &tokens), Some("///")); - assert_eq!(get_comment_token(&doc, 4, &tokens), Some("//!")); + assert_eq!(continue_single_comment(&doc, 0, &tokens), None); + assert_eq!(continue_single_comment(&doc, 1, &tokens), Some("//")); + assert_eq!(continue_single_comment(&doc, 2, &tokens), Some("///")); + assert_eq!(continue_single_comment(&doc, 3, &tokens), Some("///")); + assert_eq!(continue_single_comment(&doc, 4, &tokens), Some("//!")); } } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 881b45098a9e..618649bb5afb 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -102,7 +102,9 @@ pub struct LanguageConfiguration { #[serde(default)] pub shebangs: Vec, // interpreter(s) associated with language pub roots: Vec, // these indicate project roots <.git, Cargo.toml> - pub comment_token: Option, + pub comment_token: Option, // TODO: Replace all usages of `comment_token` with `comment_tokens` + #[serde(default)] + pub comment_tokens: Vec, pub text_width: Option, pub soft_wrap: Option, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0fd011cc936b..b252fd512325 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3118,6 +3118,9 @@ fn open(cx: &mut Context, open: Open) { let mut text = String::with_capacity(1 + indent_len); text.push_str(doc.line_ending.as_str()); text.push_str(&indent); + + handle_comment_continue(doc, &mut text, cursor_line); + let text = text.repeat(count); // calculate new selection ranges @@ -3137,6 +3140,24 @@ fn open(cx: &mut Context, open: Open) { transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); doc.apply(&transaction, view.id); + + // Since we might have added a comment token, move to the end of the line. + goto_line_end_newline(cx); +} + +// Currently only continues single-line comments +// TODO: Handle block comments as well +fn handle_comment_continue(doc: &Document, text: &mut String, cursor_line: usize) { + if let Some(lang_config) = doc.language_config() { + let line_comment_tokens = &lang_config.comment_tokens; + + if let Some(token) = + comment::continue_single_comment(doc.text(), cursor_line, line_comment_tokens) + { + text.push_str(token); + text.push(' '); + } + } } // o inserts a new line after each line with a selection @@ -3674,6 +3695,9 @@ pub mod insert { new_text.reserve_exact(1 + indent.len()); new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); + + handle_comment_continue(doc, &mut new_text, current_line); + new_text.chars().count() }; @@ -4576,7 +4600,7 @@ fn toggle_comments(cx: &mut Context) { let (view, doc) = current!(cx.editor); let token = doc .language_config() - .and_then(|lc| lc.comment_token.as_ref()) + .and_then(|lc| lc.comment_tokens.get(0)) .map(|tc| tc.as_ref()); let transaction = comment::toggle_line_comments(doc.text(), doc.selection(view.id), token); From 036e2bff66afcf4fe46f71808ccd6dbbb3de7750 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 12:32:25 -0500 Subject: [PATCH 05/59] Add `comment-tokens` field to languages.toml --- helix-core/src/comment.rs | 4 +- languages.toml | 140 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index d4e365dbe98e..08df27c2766d 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -188,7 +188,7 @@ mod test { #[test] fn test_continue_single_comment() { - let doc = Rope::from("# 1\n // 2 \n///3\n/// 4\n//! 5"); + let doc = Rope::from("# 1\n // 2 \n///3\n/// 4\n//! 5\n//! /// 6\n7 ///"); let tokens = vec![String::from("//"), String::from("///"), String::from("//!")]; assert_eq!(continue_single_comment(&doc, 0, &tokens), None); @@ -196,5 +196,7 @@ mod test { assert_eq!(continue_single_comment(&doc, 2, &tokens), Some("///")); assert_eq!(continue_single_comment(&doc, 3, &tokens), Some("///")); assert_eq!(continue_single_comment(&doc, 4, &tokens), Some("//!")); + assert_eq!(continue_single_comment(&doc, 5, &tokens), Some("//!")); + assert_eq!(continue_single_comment(&doc, 6, &tokens), None); } } diff --git a/languages.toml b/languages.toml index cf2783de96bf..0a71144f652a 100644 --- a/languages.toml +++ b/languages.toml @@ -179,6 +179,7 @@ file-types = ["rs"] roots = ["Cargo.toml", "Cargo.lock"] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "rust-analyzer" ] indent = { tab-width = 4, unit = " " } @@ -231,6 +232,7 @@ language-servers = [ "forc" ] roots = ["Forc.toml", "Forc.lock"] indent = { tab-width = 4, unit = " " } comment-token = "//" +comment-tokens = ["//"] [[grammar]] name = "sway" @@ -243,6 +245,7 @@ injection-regex = "toml" file-types = ["toml", "poetry.lock", "Cargo.lock"] roots = [] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "taplo" ] indent = { tab-width = 2, unit = " " } @@ -257,6 +260,7 @@ injection-regex = "awk" file-types = ["awk", "gawk", "nawk", "mawk"] roots = [] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "awk-language-server" ] indent = { tab-width = 2, unit = " " } @@ -272,6 +276,7 @@ file-types = ["proto"] language-servers = [ "bufls", "pbkit" ] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -286,6 +291,7 @@ file-types = ["ex", "exs", "mix.lock"] shebangs = ["elixir"] roots = ["mix.exs", "mix.lock"] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "elixir-ls" ] indent = { tab-width = 2, unit = " " } @@ -301,6 +307,7 @@ file-types = ["fish"] shebangs = ["fish"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } [[grammar]] @@ -315,6 +322,7 @@ file-types = ["mint"] shebangs = [] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "mint" ] indent = { tab-width = 2, unit = " " } @@ -361,6 +369,7 @@ file-types = ["json5"] roots = [] language-servers = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } # https://json5.org @@ -375,6 +384,7 @@ injection-regex = "c" file-types = ["c"] # TODO: ["h"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "clangd" ] indent = { tab-width = 2, unit = " " } @@ -412,6 +422,7 @@ injection-regex = "cpp" file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H", "cu", "cuh", "cppm", "h++", "ii", "inl", { suffix = ".hpp.in" }, { suffix = ".h.in" }] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "clangd" ] indent = { tab-width = 2, unit = " " } @@ -448,6 +459,7 @@ scope = "source.cr" file-types = ["cr"] roots = ["shard.yml", "shard.lock"] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } grammar = "ruby" language-servers = [ "crystalline" ] @@ -459,6 +471,7 @@ injection-regex = "c-?sharp" file-types = ["cs", "csx", "cake"] roots = ["sln", "csproj"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } language-servers = [ "omnisharp" ] @@ -493,6 +506,7 @@ file-types = ["go"] roots = ["go.work", "go.mod"] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "gopls" ] # TODO: gopls needs utf-8 offsets? indent = { tab-width = 4, unit = "\t" } @@ -546,6 +560,7 @@ file-types = ["go.mod"] roots = [] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "gopls" ] indent = { tab-width = 4, unit = "\t" } @@ -560,6 +575,7 @@ injection-regex = "gotmpl" file-types = ["gotmpl"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "gopls" ] indent = { tab-width = 2, unit = " " } @@ -575,6 +591,7 @@ file-types = ["go.work"] roots = [] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "gopls" ] indent = { tab-width = 4, unit = "\t" } @@ -591,6 +608,7 @@ file-types = ["js", "mjs", "cjs", "rules", "es6", "pac", "jakefile"] shebangs = ["node"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "typescript-language-server" ] indent = { tab-width = 2, unit = " " } @@ -618,6 +636,7 @@ language-id = "javascriptreact" file-types = ["jsx"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "typescript-language-server" ] indent = { tab-width = 2, unit = " " } grammar = "javascript" @@ -701,6 +720,7 @@ file-types = ["py","pyi","py3","pyw","ptl",".pythonstartup",".pythonrc","SConstr shebangs = ["python"] roots = ["pyproject.toml", "setup.py", "poetry.lock", "pyrightconfig.json"] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "pylsp" ] # TODO: pyls needs utf-8 offsets indent = { tab-width = 4, unit = " " } @@ -717,6 +737,7 @@ file-types = ["ncl"] shebangs = [] roots = [] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "nls" ] indent = { tab-width = 2, unit = " " } @@ -738,6 +759,7 @@ file-types = ["nix"] shebangs = [] roots = [] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "nil" ] indent = { tab-width = 2, unit = " " } @@ -788,6 +810,7 @@ file-types = [ shebangs = ["ruby"] roots = [] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "solargraph" ] indent = { tab-width = 2, unit = " " } @@ -843,6 +866,7 @@ file-types = [ shebangs = ["sh", "bash", "dash", "zsh"] roots = [] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "bash-language-server" ] indent = { tab-width = 2, unit = " " } @@ -883,6 +907,7 @@ injection-regex = "tex" file-types = ["tex", "sty", "cls", "Rd", "bbx", "cbx"] roots = [] comment-token = "%" +comment-tokens = ["//"] language-servers = [ "texlab" ] indent = { tab-width = 4, unit = "\t" } @@ -897,6 +922,7 @@ injection-regex = "bib" file-types = ["bib"] roots = [] comment-token = "%" +comment-tokens = ["//"] language-servers = [ "texlab" ] indent = { tab-width = 4, unit = "\t" } auto-format = true @@ -925,6 +951,7 @@ injection-regex = "lean" file-types = ["lean"] roots = [ "lakefile.lean" ] comment-token = "--" +comment-tokens = ["//"] language-servers = [ "lean" ] indent = { tab-width = 2, unit = " " } @@ -940,6 +967,7 @@ file-types = ["jl"] shebangs = ["julia"] roots = ["Manifest.toml", "Project.toml"] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "julia" ] indent = { tab-width = 4, unit = " " } @@ -967,6 +995,7 @@ injection-regex = "ledger" file-types = ["ldg", "ledger", "journal"] roots = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } [[grammar]] @@ -980,6 +1009,7 @@ injection-regex = "beancount" file-types = ["beancount", "bean"] roots = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -994,6 +1024,7 @@ file-types = ["ml"] shebangs = ["ocaml", "ocamlrun", "ocamlscript"] roots = [] comment-token = "(**)" +comment-tokens = ["//"] language-servers = [ "ocamllsp" ] indent = { tab-width = 2, unit = " " } @@ -1014,6 +1045,7 @@ file-types = ["mli"] shebangs = [] roots = [] comment-token = "(**)" +comment-tokens = ["//"] language-servers = [ "ocamllsp" ] indent = { tab-width = 2, unit = " " } @@ -1035,6 +1067,7 @@ file-types = ["lua"] shebangs = ["lua"] roots = [".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git"] comment-token = "--" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "lua-language-server" ] @@ -1074,6 +1107,7 @@ scope = "source.yaml" file-types = ["yml", "yaml"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "yaml-language-server", "ansible-language-server" ] injection-regex = "yml|yaml" @@ -1089,6 +1123,7 @@ injection-regex = "haskell" file-types = ["hs", "hs-boot"] roots = ["Setup.hs", "stack.yaml", "cabal.project"] comment-token = "--" +comment-tokens = ["//"] language-servers = [ "haskell-language-server" ] indent = { tab-width = 2, unit = " " } @@ -1102,6 +1137,7 @@ scope = "source.persistentmodels" file-types = ["persistentmodels"] roots = [] comment-token = "--" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1115,6 +1151,7 @@ injection-regex = "purescript" file-types = ["purs"] roots = ["spago.dhall", "bower.json"] comment-token = "--" +comment-tokens = ["//"] language-servers = [ "purescript-language-server" ] indent = { tab-width = 2, unit = " " } auto-format = true @@ -1132,6 +1169,7 @@ file-types = ["zig"] roots = ["build.zig"] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "zls" ] indent = { tab-width = 4, unit = " " } formatter = { command = "zig" , args = ["fmt", "--stdin"] } @@ -1170,6 +1208,7 @@ roots = [] file-types = ["pl", "prolog"] shebangs = ["swipl"] comment-token = "%" +comment-tokens = ["//"] language-servers = [ "swipl" ] [[language]] @@ -1178,6 +1217,7 @@ scope = "source.tsq" file-types = ["tsq"] roots = [] comment-token = ";" +comment-tokens = ["//"] injection-regex = "tsq" indent = { tab-width = 2, unit = " " } @@ -1191,6 +1231,7 @@ scope = "source.cmake" file-types = ["cmake", "CMakeLists.txt"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "cmake-language-server" ] injection-regex = "cmake" @@ -1207,6 +1248,7 @@ shebangs = ["make", "gmake"] injection-regex = "(make|makefile|Makefile|mk)" roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1219,6 +1261,7 @@ scope = "source.glsl" file-types = ["glsl", "vert", "tesc", "tese", "geom", "frag", "comp" ] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } injection-regex = "glsl" @@ -1233,6 +1276,7 @@ file-types = ["pl", "pm", "t", "psgi", "raku", "rakumod", "rakutest", "rakudoc", shebangs = ["perl"] roots = [] comment-token = "#" +comment-tokens = ["//"] language-servers = [ "perlnavigator" ] indent = { tab-width = 2, unit = " " } @@ -1258,6 +1302,7 @@ roots = [] file-types = ["rkt", "rktd", "rktl", "scrbl"] shebangs = ["racket"] comment-token = ";" +comment-tokens = ["//"] language-servers = [ "racket" ] grammar = "scheme" @@ -1268,6 +1313,7 @@ roots = [] file-types = ["lisp", "asd", "cl", "l", "lsp", "ny", "podsl", "sexp"] shebangs = ["lisp", "sbcl", "ccl", "clisp", "ecl"] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "cl-lsp" ] grammar = "scheme" @@ -1295,6 +1341,7 @@ scope = "source.wgsl" file-types = ["wgsl"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "wgsl_analyzer" ] indent = { tab-width = 4, unit = " " } @@ -1308,6 +1355,7 @@ scope = "source.llvm" roots = [] file-types = ["ll"] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } injection-regex = "llvm" @@ -1321,6 +1369,7 @@ scope = "source.llvm_mir" roots = [] file-types = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } injection-regex = "mir" @@ -1337,6 +1386,7 @@ scope = "source.yaml" roots = [] file-types = ["mir"] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[language]] @@ -1345,6 +1395,7 @@ scope = "source.tablegen" roots = [] file-types = ["td"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } injection-regex = "tablegen" @@ -1384,6 +1435,7 @@ file-types = ["dart"] roots = ["pubspec.yaml"] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "dart" ] indent = { tab-width = 2, unit = " " } @@ -1397,6 +1449,7 @@ scope = "source.scala" roots = ["build.sbt", "build.sc", "build.gradle", "build.gradle.kts", "pom.xml", ".scala-build"] file-types = ["scala", "sbt", "sc"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "metals" ] @@ -1411,6 +1464,7 @@ injection-regex = "docker|dockerfile" roots = ["Dockerfile", "Containerfile"] file-types = ["Dockerfile", "dockerfile", "Containerfile", "containerfile"] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "docker-langserver" ] @@ -1424,6 +1478,7 @@ scope = "git.commitmsg" roots = [] file-types = ["COMMIT_EDITMSG"] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } rulers = [51, 73] text-width = 72 @@ -1439,6 +1494,7 @@ roots = [] file-types = ["diff", "patch", "rej"] injection-regex = "diff" comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1452,6 +1508,7 @@ roots = [] file-types = ["git-rebase-todo"] injection-regex = "git-rebase" comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = "y" } [[grammar]] @@ -1476,6 +1533,7 @@ roots = [] file-types = [".gitmodules", ".gitconfig", { suffix = ".git/config" }, { suffix = ".config/git/config" }] injection-regex = "git-config" comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1489,6 +1547,7 @@ roots = [] file-types = [".gitattributes"] injection-regex = "git-attributes" comment-token = "#" +comment-tokens = ["//"] grammar = "gitattributes" [[grammar]] @@ -1502,6 +1561,7 @@ roots = [] file-types = [".gitignore", ".gitignore_global", ".ignore", ".prettierignore", ".eslintignore", ".npmignore", "CODEOWNERS"] injection-regex = "git-ignore" comment-token = "#" +comment-tokens = ["//"] grammar = "gitignore" [[grammar]] @@ -1529,6 +1589,7 @@ file-types = ["elm"] roots = ["elm.json"] auto-format = true comment-token = "--" +comment-tokens = ["//"] language-servers = [ "elm-language-server" ] indent = { tab-width = 4, unit = " " } @@ -1555,6 +1616,7 @@ file-types = ["res"] roots = ["bsconfig.json"] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "rescript-language-server" ] indent = { tab-width = 2, unit = " " } @@ -1570,6 +1632,7 @@ file-types = ["erl", "hrl", "app", "rebar.config", "rebar.lock"] roots = ["rebar.config"] shebangs = ["escript"] comment-token = "%%" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } language-servers = [ "erlang-ls" ] @@ -1591,6 +1654,7 @@ scope = "source.kotlin" file-types = ["kt", "kts"] roots = ["settings.gradle", "settings.gradle.kts"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } language-servers = [ "kotlin-language-server" ] @@ -1606,6 +1670,7 @@ language-id = "terraform" file-types = ["hcl", "tf", "nomad"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "terraform-ls" ] auto-format = true @@ -1621,6 +1686,7 @@ language-id = "terraform-vars" file-types = ["tfvars"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "terraform-ls" ] auto-format = true @@ -1645,6 +1711,7 @@ injection-regex = "(sol|solidity)" file-types = ["sol"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } language-servers = [ "solc" ] @@ -1659,6 +1726,7 @@ injection-regex = "gleam" file-types = ["gleam"] roots = ["gleam.toml"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "gleam" ] auto-format = true @@ -1674,6 +1742,7 @@ injection-regex = "ron" file-types = ["ron"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } grammar = "rust" @@ -1683,6 +1752,7 @@ scope = "source.robot" injection-regex = "robot" file-types = ["robot", "resource"] comment-token = "#" +comment-tokens = ["//"] roots = [] indent = { tab-width = 4, unit = " " } language-servers = [ "robotframework_ls" ] @@ -1699,6 +1769,7 @@ file-types = ["r", "R", ".Rprofile", "Rprofile.site", ".RHistory"] shebangs = ["r", "R"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "r" ] @@ -1723,6 +1794,7 @@ injection-regex = "swift" file-types = ["swift"] roots = [ "Package.swift" ] comment-token = "//" +comment-tokens = ["//"] auto-format = true language-servers = [ "sourcekit-lsp" ] @@ -1783,6 +1855,7 @@ scope = "source.sql" file-types = ["sql", "dsql"] roots = [] comment-token = "--" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } injection-regex = "sql" @@ -1800,6 +1873,7 @@ roots = ["project.godot"] auto-format = true formatter = { command = "gdformat", args = ["-"] } comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1815,6 +1889,7 @@ shebangs = [] roots = ["project.godot"] auto-format = false comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1829,6 +1904,7 @@ file-types = ["nu"] shebangs = ["nu"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1842,6 +1918,7 @@ injection-regex = "vala" file-types = ["vala", "vapi"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "vala-language-server" ] @@ -1856,6 +1933,7 @@ injection-regex = "hare" file-types = ["ha"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 8, unit = "\t" } [[grammar]] @@ -1869,6 +1947,7 @@ injection-regex = "(dtsi?|devicetree|fdt)" file-types = ["dts", "dtsi"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1882,6 +1961,7 @@ injection-regex = "cairo" file-types = ["cairo"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } # auto-format = true grammar = "rust" @@ -1895,6 +1975,7 @@ file-types = ["cpon", "cp"] roots = [] auto-format = true comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1909,6 +1990,7 @@ file-types = ["odin"] roots = ["ols.json"] language-servers = [ "ols" ] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1922,6 +2004,7 @@ injection-regex = "meson" file-types = ["meson.build"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1934,6 +2017,7 @@ scope = "source.sshclientconfig" file-types = [{ suffix = ".ssh/config" }, { suffix = "/etc/ssh/ssh_config" }] roots = [] comment-token = "#" +comment-tokens = ["//"] [[grammar]] name = "sshclientconfig" @@ -1947,6 +2031,7 @@ file-types = ["ss", "scm"] shebangs = ["scheme", "guile", "chicken"] roots = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1962,6 +2047,7 @@ roots = ["v.mod"] language-servers = [ "vlang-language-server" ] auto-format = true comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1974,6 +2060,7 @@ scope = "source.verilog" file-types = ["v", "vh", "sv", "svh"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "svlangserver" ] indent = { tab-width = 2, unit = " " } injection-regex = "verilog" @@ -2013,6 +2100,7 @@ injection-regex = "openscad" file-types = ["scad"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "openscad-lsp" ] indent = { tab-width = 2, unit = "\t" } @@ -2027,6 +2115,7 @@ injection-regex = "prisma" file-types = ["prisma"] roots = ["package.json"] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "prisma-language-server" ] indent = { tab-width = 2, unit = " " } @@ -2041,6 +2130,7 @@ injection-regex = "(clojure|clj|edn|boot)" file-types = ["clj", "cljs", "cljc", "clje", "cljr", "cljx", "edn", "boot"] roots = ["project.clj", "build.boot", "deps.edn", "shadow-cljs.edn"] comment-token = ";" +comment-tokens = ["//"] language-servers = [ "clojure-lsp" ] indent = { tab-width = 2, unit = " " } @@ -2055,6 +2145,7 @@ injection-regex = "(starlark|bzl|bazel)" file-types = ["bzl", "bazel", "BUILD", "star"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } grammar = "python" @@ -2064,6 +2155,7 @@ scope = "source.elvish" file-types = ["elv"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "elvish" ] grammar = "elvish" @@ -2080,6 +2172,7 @@ file-types = ["idr"] shebangs = [] roots = [] comment-token = "--" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "idris2-lsp" ] @@ -2090,6 +2183,7 @@ injection-regex = "fortran" file-types = ["f", "for", "f90", "f95", "f03"] roots = ["fpm.toml"] comment-token = "!" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " "} language-servers = [ "fortls" ] @@ -2104,6 +2198,7 @@ injection-regex = "ungrammar" file-types = ["ungram", "ungrammar"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2117,6 +2212,7 @@ injection-regex = "dot" file-types = ["dot"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } language-servers = [ "dot-language-server" ] @@ -2132,6 +2228,7 @@ file-types = ["cue"] roots = ["cue.mod"] auto-format = true comment-token = "//" +comment-tokens = ["//"] language-servers = [ "cuelsp" ] indent = { tab-width = 4, unit = "\t" } formatter = { command = "cue", args = ["fmt", "-"] } @@ -2147,6 +2244,7 @@ injection-regex = "slint" file-types = ["slint"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } language-servers = [ "slint-lsp" ] @@ -2161,6 +2259,7 @@ injection-regex = "task" file-types = ["task"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2185,6 +2284,7 @@ scope = "source.esdl" injection-regex = "esdl" file-types = ["esdl"] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } roots = ["edgedb.toml"] @@ -2199,6 +2299,7 @@ injection-regex = "pascal" file-types = ["pas", "pp", "inc", "lpr", "lfm"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "pasls" ] @@ -2212,6 +2313,7 @@ scope = "source.sml" injection-regex = "sml" file-types = ["sml"] comment-token = "(*" +comment-tokens = ["//"] roots = [] [[grammar]] @@ -2224,6 +2326,7 @@ scope = "source.jsonnet" file-types = ["libsonnet", "jsonnet"] roots = ["jsonnetfile.json"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "jsonnet-language-server" ] @@ -2250,6 +2353,7 @@ injection-regex = "bass" file-types = ["bass"] roots = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "bass" ] @@ -2261,6 +2365,7 @@ source = { git = "https://github.com/vito/tree-sitter-bass", rev = "501133e260d7 name = "wat" scope = "source.wat" comment-token = ";;" +comment-tokens = ["//"] file-types = ["wat"] roots = [] @@ -2272,6 +2377,7 @@ source = { git = "https://github.com/wasm-lsp/tree-sitter-wasm", rev = "2ca28a9f name = "wast" scope = "source.wast" comment-token = ";;" +comment-tokens = ["//"] file-types = ["wast"] roots = [] @@ -2285,6 +2391,7 @@ scope = "source.d" file-types = [ "d", "dd" ] roots = [] comment-token = "//" +comment-tokens = ["//"] injection-regex = "d" indent = { tab-width = 4, unit = " "} language-servers = [ "serve-d" ] @@ -2300,6 +2407,7 @@ scope = "source.vhs" file-types = ["tape"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } grammar = "vhs" @@ -2313,6 +2421,7 @@ scope = "source.kdl" file-types = ["kdl"] roots = [] comment-token = "//" +comment-tokens = ["//"] injection-regex = "kdl" [[grammar]] @@ -2421,6 +2530,7 @@ injection-regex = "wit" file-types = ["wit"] roots = [] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [language.auto-pairs] @@ -2441,6 +2551,7 @@ scope = "source.env" file-types = [".env", ".env.local", ".env.development", ".env.production", ".env.dist", ".envrc"] injection-regex = "env" comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } roots = [] grammar = "bash" @@ -2474,6 +2585,7 @@ file-types = [ ] injection-regex = "ini" comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } roots = [] @@ -2488,6 +2600,7 @@ file-types = ["bicep"] roots = [] auto-format = true comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " "} language-servers = [ "bicep-langserver" ] @@ -2515,6 +2628,7 @@ injection-regex = "mermaid" file-types = ["mermaid"] roots = [] comment-token = "%%" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } [[grammar]] @@ -2526,6 +2640,7 @@ name = "matlab" scope = "source.m" file-types = ["m"] comment-token = "%" +comment-tokens = ["//"] shebangs = ["octave-cli", "matlab"] roots = [] indent = { tab-width = 2, unit = " " } @@ -2542,6 +2657,7 @@ injection-regex = "pony" roots = ["corral.json", "lock.json"] indent = { tab-width = 2, unit = " " } comment-token = "//" +comment-tokens = ["//"] [[grammar]] name = "ponylang" @@ -2554,6 +2670,7 @@ injection-regex = "dhall" file-types = ["dhall"] roots = [] comment-token = "--" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "dhall-lsp-server" ] formatter = { command = "dhall" , args = ["format"] } @@ -2569,6 +2686,7 @@ file-types = ["sage"] injection-regex = "sage" roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } grammar = "python" @@ -2617,6 +2735,7 @@ scope = "source.hosts" file-types = ["hosts"] roots = [] comment-token = "#" +comment-tokens = ["//"] [[grammar]] name = "hosts" @@ -2630,6 +2749,7 @@ file-types = ["tal"] roots = [] auto-format = false comment-token = "(" +comment-tokens = ["//"] [[grammar]] name = "uxntal" @@ -2642,6 +2762,7 @@ injection-regex = "yuck" file-types = ["yuck"] roots = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2655,6 +2776,7 @@ injection-regex = "prql" file-types = ["prql"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } [[grammar]] @@ -2667,6 +2789,7 @@ scope = "source.po" file-types = ["po", "pot"] roots = [] comment-token = "#" +comment-tokens = ["//"] [[grammar]] name = "po" @@ -2679,6 +2802,7 @@ file-types = ["asm", "S", "nasm"] injection-regex = "n?asm" roots = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 8, unit = " " } [[grammar]] @@ -2692,6 +2816,7 @@ file-types = ["s"] injection-regex = "gas" roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 8, unit = " " } [[grammar]] @@ -2702,6 +2827,7 @@ source = { git = "https://github.com/sirius94/tree-sitter-gas", rev = "60f443646 name = "rst" scope = "source.rst" comment-token = ".." +comment-tokens = ["//"] file-types = ["rst"] roots = [] @@ -2716,6 +2842,7 @@ injection-regex = "capnp" file-types = ["capnp"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2729,6 +2856,7 @@ injection-regex = "smithy" file-types = ["smithy"] roots = ["smithy-build.json"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } language-servers = [ "cs" ] @@ -2742,6 +2870,7 @@ scope = "source.vhdl" file-types = ["vhd", "vhdl"] roots = [] comment-token = "--" +comment-tokens = ["//"] language-servers = [ "vhdl_ls" ] indent = { tab-width = 2, unit = " " } injection-regex = "vhdl" @@ -2758,6 +2887,7 @@ injection-regex = "rego" file-types = ["rego"] auto-format = true comment-token = "#" +comment-tokens = ["//"] language-servers = [ "regols" ] grammar = "rego" @@ -2773,6 +2903,7 @@ file-types = ["nim", "nims", "nimble"] shebangs = [] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } language-servers = [ "nimlangserver" ] @@ -2795,6 +2926,7 @@ file-types = [ "cabal" ] roots = ["cabal.project", "Setup.hs"] indent = { tab-width = 2, unit = " " } comment-token = "--" +comment-tokens = ["//"] [[language]] name = "hurl" @@ -2803,6 +2935,7 @@ injection-regex = "hurl" file-types = ["hurl"] roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2827,6 +2960,7 @@ injection-regex = "(cl|opencl)" file-types = ["cl"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "clangd" ] [[grammar]] @@ -2840,6 +2974,7 @@ file-types = ["justfile", "Justfile", ".justfile", ".Justfile"] injection-regex = "just" roots = [] comment-token = "#" +comment-tokens = ["//"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -2853,6 +2988,7 @@ injection-regex = "blueprint" file-types = ["blp"] roots = [] comment-token = "//" +comment-tokens = ["//"] language-servers = [ "blueprint-compiler" ] indent = { tab-width = 4, unit = " " } @@ -2867,6 +3003,7 @@ injection-regex = "forth" file-types = ["fs", "forth", "fth", "4th"] roots = [] comment-token = "\\" +comment-tokens = ["//"] language-servers = [ "forth-lsp" ] indent = { tab-width = 3, unit = " " } @@ -2881,6 +3018,7 @@ roots = ["sln", "fsproj"] injection-regex = "fsharp" file-types = ["fs", "fsx", "fsi", "fsscript"] comment-token = "//" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } auto-format = true language-servers = ["fsharp-ls"] @@ -2896,6 +3034,7 @@ injection-regex = "t32" file-types = ["cmm", "t32"] roots = [] comment-token = ";" +comment-tokens = ["//"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2954,6 +3093,7 @@ shebangs = [] roots = [] auto-format = false comment-token = "--" +comment-tokens = ["//"] indent = { tab-width = 4, unit = " " } [language.auto-pairs] From adda26683fce856d6504e831d7c48244159ae261 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 12:34:50 -0500 Subject: [PATCH 06/59] Add additional comment tokens for Rust --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 0a71144f652a..2aba7613a1b4 100644 --- a/languages.toml +++ b/languages.toml @@ -179,7 +179,7 @@ file-types = ["rs"] roots = ["Cargo.toml", "Cargo.lock"] auto-format = true comment-token = "//" -comment-tokens = ["//"] +comment-tokens = ["//", "///", "//!"] language-servers = [ "rust-analyzer" ] indent = { tab-width = 4, unit = " " } From be9224e3364bfff3a5baeee1eafe03b75e93dd04 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 13:20:27 -0500 Subject: [PATCH 07/59] Match all comment-tokens fields with comment-token fields --- languages.toml | 176 ++++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/languages.toml b/languages.toml index 2aba7613a1b4..14a413cbaaa2 100644 --- a/languages.toml +++ b/languages.toml @@ -245,7 +245,7 @@ injection-regex = "toml" file-types = ["toml", "poetry.lock", "Cargo.lock"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "taplo" ] indent = { tab-width = 2, unit = " " } @@ -260,7 +260,7 @@ injection-regex = "awk" file-types = ["awk", "gawk", "nawk", "mawk"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "awk-language-server" ] indent = { tab-width = 2, unit = " " } @@ -291,7 +291,7 @@ file-types = ["ex", "exs", "mix.lock"] shebangs = ["elixir"] roots = ["mix.exs", "mix.lock"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "elixir-ls" ] indent = { tab-width = 2, unit = " " } @@ -459,7 +459,7 @@ scope = "source.cr" file-types = ["cr"] roots = ["shard.yml", "shard.lock"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } grammar = "ruby" language-servers = [ "crystalline" ] @@ -720,7 +720,7 @@ file-types = ["py","pyi","py3","pyw","ptl",".pythonstartup",".pythonrc","SConstr shebangs = ["python"] roots = ["pyproject.toml", "setup.py", "poetry.lock", "pyrightconfig.json"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "pylsp" ] # TODO: pyls needs utf-8 offsets indent = { tab-width = 4, unit = " " } @@ -737,7 +737,7 @@ file-types = ["ncl"] shebangs = [] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "nls" ] indent = { tab-width = 2, unit = " " } @@ -759,7 +759,7 @@ file-types = ["nix"] shebangs = [] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "nil" ] indent = { tab-width = 2, unit = " " } @@ -810,7 +810,7 @@ file-types = [ shebangs = ["ruby"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "solargraph" ] indent = { tab-width = 2, unit = " " } @@ -866,7 +866,7 @@ file-types = [ shebangs = ["sh", "bash", "dash", "zsh"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "bash-language-server" ] indent = { tab-width = 2, unit = " " } @@ -907,7 +907,7 @@ injection-regex = "tex" file-types = ["tex", "sty", "cls", "Rd", "bbx", "cbx"] roots = [] comment-token = "%" -comment-tokens = ["//"] +comment-tokens = ["%"] language-servers = [ "texlab" ] indent = { tab-width = 4, unit = "\t" } @@ -922,7 +922,7 @@ injection-regex = "bib" file-types = ["bib"] roots = [] comment-token = "%" -comment-tokens = ["//"] +comment-tokens = ["%"] language-servers = [ "texlab" ] indent = { tab-width = 4, unit = "\t" } auto-format = true @@ -951,7 +951,7 @@ injection-regex = "lean" file-types = ["lean"] roots = [ "lakefile.lean" ] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] language-servers = [ "lean" ] indent = { tab-width = 2, unit = " " } @@ -967,7 +967,7 @@ file-types = ["jl"] shebangs = ["julia"] roots = ["Manifest.toml", "Project.toml"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "julia" ] indent = { tab-width = 4, unit = " " } @@ -995,7 +995,7 @@ injection-regex = "ledger" file-types = ["ldg", "ledger", "journal"] roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 4, unit = " " } [[grammar]] @@ -1009,7 +1009,7 @@ injection-regex = "beancount" file-types = ["beancount", "bean"] roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1024,7 +1024,7 @@ file-types = ["ml"] shebangs = ["ocaml", "ocamlrun", "ocamlscript"] roots = [] comment-token = "(**)" -comment-tokens = ["//"] +comment-tokens = ["(**)"] language-servers = [ "ocamllsp" ] indent = { tab-width = 2, unit = " " } @@ -1045,7 +1045,7 @@ file-types = ["mli"] shebangs = [] roots = [] comment-token = "(**)" -comment-tokens = ["//"] +comment-tokens = ["(**)"] language-servers = [ "ocamllsp" ] indent = { tab-width = 2, unit = " " } @@ -1067,7 +1067,7 @@ file-types = ["lua"] shebangs = ["lua"] roots = [".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git"] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] indent = { tab-width = 2, unit = " " } language-servers = [ "lua-language-server" ] @@ -1107,7 +1107,7 @@ scope = "source.yaml" file-types = ["yml", "yaml"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "yaml-language-server", "ansible-language-server" ] injection-regex = "yml|yaml" @@ -1123,7 +1123,7 @@ injection-regex = "haskell" file-types = ["hs", "hs-boot"] roots = ["Setup.hs", "stack.yaml", "cabal.project"] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] language-servers = [ "haskell-language-server" ] indent = { tab-width = 2, unit = " " } @@ -1137,7 +1137,7 @@ scope = "source.persistentmodels" file-types = ["persistentmodels"] roots = [] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1151,7 +1151,7 @@ injection-regex = "purescript" file-types = ["purs"] roots = ["spago.dhall", "bower.json"] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] language-servers = [ "purescript-language-server" ] indent = { tab-width = 2, unit = " " } auto-format = true @@ -1208,7 +1208,7 @@ roots = [] file-types = ["pl", "prolog"] shebangs = ["swipl"] comment-token = "%" -comment-tokens = ["//"] +comment-tokens = ["%"] language-servers = [ "swipl" ] [[language]] @@ -1217,7 +1217,7 @@ scope = "source.tsq" file-types = ["tsq"] roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] injection-regex = "tsq" indent = { tab-width = 2, unit = " " } @@ -1231,7 +1231,7 @@ scope = "source.cmake" file-types = ["cmake", "CMakeLists.txt"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "cmake-language-server" ] injection-regex = "cmake" @@ -1248,7 +1248,7 @@ shebangs = ["make", "gmake"] injection-regex = "(make|makefile|Makefile|mk)" roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1276,7 +1276,7 @@ file-types = ["pl", "pm", "t", "psgi", "raku", "rakumod", "rakutest", "rakudoc", shebangs = ["perl"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "perlnavigator" ] indent = { tab-width = 2, unit = " " } @@ -1302,7 +1302,7 @@ roots = [] file-types = ["rkt", "rktd", "rktl", "scrbl"] shebangs = ["racket"] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] language-servers = [ "racket" ] grammar = "scheme" @@ -1313,7 +1313,7 @@ roots = [] file-types = ["lisp", "asd", "cl", "l", "lsp", "ny", "podsl", "sexp"] shebangs = ["lisp", "sbcl", "ccl", "clisp", "ecl"] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } language-servers = [ "cl-lsp" ] grammar = "scheme" @@ -1355,7 +1355,7 @@ scope = "source.llvm" roots = [] file-types = ["ll"] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } injection-regex = "llvm" @@ -1369,7 +1369,7 @@ scope = "source.llvm_mir" roots = [] file-types = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } injection-regex = "mir" @@ -1386,7 +1386,7 @@ scope = "source.yaml" roots = [] file-types = ["mir"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } [[language]] @@ -1464,7 +1464,7 @@ injection-regex = "docker|dockerfile" roots = ["Dockerfile", "Containerfile"] file-types = ["Dockerfile", "dockerfile", "Containerfile", "containerfile"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "docker-langserver" ] @@ -1478,7 +1478,7 @@ scope = "git.commitmsg" roots = [] file-types = ["COMMIT_EDITMSG"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } rulers = [51, 73] text-width = 72 @@ -1494,7 +1494,7 @@ roots = [] file-types = ["diff", "patch", "rej"] injection-regex = "diff" comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -1508,7 +1508,7 @@ roots = [] file-types = ["git-rebase-todo"] injection-regex = "git-rebase" comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = "y" } [[grammar]] @@ -1533,7 +1533,7 @@ roots = [] file-types = [".gitmodules", ".gitconfig", { suffix = ".git/config" }, { suffix = ".config/git/config" }] injection-regex = "git-config" comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1547,7 +1547,7 @@ roots = [] file-types = [".gitattributes"] injection-regex = "git-attributes" comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] grammar = "gitattributes" [[grammar]] @@ -1561,7 +1561,7 @@ roots = [] file-types = [".gitignore", ".gitignore_global", ".ignore", ".prettierignore", ".eslintignore", ".npmignore", "CODEOWNERS"] injection-regex = "git-ignore" comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] grammar = "gitignore" [[grammar]] @@ -1589,7 +1589,7 @@ file-types = ["elm"] roots = ["elm.json"] auto-format = true comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] language-servers = [ "elm-language-server" ] indent = { tab-width = 4, unit = " " } @@ -1632,7 +1632,7 @@ file-types = ["erl", "hrl", "app", "rebar.config", "rebar.lock"] roots = ["rebar.config"] shebangs = ["escript"] comment-token = "%%" -comment-tokens = ["//"] +comment-tokens = ["%%"] indent = { tab-width = 4, unit = " " } language-servers = [ "erlang-ls" ] @@ -1670,7 +1670,7 @@ language-id = "terraform" file-types = ["hcl", "tf", "nomad"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "terraform-ls" ] auto-format = true @@ -1686,7 +1686,7 @@ language-id = "terraform-vars" file-types = ["tfvars"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "terraform-ls" ] auto-format = true @@ -1752,7 +1752,7 @@ scope = "source.robot" injection-regex = "robot" file-types = ["robot", "resource"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] roots = [] indent = { tab-width = 4, unit = " " } language-servers = [ "robotframework_ls" ] @@ -1769,7 +1769,7 @@ file-types = ["r", "R", ".Rprofile", "Rprofile.site", ".RHistory"] shebangs = ["r", "R"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "r" ] @@ -1855,7 +1855,7 @@ scope = "source.sql" file-types = ["sql", "dsql"] roots = [] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] indent = { tab-width = 4, unit = " " } injection-regex = "sql" @@ -1873,7 +1873,7 @@ roots = ["project.godot"] auto-format = true formatter = { command = "gdformat", args = ["-"] } comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1889,7 +1889,7 @@ shebangs = [] roots = ["project.godot"] auto-format = false comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -1904,7 +1904,7 @@ file-types = ["nu"] shebangs = ["nu"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2004,7 +2004,7 @@ injection-regex = "meson" file-types = ["meson.build"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2017,7 +2017,7 @@ scope = "source.sshclientconfig" file-types = [{ suffix = ".ssh/config" }, { suffix = "/etc/ssh/ssh_config" }] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] [[grammar]] name = "sshclientconfig" @@ -2031,7 +2031,7 @@ file-types = ["ss", "scm"] shebangs = ["scheme", "guile", "chicken"] roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2130,7 +2130,7 @@ injection-regex = "(clojure|clj|edn|boot)" file-types = ["clj", "cljs", "cljc", "clje", "cljr", "cljx", "edn", "boot"] roots = ["project.clj", "build.boot", "deps.edn", "shadow-cljs.edn"] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] language-servers = [ "clojure-lsp" ] indent = { tab-width = 2, unit = " " } @@ -2145,7 +2145,7 @@ injection-regex = "(starlark|bzl|bazel)" file-types = ["bzl", "bazel", "BUILD", "star"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = " " } grammar = "python" @@ -2155,7 +2155,7 @@ scope = "source.elvish" file-types = ["elv"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "elvish" ] grammar = "elvish" @@ -2172,7 +2172,7 @@ file-types = ["idr"] shebangs = [] roots = [] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] indent = { tab-width = 2, unit = " " } language-servers = [ "idris2-lsp" ] @@ -2183,7 +2183,7 @@ injection-regex = "fortran" file-types = ["f", "for", "f90", "f95", "f03"] roots = ["fpm.toml"] comment-token = "!" -comment-tokens = ["//"] +comment-tokens = ["!"] indent = { tab-width = 4, unit = " "} language-servers = [ "fortls" ] @@ -2259,7 +2259,7 @@ injection-regex = "task" file-types = ["task"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2284,7 +2284,7 @@ scope = "source.esdl" injection-regex = "esdl" file-types = ["esdl"] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } roots = ["edgedb.toml"] @@ -2313,7 +2313,7 @@ scope = "source.sml" injection-regex = "sml" file-types = ["sml"] comment-token = "(*" -comment-tokens = ["//"] +comment-tokens = ["(*"] roots = [] [[grammar]] @@ -2353,7 +2353,7 @@ injection-regex = "bass" file-types = ["bass"] roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } language-servers = [ "bass" ] @@ -2365,7 +2365,7 @@ source = { git = "https://github.com/vito/tree-sitter-bass", rev = "501133e260d7 name = "wat" scope = "source.wat" comment-token = ";;" -comment-tokens = ["//"] +comment-tokens = [";;"] file-types = ["wat"] roots = [] @@ -2377,7 +2377,7 @@ source = { git = "https://github.com/wasm-lsp/tree-sitter-wasm", rev = "2ca28a9f name = "wast" scope = "source.wast" comment-token = ";;" -comment-tokens = ["//"] +comment-tokens = [";;"] file-types = ["wast"] roots = [] @@ -2407,7 +2407,7 @@ scope = "source.vhs" file-types = ["tape"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } grammar = "vhs" @@ -2551,7 +2551,7 @@ scope = "source.env" file-types = [".env", ".env.local", ".env.development", ".env.production", ".env.dist", ".envrc"] injection-regex = "env" comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = "\t" } roots = [] grammar = "bash" @@ -2585,7 +2585,7 @@ file-types = [ ] injection-regex = "ini" comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = "\t" } roots = [] @@ -2628,7 +2628,7 @@ injection-regex = "mermaid" file-types = ["mermaid"] roots = [] comment-token = "%%" -comment-tokens = ["//"] +comment-tokens = ["%%"] indent = { tab-width = 4, unit = " " } [[grammar]] @@ -2640,7 +2640,7 @@ name = "matlab" scope = "source.m" file-types = ["m"] comment-token = "%" -comment-tokens = ["//"] +comment-tokens = ["%"] shebangs = ["octave-cli", "matlab"] roots = [] indent = { tab-width = 2, unit = " " } @@ -2670,7 +2670,7 @@ injection-regex = "dhall" file-types = ["dhall"] roots = [] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] indent = { tab-width = 2, unit = " " } language-servers = [ "dhall-lsp-server" ] formatter = { command = "dhall" , args = ["format"] } @@ -2686,7 +2686,7 @@ file-types = ["sage"] injection-regex = "sage" roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = " " } grammar = "python" @@ -2735,7 +2735,7 @@ scope = "source.hosts" file-types = ["hosts"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] [[grammar]] name = "hosts" @@ -2749,7 +2749,7 @@ file-types = ["tal"] roots = [] auto-format = false comment-token = "(" -comment-tokens = ["//"] +comment-tokens = ["("] [[grammar]] name = "uxntal" @@ -2762,7 +2762,7 @@ injection-regex = "yuck" file-types = ["yuck"] roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2776,7 +2776,7 @@ injection-regex = "prql" file-types = ["prql"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = " " } [[grammar]] @@ -2789,7 +2789,7 @@ scope = "source.po" file-types = ["po", "pot"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] [[grammar]] name = "po" @@ -2802,7 +2802,7 @@ file-types = ["asm", "S", "nasm"] injection-regex = "n?asm" roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 8, unit = " " } [[grammar]] @@ -2816,7 +2816,7 @@ file-types = ["s"] injection-regex = "gas" roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 8, unit = " " } [[grammar]] @@ -2827,7 +2827,7 @@ source = { git = "https://github.com/sirius94/tree-sitter-gas", rev = "60f443646 name = "rst" scope = "source.rst" comment-token = ".." -comment-tokens = ["//"] +comment-tokens = [".."] file-types = ["rst"] roots = [] @@ -2842,7 +2842,7 @@ injection-regex = "capnp" file-types = ["capnp"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2870,7 +2870,7 @@ scope = "source.vhdl" file-types = ["vhd", "vhdl"] roots = [] comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] language-servers = [ "vhdl_ls" ] indent = { tab-width = 2, unit = " " } injection-regex = "vhdl" @@ -2887,7 +2887,7 @@ injection-regex = "rego" file-types = ["rego"] auto-format = true comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] language-servers = [ "regols" ] grammar = "rego" @@ -2903,7 +2903,7 @@ file-types = ["nim", "nims", "nimble"] shebangs = [] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } language-servers = [ "nimlangserver" ] @@ -2926,7 +2926,7 @@ file-types = [ "cabal" ] roots = ["cabal.project", "Setup.hs"] indent = { tab-width = 2, unit = " " } comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] [[language]] name = "hurl" @@ -2935,7 +2935,7 @@ injection-regex = "hurl" file-types = ["hurl"] roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -2974,7 +2974,7 @@ file-types = ["justfile", "Justfile", ".justfile", ".Justfile"] injection-regex = "just" roots = [] comment-token = "#" -comment-tokens = ["//"] +comment-tokens = ["#"] indent = { tab-width = 4, unit = "\t" } [[grammar]] @@ -3003,7 +3003,7 @@ injection-regex = "forth" file-types = ["fs", "forth", "fth", "4th"] roots = [] comment-token = "\\" -comment-tokens = ["//"] +comment-tokens = ["\\"] language-servers = [ "forth-lsp" ] indent = { tab-width = 3, unit = " " } @@ -3034,7 +3034,7 @@ injection-regex = "t32" file-types = ["cmm", "t32"] roots = [] comment-token = ";" -comment-tokens = ["//"] +comment-tokens = [";"] indent = { tab-width = 2, unit = " " } [[grammar]] @@ -3093,7 +3093,7 @@ shebangs = [] roots = [] auto-format = false comment-token = "--" -comment-tokens = ["//"] +comment-tokens = ["--"] indent = { tab-width = 4, unit = " " } [language.auto-pairs] From e77d15d06ee7bcabcdef4621aa056fdd547d80fb Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Oct 2023 13:56:15 -0500 Subject: [PATCH 08/59] Refactor continue comment function to also return position of comment token --- helix-core/src/chars.rs | 10 ++++++ helix-core/src/comment.rs | 63 ++++++++++++++++++++++++++------------ helix-core/src/lib.rs | 3 -- helix-core/tests/indent.rs | 2 +- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index 817bbb86b40c..f09b1d648289 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -1,5 +1,7 @@ //! Utility functions to categorize a `char`. +use ropey::RopeSlice; + use crate::LineEnding; #[derive(Debug, Eq, PartialEq)] @@ -85,6 +87,14 @@ pub fn char_is_word(ch: char) -> bool { ch.is_alphanumeric() || ch == '_' } +pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { + line.chars().position(|ch| !ch.is_whitespace()) +} + +pub fn count_whitespace_after(_line: RopeSlice) -> Option { + None +} + #[cfg(test)] mod test { use super::*; diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 08df27c2766d..5011ed69bbcd 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -3,9 +3,7 @@ //! * toggle comments on lines over the selection //! * continue comment when opening a new line -use crate::{ - find_first_non_whitespace_char, Change, Rope, RopeSlice, Selection, Tendril, Transaction, -}; +use crate::{chars, Change, Rope, RopeSlice, Selection, Tendril, Transaction}; use std::borrow::Cow; /// Given text, a comment token, and a set of line indices, returns the following: @@ -29,7 +27,7 @@ fn find_line_comment( let token_len = token.chars().count(); for line in lines { let line_slice = text.line(line); - if let Some(pos) = find_first_non_whitespace_char(line_slice) { + if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { let len = line_slice.len_chars(); if pos < min { @@ -96,13 +94,14 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st Transaction::change(doc, changes.into_iter()) } -/// Return the comment token of the current line if it is commented. +/// Return the comment token of the current line if it is commented, along with the +/// position of the last character in the comment token. /// Return None otherwise. -pub fn continue_single_comment<'a>( +pub fn get_comment_token_and_position<'a>( doc: &Rope, line: usize, tokens: &'a [String], -) -> Option<&'a str> { +) -> Option<(&'a str, usize)> { // TODO: don't continue shebangs if tokens.is_empty() { return None; @@ -111,7 +110,7 @@ pub fn continue_single_comment<'a>( let mut result = None; let line_slice = doc.line(line); - if let Some(pos) = find_first_non_whitespace_char(line_slice) { + if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { let len = line_slice.len_chars(); for token in tokens { @@ -122,7 +121,7 @@ pub fn continue_single_comment<'a>( // We don't necessarily want to break upon finding the first matching comment token // Instead, we check against all of the comment tokens and end up returning the longest // comment token that matches - result = Some(token.as_str()); + result = Some((token.as_str(), pos + token.len() - 1)); } } } @@ -187,16 +186,40 @@ mod test { } #[test] - fn test_continue_single_comment() { - let doc = Rope::from("# 1\n // 2 \n///3\n/// 4\n//! 5\n//! /// 6\n7 ///"); - let tokens = vec![String::from("//"), String::from("///"), String::from("//!")]; - - assert_eq!(continue_single_comment(&doc, 0, &tokens), None); - assert_eq!(continue_single_comment(&doc, 1, &tokens), Some("//")); - assert_eq!(continue_single_comment(&doc, 2, &tokens), Some("///")); - assert_eq!(continue_single_comment(&doc, 3, &tokens), Some("///")); - assert_eq!(continue_single_comment(&doc, 4, &tokens), Some("//!")); - assert_eq!(continue_single_comment(&doc, 5, &tokens), Some("//!")); - assert_eq!(continue_single_comment(&doc, 6, &tokens), None); + fn test_get_comment_token_and_position() { + let doc = Rope::from("# 1\n // 2 \n///3\n/// 4\n//! 5\n//! /// 6\n7 ///\n;"); + let tokens = vec![ + String::from("//"), + String::from("///"), + String::from("//!"), + String::from(";"), + ]; + + assert_eq!(get_comment_token_and_position(&doc, 0, &tokens), None); + assert_eq!( + get_comment_token_and_position(&doc, 1, &tokens), + Some(("//", 5)) + ); + assert_eq!( + get_comment_token_and_position(&doc, 2, &tokens), + Some(("///", 2)) + ); + assert_eq!( + get_comment_token_and_position(&doc, 3, &tokens), + Some(("///", 2)) + ); + assert_eq!( + get_comment_token_and_position(&doc, 4, &tokens), + Some(("//!", 2)) + ); + assert_eq!( + get_comment_token_and_position(&doc, 5, &tokens), + Some(("//!", 2)) + ); + assert_eq!(get_comment_token_and_position(&doc, 6, &tokens), None); + assert_eq!( + get_comment_token_and_position(&doc, 7, &tokens), + Some((";", 0)) + ); } } diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 0acdb238054c..802edf0d874c 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -38,9 +38,6 @@ pub mod unicode { pub use helix_loader::find_workspace; -pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { - line.chars().position(|ch| !ch.is_whitespace()) -} mod rope_reader; pub use rope_reader::RopeReader; diff --git a/helix-core/tests/indent.rs b/helix-core/tests/indent.rs index 26010c906ae1..ce969ea13aef 100644 --- a/helix-core/tests/indent.rs +++ b/helix-core/tests/indent.rs @@ -205,7 +205,7 @@ fn test_treesitter_indent( if ignored_lines.iter().any(|range| range.contains(&(i + 1))) { continue; } - if let Some(pos) = helix_core::find_first_non_whitespace_char(line) { + if let Some(pos) = helix_core::chars::find_first_non_whitespace_char(line) { let tab_width: usize = 4; let suggested_indent = treesitter_indent_for_pos( indent_query, From 751d15d210455bd1045ccbac2f8088cb22ecda7a Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Sun, 22 Oct 2023 09:55:16 -0500 Subject: [PATCH 09/59] Update calls to find_first_non_whitespace_char --- helix-core/src/chars.rs | 16 +++++++++++----- helix-core/src/comment.rs | 12 +++++++++--- helix-core/tests/indent.rs | 2 +- helix-term/src/commands.rs | 16 ++++++++-------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index f09b1d648289..25b306f13489 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -87,12 +87,18 @@ pub fn char_is_word(ch: char) -> bool { ch.is_alphanumeric() || ch == '_' } -pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { - line.chars().position(|ch| !ch.is_whitespace()) -} +/// Find the first non-whitespace character in the line starting at the specified +/// position in the line. +/// +/// Returns None if the specified position index is out of the bounds on the line. +pub fn find_first_non_whitespace_char(line: RopeSlice, pos: usize) -> Option { + let len = line.len_chars(); + + if pos >= len { + return None; + } -pub fn count_whitespace_after(_line: RopeSlice) -> Option { - None + line.chars_at(pos).position(|ch| !ch.is_whitespace()) } #[cfg(test)] diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 5011ed69bbcd..71d17723930a 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -27,7 +27,7 @@ fn find_line_comment( let token_len = token.chars().count(); for line in lines { let line_slice = text.line(line); - if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { + if let Some(pos) = chars::find_first_non_whitespace_char(line_slice, 0) { let len = line_slice.len_chars(); if pos < min { @@ -110,7 +110,7 @@ pub fn get_comment_token_and_position<'a>( let mut result = None; let line_slice = doc.line(line); - if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { + if let Some(pos) = chars::find_first_non_whitespace_char(line_slice, 0) { let len = line_slice.len_chars(); for token in tokens { @@ -187,7 +187,9 @@ mod test { #[test] fn test_get_comment_token_and_position() { - let doc = Rope::from("# 1\n // 2 \n///3\n/// 4\n//! 5\n//! /// 6\n7 ///\n;"); + let doc = Rope::from( + "# 1\n // 2 \n///3\n/// 4\n//! 5\n//! /// 6\n7 ///\n;8\n//////////// 9", + ); let tokens = vec![ String::from("//"), String::from("///"), @@ -221,5 +223,9 @@ mod test { get_comment_token_and_position(&doc, 7, &tokens), Some((";", 0)) ); + assert_eq!( + get_comment_token_and_position(&doc, 8, &tokens), + Some(("///", 2)) + ); } } diff --git a/helix-core/tests/indent.rs b/helix-core/tests/indent.rs index ce969ea13aef..35c52b47955d 100644 --- a/helix-core/tests/indent.rs +++ b/helix-core/tests/indent.rs @@ -205,7 +205,7 @@ fn test_treesitter_indent( if ignored_lines.iter().any(|range| range.contains(&(i + 1))) { continue; } - if let Some(pos) = helix_core::chars::find_first_non_whitespace_char(line) { + if let Some(pos) = helix_core::chars::find_first_non_whitespace_char(line, 0) { let tab_width: usize = 4; let suggested_indent = treesitter_indent_for_pos( indent_query, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b252fd512325..da8a75ef0b6c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -10,9 +10,9 @@ use tui::widgets::Row; pub use typed::*; use helix_core::{ - char_idx_at_visual_offset, comment, + char_idx_at_visual_offset, chars, comment, doc_formatter::TextFormat, - encoding, find_first_non_whitespace_char, find_workspace, graphemes, + encoding, find_workspace, graphemes, history::UndoKind, increment, indent, indent::IndentStyle, @@ -814,7 +814,7 @@ fn kill_to_line_start(cx: &mut Context) { let head = if anchor == first_char && line != 0 { // select until previous line line_end_char_index(&text, line - 1) - } else if let Some(pos) = find_first_non_whitespace_char(text.line(line)) { + } else if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line), 0) { if first_char + pos < anchor { // select until first non-blank in line if cursor is after it first_char + pos @@ -876,7 +876,7 @@ fn goto_first_nonwhitespace_impl(view: &mut View, doc: &mut Document, movement: let selection = doc.selection(view.id).clone().transform(|range| { let line = range.cursor_line(text); - if let Some(pos) = find_first_non_whitespace_char(text.line(line)) { + if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line), 0) { let pos = pos + text.line_to_char(line); range.put_cursor(text, pos, movement == Movement::Extend) } else { @@ -2997,7 +2997,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { // move cursor to the fallback position let pos = match cursor_fallback { IndentFallbackPos::LineStart => { - find_first_non_whitespace_char(text.line(cursor_line)) + chars::find_first_non_whitespace_char(text.line(cursor_line), 0) .map(|ws_offset| ws_offset + cursor_line_start) .unwrap_or(cursor_line_start) } @@ -3151,9 +3151,10 @@ fn handle_comment_continue(doc: &Document, text: &mut String, cursor_line: usize if let Some(lang_config) = doc.language_config() { let line_comment_tokens = &lang_config.comment_tokens; - if let Some(token) = - comment::continue_single_comment(doc.text(), cursor_line, line_comment_tokens) + if let Some((token, pos)) = + comment::get_comment_token_and_position(doc.text(), cursor_line, line_comment_tokens) { + let trailing_whitespace = chars::find_first_non_whitespace_char(cursor_line, pos) - pos; text.push_str(token); text.push(' '); } @@ -4531,7 +4532,6 @@ pub fn completion(cx: &mut Context) { // TODO: trigger_offset should be the cursor offset but we also need a starting offset from where we want to apply // completion filtering. For example logger.te| should filter the initial suggestion list with "te". - use helix_core::chars; let mut iter = text.chars_at(cursor); iter.reverse(); let offset = iter.take_while(|ch| chars::char_is_word(*ch)).count(); From 43159063555e864fdc2c70b7f1930499a67986da Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Sun, 22 Oct 2023 10:33:38 -0500 Subject: [PATCH 10/59] Continue single comments with indentation --- helix-term/src/commands.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index da8a75ef0b6c..be4e3c6e3741 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3151,12 +3151,25 @@ fn handle_comment_continue(doc: &Document, text: &mut String, cursor_line: usize if let Some(lang_config) = doc.language_config() { let line_comment_tokens = &lang_config.comment_tokens; - if let Some((token, pos)) = + if let Some((token, comment_token_ending_pos)) = comment::get_comment_token_and_position(doc.text(), cursor_line, line_comment_tokens) { - let trailing_whitespace = chars::find_first_non_whitespace_char(cursor_line, pos) - pos; text.push_str(token); - text.push(' '); + + // find the position of the first non-whitespace char after the commet token + // so that lines that continue a comment are indented to the same level as the + // previous line + if let Some(first_char_pos) = chars::find_first_non_whitespace_char( + doc.text().line(cursor_line), + comment_token_ending_pos, + ) { + let trailing_whitespace = first_char_pos - comment_token_ending_pos; + let whitespace = (0..trailing_whitespace).map(|_| ' ').collect::(); + + text.push_str(&whitespace); + } else { + text.push(' '); + } } } } From 0d224e55c818a031bc08bf917665dd2d9c432cc0 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Tue, 24 Oct 2023 08:38:02 -0500 Subject: [PATCH 11/59] Implement `count_whitespace_after` fn --- helix-core/src/chars.rs | 35 ++++++++++++++++++---- helix-core/src/comment.rs | 59 ++++++++++++++++++++++++++++++++++++-- helix-core/tests/indent.rs | 2 +- helix-term/src/commands.rs | 27 +++-------------- 4 files changed, 91 insertions(+), 32 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index 25b306f13489..ad78c5048e91 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -87,18 +87,27 @@ pub fn char_is_word(ch: char) -> bool { ch.is_alphanumeric() || ch == '_' } -/// Find the first non-whitespace character in the line starting at the specified -/// position in the line. +/// Find the first non-whitespace character in the line. +pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { + line.chars().position(|ch| !ch.is_whitespace()) +} + +/// Count how much whitespace there is starting at the specified index in the line. /// -/// Returns None if the specified position index is out of the bounds on the line. -pub fn find_first_non_whitespace_char(line: RopeSlice, pos: usize) -> Option { +/// Returns None if the specified starting index >= the length of the line. +pub fn count_whitespace_after(line: RopeSlice, starting_idx: usize) -> Option { let len = line.len_chars(); - if pos >= len { + if starting_idx >= len { return None; } - line.chars_at(pos).position(|ch| !ch.is_whitespace()) + let count = line + .chars_at(starting_idx + 1) + .take_while(|ch| ch.is_whitespace()) + .count(); + + Some(count) } #[cfg(test)] @@ -150,4 +159,18 @@ mod test { ); } } + + #[test] + fn test_count_whitespace_after() { + let mut line = RopeSlice::from("a 1"); + + assert_eq!(count_whitespace_after(line, 0), Some(7)); + assert_eq!(count_whitespace_after(line, 3), Some(4)); + assert_eq!(count_whitespace_after(line, 8), Some(0)); + assert_eq!(count_whitespace_after(line, 10), None); + + line = RopeSlice::from("1\n 2"); + + assert_eq!(count_whitespace_after(line, 0), Some(7)); + } } diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 71d17723930a..5037d4758ce0 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -27,7 +27,7 @@ fn find_line_comment( let token_len = token.chars().count(); for line in lines { let line_slice = text.line(line); - if let Some(pos) = chars::find_first_non_whitespace_char(line_slice, 0) { + if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { let len = line_slice.len_chars(); if pos < min { @@ -110,7 +110,7 @@ pub fn get_comment_token_and_position<'a>( let mut result = None; let line_slice = doc.line(line); - if let Some(pos) = chars::find_first_non_whitespace_char(line_slice, 0) { + if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { let len = line_slice.len_chars(); for token in tokens { @@ -129,6 +129,33 @@ pub fn get_comment_token_and_position<'a>( result } +/// Determines whether the new line following the line at `line_idx` in +/// document should be prepended with a comment token. +pub fn handle_comment_continue<'a>( + doc: &'a Rope, + text: &'a mut String, + line_idx: usize, + comment_tokens: &'a [String], +) { + if let Some((token, comment_token_ending_pos)) = + get_comment_token_and_position(doc, line_idx, comment_tokens) + { + text.push_str(token); + + // find the position of the first non-whitespace char after the commet token so that + // lines that continue a comment are indented to the same level as the previous line + if let Some(trailing_whitespace) = + chars::count_whitespace_after(doc.line(line_idx), comment_token_ending_pos) + { + let whitespace_to_insert = (0..=trailing_whitespace).map(|_| ' ').collect::(); + + text.push_str(&whitespace_to_insert); + } else { + text.push(' '); + } + } +} + #[cfg(test)] mod test { use super::*; @@ -228,4 +255,32 @@ mod test { Some(("///", 2)) ); } + + #[test] + fn test_handle_continue_comment() { + let mut doc = Rope::from("// 1\n"); + let mut text = String::from(&doc); + let comment_tokens = vec![String::from("//"), String::from("///")]; + + handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + + assert_eq!(text, String::from("// 1\n// ")); + + doc = Rope::from("///2\n"); + text = String::from(&doc); + + handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + + assert_eq!(text, String::from("///2\n/// ")); + + doc = Rope::from(" // 3\n"); + text = String::from(&doc); + + handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + + doc = Rope::from("/// 4\n"); + text = String::from(&doc); + + handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + } } diff --git a/helix-core/tests/indent.rs b/helix-core/tests/indent.rs index 35c52b47955d..ce969ea13aef 100644 --- a/helix-core/tests/indent.rs +++ b/helix-core/tests/indent.rs @@ -205,7 +205,7 @@ fn test_treesitter_indent( if ignored_lines.iter().any(|range| range.contains(&(i + 1))) { continue; } - if let Some(pos) = helix_core::chars::find_first_non_whitespace_char(line, 0) { + if let Some(pos) = helix_core::chars::find_first_non_whitespace_char(line) { let tab_width: usize = 4; let suggested_indent = treesitter_indent_for_pos( indent_query, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index be4e3c6e3741..931a2ccd2327 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -814,7 +814,7 @@ fn kill_to_line_start(cx: &mut Context) { let head = if anchor == first_char && line != 0 { // select until previous line line_end_char_index(&text, line - 1) - } else if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line), 0) { + } else if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line)) { if first_char + pos < anchor { // select until first non-blank in line if cursor is after it first_char + pos @@ -876,7 +876,7 @@ fn goto_first_nonwhitespace_impl(view: &mut View, doc: &mut Document, movement: let selection = doc.selection(view.id).clone().transform(|range| { let line = range.cursor_line(text); - if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line), 0) { + if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line)) { let pos = pos + text.line_to_char(line); range.put_cursor(text, pos, movement == Movement::Extend) } else { @@ -2997,7 +2997,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { // move cursor to the fallback position let pos = match cursor_fallback { IndentFallbackPos::LineStart => { - chars::find_first_non_whitespace_char(text.line(cursor_line), 0) + chars::find_first_non_whitespace_char(text.line(cursor_line)) .map(|ws_offset| ws_offset + cursor_line_start) .unwrap_or(cursor_line_start) } @@ -3151,26 +3151,7 @@ fn handle_comment_continue(doc: &Document, text: &mut String, cursor_line: usize if let Some(lang_config) = doc.language_config() { let line_comment_tokens = &lang_config.comment_tokens; - if let Some((token, comment_token_ending_pos)) = - comment::get_comment_token_and_position(doc.text(), cursor_line, line_comment_tokens) - { - text.push_str(token); - - // find the position of the first non-whitespace char after the commet token - // so that lines that continue a comment are indented to the same level as the - // previous line - if let Some(first_char_pos) = chars::find_first_non_whitespace_char( - doc.text().line(cursor_line), - comment_token_ending_pos, - ) { - let trailing_whitespace = first_char_pos - comment_token_ending_pos; - let whitespace = (0..trailing_whitespace).map(|_| ' ').collect::(); - - text.push_str(&whitespace); - } else { - text.push(' '); - } - } + comment::handle_comment_continue(doc.text(), text, cursor_line, line_comment_tokens); } } From ee9c0152dfbe29273d9452c036a0d7a2373c7215 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Tue, 24 Oct 2023 08:58:05 -0500 Subject: [PATCH 12/59] Get tests for continue comment logic passing --- helix-core/src/comment.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 5037d4758ce0..5917e624aac1 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -144,14 +144,14 @@ pub fn handle_comment_continue<'a>( // find the position of the first non-whitespace char after the commet token so that // lines that continue a comment are indented to the same level as the previous line - if let Some(trailing_whitespace) = - chars::count_whitespace_after(doc.line(line_idx), comment_token_ending_pos) - { - let whitespace_to_insert = (0..=trailing_whitespace).map(|_| ' ').collect::(); + match chars::count_whitespace_after(doc.line(line_idx), comment_token_ending_pos) { + None | Some(0) => text.push(' '), + Some(trailing_whitespace) => { + let whitespace_to_insert = + (0..trailing_whitespace).map(|_| ' ').collect::(); - text.push_str(&whitespace_to_insert); - } else { - text.push(' '); + text.push_str(&whitespace_to_insert); + } } } } From e44d55ab443d6b6d49c812437f5cf65db3b3b757 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Tue, 24 Oct 2023 11:08:28 -0500 Subject: [PATCH 13/59] Don't count newlines when counting whitespace --- helix-core/src/chars.rs | 2 +- helix-core/src/comment.rs | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index ad78c5048e91..69a6d85fb777 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -104,7 +104,7 @@ pub fn count_whitespace_after(line: RopeSlice, starting_idx: usize) -> Option( doc: &Rope, @@ -140,19 +141,25 @@ pub fn handle_comment_continue<'a>( if let Some((token, comment_token_ending_pos)) = get_comment_token_and_position(doc, line_idx, comment_tokens) { + let leading_whitespace = match chars::count_whitespace_after(doc.line(line_idx), 0) { + None | Some(0) => String::from(""), + Some(leading_whitespace) => (0..=leading_whitespace).map(|_| ' ').collect::(), + }; + + text.push_str(&leading_whitespace); text.push_str(token); // find the position of the first non-whitespace char after the commet token so that // lines that continue a comment are indented to the same level as the previous line - match chars::count_whitespace_after(doc.line(line_idx), comment_token_ending_pos) { - None | Some(0) => text.push(' '), - Some(trailing_whitespace) => { - let whitespace_to_insert = - (0..trailing_whitespace).map(|_| ' ').collect::(); - - text.push_str(&whitespace_to_insert); - } - } + let trailing_whitespace = + match chars::count_whitespace_after(doc.line(line_idx), comment_token_ending_pos) { + None | Some(0) => String::from(" "), + Some(trailing_whitespace) => { + (0..trailing_whitespace).map(|_| ' ').collect::() + } + }; + + text.push_str(&trailing_whitespace); } } @@ -257,7 +264,7 @@ mod test { } #[test] - fn test_handle_continue_comment() { + fn test_handle_comment_continue() { let mut doc = Rope::from("// 1\n"); let mut text = String::from(&doc); let comment_tokens = vec![String::from("//"), String::from("///")]; @@ -278,9 +285,20 @@ mod test { handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + assert_eq!(text, String::from(" // 3\n // ")); + doc = Rope::from("/// 4\n"); text = String::from(&doc); handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + + assert_eq!(text, String::from("/// 4\n/// ")); + + doc = Rope::from("// \n"); + text = String::from(&doc); + + handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + + assert_eq!(text, String::from("// \n// ")); } } From d8169820c2a233a907e98f4862fa545d42694a21 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Tue, 24 Oct 2023 11:09:47 -0500 Subject: [PATCH 14/59] Rename a variable --- helix-core/src/chars.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index 69a6d85fb777..5eade617a383 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -102,12 +102,12 @@ pub fn count_whitespace_after(line: RopeSlice, starting_idx: usize) -> Option Date: Wed, 25 Oct 2023 09:10:19 -0500 Subject: [PATCH 15/59] Add `continue-comment` config parameter --- helix-term/src/commands.rs | 5 ++++- helix-view/src/editor.rs | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 931a2ccd2327..867ff65d15ac 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3070,6 +3070,7 @@ fn open(cx: &mut Context, open: Open) { enter_insert_mode(cx); let (view, doc) = current!(cx.editor); + let config = doc.config.load(); let text = doc.text().slice(..); let contents = doc.text(); let selection = doc.selection(view.id); @@ -3119,7 +3120,9 @@ fn open(cx: &mut Context, open: Open) { text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - handle_comment_continue(doc, &mut text, cursor_line); + if config.continue_comments { + handle_comment_continue(doc, &mut text, cursor_line); + } let text = text.repeat(count); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 7af28ccc680a..3c149f97a034 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -291,6 +291,8 @@ pub struct Config { pub insert_final_newline: bool, /// Enables smart tab pub smart_tab: Option, + /// Whether to prepend a comment token onto a new line that follows a commented line. Defaults to `true`. + pub continue_comments: bool, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -846,6 +848,7 @@ impl Default for Config { default_line_ending: LineEndingConfig::default(), insert_final_newline: true, smart_tab: Some(SmartTabConfig::default()), + continue_comments: true, } } } From c3a61901c6e1c06d67b0e7f25dc272d70b33746c Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 25 Oct 2023 09:30:45 -0500 Subject: [PATCH 16/59] Contiue comments in insert mode based on config --- helix-term/src/commands.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 867ff65d15ac..f15b83e9ea1d 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3625,6 +3625,7 @@ pub mod insert { pub fn insert_newline(cx: &mut Context) { let (view, doc) = current_ref!(cx.editor); + let config = doc.config.load(); let text = doc.text().slice(..); let contents = doc.text(); @@ -3694,7 +3695,9 @@ pub mod insert { new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); - handle_comment_continue(doc, &mut new_text, current_line); + if config.continue_comments { + handle_comment_continue(doc, &mut new_text, current_line); + } new_text.chars().count() }; From cbd05dcaf110bae6f3a4c7fb6511ed402273d26d Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 26 Oct 2023 15:11:56 -0500 Subject: [PATCH 17/59] Use pre-existing indentation functions to indent comment lines --- helix-core/src/chars.rs | 14 ++-- helix-core/src/comment.rs | 127 ++++++++++++++++++++----------------- helix-core/src/indent.rs | 26 +++++++- helix-core/tests/indent.rs | 2 +- helix-term/src/commands.rs | 36 ++++++++--- 5 files changed, 129 insertions(+), 76 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index 5eade617a383..3ad405168a63 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -88,14 +88,14 @@ pub fn char_is_word(ch: char) -> bool { } /// Find the first non-whitespace character in the line. -pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { +pub fn find_first_non_whitespace_char(line: &RopeSlice) -> Option { line.chars().position(|ch| !ch.is_whitespace()) } /// Count how much whitespace there is starting at the specified index in the line. /// /// Returns None if the specified starting index >= the length of the line. -pub fn count_whitespace_after(line: RopeSlice, starting_idx: usize) -> Option { +pub fn count_whitespace_after(line: &RopeSlice, starting_idx: usize) -> Option { let len = line.len_chars(); if starting_idx >= len { @@ -164,13 +164,13 @@ mod test { fn test_count_whitespace_after() { let mut line = RopeSlice::from("a 1"); - assert_eq!(count_whitespace_after(line, 0), Some(7)); - assert_eq!(count_whitespace_after(line, 3), Some(4)); - assert_eq!(count_whitespace_after(line, 8), Some(0)); - assert_eq!(count_whitespace_after(line, 10), None); + assert_eq!(count_whitespace_after(&line, 0), Some(7)); + assert_eq!(count_whitespace_after(&line, 3), Some(4)); + assert_eq!(count_whitespace_after(&line, 8), Some(0)); + assert_eq!(count_whitespace_after(&line, 10), None); line = RopeSlice::from("1\n 2"); - assert_eq!(count_whitespace_after(line, 0), Some(7)); + assert_eq!(count_whitespace_after(&line, 0), Some(7)); } } diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 907ce9164544..bba2080562aa 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -3,7 +3,11 @@ //! * toggle comments on lines over the selection //! * continue comment when opening a new line -use crate::{chars, Change, Rope, RopeSlice, Selection, Tendril, Transaction}; +use crate::{ + chars, + indent::{indent_level_at, IndentStyle}, + Change, Rope, RopeSlice, Selection, Tendril, Transaction, +}; use std::borrow::Cow; /// Given text, a comment token, and a set of line indices, returns the following: @@ -27,7 +31,7 @@ fn find_line_comment( let token_len = token.chars().count(); for line in lines { let line_slice = text.line(line); - if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { + if let Some(pos) = chars::find_first_non_whitespace_char(&line_slice) { let len = line_slice.len_chars(); if pos < min { @@ -99,8 +103,7 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st /// /// Return None otherwise. pub fn get_comment_token_and_position<'a>( - doc: &Rope, - line: usize, + line: &RopeSlice, tokens: &'a [String], ) -> Option<(&'a str, usize)> { // TODO: don't continue shebangs @@ -109,14 +112,13 @@ pub fn get_comment_token_and_position<'a>( } let mut result = None; - let line_slice = doc.line(line); - if let Some(pos) = chars::find_first_non_whitespace_char(line_slice) { - let len = line_slice.len_chars(); + if let Some(pos) = chars::find_first_non_whitespace_char(line) { + let len = line.len_chars(); for token in tokens { // line can be shorter than pos + token length - let fragment = Cow::from(line_slice.slice(pos..std::cmp::min(pos + token.len(), len))); + let fragment = Cow::from(line.slice(pos..std::cmp::min(pos + token.len(), len))); if fragment == *token { // We don't necessarily want to break upon finding the first matching comment token @@ -130,35 +132,31 @@ pub fn get_comment_token_and_position<'a>( result } -/// Determines whether the new line following the line at `line_idx` in -/// document should be prepended with a comment token. +/// Determines whether the new line following the given line should be +/// prepended with a comment token. If it does, the `text` string is +/// appended with the appropriate comment token and indented to the same +/// level as the previous comment line. pub fn handle_comment_continue<'a>( - doc: &'a Rope, + line: &'a RopeSlice, text: &'a mut String, - line_idx: usize, + indent_style: &'a IndentStyle, + tab_width: usize, comment_tokens: &'a [String], ) { if let Some((token, comment_token_ending_pos)) = - get_comment_token_and_position(doc, line_idx, comment_tokens) + get_comment_token_and_position(line, comment_tokens) { - let leading_whitespace = match chars::count_whitespace_after(doc.line(line_idx), 0) { - None | Some(0) => String::from(""), - Some(leading_whitespace) => (0..=leading_whitespace).map(|_| ' ').collect::(), - }; - - text.push_str(&leading_whitespace); text.push_str(token); - // find the position of the first non-whitespace char after the commet token so that - // lines that continue a comment are indented to the same level as the previous line - let trailing_whitespace = - match chars::count_whitespace_after(doc.line(line_idx), comment_token_ending_pos) { - None | Some(0) => String::from(" "), - Some(trailing_whitespace) => { - (0..trailing_whitespace).map(|_| ' ').collect::() - } + let indent_width = indent_style.indent_width(tab_width); + let indent_level = + match indent_level_at(line, tab_width, indent_width, comment_token_ending_pos + 1) { + Some(indent_level) => indent_level, + None => 1, }; + let trailing_whitespace = indent_style.as_str().repeat(indent_level); + text.push_str(&trailing_whitespace); } } @@ -221,9 +219,6 @@ mod test { #[test] fn test_get_comment_token_and_position() { - let doc = Rope::from( - "# 1\n // 2 \n///3\n/// 4\n//! 5\n//! /// 6\n7 ///\n;8\n//////////// 9", - ); let tokens = vec![ String::from("//"), String::from("///"), @@ -231,74 +226,90 @@ mod test { String::from(";"), ]; - assert_eq!(get_comment_token_and_position(&doc, 0, &tokens), None); assert_eq!( - get_comment_token_and_position(&doc, 1, &tokens), + get_comment_token_and_position(&RopeSlice::from("# 1\n"), &tokens), + None + ); + assert_eq!( + get_comment_token_and_position(&RopeSlice::from(" // 2 \n"), &tokens), Some(("//", 5)) ); assert_eq!( - get_comment_token_and_position(&doc, 2, &tokens), + get_comment_token_and_position(&RopeSlice::from("///3\n"), &tokens), Some(("///", 2)) ); assert_eq!( - get_comment_token_and_position(&doc, 3, &tokens), + get_comment_token_and_position(&RopeSlice::from("/// 4\n"), &tokens), Some(("///", 2)) ); assert_eq!( - get_comment_token_and_position(&doc, 4, &tokens), + get_comment_token_and_position(&RopeSlice::from("//! 5\n"), &tokens), Some(("//!", 2)) ); assert_eq!( - get_comment_token_and_position(&doc, 5, &tokens), + get_comment_token_and_position(&RopeSlice::from("//! /// 6\n"), &tokens), Some(("//!", 2)) ); - assert_eq!(get_comment_token_and_position(&doc, 6, &tokens), None); assert_eq!( - get_comment_token_and_position(&doc, 7, &tokens), + get_comment_token_and_position(&RopeSlice::from("7 ///\n"), &tokens), + None + ); + assert_eq!( + get_comment_token_and_position(&RopeSlice::from(";8\n"), &tokens), Some((";", 0)) ); assert_eq!( - get_comment_token_and_position(&doc, 8, &tokens), + get_comment_token_and_position(&RopeSlice::from("//////////// 9"), &tokens), Some(("///", 2)) ); } #[test] fn test_handle_comment_continue() { - let mut doc = Rope::from("// 1\n"); - let mut text = String::from(&doc); let comment_tokens = vec![String::from("//"), String::from("///")]; + let doc = RopeSlice::from("// 1\n"); + let mut text = String::from(doc); - handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + handle_comment_continue(&doc, &mut text, &IndentStyle::Spaces(4), 4, &comment_tokens); assert_eq!(text, String::from("// 1\n// ")); - doc = Rope::from("///2\n"); - text = String::from(&doc); + // doc = Rope::from("///2\n"); + // text = String::from(&doc); + + // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + + // assert_eq!(text, String::from("///2\n/// ")); + + // doc = Rope::from(" // 3\n"); + // text = String::from(&doc); - handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); - assert_eq!(text, String::from("///2\n/// ")); + // assert_eq!(text, String::from(" // 3\n // ")); - doc = Rope::from(" // 3\n"); - text = String::from(&doc); + // doc = Rope::from("/// 4\n"); + // text = String::from(&doc); - handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); - assert_eq!(text, String::from(" // 3\n // ")); + // assert_eq!(text, String::from("/// 4\n/// ")); - doc = Rope::from("/// 4\n"); - text = String::from(&doc); + // doc = Rope::from("// \n"); + // text = String::from(&doc); - handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); - assert_eq!(text, String::from("/// 4\n/// ")); + // assert_eq!(text, String::from("// \n// ")); - doc = Rope::from("// \n"); - text = String::from(&doc); + // doc = Rope::from(" // Lorem Ipsum\n // dolor sit amet\n"); + // text = String::from(&doc); - handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + // handle_comment_continue(&doc, &mut text, 1, &comment_tokens); - assert_eq!(text, String::from("// \n// ")); + // assert_eq!( + // text, + // String::from(" // Lorem Ipsum\n // dolor sit amet\n // ") + // ); } } diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index 6ccdc5952377..6d9d70c18b53 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -184,8 +184,30 @@ pub fn auto_detect_indent_style(document_text: &Rope) -> Option { /// To determine indentation of a newly inserted line, figure out the indentation at the last col /// of the previous line. pub fn indent_level_for_line(line: RopeSlice, tab_width: usize, indent_width: usize) -> usize { + if let Some(indent_level) = indent_level_at(&line, tab_width, indent_width, 0) { + indent_level + } else { + 0 + } +} + +/// Determine the indentation level starting from the specified position index in the line. +/// +/// Returns None if the specified index is out of bounds of the line. +pub fn indent_level_at( + line: &RopeSlice, + tab_width: usize, + indent_width: usize, + starting_pos: usize, +) -> Option { + let line_len = line.len_chars(); + + if starting_pos >= line_len { + return None; + } + let mut len = 0; - for ch in line.chars() { + for ch in line.chars_at(starting_pos) { match ch { '\t' => len += tab_width_at(len, tab_width as u16), ' ' => len += 1, @@ -193,7 +215,7 @@ pub fn indent_level_for_line(line: RopeSlice, tab_width: usize, indent_width: us } } - len / indent_width + Some(len / indent_width) } /// Computes for node and all ancestors whether they are the first node on their line. diff --git a/helix-core/tests/indent.rs b/helix-core/tests/indent.rs index ce969ea13aef..cc64271fd3ea 100644 --- a/helix-core/tests/indent.rs +++ b/helix-core/tests/indent.rs @@ -205,7 +205,7 @@ fn test_treesitter_indent( if ignored_lines.iter().any(|range| range.contains(&(i + 1))) { continue; } - if let Some(pos) = helix_core::chars::find_first_non_whitespace_char(line) { + if let Some(pos) = helix_core::chars::find_first_non_whitespace_char(&line) { let tab_width: usize = 4; let suggested_indent = treesitter_indent_for_pos( indent_query, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index f15b83e9ea1d..f12819d5fc15 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -814,7 +814,7 @@ fn kill_to_line_start(cx: &mut Context) { let head = if anchor == first_char && line != 0 { // select until previous line line_end_char_index(&text, line - 1) - } else if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line)) { + } else if let Some(pos) = chars::find_first_non_whitespace_char(&text.line(line)) { if first_char + pos < anchor { // select until first non-blank in line if cursor is after it first_char + pos @@ -876,7 +876,7 @@ fn goto_first_nonwhitespace_impl(view: &mut View, doc: &mut Document, movement: let selection = doc.selection(view.id).clone().transform(|range| { let line = range.cursor_line(text); - if let Some(pos) = chars::find_first_non_whitespace_char(text.line(line)) { + if let Some(pos) = chars::find_first_non_whitespace_char(&text.line(line)) { let pos = pos + text.line_to_char(line); range.put_cursor(text, pos, movement == Movement::Extend) } else { @@ -2997,7 +2997,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { // move cursor to the fallback position let pos = match cursor_fallback { IndentFallbackPos::LineStart => { - chars::find_first_non_whitespace_char(text.line(cursor_line)) + chars::find_first_non_whitespace_char(&text.line(cursor_line)) .map(|ws_offset| ws_offset + cursor_line_start) .unwrap_or(cursor_line_start) } @@ -3121,7 +3121,13 @@ fn open(cx: &mut Context, open: Open) { text.push_str(&indent); if config.continue_comments { - handle_comment_continue(doc, &mut text, cursor_line); + handle_comment_continue( + doc, + &mut text, + &doc.indent_style, + doc.tab_width(), + cursor_line, + ); } let text = text.repeat(count); @@ -3150,11 +3156,19 @@ fn open(cx: &mut Context, open: Open) { // Currently only continues single-line comments // TODO: Handle block comments as well -fn handle_comment_continue(doc: &Document, text: &mut String, cursor_line: usize) { +fn handle_comment_continue( + doc: &Document, + text: &mut String, + indent_style: &IndentStyle, + tab_width: usize, + cursor_line: usize, +) { + let line = doc.text().line(cursor_line); + if let Some(lang_config) = doc.language_config() { - let line_comment_tokens = &lang_config.comment_tokens; + let comment_tokens = &lang_config.comment_tokens; - comment::handle_comment_continue(doc.text(), text, cursor_line, line_comment_tokens); + comment::handle_comment_continue(&line, text, indent_style, tab_width, comment_tokens); } } @@ -3696,7 +3710,13 @@ pub mod insert { new_text.push_str(&indent); if config.continue_comments { - handle_comment_continue(doc, &mut new_text, current_line); + handle_comment_continue( + doc, + &mut new_text, + &doc.indent_style, + doc.tab_width(), + current_line, + ); } new_text.chars().count() From e170d40f6d65a87de2936f17eb9a5f44ab12fdd3 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Mon, 30 Oct 2023 09:16:50 -0500 Subject: [PATCH 18/59] Clean up for PR submission --- helix-core/src/chars.rs | 33 ---------- helix-core/src/comment.rs | 128 +++++++++++++++---------------------- helix-term/src/commands.rs | 26 ++------ 3 files changed, 55 insertions(+), 132 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index 3ad405168a63..8c3973778ee5 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -87,29 +87,10 @@ pub fn char_is_word(ch: char) -> bool { ch.is_alphanumeric() || ch == '_' } -/// Find the first non-whitespace character in the line. pub fn find_first_non_whitespace_char(line: &RopeSlice) -> Option { line.chars().position(|ch| !ch.is_whitespace()) } -/// Count how much whitespace there is starting at the specified index in the line. -/// -/// Returns None if the specified starting index >= the length of the line. -pub fn count_whitespace_after(line: &RopeSlice, starting_idx: usize) -> Option { - let len = line.len_chars(); - - if starting_idx >= len { - return None; - } - - let whitespace_count = line - .chars_at(starting_idx + 1) - .take_while(|ch| ch.is_whitespace() && *ch != '\n') - .count(); - - Some(whitespace_count) -} - #[cfg(test)] mod test { use super::*; @@ -159,18 +140,4 @@ mod test { ); } } - - #[test] - fn test_count_whitespace_after() { - let mut line = RopeSlice::from("a 1"); - - assert_eq!(count_whitespace_after(&line, 0), Some(7)); - assert_eq!(count_whitespace_after(&line, 3), Some(4)); - assert_eq!(count_whitespace_after(&line, 8), Some(0)); - assert_eq!(count_whitespace_after(&line, 10), None); - - line = RopeSlice::from("1\n 2"); - - assert_eq!(count_whitespace_after(&line, 0), Some(7)); - } } diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index bba2080562aa..9385e6083299 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -3,11 +3,7 @@ //! * toggle comments on lines over the selection //! * continue comment when opening a new line -use crate::{ - chars, - indent::{indent_level_at, IndentStyle}, - Change, Rope, RopeSlice, Selection, Tendril, Transaction, -}; +use crate::{chars, Change, Rope, RopeSlice, Selection, Tendril, Transaction}; use std::borrow::Cow; /// Given text, a comment token, and a set of line indices, returns the following: @@ -98,14 +94,10 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st Transaction::change(doc, changes.into_iter()) } -/// Return the comment token of the current line if it is commented, along with the -/// position of the last character in the comment token. +/// Return the comment token of the current line if it is commented. /// /// Return None otherwise. -pub fn get_comment_token_and_position<'a>( - line: &RopeSlice, - tokens: &'a [String], -) -> Option<(&'a str, usize)> { +pub fn get_comment_token<'a>(line: &RopeSlice, tokens: &'a [String]) -> Option<&'a str> { // TODO: don't continue shebangs if tokens.is_empty() { return None; @@ -124,7 +116,7 @@ pub fn get_comment_token_and_position<'a>( // We don't necessarily want to break upon finding the first matching comment token // Instead, we check against all of the comment tokens and end up returning the longest // comment token that matches - result = Some((token.as_str(), pos + token.len() - 1)); + result = Some(token.as_str()); } } } @@ -134,30 +126,15 @@ pub fn get_comment_token_and_position<'a>( /// Determines whether the new line following the given line should be /// prepended with a comment token. If it does, the `text` string is -/// appended with the appropriate comment token and indented to the same -/// level as the previous comment line. +/// appended with the appropriate comment token. pub fn handle_comment_continue<'a>( line: &'a RopeSlice, text: &'a mut String, - indent_style: &'a IndentStyle, - tab_width: usize, comment_tokens: &'a [String], ) { - if let Some((token, comment_token_ending_pos)) = - get_comment_token_and_position(line, comment_tokens) - { - text.push_str(token); - - let indent_width = indent_style.indent_width(tab_width); - let indent_level = - match indent_level_at(line, tab_width, indent_width, comment_token_ending_pos + 1) { - Some(indent_level) => indent_level, - None => 1, - }; - - let trailing_whitespace = indent_style.as_str().repeat(indent_level); - - text.push_str(&trailing_whitespace); + if let Some(token) = get_comment_token(line, comment_tokens) { + let new_line = format!("{} ", token); + text.push_str(new_line.as_str()); } } @@ -218,7 +195,7 @@ mod test { } #[test] - fn test_get_comment_token_and_position() { + fn test_get_comment_token() { let tokens = vec![ String::from("//"), String::from("///"), @@ -226,90 +203,87 @@ mod test { String::from(";"), ]; + assert_eq!(get_comment_token(&RopeSlice::from("# 1\n"), &tokens), None); assert_eq!( - get_comment_token_and_position(&RopeSlice::from("# 1\n"), &tokens), - None - ); - assert_eq!( - get_comment_token_and_position(&RopeSlice::from(" // 2 \n"), &tokens), - Some(("//", 5)) + get_comment_token(&RopeSlice::from(" // 2 \n"), &tokens), + Some("//") ); assert_eq!( - get_comment_token_and_position(&RopeSlice::from("///3\n"), &tokens), - Some(("///", 2)) + get_comment_token(&RopeSlice::from("///3\n"), &tokens), + Some("///") ); assert_eq!( - get_comment_token_and_position(&RopeSlice::from("/// 4\n"), &tokens), - Some(("///", 2)) + get_comment_token(&RopeSlice::from("/// 4\n"), &tokens), + Some("///") ); assert_eq!( - get_comment_token_and_position(&RopeSlice::from("//! 5\n"), &tokens), - Some(("//!", 2)) + get_comment_token(&RopeSlice::from("//! 5\n"), &tokens), + Some("//!") ); assert_eq!( - get_comment_token_and_position(&RopeSlice::from("//! /// 6\n"), &tokens), - Some(("//!", 2)) + get_comment_token(&RopeSlice::from("//! /// 6\n"), &tokens), + Some("//!") ); assert_eq!( - get_comment_token_and_position(&RopeSlice::from("7 ///\n"), &tokens), + get_comment_token(&RopeSlice::from("7 ///\n"), &tokens), None ); assert_eq!( - get_comment_token_and_position(&RopeSlice::from(";8\n"), &tokens), - Some((";", 0)) + get_comment_token(&RopeSlice::from(";8\n"), &tokens), + Some(";") ); assert_eq!( - get_comment_token_and_position(&RopeSlice::from("//////////// 9"), &tokens), - Some(("///", 2)) + get_comment_token(&RopeSlice::from("//////////// 9"), &tokens), + Some("///") ); } #[test] fn test_handle_comment_continue() { let comment_tokens = vec![String::from("//"), String::from("///")]; - let doc = RopeSlice::from("// 1\n"); - let mut text = String::from(doc); + let mut line = RopeSlice::from("// 1\n"); + let mut text = String::from(line); - handle_comment_continue(&doc, &mut text, &IndentStyle::Spaces(4), 4, &comment_tokens); + handle_comment_continue(&line, &mut text, &comment_tokens); assert_eq!(text, String::from("// 1\n// ")); - // doc = Rope::from("///2\n"); - // text = String::from(&doc); + line = RopeSlice::from("///2\n"); + text = String::from(line); - // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + handle_comment_continue(&line, &mut text, &comment_tokens); - // assert_eq!(text, String::from("///2\n/// ")); + assert_eq!(text, String::from("///2\n/// ")); - // doc = Rope::from(" // 3\n"); - // text = String::from(&doc); + line = RopeSlice::from(" // 3\n"); + text = String::from(line); - // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + handle_comment_continue(&line, &mut text, &comment_tokens); - // assert_eq!(text, String::from(" // 3\n // ")); + assert_eq!(text, String::from(" // 3\n // ")); - // doc = Rope::from("/// 4\n"); - // text = String::from(&doc); + line = RopeSlice::from("/// 4\n"); + text = String::from(line); - // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + handle_comment_continue(&line, &mut text, &comment_tokens); - // assert_eq!(text, String::from("/// 4\n/// ")); + assert_eq!(text, String::from("/// 4\n/// ")); - // doc = Rope::from("// \n"); - // text = String::from(&doc); + line = RopeSlice::from("// \n"); + text = String::from(line); - // handle_comment_continue(&doc, &mut text, 0, &comment_tokens); + handle_comment_continue(&line, &mut text, &comment_tokens); - // assert_eq!(text, String::from("// \n// ")); + assert_eq!(text, String::from("// \n// ")); - // doc = Rope::from(" // Lorem Ipsum\n // dolor sit amet\n"); - // text = String::from(&doc); + line = RopeSlice::from(" // Lorem Ipsum\n // dolor sit amet\n"); + text = String::from(line); - // handle_comment_continue(&doc, &mut text, 1, &comment_tokens); + handle_comment_continue(&line, &mut text, &comment_tokens); - // assert_eq!( - // text, - // String::from(" // Lorem Ipsum\n // dolor sit amet\n // ") - // ); + assert_eq!( + text, + String::from(" // Lorem Ipsum\n // dolor sit amet\n // ") + ); } } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 32f6ac7cbfdf..36e1a0b5ff27 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3128,13 +3128,7 @@ fn open(cx: &mut Context, open: Open) { text.push_str(&indent); if config.continue_comments { - handle_comment_continue( - doc, - &mut text, - &doc.indent_style, - doc.tab_width(), - cursor_line, - ); + handle_comment_continue(doc, &mut text, cursor_line); } let text = text.repeat(count); @@ -3163,19 +3157,13 @@ fn open(cx: &mut Context, open: Open) { // Currently only continues single-line comments // TODO: Handle block comments as well -fn handle_comment_continue( - doc: &Document, - text: &mut String, - indent_style: &IndentStyle, - tab_width: usize, - cursor_line: usize, -) { +fn handle_comment_continue(doc: &Document, text: &mut String, cursor_line: usize) { let line = doc.text().line(cursor_line); if let Some(lang_config) = doc.language_config() { let comment_tokens = &lang_config.comment_tokens; - comment::handle_comment_continue(&line, text, indent_style, tab_width, comment_tokens); + comment::handle_comment_continue(&line, text, comment_tokens); } } @@ -3717,13 +3705,7 @@ pub mod insert { new_text.push_str(&indent); if config.continue_comments { - handle_comment_continue( - doc, - &mut new_text, - &doc.indent_style, - doc.tab_width(), - current_line, - ); + handle_comment_continue(doc, &mut new_text, current_line); } new_text.chars().count() From b03f870122c56a96a206699debd7756a159332d4 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Mon, 30 Oct 2023 09:47:32 -0500 Subject: [PATCH 19/59] Remove changes in indent.rs --- helix-core/src/indent.rs | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index b676f7f653d7..abf45d6faf36 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -184,30 +184,8 @@ pub fn auto_detect_indent_style(document_text: &Rope) -> Option { /// To determine indentation of a newly inserted line, figure out the indentation at the last col /// of the previous line. pub fn indent_level_for_line(line: RopeSlice, tab_width: usize, indent_width: usize) -> usize { - if let Some(indent_level) = indent_level_at(&line, tab_width, indent_width, 0) { - indent_level - } else { - 0 - } -} - -/// Determine the indentation level starting from the specified position index in the line. -/// -/// Returns None if the specified index is out of bounds of the line. -pub fn indent_level_at( - line: &RopeSlice, - tab_width: usize, - indent_width: usize, - starting_pos: usize, -) -> Option { - let line_len = line.len_chars(); - - if starting_pos >= line_len { - return None; - } - let mut len = 0; - for ch in line.chars_at(starting_pos) { + for ch in line.chars() { match ch { '\t' => len += tab_width_at(len, tab_width as u16), ' ' => len += 1, @@ -215,7 +193,7 @@ pub fn indent_level_at( } } - Some(len / indent_width) + len / indent_width } /// Computes for node and all ancestors whether they are the first node on their line. From 57261e5e495827b2eed0b698045ec91c9a176933 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 1 Nov 2023 09:09:53 -0500 Subject: [PATCH 20/59] Remove incorrect unit test --- helix-core/src/comment.rs | 49 --------------------------------------- 1 file changed, 49 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 9385e6083299..bc768a1e0abf 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -237,53 +237,4 @@ mod test { Some("///") ); } - - #[test] - fn test_handle_comment_continue() { - let comment_tokens = vec![String::from("//"), String::from("///")]; - let mut line = RopeSlice::from("// 1\n"); - let mut text = String::from(line); - - handle_comment_continue(&line, &mut text, &comment_tokens); - - assert_eq!(text, String::from("// 1\n// ")); - - line = RopeSlice::from("///2\n"); - text = String::from(line); - - handle_comment_continue(&line, &mut text, &comment_tokens); - - assert_eq!(text, String::from("///2\n/// ")); - - line = RopeSlice::from(" // 3\n"); - text = String::from(line); - - handle_comment_continue(&line, &mut text, &comment_tokens); - - assert_eq!(text, String::from(" // 3\n // ")); - - line = RopeSlice::from("/// 4\n"); - text = String::from(line); - - handle_comment_continue(&line, &mut text, &comment_tokens); - - assert_eq!(text, String::from("/// 4\n/// ")); - - line = RopeSlice::from("// \n"); - text = String::from(line); - - handle_comment_continue(&line, &mut text, &comment_tokens); - - assert_eq!(text, String::from("// \n// ")); - - line = RopeSlice::from(" // Lorem Ipsum\n // dolor sit amet\n"); - text = String::from(line); - - handle_comment_continue(&line, &mut text, &comment_tokens); - - assert_eq!( - text, - String::from(" // Lorem Ipsum\n // dolor sit amet\n // ") - ); - } } From 8fa3cc9595c1cbfa28de3c395665b7558b45a892 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Thu, 20 Jun 2024 03:31:44 +0200 Subject: [PATCH 21/59] add `has_line_comment` method and fix `starts_with` for RopeSlice --- helix-core/src/chars.rs | 6 ----- helix-core/src/comment.rs | 8 +++--- helix-stdx/src/rope.rs | 2 +- helix-term/src/commands.rs | 52 +++++++++++++++++++++++++------------- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index 531f378aead2..220500694b6b 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -1,7 +1,5 @@ //! Utility functions to categorize a `char`. -use ropey::RopeSlice; - use crate::LineEnding; #[derive(Debug, Eq, PartialEq)] @@ -87,10 +85,6 @@ pub fn char_is_word(ch: char) -> bool { ch.is_alphanumeric() || ch == '_' } -pub fn find_first_non_whitespace_char(line: &RopeSlice) -> Option { - line.chars().position(|ch| !ch.is_whitespace()) -} - #[cfg(test)] mod test { use super::*; diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 133b3003f3fd..536b710abf0f 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -1,7 +1,5 @@ -//! This module contains the functionality for the following comment-related features -//! using the comment character defined in the user's `languages.toml`: -//! * toggle comments on lines over the selection -//! * continue comment when opening a new line +//! This module contains the functionality toggle comments on lines over the selection +//! using the comment character defined in the user's `languages.toml` use smallvec::SmallVec; @@ -320,7 +318,7 @@ mod test { use super::*; #[test] - fn test_toggle_line_comments() { + fn test_find_line_comment() { // four lines, two space indented, except for line 1 which is blank. let mut doc = Rope::from(" 1\n\n 2\n 3"); // select whole document diff --git a/helix-stdx/src/rope.rs b/helix-stdx/src/rope.rs index 2695555e39d6..5cb45c2cd14f 100644 --- a/helix-stdx/src/rope.rs +++ b/helix-stdx/src/rope.rs @@ -51,7 +51,7 @@ impl<'a> RopeSliceExt<'a> for RopeSlice<'a> { if len < text.len() { return false; } - self.get_byte_slice(..len - text.len()) + self.get_byte_slice(..text.len()) .map_or(false, |start| start == text) } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index de3a5c9aaa8b..4489d5e9d293 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -42,7 +42,7 @@ use helix_core::{ }; use helix_view::{ document::{FormatterError, Mode, SCRATCH_BUFFER_NAME}, - editor::Action, + editor::{Action, Config}, info::Info, input::KeyEvent, keyboard::KeyCode, @@ -1668,6 +1668,34 @@ fn switch_to_lowercase(cx: &mut Context) { }); } +/// Checks, if the line from line `line_num` is commented with one of the comment tokens in the language config and +/// returns the token which comments out the line. +fn has_line_comment(config: &Config, doc: &Document, line_num: usize) -> Option { + if config.continue_comments { + let line_tokens = { + let mut line_tokens: Vec = doc + .language_config() + .and_then(|lc| lc.comment_tokens.as_ref())? + .clone(); + line_tokens.sort_by(|a, b| a.len().partial_cmp(&b.len()).unwrap().reverse()); + line_tokens + }; + + let text = doc.text(); + let line = text.line(line_num); + + if let Some(pos) = line.first_non_whitespace_char() { + let text_line = line.slice(pos..); + return line_tokens + .iter() + .find(|&token| text_line.starts_with(token.as_str())) + .map(|token| token.clone()); + } + } + + None +} + pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor: bool) { use Direction::*; let config = cx.editor.config(); @@ -3417,8 +3445,9 @@ fn open(cx: &mut Context, open: Open) { text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - if config.continue_comments { - handle_comment_continue(doc, &mut text, cursor_line); + if let Some(comment_token) = has_line_comment(&config, &doc, line_num) { + text.push_str(&comment_token); + text.push(' '); } let text = text.repeat(count); @@ -3445,18 +3474,6 @@ fn open(cx: &mut Context, open: Open) { goto_line_end_newline(cx); } -// Currently only continues single-line comments -// TODO: Handle block comments as well -fn handle_comment_continue(doc: &Document, text: &mut String, cursor_line: usize) { - let line = doc.text().line(cursor_line); - - if let Some(lang_config) = doc.language_config() { - let comment_tokens = &lang_config.comment_tokens; - - comment::handle_comment_continue(&line, text, comment_tokens); - } -} - // o inserts a new line after each line with a selection fn open_below(cx: &mut Context) { open(cx, Open::Below) @@ -3918,8 +3935,9 @@ pub mod insert { new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); - if config.continue_comments { - handle_comment_continue(doc, &mut new_text, current_line); + if let Some(comment_token) = has_line_comment(&config, &doc, current_line) { + new_text.push_str(&comment_token); + new_text.push(' '); } new_text.chars().count() From c70acf7fee2b1ca7cbae1034b1055c7a1cb083b0 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Thu, 20 Jun 2024 03:39:23 +0200 Subject: [PATCH 22/59] make clippy happy --- helix-term/src/commands.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4489d5e9d293..08c772259532 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1689,7 +1689,7 @@ fn has_line_comment(config: &Config, doc: &Document, line_num: usize) -> Option< return line_tokens .iter() .find(|&token| text_line.starts_with(token.as_str())) - .map(|token| token.clone()); + .cloned(); } } @@ -3445,7 +3445,7 @@ fn open(cx: &mut Context, open: Open) { text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - if let Some(comment_token) = has_line_comment(&config, &doc, line_num) { + if let Some(comment_token) = has_line_comment(&config, doc, line_num) { text.push_str(&comment_token); text.push(' '); } @@ -3935,7 +3935,7 @@ pub mod insert { new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); - if let Some(comment_token) = has_line_comment(&config, &doc, current_line) { + if let Some(comment_token) = has_line_comment(&config, doc, current_line) { new_text.push_str(&comment_token); new_text.push(' '); } From 38bc94b9ac8404ec03b713c66372bb1452081fcb Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sat, 20 Jul 2024 05:56:08 +0200 Subject: [PATCH 23/59] continue-line-comment: add explanation --- helix-term/src/commands.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5c2697c28dca..a3b782473678 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1670,6 +1670,8 @@ fn has_line_comment(config: &Config, doc: &Document, line_num: usize) -> Option< .language_config() .and_then(|lc| lc.comment_tokens.as_ref())? .clone(); + // Use case (example): Rust supports `//` and `///`. We're reverse-sorting them to priorize `///` before `//` + // because otherwise a doc comment `/// like this` would get `//` as the next comment-token line_tokens.sort_by(|a, b| a.len().partial_cmp(&b.len()).unwrap().reverse()); line_tokens }; From fa50e510eadef9566322f570389296b5e22d74af Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sat, 20 Jul 2024 05:59:53 +0200 Subject: [PATCH 24/59] single-line-comment: improve performance --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index a3b782473678..c085f993312e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1672,7 +1672,7 @@ fn has_line_comment(config: &Config, doc: &Document, line_num: usize) -> Option< .clone(); // Use case (example): Rust supports `//` and `///`. We're reverse-sorting them to priorize `///` before `//` // because otherwise a doc comment `/// like this` would get `//` as the next comment-token - line_tokens.sort_by(|a, b| a.len().partial_cmp(&b.len()).unwrap().reverse()); + line_tokens.sort_unstable_by(|a, b| b.len().partial_cmp(&a.len()).unwrap()); line_tokens }; From e318a30ce9dffc118b9e1721adec28aadd56ea25 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Tue, 6 Aug 2024 19:20:04 +0200 Subject: [PATCH 25/59] comment: Add invariant to comment-tokens in config Comment tokens are sorted by their length, starting with the longest to the smallest --- helix-core/src/syntax.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 93f618c09736..5fb44d8b2d3c 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -103,6 +103,7 @@ pub struct LanguageConfiguration { pub shebangs: Vec, // interpreter(s) associated with language #[serde(default)] pub roots: Vec, // these indicate project roots <.git, Cargo.toml> + // Invariant: Tokens are sorted by their length. Starting from the longest up to smallest. #[serde( default, skip_serializing, @@ -269,7 +270,10 @@ where Ok( Option::::deserialize(deserializer)?.map(|tokens| match tokens { CommentTokens::Single(val) => vec![val], - CommentTokens::Multiple(vals) => vals, + CommentTokens::Multiple(mut vals) => { + vals.sort_unstable_by(|a, b| b.len().partial_cmp(&a.len()).unwrap()); + vals + } }), ) } From 76a42d9a644cda204dca7a7a367f15c81d272578 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Tue, 6 Aug 2024 20:01:35 +0200 Subject: [PATCH 26/59] continue-comment: improve continue comment when opening new lines with `o` --- helix-core/src/comment.rs | 6 ++- helix-term/src/commands.rs | 80 +++++++++++++++----------------------- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 536b710abf0f..4fa5ba2bf522 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -9,6 +9,8 @@ use crate::{ use helix_stdx::rope::RopeSliceExt; use std::borrow::Cow; +pub const DEFAULT_COMMENT_TOKEN: &str = "//"; + /// Given text, a comment token, and a set of line indices, returns the following: /// - Whether the given lines should be considered commented /// - If any of the lines are uncommented, all lines are considered as such. @@ -18,7 +20,7 @@ use std::borrow::Cow; /// - Column of existing tokens, if the lines are commented; column to place tokens at otherwise. /// - The margin to the right of the comment tokens /// - Defaults to `1`. If any existing comment token is not followed by a space, changes to `0`. -fn find_line_comment( +pub fn find_line_comment( token: &str, text: RopeSlice, lines: impl IntoIterator, @@ -63,7 +65,7 @@ fn find_line_comment( pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&str>) -> Transaction { let text = doc.slice(..); - let token = token.unwrap_or("//"); + let token = token.unwrap_or(DEFAULT_COMMENT_TOKEN); let comment = Tendril::from(format!("{} ", token)); let mut lines: Vec = Vec::with_capacity(selection.len()); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c085f993312e..0713cede180d 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -17,13 +17,13 @@ pub use typed::*; use helix_core::{ char_idx_at_visual_offset, chars::char_is_word, - comment, + comment::{self, find_line_comment}, doc_formatter::TextFormat, encoding, find_workspace, graphemes::{self, next_grapheme_boundary, RevRopeGraphemes}, history::UndoKind, - increment, indent, - indent::IndentStyle, + increment, + indent::{self, IndentStyle}, line_ending::{get_line_ending_of_str, line_end_char_index}, match_brackets, movement::{self, move_vertically_visual, Direction}, @@ -40,7 +40,7 @@ use helix_core::{ }; use helix_view::{ document::{FormatterError, Mode, SCRATCH_BUFFER_NAME}, - editor::{Action, Config}, + editor::Action, info::Info, input::KeyEvent, keyboard::KeyCode, @@ -1661,36 +1661,6 @@ fn switch_to_lowercase(cx: &mut Context) { }); } -/// Checks, if the line from line `line_num` is commented with one of the comment tokens in the language config and -/// returns the token which comments out the line. -fn has_line_comment(config: &Config, doc: &Document, line_num: usize) -> Option { - if config.continue_comments { - let line_tokens = { - let mut line_tokens: Vec = doc - .language_config() - .and_then(|lc| lc.comment_tokens.as_ref())? - .clone(); - // Use case (example): Rust supports `//` and `///`. We're reverse-sorting them to priorize `///` before `//` - // because otherwise a doc comment `/// like this` would get `//` as the next comment-token - line_tokens.sort_unstable_by(|a, b| b.len().partial_cmp(&a.len()).unwrap()); - line_tokens - }; - - let text = doc.text(); - let line = text.line(line_num); - - if let Some(pos) = line.first_non_whitespace_char() { - let text_line = line.slice(pos..); - return line_tokens - .iter() - .find(|&token| text_line.starts_with(token.as_str())) - .cloned(); - } - } - - None -} - pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor: bool) { use Direction::*; let config = cx.editor.config(); @@ -3372,7 +3342,7 @@ fn open(cx: &mut Context, open: Open) { let (view, doc) = current!(cx.editor); let config = doc.config.load(); - let text = doc.text().slice(..); + let doc_text = doc.text().slice(..); let contents = doc.text(); let selection = doc.selection(view.id); @@ -3380,8 +3350,8 @@ fn open(cx: &mut Context, open: Open) { let mut offs = 0; let mut transaction = Transaction::change_by_selection(contents, selection, |range| { - let cursor_line = text.char_to_line(match open { - Open::Below => graphemes::prev_grapheme_boundary(text, range.to()), + let cursor_line = doc_text.char_to_line(match open { + Open::Below => graphemes::prev_grapheme_boundary(doc_text, range.to()), Open::Above => range.from(), }); @@ -3400,18 +3370,24 @@ fn open(cx: &mut Context, open: Open) { (0, 0) } else { ( - line_end_char_index(&text, line_num), + line_end_char_index(&doc_text, line_num), doc.line_ending.len_chars(), ) }; + let indent_heuristic = if config.continue_comments { + helix_core::syntax::IndentationHeuristic::Simple + } else { + doc.config.load().indent_heuristic.clone() + }; + let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic, + &indent_heuristic, &doc.indent_style, doc.tab_width(), - text, + doc_text, line_num, line_end_index, cursor_line, @@ -3422,9 +3398,21 @@ fn open(cx: &mut Context, open: Open) { text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - if let Some(comment_token) = has_line_comment(&config, doc, line_num) { - text.push_str(&comment_token); - text.push(' '); + if config.continue_comments { + let tokens = doc + .language_config() + .and_then(|config| config.comment_tokens.as_ref()) + .unwrap(); + + for token in tokens { + let (is_commented, _, _, _) = find_line_comment(token, doc_text, [line_num]); + + if is_commented { + text.push_str(token); + text.push(' '); + break; + } + } } let text = text.repeat(count); @@ -3849,7 +3837,6 @@ pub mod insert { pub fn insert_newline(cx: &mut Context) { let (view, doc) = current_ref!(cx.editor); - let config = doc.config.load(); let text = doc.text().slice(..); let contents = doc.text(); @@ -3920,11 +3907,6 @@ pub mod insert { new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); - if let Some(comment_token) = has_line_comment(&config, doc, current_line) { - new_text.push_str(&comment_token); - new_text.push(' '); - } - new_text.chars().count() }; From b5f3dd4b0ab550dc4efce0904e4656f703b67409 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Tue, 6 Aug 2024 20:22:29 +0200 Subject: [PATCH 27/59] continue-comment: improve continue comment when writing new line --- helix-term/src/commands.rs | 34 ++++++++++++++++++++++++---------- helix-view/src/editor.rs | 12 +++++++++++- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0713cede180d..6a29398c8031 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3248,7 +3248,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { let indent = indent::indent_for_newline( language_config, syntax, - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, tab_width, text, @@ -3375,16 +3375,10 @@ fn open(cx: &mut Context, open: Open) { ) }; - let indent_heuristic = if config.continue_comments { - helix_core::syntax::IndentationHeuristic::Simple - } else { - doc.config.load().indent_heuristic.clone() - }; - let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, doc.tab_width(), doc_text, @@ -3837,6 +3831,7 @@ pub mod insert { pub fn insert_newline(cx: &mut Context) { let (view, doc) = current_ref!(cx.editor); + let config = doc.config.load(); let text = doc.text().slice(..); let contents = doc.text(); @@ -3876,7 +3871,7 @@ pub mod insert { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, doc.tab_width(), text, @@ -3893,7 +3888,7 @@ pub mod insert { .and_then(|pairs| pairs.get(prev)) .map_or(false, |pair| pair.open == prev && pair.close == curr); - let local_offs = if on_auto_pair { + let mut local_offs = if on_auto_pair { let inner_indent = indent.clone() + doc.indent_style.as_str(); new_text.reserve_exact(2 + indent.len() + inner_indent.len()); new_text.push_str(doc.line_ending.as_str()); @@ -3910,6 +3905,25 @@ pub mod insert { new_text.chars().count() }; + if config.continue_comments { + let tokens = doc + .language_config() + .and_then(|config| config.comment_tokens.as_ref()) + .unwrap(); + + for token in tokens { + let (is_commented, _, _, _) = + find_line_comment(token, text, [current_line]); + + if is_commented { + new_text.push_str(token); + new_text.push(' '); + + local_offs += token.len() + 1; // '1' for ' ' + break; + } + } + } (pos, pos, local_offs) }; diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 5bb9bcb7b0e7..979f5ca3c7ac 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -337,7 +337,7 @@ pub struct Config { pub popup_border: PopupBorderConfig, /// Which indent heuristic to use when a new line is inserted #[serde(default)] - pub indent_heuristic: IndentationHeuristic, + indent_heuristic: IndentationHeuristic, /// labels characters used in jumpmode #[serde( serialize_with = "serialize_alphabet", @@ -351,6 +351,16 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, } +impl Config { + pub fn indent_heuristic(&self) -> IndentationHeuristic { + if self.continue_comments { + IndentationHeuristic::Simple + } else { + self.indent_heuristic.clone() + } + } +} + #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[serde(rename_all = "kebab-case", default)] pub struct SmartTabConfig { From 22734da35c856b02753b51f80d02d943d930be6a Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Tue, 6 Aug 2024 21:12:24 +0200 Subject: [PATCH 28/59] continue-comment: add hepler function to reduce LOC and improve readability --- helix-core/src/comment.rs | 23 +++++++++++++++++- helix-core/src/syntax.rs | 12 ++++++++-- helix-term/src/commands.rs | 49 +++++++++++++------------------------- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 4fa5ba2bf522..f0c55d93fbcd 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -11,6 +11,27 @@ use std::borrow::Cow; pub const DEFAULT_COMMENT_TOKEN: &str = "//"; +/// Little helper function append the comment token of the previous line, if it's also commented. +pub fn continue_comment<'a>( + doc: &Rope, + tokens: &'a [String], + line_num: usize, + new_line: &mut String, +) -> Option<&'a str> { + let text = doc.slice(..); + + for token in tokens { + let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); + + if is_commented { + new_line.push_str(token); + new_line.push(' '); + return Some(token); + } + } + None +} + /// Given text, a comment token, and a set of line indices, returns the following: /// - Whether the given lines should be considered commented /// - If any of the lines are uncommented, all lines are considered as such. @@ -20,7 +41,7 @@ pub const DEFAULT_COMMENT_TOKEN: &str = "//"; /// - Column of existing tokens, if the lines are commented; column to place tokens at otherwise. /// - The margin to the right of the comment tokens /// - Defaults to `1`. If any existing comment token is not followed by a space, changes to `0`. -pub fn find_line_comment( +fn find_line_comment( token: &str, text: RopeSlice, lines: impl IntoIterator, diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 5fb44d8b2d3c..62d15a77d5d2 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -3,6 +3,7 @@ mod tree_cursor; use crate::{ auto_pairs::AutoPairs, chars::char_is_line_ending, + comment::DEFAULT_COMMENT_TOKEN, diagnostic::Severity, regex::Regex, transaction::{ChangeSet, Operation}, @@ -103,9 +104,12 @@ pub struct LanguageConfiguration { pub shebangs: Vec, // interpreter(s) associated with language #[serde(default)] pub roots: Vec, // these indicate project roots <.git, Cargo.toml> - // Invariant: Tokens are sorted by their length. Starting from the longest up to smallest. + // Invariants: + // - Tokens are sorted by their length. Starting from the longest up to smallest. + // - `comment_tokens.is_some()` is always true + // - the inner Vec is never empty #[serde( - default, + default = "default_comment_tokens", skip_serializing, deserialize_with = "from_comment_tokens", alias = "comment-token" @@ -278,6 +282,10 @@ where ) } +fn default_comment_tokens() -> Option> { + Some(vec![DEFAULT_COMMENT_TOKEN.to_string()]) +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct BlockCommentToken { pub start: String, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 6a29398c8031..5c1e107c667f 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -17,7 +17,7 @@ pub use typed::*; use helix_core::{ char_idx_at_visual_offset, chars::char_is_word, - comment::{self, find_line_comment}, + comment::{self, continue_comment}, doc_formatter::TextFormat, encoding, find_workspace, graphemes::{self, next_grapheme_boundary, RevRopeGraphemes}, @@ -3398,15 +3398,7 @@ fn open(cx: &mut Context, open: Open) { .and_then(|config| config.comment_tokens.as_ref()) .unwrap(); - for token in tokens { - let (is_commented, _, _, _) = find_line_comment(token, doc_text, [line_num]); - - if is_commented { - text.push_str(token); - text.push(' '); - break; - } - } + continue_comment(doc.text(), tokens, line_num, &mut text); } let text = text.repeat(count); @@ -3858,6 +3850,10 @@ pub mod insert { .all(|char| char.is_ascii_whitespace()); let mut new_text = String::new(); + let comment_tokens = doc + .language_config() + .and_then(|config| config.comment_tokens.as_ref()) + .unwrap(); // If the current line is all whitespace, insert a line ending at the beginning of // the current line. This makes the current line empty and the new line contain the @@ -3888,42 +3884,31 @@ pub mod insert { .and_then(|pairs| pairs.get(prev)) .map_or(false, |pair| pair.open == prev && pair.close == curr); - let mut local_offs = if on_auto_pair { + let local_offs = if on_auto_pair { + // line where the cursor will be let inner_indent = indent.clone() + doc.indent_style.as_str(); - new_text.reserve_exact(2 + indent.len() + inner_indent.len()); + new_text.reserve_exact(4 + indent.len() + inner_indent.len()); new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&inner_indent); + + // line where the matching pair will be let local_offs = new_text.chars().count(); new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); + local_offs } else { - new_text.reserve_exact(1 + indent.len()); + new_text.reserve_exact(3 + indent.len()); new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); + if config.continue_comments { + continue_comment(doc.text(), comment_tokens, current_line, &mut new_text); + } + new_text.chars().count() }; - if config.continue_comments { - let tokens = doc - .language_config() - .and_then(|config| config.comment_tokens.as_ref()) - .unwrap(); - - for token in tokens { - let (is_commented, _, _, _) = - find_line_comment(token, text, [current_line]); - - if is_commented { - new_text.push_str(token); - new_text.push(' '); - - local_offs += token.len() + 1; // '1' for ' ' - break; - } - } - } (pos, pos, local_offs) }; From de5ebe68cf0fa460e53f617abb5b3d071c4c5c4a Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 10:30:36 +0200 Subject: [PATCH 29/59] comment.rs: revamp tests --- helix-core/src/comment.rs | 109 +++++++++++++++++++++++-------------- helix-term/src/commands.rs | 2 +- helix-view/src/editor.rs | 5 ++ 3 files changed, 75 insertions(+), 41 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index f0c55d93fbcd..e126a5c86046 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -51,6 +51,7 @@ fn find_line_comment( let mut min = usize::MAX; // minimum col for first_non_whitespace_char let mut margin = 1; let token_len = token.chars().count(); + for line in lines { let line_slice = text.line(line); if let Some(pos) = line_slice.first_non_whitespace_char() { @@ -340,56 +341,84 @@ pub fn split_lines_of_selection(text: RopeSlice, selection: &Selection) -> Selec mod test { use super::*; - #[test] - fn test_find_line_comment() { - // four lines, two space indented, except for line 1 which is blank. - let mut doc = Rope::from(" 1\n\n 2\n 3"); - // select whole document - let mut selection = Selection::single(0, doc.len_chars() - 1); + mod find_line_comment { + use super::*; - let text = doc.slice(..); + // #[test] + // fn empty_line() { + // let doc = Rope::from(""); - let res = find_line_comment("//", text, 0..3); - // (commented = true, to_change = [line 0, line 2], min = col 2, margin = 0) - assert_eq!(res, (false, vec![0, 2], 2, 0)); + // let (is_commented, _, _, _) = find_line_comment("//", doc.slice(..), [0]); + // assert_eq!(is_commented, false); + // } - // comment - let transaction = toggle_line_comments(&doc, &selection, None); - transaction.apply(&mut doc); - selection = selection.map(transaction.changes()); + #[test] + fn not_commented() { + // four lines, two space indented, except for line 1 which is blank. + let doc = Rope::from(" 1\n\n 2\n 3"); - assert_eq!(doc, " // 1\n\n // 2\n // 3"); + let text = doc.slice(..); - // uncomment - let transaction = toggle_line_comments(&doc, &selection, None); - transaction.apply(&mut doc); - selection = selection.map(transaction.changes()); - assert_eq!(doc, " 1\n\n 2\n 3"); - assert!(selection.len() == 1); // to ignore the selection unused warning + let res = find_line_comment("//", text, 0..3); + // (commented = true, to_change = [line 0, line 2], min = col 2, margin = 0) + assert_eq!(res, (false, vec![0, 2], 2, 0)); + } + } - // 0 margin comments - doc = Rope::from(" //1\n\n //2\n //3"); - // reset the selection. - selection = Selection::single(0, doc.len_chars() - 1); + // TODO: account for uncommenting with uneven comment indentation + mod toggle_line_comment { + use super::*; - let transaction = toggle_line_comments(&doc, &selection, None); - transaction.apply(&mut doc); - selection = selection.map(transaction.changes()); - assert_eq!(doc, " 1\n\n 2\n 3"); - assert!(selection.len() == 1); // to ignore the selection unused warning + #[test] + fn comment() { + // four lines, two space indented, except for line 1 which is blank. + let mut doc = Rope::from(" 1\n\n 2\n 3"); + // select whole document + let selection = Selection::single(0, doc.len_chars() - 1); - // 0 margin comments, with no space - doc = Rope::from("//"); - // reset the selection. - selection = Selection::single(0, doc.len_chars() - 1); + let transaction = toggle_line_comments(&doc, &selection, None); + transaction.apply(&mut doc); - let transaction = toggle_line_comments(&doc, &selection, None); - transaction.apply(&mut doc); - selection = selection.map(transaction.changes()); - assert_eq!(doc, ""); - assert!(selection.len() == 1); // to ignore the selection unused warning + assert_eq!(doc, " // 1\n\n // 2\n // 3"); + } + + #[test] + fn uncomment() { + let mut doc = Rope::from(" // 1\n\n // 2\n // 3"); + let mut selection = Selection::single(0, doc.len_chars() - 1); + + let transaction = toggle_line_comments(&doc, &selection, None); + transaction.apply(&mut doc); + selection = selection.map(transaction.changes()); + + assert_eq!(doc, " 1\n\n 2\n 3"); + assert!(selection.len() == 1); // to ignore the selection unused warning + } - // TODO: account for uncommenting with uneven comment indentation + #[test] + fn uncomment_0_margin_comments() { + let mut doc = Rope::from(" //1\n\n //2\n //3"); + let mut selection = Selection::single(0, doc.len_chars() - 1); + + let transaction = toggle_line_comments(&doc, &selection, None); + transaction.apply(&mut doc); + selection = selection.map(transaction.changes()); + + assert_eq!(doc, " 1\n\n 2\n 3"); + assert!(selection.len() == 1); // to ignore the selection unused warning + } + + #[test] + fn uncomment_0_margin_comments_with_no_space() { + let mut doc = Rope::from("//"); + let mut selection = Selection::single(0, doc.len_chars() - 1); + + let transaction = toggle_line_comments(&doc, &selection, None); + transaction.apply(&mut doc); + selection = selection.map(transaction.changes()); + assert_eq!(doc, ""); + assert!(selection.len() == 1); // to ignore the selection unused warning + } } #[test] diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5c1e107c667f..bb2f37b393e2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3398,7 +3398,7 @@ fn open(cx: &mut Context, open: Open) { .and_then(|config| config.comment_tokens.as_ref()) .unwrap(); - continue_comment(doc.text(), tokens, line_num, &mut text); + continue_comment(doc.text(), tokens, cursor_line, &mut text); } let text = text.repeat(count); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 979f5ca3c7ac..8eff66617a21 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -217,6 +217,10 @@ impl Default for FilePickerConfig { } } +fn default_continue_comments() -> bool { + true +} + fn serialize_alphabet(alphabet: &[char], serializer: S) -> Result where S: Serializer, @@ -345,6 +349,7 @@ pub struct Config { )] pub jump_label_alphabet: Vec, /// Whether to prepend a comment token onto a new line that follows a commented line. + #[serde(default = "default_continue_comments")] pub continue_comments: bool, /// Display diagnostic below the line they occur. pub inline_diagnostics: InlineDiagnosticsConfig, From dc6411dcdb17b482309aa1a3e7e62e045c3398d9 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 10:39:01 +0200 Subject: [PATCH 30/59] comments: remove some if-guards --- helix-core/src/comment.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index e126a5c86046..b9db7e465be3 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -57,18 +57,14 @@ fn find_line_comment( if let Some(pos) = line_slice.first_non_whitespace_char() { let len = line_slice.len_chars(); - if pos < min { - min = pos; - } + min = std::cmp::min(min, pos); // line can be shorter than pos + token len let fragment = Cow::from(line_slice.slice(pos..std::cmp::min(pos + token.len(), len))); - if fragment != token { - // as soon as one of the non-blank lines doesn't have a comment, the whole block is - // considered uncommented. - commented = false; - } + // as soon as one of the non-blank lines doesn't have a comment, the whole block is + // considered uncommented. + commented = commented && !(fragment != token); // determine margin of 0 or 1 for uncommenting; if any comment token is not followed by a space, // a margin of 0 is used for all lines. @@ -344,13 +340,13 @@ mod test { mod find_line_comment { use super::*; - // #[test] - // fn empty_line() { - // let doc = Rope::from(""); + #[test] + fn empty_line() { + let doc = Rope::from(""); - // let (is_commented, _, _, _) = find_line_comment("//", doc.slice(..), [0]); - // assert_eq!(is_commented, false); - // } + let (is_commented, _, _, _) = find_line_comment("//", doc.slice(..), [0]); + assert_eq!(is_commented, false); + } #[test] fn not_commented() { @@ -360,9 +356,20 @@ mod test { let text = doc.slice(..); let res = find_line_comment("//", text, 0..3); - // (commented = true, to_change = [line 0, line 2], min = col 2, margin = 0) + // (commented = false, to_change = [line 0, line 2], min = col 2, margin = 0) assert_eq!(res, (false, vec![0, 2], 2, 0)); } + + #[test] + fn is_commented() { + // three lines where the second line is empty. + let doc = Rope::from("// hello\n\n// there"); + + let res = find_line_comment("//", doc.slice(..), 0..3); + + // (commented = true, to_change = [line 0, line 2], min = col 0, margin = 1) + assert_eq!(res, (true, vec![0, 2], 0, 1)); + } } // TODO: account for uncommenting with uneven comment indentation From ca6ee48b42af500be73ceeab9b9455b2e85af63e Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 10:42:28 +0200 Subject: [PATCH 31/59] comments: add special case if the text is empty it won't be considered as a comment --- helix-core/src/comment.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index b9db7e465be3..2469deb00fb9 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -47,6 +47,7 @@ fn find_line_comment( lines: impl IntoIterator, ) -> (bool, Vec, usize, usize) { let mut commented = true; + let mut text_is_empty = true; let mut to_change = Vec::new(); let mut min = usize::MAX; // minimum col for first_non_whitespace_char let mut margin = 1; @@ -55,6 +56,7 @@ fn find_line_comment( for line in lines { let line_slice = text.line(line); if let Some(pos) = line_slice.first_non_whitespace_char() { + text_is_empty = false; let len = line_slice.len_chars(); min = std::cmp::min(min, pos); @@ -64,7 +66,9 @@ fn find_line_comment( // as soon as one of the non-blank lines doesn't have a comment, the whole block is // considered uncommented. - commented = commented && !(fragment != token); + if fragment != token { + commented = false; + } // determine margin of 0 or 1 for uncommenting; if any comment token is not followed by a space, // a margin of 0 is used for all lines. @@ -76,6 +80,11 @@ fn find_line_comment( to_change.push(line); } } + + if text_is_empty { + commented = false; + } + (commented, to_change, min, margin) } From 1a95d402ed184fc991d17b05f3f2f2e63a3930bb Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 11:10:52 +0200 Subject: [PATCH 32/59] continue-comment: fix token finding --- helix-core/src/comment.rs | 21 ++++++++++++++++++--- helix-core/src/syntax.rs | 6 +----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 2469deb00fb9..5ae22bcab5a7 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -19,16 +19,31 @@ pub fn continue_comment<'a>( new_line: &mut String, ) -> Option<&'a str> { let text = doc.slice(..); + let mut apply_token = false; + + let mut used_token = tokens + .first() + .map(|token| token.as_str()) + .unwrap_or(DEFAULT_COMMENT_TOKEN); for token in tokens { let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); if is_commented { - new_line.push_str(token); - new_line.push(' '); - return Some(token); + apply_token = true; + + if token.len() > used_token.len() { + used_token = token; + } } } + + if apply_token { + new_line.push_str(used_token); + new_line.push(' '); + return Some(used_token); + } + None } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 62d15a77d5d2..b8f1e0db681a 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -105,7 +105,6 @@ pub struct LanguageConfiguration { #[serde(default)] pub roots: Vec, // these indicate project roots <.git, Cargo.toml> // Invariants: - // - Tokens are sorted by their length. Starting from the longest up to smallest. // - `comment_tokens.is_some()` is always true // - the inner Vec is never empty #[serde( @@ -274,10 +273,7 @@ where Ok( Option::::deserialize(deserializer)?.map(|tokens| match tokens { CommentTokens::Single(val) => vec![val], - CommentTokens::Multiple(mut vals) => { - vals.sort_unstable_by(|a, b| b.len().partial_cmp(&a.len()).unwrap()); - vals - } + CommentTokens::Multiple(vals) => vals, }), ) } From dc925007ecb1a7d08f8d535e7f4de7ea0d5b6d01 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 11:42:12 +0200 Subject: [PATCH 33/59] make clippy happy --- helix-core/src/comment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 5ae22bcab5a7..345cc2caca3a 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -369,7 +369,7 @@ mod test { let doc = Rope::from(""); let (is_commented, _, _, _) = find_line_comment("//", doc.slice(..), [0]); - assert_eq!(is_commented, false); + assert!(!is_commented); } #[test] From 1e18f1bc9dfd4491b96ffc5d89a3ded2143521d9 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 11:51:57 +0200 Subject: [PATCH 34/59] config: fix tests --- helix-view/src/editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 8eff66617a21..65ede18c10de 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -341,7 +341,7 @@ pub struct Config { pub popup_border: PopupBorderConfig, /// Which indent heuristic to use when a new line is inserted #[serde(default)] - indent_heuristic: IndentationHeuristic, + pub indent_heuristic: IndentationHeuristic, /// labels characters used in jumpmode #[serde( serialize_with = "serialize_alphabet", From f68cf646c174a9d535e0aa318bae2affa7d8d301 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 11:55:22 +0200 Subject: [PATCH 35/59] continue-comments: add some docs --- helix-view/src/editor.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 65ede18c10de..bf967d4ffb4b 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -357,6 +357,7 @@ pub struct Config { } impl Config { + /// Returns the `indent_heuristic` depending, if `continue_comments` is set or not. pub fn indent_heuristic(&self) -> IndentationHeuristic { if self.continue_comments { IndentationHeuristic::Simple From 4cc5148009838e5917a518aab7c3a47c1acddc53 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Wed, 7 Aug 2024 12:19:18 +0200 Subject: [PATCH 36/59] continue-comment: remove unwraps --- helix-core/src/comment.rs | 41 +++++++++++++++++++++++--------------- helix-term/src/commands.rs | 6 ++---- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 345cc2caca3a..07921b253949 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -14,34 +14,43 @@ pub const DEFAULT_COMMENT_TOKEN: &str = "//"; /// Little helper function append the comment token of the previous line, if it's also commented. pub fn continue_comment<'a>( doc: &Rope, - tokens: &'a [String], + tokens: Option<&'a Vec>, line_num: usize, new_line: &mut String, ) -> Option<&'a str> { let text = doc.slice(..); let mut apply_token = false; - let mut used_token = tokens - .first() - .map(|token| token.as_str()) - .unwrap_or(DEFAULT_COMMENT_TOKEN); + if let Some(tokens) = tokens { + let mut used_token = tokens + .first() + .map(|token| token.as_str()) + .unwrap_or(DEFAULT_COMMENT_TOKEN); - for token in tokens { - let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); + for token in tokens { + let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); - if is_commented { - apply_token = true; + if is_commented { + apply_token = true; - if token.len() > used_token.len() { - used_token = token; + if token.len() > used_token.len() { + used_token = token; + } } } - } - if apply_token { - new_line.push_str(used_token); - new_line.push(' '); - return Some(used_token); + if apply_token { + new_line.push_str(used_token); + new_line.push(' '); + return Some(used_token); + } + } else { + let (is_commented, _, _, _) = find_line_comment(DEFAULT_COMMENT_TOKEN, text, [line_num]); + if is_commented { + new_line.push_str(DEFAULT_COMMENT_TOKEN); + new_line.push(' '); + return Some(DEFAULT_COMMENT_TOKEN); + } } None diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index bb2f37b393e2..1229fbb81939 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3395,8 +3395,7 @@ fn open(cx: &mut Context, open: Open) { if config.continue_comments { let tokens = doc .language_config() - .and_then(|config| config.comment_tokens.as_ref()) - .unwrap(); + .and_then(|config| config.comment_tokens.as_ref()); continue_comment(doc.text(), tokens, cursor_line, &mut text); } @@ -3852,8 +3851,7 @@ pub mod insert { let mut new_text = String::new(); let comment_tokens = doc .language_config() - .and_then(|config| config.comment_tokens.as_ref()) - .unwrap(); + .and_then(|config| config.comment_tokens.as_ref()); // If the current line is all whitespace, insert a line ending at the beginning of // the current line. This makes the current line empty and the new line contain the From da2a4440299a0376b5a09d76179f501928d62e3f Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Fri, 9 Aug 2024 23:31:16 +0200 Subject: [PATCH 37/59] continue-comment: removing indent_heuristic function --- helix-term/src/commands.rs | 6 +++--- helix-view/src/editor.rs | 11 ----------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 7e7bbf75cc93..2d39c69a7b41 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3298,7 +3298,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { let indent = indent::indent_for_newline( language_config, syntax, - &doc.config.load().indent_heuristic(), + &doc.config.load().indent_heuristic, &doc.indent_style, tab_width, text, @@ -3428,7 +3428,7 @@ fn open(cx: &mut Context, open: Open) { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic(), + &doc.config.load().indent_heuristic, &doc.indent_style, doc.tab_width(), doc_text, @@ -3915,7 +3915,7 @@ pub mod insert { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic(), + &doc.config.load().indent_heuristic, &doc.indent_style, doc.tab_width(), text, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 53ccec21d878..f0c81b7b9b87 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -354,17 +354,6 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, } -impl Config { - /// Returns the `indent_heuristic` depending, if `continue_comments` is set or not. - pub fn indent_heuristic(&self) -> IndentationHeuristic { - if self.continue_comments { - IndentationHeuristic::Simple - } else { - self.indent_heuristic.clone() - } - } -} - #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[serde(rename_all = "kebab-case", default)] pub struct SmartTabConfig { From 1eb963d2c04bd200190705de5248d9a54085656f Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Fri, 9 Aug 2024 23:39:17 +0200 Subject: [PATCH 38/59] Revert "continue-comment: removing indent_heuristic function" This reverts commit da2a4440299a0376b5a09d76179f501928d62e3f. --- helix-term/src/commands.rs | 6 +++--- helix-view/src/editor.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2d39c69a7b41..7e7bbf75cc93 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3298,7 +3298,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { let indent = indent::indent_for_newline( language_config, syntax, - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, tab_width, text, @@ -3428,7 +3428,7 @@ fn open(cx: &mut Context, open: Open) { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, doc.tab_width(), doc_text, @@ -3915,7 +3915,7 @@ pub mod insert { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, doc.tab_width(), text, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f0c81b7b9b87..53ccec21d878 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -354,6 +354,17 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, } +impl Config { + /// Returns the `indent_heuristic` depending, if `continue_comments` is set or not. + pub fn indent_heuristic(&self) -> IndentationHeuristic { + if self.continue_comments { + IndentationHeuristic::Simple + } else { + self.indent_heuristic.clone() + } + } +} + #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[serde(rename_all = "kebab-case", default)] pub struct SmartTabConfig { From 9c091414da40e5402127accaf8200947d3ff27d3 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Fri, 9 Aug 2024 23:39:22 +0200 Subject: [PATCH 39/59] Reapply "continue-comment: removing indent_heuristic function" This reverts commit 1eb963d2c04bd200190705de5248d9a54085656f. --- helix-term/src/commands.rs | 6 +++--- helix-view/src/editor.rs | 11 ----------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 7e7bbf75cc93..2d39c69a7b41 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3298,7 +3298,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { let indent = indent::indent_for_newline( language_config, syntax, - &doc.config.load().indent_heuristic(), + &doc.config.load().indent_heuristic, &doc.indent_style, tab_width, text, @@ -3428,7 +3428,7 @@ fn open(cx: &mut Context, open: Open) { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic(), + &doc.config.load().indent_heuristic, &doc.indent_style, doc.tab_width(), doc_text, @@ -3915,7 +3915,7 @@ pub mod insert { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic(), + &doc.config.load().indent_heuristic, &doc.indent_style, doc.tab_width(), text, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 53ccec21d878..f0c81b7b9b87 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -354,17 +354,6 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, } -impl Config { - /// Returns the `indent_heuristic` depending, if `continue_comments` is set or not. - pub fn indent_heuristic(&self) -> IndentationHeuristic { - if self.continue_comments { - IndentationHeuristic::Simple - } else { - self.indent_heuristic.clone() - } - } -} - #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[serde(rename_all = "kebab-case", default)] pub struct SmartTabConfig { From d4b1dfbb3825aa005895c3ae46b635f840851786 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Fri, 9 Aug 2024 23:40:10 +0200 Subject: [PATCH 40/59] Revert "continue-comment: removing indent_heuristic function" This reverts commit da2a4440299a0376b5a09d76179f501928d62e3f. --- helix-term/src/commands.rs | 6 +++--- helix-view/src/editor.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2d39c69a7b41..7e7bbf75cc93 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3298,7 +3298,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { let indent = indent::indent_for_newline( language_config, syntax, - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, tab_width, text, @@ -3428,7 +3428,7 @@ fn open(cx: &mut Context, open: Open) { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, doc.tab_width(), doc_text, @@ -3915,7 +3915,7 @@ pub mod insert { let indent = indent::indent_for_newline( doc.language_config(), doc.syntax(), - &doc.config.load().indent_heuristic, + &doc.config.load().indent_heuristic(), &doc.indent_style, doc.tab_width(), text, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f0c81b7b9b87..53ccec21d878 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -354,6 +354,17 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, } +impl Config { + /// Returns the `indent_heuristic` depending, if `continue_comments` is set or not. + pub fn indent_heuristic(&self) -> IndentationHeuristic { + if self.continue_comments { + IndentationHeuristic::Simple + } else { + self.indent_heuristic.clone() + } + } +} + #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[serde(rename_all = "kebab-case", default)] pub struct SmartTabConfig { From f53ec12dcf9612e56655047f22013e228c86cda8 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Fri, 9 Aug 2024 23:41:34 +0200 Subject: [PATCH 41/59] continue-comment: set default value for continue comments to false --- helix-view/src/editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 53ccec21d878..0073d1bef9fc 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -216,7 +216,7 @@ impl Default for FilePickerConfig { } fn default_continue_comments() -> bool { - true + false } fn serialize_alphabet(alphabet: &[char], serializer: S) -> Result From 372550dcfd2b132ee2c6fa093434b564ccc13910 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Fri, 9 Aug 2024 23:55:10 +0200 Subject: [PATCH 42/59] continue-comment: enable by default and use hybrid indentation --- helix-view/src/editor.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 0073d1bef9fc..e175c0ff1ef4 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -216,7 +216,7 @@ impl Default for FilePickerConfig { } fn default_continue_comments() -> bool { - false + true } fn serialize_alphabet(alphabet: &[char], serializer: S) -> Result @@ -346,7 +346,7 @@ pub struct Config { deserialize_with = "deserialize_alphabet" )] pub jump_label_alphabet: Vec, - /// Whether to prepend a comment token onto a new line that follows a commented line. + /// Whether to prepend a comment token onto a new line that follows a commented line. (default: false) #[serde(default = "default_continue_comments")] pub continue_comments: bool, /// Display diagnostic below the line they occur. @@ -358,7 +358,7 @@ impl Config { /// Returns the `indent_heuristic` depending, if `continue_comments` is set or not. pub fn indent_heuristic(&self) -> IndentationHeuristic { if self.continue_comments { - IndentationHeuristic::Simple + IndentationHeuristic::Hybrid } else { self.indent_heuristic.clone() } From 83093f81b40dbc574bbcddb7ddd68a24c7f017ee Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sat, 10 Aug 2024 09:43:14 +0200 Subject: [PATCH 43/59] continue-comments: fix indent-logic if continue-comments wants to place a comment --- helix-core/src/comment.rs | 9 +-- helix-term/src/commands.rs | 111 ++++++++++++++++++++++++++----------- helix-view/src/editor.rs | 11 ---- 3 files changed, 80 insertions(+), 51 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 07921b253949..0a5a511b8e1f 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -11,12 +11,11 @@ use std::borrow::Cow; pub const DEFAULT_COMMENT_TOKEN: &str = "//"; -/// Little helper function append the comment token of the previous line, if it's also commented. -pub fn continue_comment<'a>( +/// Returns the matching comment token of the given line (if it exists). +pub fn get_comment_token<'a>( doc: &Rope, tokens: Option<&'a Vec>, line_num: usize, - new_line: &mut String, ) -> Option<&'a str> { let text = doc.slice(..); let mut apply_token = false; @@ -40,15 +39,11 @@ pub fn continue_comment<'a>( } if apply_token { - new_line.push_str(used_token); - new_line.push(' '); return Some(used_token); } } else { let (is_commented, _, _, _) = find_line_comment(DEFAULT_COMMENT_TOKEN, text, [line_num]); if is_commented { - new_line.push_str(DEFAULT_COMMENT_TOKEN); - new_line.push(' '); return Some(DEFAULT_COMMENT_TOKEN); } } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 7e7bbf75cc93..de83754218e8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -17,7 +17,7 @@ pub use typed::*; use helix_core::{ char_idx_at_visual_offset, chars::char_is_word, - comment::{self, continue_comment}, + comment::{self, get_comment_token}, doc_formatter::TextFormat, encoding, find_workspace, graphemes::{self, next_grapheme_boundary, RevRopeGraphemes}, @@ -3298,7 +3298,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) { let indent = indent::indent_for_newline( language_config, syntax, - &doc.config.load().indent_heuristic(), + &doc.config.load().indent_heuristic, &doc.indent_style, tab_width, text, @@ -3425,17 +3425,39 @@ fn open(cx: &mut Context, open: Open) { ) }; - let indent = indent::indent_for_newline( - doc.language_config(), - doc.syntax(), - &doc.config.load().indent_heuristic(), - &doc.indent_style, - doc.tab_width(), - doc_text, - line_num, - line_end_index, - cursor_line, - ); + let comment_token = { + let tokens = doc + .language_config() + .and_then(|config| config.comment_tokens.as_ref()); + + get_comment_token(doc.text(), tokens, cursor_line) + }; + let new_line_will_be_comment = config.continue_comments && comment_token.is_some(); + let indent = if new_line_will_be_comment { + indent::indent_for_newline( + doc.language_config(), + doc.syntax(), + &helix_core::syntax::IndentationHeuristic::Simple, + &doc.indent_style, + doc.tab_width(), + doc_text, + line_num, + line_end_index, + cursor_line, + ) + } else { + indent::indent_for_newline( + doc.language_config(), + doc.syntax(), + &doc.config.load().indent_heuristic, + &doc.indent_style, + doc.tab_width(), + doc_text, + line_num, + line_end_index, + cursor_line, + ) + }; let indent_len = indent.len(); let mut text = String::with_capacity(1 + indent_len); @@ -3443,11 +3465,10 @@ fn open(cx: &mut Context, open: Open) { text.push_str(&indent); if config.continue_comments { - let tokens = doc - .language_config() - .and_then(|config| config.comment_tokens.as_ref()); - - continue_comment(doc.text(), tokens, cursor_line, &mut text); + if let Some(token) = comment_token { + text.push_str(token); + text.push(' '); + } } let text = text.repeat(count); @@ -3899,9 +3920,14 @@ pub mod insert { .all(|char| char.is_ascii_whitespace()); let mut new_text = String::new(); - let comment_tokens = doc - .language_config() - .and_then(|config| config.comment_tokens.as_ref()); + + let comment_token = { + let tokens = doc + .language_config() + .and_then(|config| config.comment_tokens.as_ref()); + + get_comment_token(doc.text(), tokens, current_line) + }; // If the current line is all whitespace, insert a line ending at the beginning of // the current line. This makes the current line empty and the new line contain the @@ -3912,17 +3938,33 @@ pub mod insert { (line_start, line_start, new_text.chars().count()) } else { - let indent = indent::indent_for_newline( - doc.language_config(), - doc.syntax(), - &doc.config.load().indent_heuristic(), - &doc.indent_style, - doc.tab_width(), - text, - current_line, - pos, - current_line, - ); + let new_line_will_be_comment = config.continue_comments && comment_token.is_some(); + + let indent = if new_line_will_be_comment { + indent::indent_for_newline( + doc.language_config(), + doc.syntax(), + &helix_core::syntax::IndentationHeuristic::Simple, + &doc.indent_style, + doc.tab_width(), + text, + current_line, + pos, + current_line, + ) + } else { + indent::indent_for_newline( + doc.language_config(), + doc.syntax(), + &doc.config.load().indent_heuristic, + &doc.indent_style, + doc.tab_width(), + text, + current_line, + pos, + current_line, + ) + }; // If we are between pairs (such as brackets), we want to // insert an additional line which is indented one level @@ -3951,7 +3993,10 @@ pub mod insert { new_text.push_str(&indent); if config.continue_comments { - continue_comment(doc.text(), comment_tokens, current_line, &mut new_text); + if let Some(token) = comment_token { + new_text.push_str(token); + new_text.push(' '); + } } new_text.chars().count() diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index e175c0ff1ef4..152f1eb6dee7 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -354,17 +354,6 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, } -impl Config { - /// Returns the `indent_heuristic` depending, if `continue_comments` is set or not. - pub fn indent_heuristic(&self) -> IndentationHeuristic { - if self.continue_comments { - IndentationHeuristic::Hybrid - } else { - self.indent_heuristic.clone() - } - } -} - #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[serde(rename_all = "kebab-case", default)] pub struct SmartTabConfig { From b842fdb48a0fbd72d0a447f51485a1327d1f7342 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sat, 10 Aug 2024 10:07:45 +0200 Subject: [PATCH 44/59] continue-comment: improve code readability --- helix-core/src/comment.rs | 4 +-- helix-term/src/commands.rs | 61 ++++++++++++++------------------------ 2 files changed, 24 insertions(+), 41 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 0a5a511b8e1f..10b73ad2b266 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -13,11 +13,11 @@ pub const DEFAULT_COMMENT_TOKEN: &str = "//"; /// Returns the matching comment token of the given line (if it exists). pub fn get_comment_token<'a>( - doc: &Rope, + text: &Rope, tokens: Option<&'a Vec>, line_num: usize, ) -> Option<&'a str> { - let text = doc.slice(..); + let text = text.slice(..); let mut apply_token = false; if let Some(tokens) = tokens { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index de83754218e8..38496f580b7a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3433,30 +3433,23 @@ fn open(cx: &mut Context, open: Open) { get_comment_token(doc.text(), tokens, cursor_line) }; let new_line_will_be_comment = config.continue_comments && comment_token.is_some(); - let indent = if new_line_will_be_comment { - indent::indent_for_newline( - doc.language_config(), - doc.syntax(), - &helix_core::syntax::IndentationHeuristic::Simple, - &doc.indent_style, - doc.tab_width(), - doc_text, - line_num, - line_end_index, - cursor_line, - ) - } else { - indent::indent_for_newline( - doc.language_config(), - doc.syntax(), - &doc.config.load().indent_heuristic, - &doc.indent_style, - doc.tab_width(), - doc_text, - line_num, - line_end_index, - cursor_line, - ) + + let indent = { + let line = doc_text.line(cursor_line); + match line.first_non_whitespace_char() { + Some(pos) if new_line_will_be_comment => line.slice(..pos).to_string(), + _ => indent::indent_for_newline( + doc.language_config(), + doc.syntax(), + &doc.config.load().indent_heuristic, + &doc.indent_style, + doc.tab_width(), + doc_text, + line_num, + line_end_index, + cursor_line, + ), + } }; let indent_len = indent.len(); @@ -3939,21 +3932,11 @@ pub mod insert { (line_start, line_start, new_text.chars().count()) } else { let new_line_will_be_comment = config.continue_comments && comment_token.is_some(); + let line = text.line(current_line); - let indent = if new_line_will_be_comment { - indent::indent_for_newline( - doc.language_config(), - doc.syntax(), - &helix_core::syntax::IndentationHeuristic::Simple, - &doc.indent_style, - doc.tab_width(), - text, - current_line, - pos, - current_line, - ) - } else { - indent::indent_for_newline( + let indent = match line.first_non_whitespace_char() { + Some(pos) if new_line_will_be_comment => line.slice(..pos).to_string(), + _ => indent::indent_for_newline( doc.language_config(), doc.syntax(), &doc.config.load().indent_heuristic, @@ -3963,7 +3946,7 @@ pub mod insert { current_line, pos, current_line, - ) + ), }; // If we are between pairs (such as brackets), we want to From b5003e957f57daf3dcc021cfe678a7a1627c9a99 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sat, 10 Aug 2024 10:13:04 +0200 Subject: [PATCH 45/59] continue-comment: add some comments and remove unused code --- helix-core/src/comment.rs | 16 +++++++++------- helix-core/src/syntax.rs | 10 +--------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 10b73ad2b266..b8defa4d1f89 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -18,10 +18,10 @@ pub fn get_comment_token<'a>( line_num: usize, ) -> Option<&'a str> { let text = text.slice(..); - let mut apply_token = false; + let mut token_found = false; if let Some(tokens) = tokens { - let mut used_token = tokens + let mut final_token = tokens .first() .map(|token| token.as_str()) .unwrap_or(DEFAULT_COMMENT_TOKEN); @@ -30,16 +30,18 @@ pub fn get_comment_token<'a>( let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); if is_commented { - apply_token = true; + token_found = true; - if token.len() > used_token.len() { - used_token = token; + // in rust for example, there's `//` and `///`. + // We need to find the longest matching comment token so we can't immediately return the first matching token. + if token.len() > final_token.len() { + final_token = token; } } } - if apply_token { - return Some(used_token); + if token_found { + return Some(final_token); } } else { let (is_commented, _, _, _) = find_line_comment(DEFAULT_COMMENT_TOKEN, text, [line_num]); diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index b9fac330b04d..7be512f52e2c 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -3,7 +3,6 @@ mod tree_cursor; use crate::{ auto_pairs::AutoPairs, chars::char_is_line_ending, - comment::DEFAULT_COMMENT_TOKEN, diagnostic::Severity, regex::Regex, transaction::{ChangeSet, Operation}, @@ -104,11 +103,8 @@ pub struct LanguageConfiguration { pub shebangs: Vec, // interpreter(s) associated with language #[serde(default)] pub roots: Vec, // these indicate project roots <.git, Cargo.toml> - // Invariants: - // - `comment_tokens.is_some()` is always true - // - the inner Vec is never empty #[serde( - default = "default_comment_tokens", + default, skip_serializing, deserialize_with = "from_comment_tokens", alias = "comment-token" @@ -278,10 +274,6 @@ where ) } -fn default_comment_tokens() -> Option> { - Some(vec![DEFAULT_COMMENT_TOKEN.to_string()]) -} - #[derive(Clone, Debug, Serialize, Deserialize)] pub struct BlockCommentToken { pub start: String, From 835b4babf3bac2d972f95a0f054c684cd1b3148e Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 00:02:19 +0200 Subject: [PATCH 46/59] revert unecessary variable renaming --- helix-term/src/commands.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 38496f580b7a..776796657e66 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3392,7 +3392,7 @@ fn open(cx: &mut Context, open: Open) { let (view, doc) = current!(cx.editor); let config = doc.config.load(); - let doc_text = doc.text().slice(..); + let text = doc.text().slice(..); let contents = doc.text(); let selection = doc.selection(view.id); @@ -3400,8 +3400,8 @@ fn open(cx: &mut Context, open: Open) { let mut offs = 0; let mut transaction = Transaction::change_by_selection(contents, selection, |range| { - let cursor_line = doc_text.char_to_line(match open { - Open::Below => graphemes::prev_grapheme_boundary(doc_text, range.to()), + let cursor_line = text.char_to_line(match open { + Open::Below => graphemes::prev_grapheme_boundary(text, range.to()), Open::Above => range.from(), }); @@ -3420,7 +3420,7 @@ fn open(cx: &mut Context, open: Open) { (0, 0) } else { ( - line_end_char_index(&doc_text, line_num), + line_end_char_index(&text, line_num), doc.line_ending.len_chars(), ) }; @@ -3435,7 +3435,7 @@ fn open(cx: &mut Context, open: Open) { let new_line_will_be_comment = config.continue_comments && comment_token.is_some(); let indent = { - let line = doc_text.line(cursor_line); + let line = text.line(cursor_line); match line.first_non_whitespace_char() { Some(pos) if new_line_will_be_comment => line.slice(..pos).to_string(), _ => indent::indent_for_newline( @@ -3444,7 +3444,7 @@ fn open(cx: &mut Context, open: Open) { &doc.config.load().indent_heuristic, &doc.indent_style, doc.tab_width(), - doc_text, + text, line_num, line_end_index, cursor_line, From 310b6dd18b46839c1120a632c5a9d03c79a9ce76 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 00:05:59 +0200 Subject: [PATCH 47/59] remove config option for continue-comments --- helix-term/src/commands.rs | 22 ++++++++-------------- helix-view/src/editor.rs | 8 -------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 776796657e66..bf8526da5f5c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3391,7 +3391,6 @@ fn open(cx: &mut Context, open: Open) { enter_insert_mode(cx); let (view, doc) = current!(cx.editor); - let config = doc.config.load(); let text = doc.text().slice(..); let contents = doc.text(); let selection = doc.selection(view.id); @@ -3432,7 +3431,7 @@ fn open(cx: &mut Context, open: Open) { get_comment_token(doc.text(), tokens, cursor_line) }; - let new_line_will_be_comment = config.continue_comments && comment_token.is_some(); + let new_line_will_be_comment = comment_token.is_some(); let indent = { let line = text.line(cursor_line); @@ -3457,11 +3456,9 @@ fn open(cx: &mut Context, open: Open) { text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - if config.continue_comments { - if let Some(token) = comment_token { - text.push_str(token); - text.push(' '); - } + if let Some(token) = comment_token { + text.push_str(token); + text.push(' '); } let text = text.repeat(count); @@ -3886,7 +3883,6 @@ pub mod insert { pub fn insert_newline(cx: &mut Context) { let (view, doc) = current_ref!(cx.editor); - let config = doc.config.load(); let text = doc.text().slice(..); let contents = doc.text(); @@ -3931,7 +3927,7 @@ pub mod insert { (line_start, line_start, new_text.chars().count()) } else { - let new_line_will_be_comment = config.continue_comments && comment_token.is_some(); + let new_line_will_be_comment = comment_token.is_some(); let line = text.line(current_line); let indent = match line.first_non_whitespace_char() { @@ -3975,11 +3971,9 @@ pub mod insert { new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); - if config.continue_comments { - if let Some(token) = comment_token { - new_text.push_str(token); - new_text.push(' '); - } + if let Some(token) = comment_token { + new_text.push_str(token); + new_text.push(' '); } new_text.chars().count() diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 152f1eb6dee7..1708b3b4e053 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -215,10 +215,6 @@ impl Default for FilePickerConfig { } } -fn default_continue_comments() -> bool { - true -} - fn serialize_alphabet(alphabet: &[char], serializer: S) -> Result where S: Serializer, @@ -346,9 +342,6 @@ pub struct Config { deserialize_with = "deserialize_alphabet" )] pub jump_label_alphabet: Vec, - /// Whether to prepend a comment token onto a new line that follows a commented line. (default: false) - #[serde(default = "default_continue_comments")] - pub continue_comments: bool, /// Display diagnostic below the line they occur. pub inline_diagnostics: InlineDiagnosticsConfig, pub end_of_line_diagnostics: DiagnosticFilter, @@ -984,7 +977,6 @@ impl Default for Config { popup_border: PopupBorderConfig::None, indent_heuristic: IndentationHeuristic::default(), jump_label_alphabet: ('a'..='z').collect(), - continue_comments: true, inline_diagnostics: InlineDiagnosticsConfig::default(), end_of_line_diagnostics: DiagnosticFilter::Disable, } From 45f230e04596b2142dcdd8c6d70dbebde5dc8f10 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 12:14:35 +0200 Subject: [PATCH 48/59] continue-comments: update parameter types of `get_comment_token` --- helix-core/src/comment.rs | 42 +++++++++++++++----------------------- helix-term/src/commands.rs | 27 +++++++++++++----------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index b8defa4d1f89..1a9985aab157 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -13,41 +13,33 @@ pub const DEFAULT_COMMENT_TOKEN: &str = "//"; /// Returns the matching comment token of the given line (if it exists). pub fn get_comment_token<'a>( - text: &Rope, - tokens: Option<&'a Vec>, + text: RopeSlice, + tokens: &'a Vec, line_num: usize, ) -> Option<&'a str> { - let text = text.slice(..); let mut token_found = false; - if let Some(tokens) = tokens { - let mut final_token = tokens - .first() - .map(|token| token.as_str()) - .unwrap_or(DEFAULT_COMMENT_TOKEN); + let mut final_token = tokens + .first() + .map(|token| token.as_str()) + .unwrap_or(DEFAULT_COMMENT_TOKEN); - for token in tokens { - let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); + for token in tokens { + let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); - if is_commented { - token_found = true; + if is_commented { + token_found = true; - // in rust for example, there's `//` and `///`. - // We need to find the longest matching comment token so we can't immediately return the first matching token. - if token.len() > final_token.len() { - final_token = token; - } + // in rust for example, there's `//` and `///`. + // We need to find the longest matching comment token so we can't immediately return the first matching token. + if token.len() > final_token.len() { + final_token = token; } } + } - if token_found { - return Some(final_token); - } - } else { - let (is_commented, _, _, _) = find_line_comment(DEFAULT_COMMENT_TOKEN, text, [line_num]); - if is_commented { - return Some(DEFAULT_COMMENT_TOKEN); - } + if token_found { + return Some(final_token); } None diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index bf8526da5f5c..4da65a17e260 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3424,13 +3424,15 @@ fn open(cx: &mut Context, open: Open) { ) }; - let comment_token = { - let tokens = doc - .language_config() - .and_then(|config| config.comment_tokens.as_ref()); - - get_comment_token(doc.text(), tokens, cursor_line) + let comment_token = if let Some(tokens) = doc + .language_config() + .and_then(|config| config.comment_tokens.as_ref()) + { + get_comment_token(doc.text().slice(..), tokens, cursor_line) + } else { + None }; + let new_line_will_be_comment = comment_token.is_some(); let indent = { @@ -3910,12 +3912,13 @@ pub mod insert { let mut new_text = String::new(); - let comment_token = { - let tokens = doc - .language_config() - .and_then(|config| config.comment_tokens.as_ref()); - - get_comment_token(doc.text(), tokens, current_line) + let comment_token = if let Some(tokens) = doc + .language_config() + .and_then(|config| config.comment_tokens.as_ref()) + { + get_comment_token(doc.text().slice(..), tokens, current_line) + } else { + None }; // If the current line is all whitespace, insert a line ending at the beginning of From ce5d174a4d7662f1fc3cb8ff15903c11eb6a2389 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 12:22:00 +0200 Subject: [PATCH 49/59] continue-comments: restructure `get_comment_token` --- helix-core/src/comment.rs | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 1a9985aab157..dbb5d144b544 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -11,38 +11,26 @@ use std::borrow::Cow; pub const DEFAULT_COMMENT_TOKEN: &str = "//"; -/// Returns the matching comment token of the given line (if it exists). +/// Returns the longest matching comment token of the given line (if it exists). pub fn get_comment_token<'a>( text: RopeSlice, - tokens: &'a Vec, + tokens: &'a [String], line_num: usize, ) -> Option<&'a str> { - let mut token_found = false; + let mut used_token: Option<&'a str> = None; - let mut final_token = tokens - .first() - .map(|token| token.as_str()) - .unwrap_or(DEFAULT_COMMENT_TOKEN); + let line = text.line(line_num); + let start = line.char_to_byte(line.first_non_whitespace_char()?); for token in tokens { - let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]); - - if is_commented { - token_found = true; - - // in rust for example, there's `//` and `///`. - // We need to find the longest matching comment token so we can't immediately return the first matching token. - if token.len() > final_token.len() { - final_token = token; - } + let end = std::cmp::min(start + token.len(), line.len_bytes()); + let fragment = Cow::from(line.byte_slice(start..end)); + if fragment == *token { + used_token = Some(token.as_str()); } } - if token_found { - return Some(final_token); - } - - None + used_token } /// Given text, a comment token, and a set of line indices, returns the following: From 170c8c2c7e02dc36398547b4991fe2450aa93226 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 12:26:19 +0200 Subject: [PATCH 50/59] continue-comments: simplify code --- helix-term/src/commands.rs | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4da65a17e260..b1f346f76d74 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3424,21 +3424,15 @@ fn open(cx: &mut Context, open: Open) { ) }; - let comment_token = if let Some(tokens) = doc + let continue_comment_token = doc .language_config() .and_then(|config| config.comment_tokens.as_ref()) - { - get_comment_token(doc.text().slice(..), tokens, cursor_line) - } else { - None - }; - - let new_line_will_be_comment = comment_token.is_some(); + .and_then(|tokens| comment::get_comment_token(text, tokens, cursor_line)); let indent = { let line = text.line(cursor_line); match line.first_non_whitespace_char() { - Some(pos) if new_line_will_be_comment => line.slice(..pos).to_string(), + Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(), _ => indent::indent_for_newline( doc.language_config(), doc.syntax(), @@ -3458,7 +3452,7 @@ fn open(cx: &mut Context, open: Open) { text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - if let Some(token) = comment_token { + if let Some(token) = continue_comment_token { text.push_str(token); text.push(' '); } @@ -3912,14 +3906,10 @@ pub mod insert { let mut new_text = String::new(); - let comment_token = if let Some(tokens) = doc + let continue_comment_token = doc .language_config() .and_then(|config| config.comment_tokens.as_ref()) - { - get_comment_token(doc.text().slice(..), tokens, current_line) - } else { - None - }; + .and_then(|tokens| comment::get_comment_token(text, tokens, current_line)); // If the current line is all whitespace, insert a line ending at the beginning of // the current line. This makes the current line empty and the new line contain the @@ -3930,11 +3920,10 @@ pub mod insert { (line_start, line_start, new_text.chars().count()) } else { - let new_line_will_be_comment = comment_token.is_some(); let line = text.line(current_line); let indent = match line.first_non_whitespace_char() { - Some(pos) if new_line_will_be_comment => line.slice(..pos).to_string(), + Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(), _ => indent::indent_for_newline( doc.language_config(), doc.syntax(), @@ -3974,7 +3963,7 @@ pub mod insert { new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); - if let Some(token) = comment_token { + if let Some(token) = continue_comment_token { new_text.push_str(token); new_text.push(' '); } From 843b9b466ce6275d9a558c3fc318267cf957f8fc Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 12:34:06 +0200 Subject: [PATCH 51/59] style-nit: reduce nested blocks --- helix-term/src/commands.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b1f346f76d74..4f5ad1fe66c3 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3429,22 +3429,20 @@ fn open(cx: &mut Context, open: Open) { .and_then(|config| config.comment_tokens.as_ref()) .and_then(|tokens| comment::get_comment_token(text, tokens, cursor_line)); - let indent = { - let line = text.line(cursor_line); - match line.first_non_whitespace_char() { - Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(), - _ => indent::indent_for_newline( - doc.language_config(), - doc.syntax(), - &doc.config.load().indent_heuristic, - &doc.indent_style, - doc.tab_width(), - text, - line_num, - line_end_index, - cursor_line, - ), - } + let line = text.line(cursor_line); + let indent = match line.first_non_whitespace_char() { + Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(), + _ => indent::indent_for_newline( + doc.language_config(), + doc.syntax(), + &doc.config.load().indent_heuristic, + &doc.indent_style, + doc.tab_width(), + text, + line_num, + line_end_index, + cursor_line, + ), }; let indent_len = indent.len(); From a5d7f52beb33009d98b37f177ddf46ecc2d4d82d Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 12:38:28 +0200 Subject: [PATCH 52/59] continue-comments: improve jumping behaviour --- helix-term/src/commands.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4f5ad1fe66c3..8e357c8ca5e3 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3459,11 +3459,16 @@ fn open(cx: &mut Context, open: Open) { // calculate new selection ranges let pos = offs + line_end_index + line_end_offset_width; + let comment_len = continue_comment_token + .map(|token| token.len() + 1) // `+ 1` for the extra space added + .unwrap_or_default(); for i in 0..count { // pos -> beginning of reference line, - // + (i * (1+indent_len)) -> beginning of i'th line from pos - // + indent_len -> -> indent for i'th line - ranges.push(Range::point(pos + (i * (1 + indent_len)) + indent_len)); + // + (i * (1+indent_len + comment_len)) -> beginning of i'th line from pos (possibly including comment token) + // + indent_len + comment_len -> -> indent for i'th line + ranges.push(Range::point( + pos + (i * (1 + indent_len + comment_len)) + indent_len + comment_len, + )); } offs += text.chars().count(); @@ -3474,9 +3479,6 @@ fn open(cx: &mut Context, open: Open) { transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); doc.apply(&transaction, view.id); - - // Since we might have added a comment token, move to the end of the line. - goto_line_end_newline(cx); } // o inserts a new line after each line with a selection From d7ca450f378cfe5fd5eec227ff3a4e95474d0c1e Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 12:43:22 +0200 Subject: [PATCH 53/59] continue-comments: improve local_offs variable calculation --- helix-term/src/commands.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8e357c8ca5e3..870209ec3ac9 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3945,10 +3945,16 @@ pub mod insert { .and_then(|pairs| pairs.get(prev)) .map_or(false, |pair| pair.open == prev && pair.close == curr); - let local_offs = if on_auto_pair { + let local_offs = if let Some(token) = continue_comment_token { + new_text.push_str(doc.line_ending.as_str()); + new_text.push_str(&indent); + new_text.push_str(token); + new_text.push(' '); + new_text.chars().count() + } else if on_auto_pair { // line where the cursor will be let inner_indent = indent.clone() + doc.indent_style.as_str(); - new_text.reserve_exact(4 + indent.len() + inner_indent.len()); + new_text.reserve_exact(2 + indent.len() + inner_indent.len()); new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&inner_indent); @@ -3959,15 +3965,10 @@ pub mod insert { local_offs } else { - new_text.reserve_exact(3 + indent.len()); + new_text.reserve_exact(1 + indent.len()); new_text.push_str(doc.line_ending.as_str()); new_text.push_str(&indent); - if let Some(token) = continue_comment_token { - new_text.push_str(token); - new_text.push(' '); - } - new_text.chars().count() }; From e9ef8383fa73e3310b52fb1885124a474c431e1e Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sun, 6 Oct 2024 12:44:17 +0200 Subject: [PATCH 54/59] fix warnings --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 870209ec3ac9..de6107f59e41 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -17,7 +17,7 @@ pub use typed::*; use helix_core::{ char_idx_at_visual_offset, chars::char_is_word, - comment::{self, get_comment_token}, + comment, doc_formatter::TextFormat, encoding, find_workspace, graphemes::{self, next_grapheme_boundary, RevRopeGraphemes}, From aca48e8281630b6c99e5bb0d095cc78019ce7b81 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Mon, 7 Oct 2024 16:59:26 +0200 Subject: [PATCH 55/59] improve code format Co-authored-by: Michael Davis --- helix-core/src/comment.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index dbb5d144b544..371c7b08715b 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -24,8 +24,7 @@ pub fn get_comment_token<'a>( for token in tokens { let end = std::cmp::min(start + token.len(), line.len_bytes()); - let fragment = Cow::from(line.byte_slice(start..end)); - if fragment == *token { + if line.byte_slice(start..end) == *token { used_token = Some(token.as_str()); } } From b7f9780153395a3801f743fc7d3ae691eef79409 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Mon, 7 Oct 2024 18:11:40 +0200 Subject: [PATCH 56/59] continue-comments: Fix panic case and add test --- helix-core/src/comment.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 371c7b08715b..8afa94704d42 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -12,20 +12,25 @@ use std::borrow::Cow; pub const DEFAULT_COMMENT_TOKEN: &str = "//"; /// Returns the longest matching comment token of the given line (if it exists). -pub fn get_comment_token<'a>( +pub fn get_comment_token<'a, S: AsRef>( text: RopeSlice, - tokens: &'a [String], + tokens: &'a [S], line_num: usize, ) -> Option<&'a str> { let mut used_token: Option<&'a str> = None; let line = text.line(line_num); - let start = line.char_to_byte(line.first_non_whitespace_char()?); + let start = line.first_non_whitespace_char()?; + let mut max_token_len = 0; for token in tokens { - let end = std::cmp::min(start + token.len(), line.len_bytes()); - if line.byte_slice(start..end) == *token { - used_token = Some(token.as_str()); + let token_str = token.as_ref(); + let end = std::cmp::min(start + token_str.len(), line.len_chars()); + + let matches_token = line.slice(start..end).starts_with(token_str); + if matches_token && token_str.len() >= max_token_len { + used_token = Some(token_str); + max_token_len = token_str.len(); } } @@ -481,4 +486,17 @@ mod test { transaction.apply(&mut doc); assert_eq!(doc, ""); } + + // Test, if `get_comment_tokens` works, even if the content of the file includes chars, whose + // byte size unequal the amount of chars + #[test] + fn test_get_comment_with_char_boundaries() { + let rope = Rope::from("··"); + let tokens = ["//", "///"]; + + assert_eq!( + super::get_comment_token(rope.slice(..), tokens.as_slice(), 0), + None + ); + } } From 5b9613cb073826afc56ccec386097909ced4d784 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Mon, 7 Oct 2024 18:36:53 +0200 Subject: [PATCH 57/59] continue-comments: adding test --- helix-core/src/comment.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 8afa94704d42..7a4fc39b6212 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -487,8 +487,8 @@ mod test { assert_eq!(doc, ""); } - // Test, if `get_comment_tokens` works, even if the content of the file includes chars, whose - // byte size unequal the amount of chars + /// Test, if `get_comment_tokens` works, even if the content of the file includes chars, whose + /// byte size unequal the amount of chars #[test] fn test_get_comment_with_char_boundaries() { let rope = Rope::from("··"); @@ -499,4 +499,19 @@ mod test { None ); } + + /// Test for `get_comment_token`. + /// + /// Assuming the comment tokens are stored as `["///", "//"]`, `get_comment_token` should still + /// return `///` instead of `//` if the user is in a doc-comment section. + #[test] + fn test_use_longest_comment() { + let text = Rope::from(" /// amogus"); + let tokens = ["///", "//"]; + + assert_eq!( + super::get_comment_token(text.slice(..), tokens.as_slice(), 0), + Some("///") + ); + } } From 898f23164e85cf66879813c472f48678ca40cce5 Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Mon, 7 Oct 2024 22:16:51 +0200 Subject: [PATCH 58/59] improve code structure --- helix-core/src/comment.rs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 7a4fc39b6212..46c37404c859 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -17,24 +17,14 @@ pub fn get_comment_token<'a, S: AsRef>( tokens: &'a [S], line_num: usize, ) -> Option<&'a str> { - let mut used_token: Option<&'a str> = None; - let line = text.line(line_num); let start = line.first_non_whitespace_char()?; - let mut max_token_len = 0; - for token in tokens { - let token_str = token.as_ref(); - let end = std::cmp::min(start + token_str.len(), line.len_chars()); - - let matches_token = line.slice(start..end).starts_with(token_str); - if matches_token && token_str.len() >= max_token_len { - used_token = Some(token_str); - max_token_len = token_str.len(); - } - } - - used_token + tokens + .iter() + .map(AsRef::as_ref) + .filter(|token| line.slice(start..).starts_with(token)) + .max_by_key(|token| token.len()) } /// Given text, a comment token, and a set of line indices, returns the following: From 12a8b3e07f866f5d6c8e04d4493d4196111ce91e Mon Sep 17 00:00:00 2001 From: TornaxO7 Date: Sat, 19 Oct 2024 09:47:41 +0200 Subject: [PATCH 59/59] comment: reverting small bug fix --- helix-core/src/comment.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 46c37404c859..4270218746ae 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -42,7 +42,6 @@ fn find_line_comment( lines: impl IntoIterator, ) -> (bool, Vec, usize, usize) { let mut commented = true; - let mut text_is_empty = true; let mut to_change = Vec::new(); let mut min = usize::MAX; // minimum col for first_non_whitespace_char let mut margin = 1; @@ -51,7 +50,6 @@ fn find_line_comment( for line in lines { let line_slice = text.line(line); if let Some(pos) = line_slice.first_non_whitespace_char() { - text_is_empty = false; let len = line_slice.len_chars(); min = std::cmp::min(min, pos); @@ -76,10 +74,6 @@ fn find_line_comment( } } - if text_is_empty { - commented = false; - } - (commented, to_change, min, margin) } @@ -344,14 +338,6 @@ mod test { mod find_line_comment { use super::*; - #[test] - fn empty_line() { - let doc = Rope::from(""); - - let (is_commented, _, _, _) = find_line_comment("//", doc.slice(..), [0]); - assert!(!is_commented); - } - #[test] fn not_commented() { // four lines, two space indented, except for line 1 which is blank.