aboutsummaryrefslogtreecommitdiff
path: root/test/functional/lua
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-05-24 19:18:11 +0000
committerJosh Rahm <joshuarahm@gmail.com>2024-05-24 19:18:11 +0000
commitff7ed8f586589d620a806c3758fac4a47a8e7e15 (patch)
tree729bbcb92231538fa61dab6c3d890b025484b7f5 /test/functional/lua
parent376914f419eb08fdf4c1a63a77e1f035898a0f10 (diff)
parent28c04948a1c887a1cc0cb64de79fa32631700466 (diff)
downloadrneovim-ff7ed8f586589d620a806c3758fac4a47a8e7e15.tar.gz
rneovim-ff7ed8f586589d620a806c3758fac4a47a8e7e15.tar.bz2
rneovim-ff7ed8f586589d620a806c3758fac4a47a8e7e15.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'test/functional/lua')
-rw-r--r--test/functional/lua/api_spec.lua21
-rw-r--r--test/functional/lua/base64_spec.lua15
-rw-r--r--test/functional/lua/buffer_updates_spec.lua127
-rw-r--r--test/functional/lua/command_line_completion_spec.lua9
-rw-r--r--test/functional/lua/commands_spec.lua35
-rw-r--r--test/functional/lua/comment_spec.lua651
-rw-r--r--test/functional/lua/diagnostic_spec.lua406
-rw-r--r--test/functional/lua/ffi_spec.lua23
-rw-r--r--test/functional/lua/filetype_spec.lua40
-rw-r--r--test/functional/lua/fs_spec.lua253
-rw-r--r--test/functional/lua/glob_spec.lua12
-rw-r--r--test/functional/lua/highlight_spec.lua28
-rw-r--r--test/functional/lua/inspector_spec.lua12
-rw-r--r--test/functional/lua/iter_spec.lua240
-rw-r--r--test/functional/lua/json_spec.lua24
-rw-r--r--test/functional/lua/loader_spec.lua29
-rw-r--r--test/functional/lua/loop_spec.lua36
-rw-r--r--test/functional/lua/luaeval_spec.lua29
-rw-r--r--test/functional/lua/mpack_spec.lua11
-rw-r--r--test/functional/lua/overrides_spec.lua27
-rw-r--r--test/functional/lua/runtime_spec.lua23
-rw-r--r--test/functional/lua/secure_spec.lua87
-rw-r--r--test/functional/lua/snippet_spec.lua78
-rw-r--r--test/functional/lua/spell_spec.lua12
-rw-r--r--test/functional/lua/system_spec.lua10
-rw-r--r--test/functional/lua/text_spec.lua8
-rw-r--r--test/functional/lua/thread_spec.lua22
-rw-r--r--test/functional/lua/ui_event_spec.lua74
-rw-r--r--test/functional/lua/ui_spec.lua33
-rw-r--r--test/functional/lua/uri_spec.lua18
-rw-r--r--test/functional/lua/version_spec.lua19
-rw-r--r--test/functional/lua/vim_spec.lua306
-rw-r--r--test/functional/lua/watch_spec.lua28
-rw-r--r--test/functional/lua/xdiff_spec.lua12
34 files changed, 2077 insertions, 681 deletions
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index acd56a0ddb..56969150bd 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -1,15 +1,16 @@
-- Test suite for testing interactions with API bindings
-local helpers = require('test.functional.helpers')(after_each)
-
-local exc_exec = helpers.exc_exec
-local remove_trace = helpers.remove_trace
-local fn = helpers.fn
-local clear = helpers.clear
-local eval = helpers.eval
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+
+local exc_exec = n.exc_exec
+local remove_trace = t.remove_trace
+local fn = n.fn
+local clear = n.clear
+local eval = n.eval
local NIL = vim.NIL
-local eq = helpers.eq
-local exec_lua = helpers.exec_lua
-local pcall_err = helpers.pcall_err
+local eq = t.eq
+local exec_lua = n.exec_lua
+local pcall_err = t.pcall_err
before_each(clear)
diff --git a/test/functional/lua/base64_spec.lua b/test/functional/lua/base64_spec.lua
index 21fd536a98..529f5f56e8 100644
--- a/test/functional/lua/base64_spec.lua
+++ b/test/functional/lua/base64_spec.lua
@@ -1,9 +1,11 @@
-local helpers = require('test.functional.helpers')(after_each)
-local clear = helpers.clear
-local exec_lua = helpers.exec_lua
-local eq = helpers.eq
-local pcall_err = helpers.pcall_err
-local matches = helpers.matches
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+
+local clear = n.clear
+local exec_lua = n.exec_lua
+local eq = t.eq
+local pcall_err = t.pcall_err
+local matches = t.matches
describe('vim.base64', function()
before_each(clear)
@@ -42,6 +44,7 @@ describe('vim.base64', function()
̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕
Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮
]],
+ 'Hello\0world',
}
for _, v in ipairs(values) do
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 714e1b951f..d4af7e4732 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -1,17 +1,19 @@
-- Test suite for testing interactions with API bindings
-local helpers = require('test.functional.helpers')(after_each)
-
-local command = helpers.command
-local api = helpers.api
-local fn = helpers.fn
-local clear = helpers.clear
-local eq = helpers.eq
-local fail = helpers.fail
-local exec_lua = helpers.exec_lua
-local feed = helpers.feed
-local expect_events = helpers.expect_events
-local write_file = helpers.write_file
-local dedent = helpers.dedent
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+
+local command = n.command
+local api = n.api
+local fn = n.fn
+local clear = n.clear
+local eq = t.eq
+local fail = t.fail
+local exec_lua = n.exec_lua
+local feed = n.feed
+local expect_events = t.expect_events
+local write_file = t.write_file
+local dedent = t.dedent
local origlines = {
'original line 1',
@@ -291,11 +293,11 @@ describe('lua buffer event callbacks: on_lines', function()
exec_lua(code)
command('q!')
- helpers.assert_alive()
+ n.assert_alive()
exec_lua(code)
command('bd!')
- helpers.assert_alive()
+ n.assert_alive()
end)
it('#12718 lnume', function()
@@ -312,31 +314,71 @@ describe('lua buffer event callbacks: on_lines', function()
feed('G0')
feed('p')
-- Is the last arg old_byte_size correct? Doesn't matter for this PR
- eq(api.nvim_get_var('linesev'), { 'lines', 1, 4, 2, 3, 5, 4 })
+ eq({ 'lines', 1, 4, 2, 3, 5, 4 }, api.nvim_get_var('linesev'))
feed('2G0')
feed('p')
- eq(api.nvim_get_var('linesev'), { 'lines', 1, 5, 1, 4, 4, 8 })
+ eq({ 'lines', 1, 5, 1, 4, 4, 8 }, api.nvim_get_var('linesev'))
feed('1G0')
feed('P')
- eq(api.nvim_get_var('linesev'), { 'lines', 1, 6, 0, 3, 3, 9 })
+ eq({ 'lines', 1, 6, 0, 3, 3, 9 }, api.nvim_get_var('linesev'))
end)
- it(
- 'calling nvim_buf_call() from callback does not cause Normal mode CTRL-A to misbehave #16729',
- function()
- exec_lua([[
+ it('nvim_buf_call() from callback does not cause wrong Normal mode CTRL-A #16729', function()
+ exec_lua([[
vim.api.nvim_buf_attach(0, false, {
on_lines = function(...)
vim.api.nvim_buf_call(0, function() end)
end,
})
]])
- feed('itest123<Esc><C-A>')
- eq('test124', api.nvim_get_current_line())
- end
- )
+ feed('itest123<Esc><C-A>')
+ eq('test124', api.nvim_get_current_line())
+ end)
+
+ it('setting extmark in on_lines callback works', function()
+ local screen = Screen.new(40, 6)
+ screen:attach()
+
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' })
+ exec_lua([[
+ local ns = vim.api.nvim_create_namespace('')
+ vim.api.nvim_buf_attach(0, false, {
+ on_lines = function(_, _, _, row, _, end_row)
+ vim.api.nvim_buf_clear_namespace(0, ns, row, end_row)
+ for i = row, end_row - 1 do
+ local id = vim.api.nvim_buf_set_extmark(0, ns, i, 0, {
+ virt_text = {{ 'NEW' .. tostring(i), 'WarningMsg' }},
+ })
+ end
+ end,
+ })
+ ]])
+
+ feed('o')
+ screen:expect({
+ grid = [[
+ aaa |
+ ^ {19:NEW1} |
+ bbb |
+ ccc |
+ {1:~ }|
+ {5:-- INSERT --} |
+ ]],
+ })
+ feed('<CR>')
+ screen:expect({
+ grid = [[
+ aaa |
+ {19:NEW1} |
+ ^ {19:NEW2} |
+ bbb |
+ ccc |
+ {5:-- INSERT --} |
+ ]],
+ })
+ end)
end)
describe('lua: nvim_buf_attach on_bytes', function()
@@ -426,14 +468,14 @@ describe('lua: nvim_buf_attach on_bytes', function()
it('opening lines', function()
local check_events = setup_eventcheck(verify, origlines)
- -- api.nvim_set_option_value('autoindent', true, {})
+ api.nvim_set_option_value('autoindent', false, {})
feed 'Go'
check_events {
{ 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 1 },
}
feed '<cr>'
check_events {
- { 'test1', 'bytes', 1, 5, 7, 0, 114, 0, 0, 0, 1, 0, 1 },
+ { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 },
}
end)
@@ -447,7 +489,7 @@ describe('lua: nvim_buf_attach on_bytes', function()
feed '<cr>'
check_events {
{ 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 4, 4, 0, 0, 0 },
- { 'test1', 'bytes', 1, 5, 7, 0, 114, 0, 0, 0, 1, 4, 5 },
+ { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 4, 5 },
}
end)
@@ -477,7 +519,7 @@ describe('lua: nvim_buf_attach on_bytes', function()
api.nvim_set_option_value('filetype', 'c', {})
feed 'A<CR>'
check_events {
- { 'test1', 'bytes', 1, 4, 0, 10, 10, 0, 0, 0, 1, 3, 4 },
+ { 'test1', 'bytes', 1, 3, 0, 10, 10, 0, 0, 0, 1, 3, 4 },
}
feed '<ESC>'
@@ -493,7 +535,7 @@ describe('lua: nvim_buf_attach on_bytes', function()
feed '<CR>'
check_events {
{ 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 1, 1, 0, 0, 0 },
- { 'test1', 'bytes', 1, 7, 1, 2, 13, 0, 0, 0, 1, 3, 4 },
+ { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 0, 0, 1, 3, 4 },
}
end)
@@ -541,7 +583,7 @@ describe('lua: nvim_buf_attach on_bytes', function()
feed 'cc'
check_events {
- { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 15, 15, 0, 0, 0 },
+ { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 15, 15, 0, 0, 0 },
}
feed '<ESC>'
@@ -924,7 +966,7 @@ describe('lua: nvim_buf_attach on_bytes', function()
command('e! Xtest-undofile')
command('set undodir=. | set undofile')
- local ns = helpers.request('nvim_create_namespace', 'ns1')
+ local ns = n.request('nvim_create_namespace', 'ns1')
api.nvim_buf_set_extmark(0, ns, 0, 0, {})
eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true))
@@ -1225,6 +1267,25 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
end)
+ it('prompt buffer', function()
+ local check_events = setup_eventcheck(verify, {})
+ api.nvim_set_option_value('buftype', 'prompt', {})
+ feed('i')
+ check_events {
+ { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
+ }
+ feed('<CR>')
+ check_events {
+ { 'test1', 'bytes', 1, 4, 1, 0, 3, 0, 0, 0, 1, 0, 1 },
+ { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 0, 0, 0, 2, 2 },
+ }
+ feed('<CR>')
+ check_events {
+ { 'test1', 'bytes', 1, 6, 2, 0, 6, 0, 0, 0, 1, 0, 1 },
+ { 'test1', 'bytes', 1, 7, 2, 0, 6, 0, 0, 0, 0, 2, 2 },
+ }
+ end)
+
local function test_lockmarks(mode)
local description = (mode ~= '') and mode or '(baseline)'
it('test_lockmarks ' .. description .. ' %delete _', function()
diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua
index b88a38082f..2ba432133b 100644
--- a/test/functional/lua/command_line_completion_spec.lua
+++ b/test/functional/lua/command_line_completion_spec.lua
@@ -1,8 +1,9 @@
-local helpers = require('test.functional.helpers')(after_each)
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
-local clear = helpers.clear
-local eq = helpers.eq
-local exec_lua = helpers.exec_lua
+local clear = n.clear
+local eq = t.eq
+local exec_lua = n.exec_lua
local get_completions = function(input, env)
return exec_lua('return {vim._expand_pat(...)}', input, env)
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index b8d0638ce5..57b084d3d6 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -1,24 +1,25 @@
-- Test suite for checking :lua* commands
-local helpers = require('test.functional.helpers')(after_each)
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local eq = helpers.eq
+local eq = t.eq
local NIL = vim.NIL
-local eval = helpers.eval
-local feed = helpers.feed
-local clear = helpers.clear
-local matches = helpers.matches
-local api = helpers.api
-local exec_lua = helpers.exec_lua
-local exec_capture = helpers.exec_capture
-local fn = helpers.fn
-local source = helpers.source
-local dedent = helpers.dedent
-local command = helpers.command
-local exc_exec = helpers.exc_exec
-local pcall_err = helpers.pcall_err
-local write_file = helpers.write_file
-local remove_trace = helpers.remove_trace
+local eval = n.eval
+local feed = n.feed
+local clear = n.clear
+local matches = t.matches
+local api = n.api
+local exec_lua = n.exec_lua
+local exec_capture = n.exec_capture
+local fn = n.fn
+local source = n.source
+local dedent = t.dedent
+local command = n.command
+local exc_exec = n.exc_exec
+local pcall_err = t.pcall_err
+local write_file = t.write_file
+local remove_trace = t.remove_trace
before_each(clear)
diff --git a/test/functional/lua/comment_spec.lua b/test/functional/lua/comment_spec.lua
new file mode 100644
index 0000000000..bbf061a2ab
--- /dev/null
+++ b/test/functional/lua/comment_spec.lua
@@ -0,0 +1,651 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+
+local api = n.api
+local clear = n.clear
+local eq = t.eq
+local exec_capture = n.exec_capture
+local exec_lua = n.exec_lua
+local feed = n.feed
+
+-- Reference text
+-- aa
+-- aa
+-- aa
+--
+-- aa
+-- aa
+-- aa
+local example_lines = { 'aa', ' aa', ' aa', '', ' aa', ' aa', 'aa' }
+
+local set_commentstring = function(commentstring)
+ api.nvim_set_option_value('commentstring', commentstring, { buf = 0 })
+end
+
+local get_lines = function(from, to)
+ from, to = from or 0, to or -1
+ return api.nvim_buf_get_lines(0, from, to, false)
+end
+
+local set_lines = function(lines, from, to)
+ from, to = from or 0, to or -1
+ api.nvim_buf_set_lines(0, from, to, false, lines)
+end
+
+local set_cursor = function(row, col)
+ api.nvim_win_set_cursor(0, { row, col })
+end
+
+local get_cursor = function()
+ return api.nvim_win_get_cursor(0)
+end
+
+local setup_treesitter = function()
+ -- NOTE: This leverages bundled Vimscript and Lua tree-sitter parsers
+ api.nvim_set_option_value('filetype', 'vim', { buf = 0 })
+ exec_lua('vim.treesitter.start()')
+end
+
+before_each(function()
+ clear({ args_rm = { '--cmd' }, args = { '--clean' } })
+end)
+
+describe('commenting', function()
+ before_each(function()
+ set_lines(example_lines)
+ set_commentstring('# %s')
+ end)
+
+ describe('toggle_lines()', function()
+ local toggle_lines = function(...)
+ exec_lua('require("vim._comment").toggle_lines(...)', ...)
+ end
+
+ it('works', function()
+ toggle_lines(3, 5)
+ eq(get_lines(2, 5), { ' # aa', ' #', ' # aa' })
+
+ toggle_lines(3, 5)
+ eq(get_lines(2, 5), { ' aa', '', ' aa' })
+ end)
+
+ it("works with different 'commentstring' options", function()
+ local validate = function(lines_before, lines_after, lines_again)
+ set_lines(lines_before)
+ toggle_lines(1, #lines_before)
+ eq(get_lines(), lines_after)
+ toggle_lines(1, #lines_before)
+ eq(get_lines(), lines_again or lines_before)
+ end
+
+ -- Single whitespace inside comment parts (main case)
+ set_commentstring('# %s #')
+ -- - General case
+ validate(
+ { 'aa', ' aa', 'aa ', ' aa ' },
+ { '# aa #', '# aa #', '# aa #', '# aa #' }
+ )
+ -- - Tabs
+ validate(
+ { 'aa', '\taa', 'aa\t', '\taa\t' },
+ { '# aa #', '# \taa #', '# aa\t #', '# \taa\t #' }
+ )
+ -- - With indent
+ validate({ ' aa', ' aa' }, { ' # aa #', ' # aa #' })
+ -- - With blank/empty lines
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' # aa #', ' ##', ' ##', ' ##' },
+ { ' aa', '', '', '' }
+ )
+
+ set_commentstring('# %s')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '# aa', '# aa', '# aa ', '# aa ' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '# aa', '# \taa', '# aa\t', '# \taa\t' })
+ validate({ ' aa', ' aa' }, { ' # aa', ' # aa' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' # aa', ' #', ' #', ' #' },
+ { ' aa', '', '', '' }
+ )
+
+ set_commentstring('%s #')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { 'aa #', ' aa #', 'aa #', ' aa #' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { 'aa #', '\taa #', 'aa\t #', '\taa\t #' })
+ validate({ ' aa', ' aa' }, { ' aa #', ' aa #' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' aa #', ' #', ' #', ' #' },
+ { ' aa', '', '', '' }
+ )
+
+ -- No whitespace in parts
+ set_commentstring('#%s#')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '#aa#', '# aa#', '#aa #', '# aa #' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '#aa#', '#\taa#', '#aa\t#', '#\taa\t#' })
+ validate({ ' aa', ' aa' }, { ' #aa#', ' # aa#' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' #aa#', ' ##', ' ##', ' ##' },
+ { ' aa', '', '', '' }
+ )
+
+ set_commentstring('#%s')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '#aa', '# aa', '#aa ', '# aa ' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '#aa', '#\taa', '#aa\t', '#\taa\t' })
+ validate({ ' aa', ' aa' }, { ' #aa', ' # aa' })
+ validate({ ' aa', '', ' ', '\t' }, { ' #aa', ' #', ' #', ' #' }, { ' aa', '', '', '' })
+
+ set_commentstring('%s#')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { 'aa#', ' aa#', 'aa #', ' aa #' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { 'aa#', '\taa#', 'aa\t#', '\taa\t#' })
+ validate({ ' aa', ' aa' }, { ' aa#', ' aa#' })
+ validate({ ' aa', '', ' ', '\t' }, { ' aa#', ' #', ' #', ' #' }, { ' aa', '', '', '' })
+
+ -- Extra whitespace inside comment parts
+ set_commentstring('# %s #')
+ validate(
+ { 'aa', ' aa', 'aa ', ' aa ' },
+ { '# aa #', '# aa #', '# aa #', '# aa #' }
+ )
+ validate(
+ { 'aa', '\taa', 'aa\t', '\taa\t' },
+ { '# aa #', '# \taa #', '# aa\t #', '# \taa\t #' }
+ )
+ validate({ ' aa', ' aa' }, { ' # aa #', ' # aa #' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' # aa #', ' ##', ' ##', ' ##' },
+ { ' aa', '', '', '' }
+ )
+
+ set_commentstring('# %s')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '# aa', '# aa', '# aa ', '# aa ' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '# aa', '# \taa', '# aa\t', '# \taa\t' })
+ validate({ ' aa', ' aa' }, { ' # aa', ' # aa' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' # aa', ' #', ' #', ' #' },
+ { ' aa', '', '', '' }
+ )
+
+ set_commentstring('%s #')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { 'aa #', ' aa #', 'aa #', ' aa #' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { 'aa #', '\taa #', 'aa\t #', '\taa\t #' })
+ validate({ ' aa', ' aa' }, { ' aa #', ' aa #' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' aa #', ' #', ' #', ' #' },
+ { ' aa', '', '', '' }
+ )
+
+ -- Whitespace outside of comment parts
+ set_commentstring(' # %s # ')
+ validate(
+ { 'aa', ' aa', 'aa ', ' aa ' },
+ { ' # aa # ', ' # aa # ', ' # aa # ', ' # aa # ' }
+ )
+ validate(
+ { 'aa', '\taa', 'aa\t', '\taa\t' },
+ { ' # aa # ', ' # \taa # ', ' # aa\t # ', ' # \taa\t # ' }
+ )
+ validate({ ' aa', ' aa' }, { ' # aa # ', ' # aa # ' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' # aa # ', ' ##', ' ##', ' ##' },
+ { ' aa', '', '', '' }
+ )
+
+ set_commentstring(' # %s ')
+ validate(
+ { 'aa', ' aa', 'aa ', ' aa ' },
+ { ' # aa ', ' # aa ', ' # aa ', ' # aa ' }
+ )
+ validate(
+ { 'aa', '\taa', 'aa\t', '\taa\t' },
+ { ' # aa ', ' # \taa ', ' # aa\t ', ' # \taa\t ' }
+ )
+ validate({ ' aa', ' aa' }, { ' # aa ', ' # aa ' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' # aa ', ' #', ' #', ' #' },
+ { ' aa', '', '', '' }
+ )
+
+ set_commentstring(' %s # ')
+ validate(
+ { 'aa', ' aa', 'aa ', ' aa ' },
+ { ' aa # ', ' aa # ', ' aa # ', ' aa # ' }
+ )
+ validate(
+ { 'aa', '\taa', 'aa\t', '\taa\t' },
+ { ' aa # ', ' \taa # ', ' aa\t # ', ' \taa\t # ' }
+ )
+ validate({ ' aa', ' aa' }, { ' aa # ', ' aa # ' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' aa # ', ' #', ' #', ' #' },
+ { ' aa', '', '', '' }
+ )
+
+ -- LaTeX
+ set_commentstring('% %s')
+ validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '% aa', '% aa', '% aa ', '% aa ' })
+ validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '% aa', '% \taa', '% aa\t', '% \taa\t' })
+ validate({ ' aa', ' aa' }, { ' % aa', ' % aa' })
+ validate(
+ { ' aa', '', ' ', '\t' },
+ { ' % aa', ' %', ' %', ' %' },
+ { ' aa', '', '', '' }
+ )
+ end)
+
+ it('respects tree-sitter injections', function()
+ setup_treesitter()
+
+ local lines = {
+ 'set background=dark',
+ 'lua << EOF',
+ 'print(1)',
+ 'vim.api.nvim_exec2([[',
+ ' set background=light',
+ ']])',
+ 'EOF',
+ }
+
+ -- Single line comments
+ local validate = function(line, ref_output)
+ set_lines(lines)
+ toggle_lines(line, line)
+ eq(get_lines(line - 1, line)[1], ref_output)
+ end
+
+ validate(1, '"set background=dark')
+ validate(2, '"lua << EOF')
+ validate(3, '-- print(1)')
+ validate(4, '-- vim.api.nvim_exec2([[')
+ validate(5, ' "set background=light')
+ validate(6, '-- ]])')
+ validate(7, '"EOF')
+
+ -- Multiline comments should be computed based on first line 'commentstring'
+ set_lines(lines)
+ toggle_lines(1, 3)
+ local out_lines = get_lines()
+ eq(out_lines[1], '"set background=dark')
+ eq(out_lines[2], '"lua << EOF')
+ eq(out_lines[3], '"print(1)')
+ end)
+
+ it('correctly computes indent', function()
+ toggle_lines(2, 4)
+ eq(get_lines(1, 4), { ' # aa', ' # aa', ' #' })
+ end)
+
+ it('correctly detects comment/uncomment', function()
+ local validate = function(from, to, ref_lines)
+ set_lines({ '', 'aa', '# aa', '# aa', 'aa', '' })
+ toggle_lines(from, to)
+ eq(get_lines(), ref_lines)
+ end
+
+ -- It should uncomment only if all non-blank lines are comments
+ validate(3, 4, { '', 'aa', 'aa', 'aa', 'aa', '' })
+ validate(2, 4, { '', '# aa', '# # aa', '# # aa', 'aa', '' })
+ validate(3, 5, { '', 'aa', '# # aa', '# # aa', '# aa', '' })
+ validate(1, 6, { '#', '# aa', '# # aa', '# # aa', '# aa', '#' })
+
+ -- Blank lines should be ignored when making a decision
+ set_lines({ '# aa', '', ' ', '\t', '# aa' })
+ toggle_lines(1, 5)
+ eq(get_lines(), { 'aa', '', ' ', '\t', 'aa' })
+ end)
+
+ it('correctly matches comment parts during checking and uncommenting', function()
+ local validate = function(from, to, ref_lines)
+ set_lines({ '/*aa*/', '/* aa */', '/* aa */' })
+ toggle_lines(from, to)
+ eq(get_lines(), ref_lines)
+ end
+
+ -- 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()
+ set_lines({ '# aa', ' # aa', ' # aa' })
+ toggle_lines(1, 3)
+ eq(get_lines(), { 'aa', ' aa', ' aa' })
+ end)
+
+ it('respects tabs', function()
+ api.nvim_set_option_value('expandtab', false, { buf = 0 })
+ set_lines({ '\t\taa', '\t\taa' })
+
+ toggle_lines(1, 2)
+ eq(get_lines(), { '\t\t# aa', '\t\t# aa' })
+
+ toggle_lines(1, 2)
+ eq(get_lines(), { '\t\taa', '\t\taa' })
+ end)
+
+ it('works with trailing whitespace', function()
+ -- Without right-hand side
+ set_commentstring('# %s')
+ set_lines({ ' aa', ' aa ', ' ' })
+ toggle_lines(1, 3)
+ eq(get_lines(), { ' # aa', ' # aa ', ' #' })
+ toggle_lines(1, 3)
+ eq(get_lines(), { ' aa', ' aa ', '' })
+
+ -- With right-hand side
+ set_commentstring('%s #')
+ set_lines({ ' aa', ' aa ', ' ' })
+ toggle_lines(1, 3)
+ eq(get_lines(), { ' aa #', ' aa #', ' #' })
+ toggle_lines(1, 3)
+ eq(get_lines(), { ' aa', ' aa ', '' })
+
+ -- Trailing whitespace after right side should be preserved for non-blanks
+ set_commentstring('%s #')
+ set_lines({ ' aa # ', ' aa #\t', ' # ', ' #\t' })
+ toggle_lines(1, 4)
+ eq(get_lines(), { ' aa ', ' aa\t', '', '' })
+ end)
+ end)
+
+ describe('Operator', function()
+ it('works in Normal mode', function()
+ set_cursor(2, 2)
+ feed('gc', 'ap')
+ eq(get_lines(), { '# aa', '# aa', '# aa', '#', ' aa', ' aa', 'aa' })
+ -- Cursor moves to start line
+ eq(get_cursor(), { 1, 0 })
+
+ -- Supports `v:count`
+ set_lines(example_lines)
+ set_cursor(2, 0)
+ feed('2gc', 'ap')
+ eq(get_lines(), { '# aa', '# aa', '# aa', '#', '# aa', '# aa', '# aa' })
+ end)
+
+ it('allows dot-repeat in Normal mode', function(