aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-05-31 17:44:13 +0200
committerGitHub <noreply@github.com>2022-05-31 17:44:13 +0200
commit7380ebfc17723662f6fe1e38372f54b3d67fe082 (patch)
treee079f85a72f851e5c0a8e08f52db0cb4a8b26163 /test/functional
parent5d840fa7e6ba7d58a89d3126ee914cb0e42168ca (diff)
parent46536f53e82967dcac8d030ee3394cdb156f9603 (diff)
downloadrneovim-7380ebfc17723662f6fe1e38372f54b3d67fe082.tar.gz
rneovim-7380ebfc17723662f6fe1e38372f54b3d67fe082.tar.bz2
rneovim-7380ebfc17723662f6fe1e38372f54b3d67fe082.zip
Merge pull request #18194 from famiu/feat/usercmd_preview
feat: user command "preview" (like inccommand)
Diffstat (limited to 'test/functional')
-rw-r--r--test/functional/api/command_spec.lua14
-rw-r--r--test/functional/ui/float_spec.lua12
-rw-r--r--test/functional/ui/inccommand_spec.lua36
-rw-r--r--test/functional/ui/inccommand_user_spec.lua329
4 files changed, 340 insertions, 51 deletions
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index d6d75e93e4..253371557a 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -16,8 +16,8 @@ local feed = helpers.feed
local funcs = helpers.funcs
describe('nvim_get_commands', function()
- local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', range=NIL, register=false, keepscript=false, script_id=0, }
- local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', range=NIL, register=false, keepscript=false, script_id=0, }
+ local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', preview=false, range=NIL, register=false, keepscript=false, script_id=0, }
+ local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', preview=false, range=NIL, register=false, keepscript=false, script_id=0, }
before_each(clear)
it('gets empty list if no commands were defined', function()
@@ -59,11 +59,11 @@ describe('nvim_get_commands', function()
end)
it('gets various command attributes', function()
- local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', range='10', register=false, keepscript=false, script_id=0, }
- local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', range=NIL, register=false, keepscript=false, script_id=1, }
- local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', range=NIL, register=false, keepscript=false, script_id=2, }
- local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, keepscript=false, script_id=3, }
- local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', range=NIL, register=true, keepscript=false, script_id=4, }
+ local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', preview=false, range='10', register=false, keepscript=false, script_id=0, }
+ local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', preview=false, range=NIL, register=false, keepscript=false, script_id=1, }
+ local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', preview=false, range=NIL, register=false, keepscript=false, script_id=2, }
+ local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', preview=false, range=NIL, register=false, keepscript=false, script_id=3, }
+ local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', preview=false, range=NIL, register=true, keepscript=false, script_id=4, }
source([[
let s:foo = 1
command -complete=custom,ListUsers -nargs=+ Finger !finger <args>
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index ca5e269f92..fdd1504b13 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -3660,10 +3660,10 @@ describe('float window', function()
screen:expect{grid=[[
## grid 1
[2:----------------------------------------]|
- {5:[No Name] }|
- [5:----------------------------------------]|
- [5:----------------------------------------]|
- [5:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
{5:[Preview] }|
[3:----------------------------------------]|
## grid 2
@@ -3674,10 +3674,6 @@ describe('float window', function()
{17:f}{1:oo }|
{17:b}{1:ar }|
{1: }|
- ## grid 5
- |1| {17:f}oo |
- |2| {17:b}ar |
- {0:~ }|
]], float_pos=expected_pos}
else
screen:expect([[
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index a1ff778da1..a95cb0e83a 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -255,42 +255,6 @@ describe(":substitute, 'inccommand' preserves", function()
end)
end
- for _, case in pairs{"", "split", "nosplit"} do
- it("visual selection for non-previewable command (inccommand="..case..") #5888", function()
- local screen = Screen.new(30,10)
- common_setup(screen, case, default_text)
- feed('1G2V')
-
- feed(':s')
- screen:expect([[
- {vis:Inc substitution on} |
- t{vis:wo lines} |
- |
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- :'<,'>s^ |
- ]])
-
- feed('o')
- screen:expect([[
- {vis:Inc substitution on} |
- t{vis:wo lines} |
- |
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- :'<,'>so^ |
- ]])
- end)
- end
-
for _, case in ipairs({'', 'split', 'nosplit'}) do
it('previous substitute string ~ (inccommand='..case..') #12109', function()
local screen = Screen.new(30,10)
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
new file mode 100644
index 0000000000..e2cd82943e
--- /dev/null
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -0,0 +1,329 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local insert = helpers.insert
+local feed = helpers.feed
+local command = helpers.command
+
+-- Implements a :Replace command that works like :substitute.
+local setup_replace_cmd = [[
+ local function show_replace_preview(buf, use_preview_win, preview_ns, preview_buf, matches)
+ -- Find the width taken by the largest line number, used for padding the line numbers
+ local highest_lnum = math.max(matches[#matches][1], 1)
+ local highest_lnum_width = math.floor(math.log10(highest_lnum))
+ local preview_buf_line = 0
+
+ vim.g.prevns = preview_ns
+ vim.g.prevbuf = preview_buf
+
+ for _, match in ipairs(matches) do
+ local lnum = match[1]
+ local line_matches = match[2]
+ local prefix
+
+ if use_preview_win then
+ prefix = string.format(
+ '|%s%d| ',
+ string.rep(' ', highest_lnum_width - math.floor(math.log10(lnum))),
+ lnum
+ )
+
+ vim.api.nvim_buf_set_lines(
+ preview_buf,
+ preview_buf_line,
+ preview_buf_line,
+ 0,
+ { prefix .. vim.api.nvim_buf_get_lines(buf, lnum - 1, lnum, false)[1] }
+ )
+ end
+
+ for _, line_match in ipairs(line_matches) do
+ vim.api.nvim_buf_add_highlight(
+ buf,
+ preview_ns,
+ 'Substitute',
+ lnum - 1,
+ line_match[1],
+ line_match[2]
+ )
+
+ if use_preview_win then
+ vim.api.nvim_buf_add_highlight(
+ preview_buf,
+ preview_ns,
+ 'Substitute',
+ preview_buf_line,
+ #prefix + line_match[1],
+ #prefix + line_match[2]
+ )
+ end
+ end
+
+ preview_buf_line = preview_buf_line + 1
+ end
+
+ if use_preview_win then
+ return 2
+ else
+ return 1
+ end
+ end
+
+ local function do_replace(opts, preview, preview_ns, preview_buf)
+ local pat1 = opts.fargs[1] or ''
+ local pat2 = opts.fargs[2] or ''
+ local line1 = opts.line1
+ local line2 = opts.line2
+
+ local buf = vim.api.nvim_get_current_buf()
+ local lines = vim.api.nvim_buf_get_lines(buf, line1 - 1, line2, 0)
+ local matches = {}
+
+ for i, line in ipairs(lines) do
+ local startidx, endidx = 0, 0
+ local line_matches = {}
+ local num = 1
+
+ while startidx ~= -1 do
+ local match = vim.fn.matchstrpos(line, pat1, 0, num)
+ startidx, endidx = match[2], match[3]
+
+ if startidx ~= -1 then
+ line_matches[#line_matches+1] = { startidx, endidx }
+ end
+
+ num = num + 1
+ end
+
+ if #line_matches > 0 then
+ matches[#matches+1] = { line1 + i - 1, line_matches }
+ end
+ end
+
+ local new_lines = {}
+
+ for _, match in ipairs(matches) do
+ local lnum = match[1]
+ local line_matches = match[2]
+ local line = lines[lnum - line1 + 1]
+ local pat_width_differences = {}
+
+ -- If previewing, only replace the text in current buffer if pat2 isn't empty
+ -- Otherwise, always replace the text
+ if pat2 ~= '' or not preview then
+ if preview then
+ for _, line_match in ipairs(line_matches) do
+ local startidx, endidx = unpack(line_match)
+ local pat_match = line:sub(startidx + 1, endidx)
+
+ pat_width_differences[#pat_width_differences+1] =
+ #vim.fn.substitute(pat_match, pat1, pat2, 'g') - #pat_match
+ end
+ end
+
+ new_lines[lnum] = vim.fn.substitute(line, pat1, pat2, 'g')
+ end
+
+ -- Highlight the matches if previewing
+ if preview then
+ local idx_offset = 0
+ for i, line_match in ipairs(line_matches) do
+ local startidx, endidx = unpack(line_match)
+ -- Starting index of replacement text
+ local repl_startidx = startidx + idx_offset
+ -- Ending index of the replacement text (if pat2 isn't empty)
+ local repl_endidx
+
+ if pat2 ~= '' then
+ repl_endidx = endidx + idx_offset + pat_width_differences[i]
+ else
+ repl_endidx = endidx + idx_offset
+ end
+
+ if pat2 ~= '' then
+ idx_offset = idx_offset + pat_width_differences[i]
+ end
+
+ line_matches[i] = { repl_startidx, repl_endidx }
+ end
+ end
+ end
+
+ for lnum, line in pairs(new_lines) do
+ vim.api.nvim_buf_set_lines(buf, lnum - 1, lnum, false, { line })
+ end
+
+ if preview then
+ local lnum = vim.api.nvim_win_get_cursor(0)[1]
+ -- Use preview window only if preview buffer is provided and range isn't just the current line
+ local use_preview_win = (preview_buf ~= nil) and (line1 ~= lnum or line2 ~= lnum)
+ return show_replace_preview(buf, use_preview_win, preview_ns, preview_buf, matches)
+ end
+ end
+
+ local function replace(opts)
+ do_replace(opts, false)
+ end
+
+ local function replace_preview(opts, preview_ns, preview_buf)
+ return do_replace(opts, true, preview_ns, preview_buf)
+ end
+
+ -- ":<range>Replace <pat1> <pat2>"
+ -- Replaces all occurences of <pat1> in <range> with <pat2>
+ vim.api.nvim_create_user_command(
+ 'Replace',
+ replace,
+ { nargs = '*', range = '%', addr = 'lines',
+ preview = replace_preview }
+ )
+]]
+
+describe("'inccommand' for user commands", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 17)
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.Yellow1},
+ [2] = {foreground = Screen.colors.Blue1, bold = true},
+ [3] = {reverse = true},
+ [4] = {reverse = true, bold = true}
+ })
+ screen:attach()
+ exec_lua(setup_replace_cmd)
+ command('set cmdwinheight=5')
+ insert[[
+ text on line 1
+ more text on line 2
+ oh no, even more text
+ will the text ever stop
+ oh well
+ did the text stop
+ why won't it stop
+ make the text stop
+ ]]
+ end)
+
+ it('works with inccommand=nosplit', function()
+ command('set inccommand=nosplit')
+ feed(':Replace text cats')
+ screen:expect([[
+ {1:cats} on line 1 |
+ more {1:cats} on line 2 |
+ oh no, even more {1:cats} |
+ will the {1:cats} ever stop |
+ oh well |
+ did the {1:cats} stop |
+ why won't it stop |
+ make the {1:cats} stop |
+ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ :Replace text cats^ |
+ ]])
+ end)
+
+ it('works with inccommand=split', function()
+ command('set inccommand=split')
+ feed(':Replace text cats')
+ screen:expect([[
+ {1:cats} on line 1 |
+ more {1:cats} on line 2 |
+ oh no, even more {1:cats} |
+ will the {1:cats} ever stop |
+ oh well |
+ did the {1:cats} stop |
+ why won't it stop |
+ make the {1:cats} stop |
+ |
+ {4:[No Name] [+] }|
+ |1| {1:cats} on line 1 |
+ |2| more {1:cats} on line 2 |
+ |3| oh no, even more {1:cats} |
+ |4| will the {1:cats} ever stop |
+ |6| did the {1:cats} stop |
+ {3:[Preview] }|
+ :Replace text cats^ |
+ ]])
+ end)
+
+ it('properly closes preview when inccommand=split', function()
+ command('set inccommand=split')
+ feed(':Replace text cats<Esc>')
+ screen:expect([[
+ text on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ end)
+
+ it('properly executes command when inccommand=split', function()
+ command('set inccommand=split')
+ feed(':Replace text cats<CR>')
+ screen:expect([[
+ cats on line 1 |
+ more cats on line 2 |
+ oh no, even more cats |
+ will the cats ever stop |
+ oh well |
+ did the cats stop |
+ why won't it stop |
+ make the cats stop |
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ :Replace text cats |
+ ]])
+ end)
+
+ it('shows preview window only when range is not current line', function()
+ command('set inccommand=split')
+ feed('gg:.Replace text cats')
+ screen:expect([[
+ {1:cats} on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
+ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ :.Replace text cats^ |
+ ]])
+ end)
+end)