aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/various.txt4
-rw-r--r--runtime/lua/vim/_comment.lua19
-rw-r--r--test/functional/lua/comment_spec.lua39
3 files changed, 35 insertions, 27 deletions
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index d41bdb5b00..662be4a7a2 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -579,6 +579,10 @@ Acting on multiple lines behaves as follows:
transformed to empty comments (e.g. `/**/`). Comment markers are aligned to
the least indented line.
+Matching 'commentstring' does not account for whitespace in comment markers.
+Removing comment markers is first attempted exactly, with fallback to using
+markers trimmed from whitespace.
+
If the filetype of the buffer is associated with a language for which a
|treesitter| parser is installed, then |vim.filetype.get_option()| is called
to look up the value of 'commentstring' corresponding to the cursor position.
diff --git a/runtime/lua/vim/_comment.lua b/runtime/lua/vim/_comment.lua
index b6cb6c9884..044cd69716 100644
--- a/runtime/lua/vim/_comment.lua
+++ b/runtime/lua/vim/_comment.lua
@@ -77,14 +77,11 @@ local function make_comment_check(parts)
local l_esc, r_esc = vim.pesc(parts.left), vim.pesc(parts.right)
-- Commented line has the following structure:
- -- <possible whitespace> <left> <anything> <right> <possible whitespace>
- local nonblank_regex = '^%s-' .. l_esc .. '.*' .. r_esc .. '%s-$'
-
- -- Commented blank line can have any amount of whitespace around parts
- local blank_regex = '^%s-' .. vim.trim(l_esc) .. '%s*' .. vim.trim(r_esc) .. '%s-$'
+ -- <whitespace> <trimmed left> <anything> <trimmed right> <whitespace>
+ local regex = '^%s-' .. vim.trim(l_esc) .. '.*' .. vim.trim(r_esc) .. '%s-$'
return function(line)
- return line:find(nonblank_regex) ~= nil or line:find(blank_regex) ~= nil
+ return line:find(regex) ~= nil
end
end
@@ -153,14 +150,14 @@ end
---@return fun(line: string): string
local function make_uncomment_function(parts)
local l_esc, r_esc = vim.pesc(parts.left), vim.pesc(parts.right)
- local nonblank_regex = '^(%s*)' .. l_esc .. '(.*)' .. r_esc .. '(%s-)$'
- local blank_regex = '^(%s*)' .. vim.trim(l_esc) .. '(%s*)' .. vim.trim(r_esc) .. '(%s-)$'
+ local regex = '^(%s*)' .. l_esc .. '(.*)' .. r_esc .. '(%s-)$'
+ local regex_trimmed = '^(%s*)' .. vim.trim(l_esc) .. '(.*)' .. vim.trim(r_esc) .. '(%s-)$'
return function(line)
- -- Try both non-blank and blank regexes
- local indent, new_line, trail = line:match(nonblank_regex)
+ -- Try regex with exact comment parts first, fall back to trimmed parts
+ local indent, new_line, trail = line:match(regex)
if new_line == nil then
- indent, new_line, trail = line:match(blank_regex)
+ indent, new_line, trail = line:match(regex_trimmed)
end
-- Return original if line is not commented
diff --git a/test/functional/lua/comment_spec.lua b/test/functional/lua/comment_spec.lua
index 9b1d9613cb..bbf061a2ab 100644
--- a/test/functional/lua/comment_spec.lua
+++ b/test/functional/lua/comment_spec.lua
@@ -301,27 +301,34 @@ describe('commenting', function()
eq(get_lines(), { 'aa', '', ' ', '\t', 'aa' })
end)
- it('matches comment parts strictly when detecting comment/uncomment', function()
+ it('correctly matches comment parts during checking and uncommenting', function()
local validate = function(from, to, ref_lines)
- set_lines({ '#aa', '# aa', '# aa' })
+ set_lines({ '/*aa*/', '/* aa */', '/* aa */' })
toggle_lines(from, to)
eq(get_lines(), ref_lines)
end
- set_commentstring('#%s')
- validate(1, 3, { 'aa', ' aa', ' aa' })
- validate(2, 3, { '#aa', ' aa', ' aa' })
- validate(3, 3, { '#aa', '# aa', ' aa' })
-
- set_commentstring('# %s')
- validate(1, 3, { '# #aa', '# # aa', '# # aa' })
- validate(2, 3, { '#aa', 'aa', ' aa' })
- validate(3, 3, { '#aa', '# aa', ' aa' })
-
- set_commentstring('# %s')
- validate(1, 3, { '# #aa', '# # aa', '# # aa' })
- validate(2, 3, { '#aa', '# # aa', '# # aa' })
- validate(3, 3, { '#aa', '# aa', 'aa' })
+ -- Should first try to match 'commentstring' parts exactly with their
+ -- whitespace, with fallback on trimmed parts
+ set_commentstring('/*%s*/')
+ validate(1, 3, { 'aa', ' aa ', ' aa ' })
+ validate(2, 3, { '/*aa*/', ' aa ', ' aa ' })
+ validate(3, 3, { '/*aa*/', '/* aa */', ' aa ' })
+
+ set_commentstring('/* %s */')
+ validate(1, 3, { 'aa', 'aa', ' aa ' })
+ validate(2, 3, { '/*aa*/', 'aa', ' aa ' })
+ validate(3, 3, { '/*aa*/', '/* aa */', ' aa ' })
+
+ set_commentstring('/* %s */')
+ validate(1, 3, { 'aa', ' aa ', 'aa' })
+ validate(2, 3, { '/*aa*/', ' aa ', 'aa' })
+ validate(3, 3, { '/*aa*/', '/* aa */', 'aa' })
+
+ set_commentstring(' /*%s*/ ')
+ validate(1, 3, { 'aa', ' aa ', ' aa ' })
+ validate(2, 3, { '/*aa*/', ' aa ', ' aa ' })
+ validate(3, 3, { '/*aa*/', '/* aa */', ' aa ' })
end)
it('uncomments on inconsistent indent levels', function()