feat: add vsplit and split actions

Now you can open the currently selected item in a vertical split or a
horizontal split. The completion callback must support the current
actions.

There is also a bit of testing in here. The vim mock has been refactored
and split out so we can use it multiple tests.
This commit is contained in:
Ade Attwood 2022-09-07 21:11:49 +01:00
parent ced6e5ae1e
commit 35e61885a5
9 changed files with 172 additions and 39 deletions

View file

@ -59,9 +59,11 @@ A command can be run that will launch the completion UI
Action can be run on selected candidates provide functionality
| Action | Description |
| -------- | ------------------------------------------------------------------------------ |
| -------------- | ------------------------------------------------------------------------------ |
| Complete | Run the completion function, usually this will be opening a file |
| Peek | Run the completion function on a selection, but don't close the results window |
| Vertical Split | Run the completion function in a new vertical split |
| Split | Run the completion function in a new split |
## API

View file

@ -1,7 +1,9 @@
local window = require "ivy.window"
local prompt = require "ivy.prompt"
local utils = require "ivy.utils"
local controller = {}
controller.action = utils.actions
controller.items = nil
controller.callback = nil
@ -36,16 +38,16 @@ controller.update = function(text)
end)
end
controller.complete = function()
controller.complete = function(action)
vim.api.nvim_set_current_win(window.origin)
controller.callback(window.get_current_selection())
controller.callback(window.get_current_selection(), action)
controller.destroy()
end
controller.checkpoint = function()
vim.api.nvim_set_current_win(window.origin)
controller.callback(window.get_current_selection())
controller.callback(window.get_current_selection(), controller.action.CHECKPOINT)
vim.api.nvim_set_current_win(window.window)
end

View file

@ -1,14 +1,8 @@
local prompt = require "ivy.prompt"
local vim_mock = require "ivy.vim_mock"
before_each(function()
-- Mock the global vim functions we are using in the prompt
_G.vim = {
notify = function() end,
api = {
nvim_echo = function() end,
},
}
vim_mock.reset()
prompt.destroy()
end)
@ -23,7 +17,7 @@ end
local assert_prompt = function(t, expected)
local text = prompt.text()
if text ~= expected then
t.error("The promp text should be '" .. expected .. "' found '" .. text .. "'")
t.error("The prompt text should be '" .. expected .. "' found '" .. text .. "'")
end
end

View file

@ -1,5 +1,22 @@
local utils = {}
-- A list of all of the actions defined by ivy. The callback function can
-- implement as many of them as necessary. As a minimum it should implement the
-- "EDIT" action that is called on the default complete.
utils.actions = {
EDIT = "EDIT",
CHECKPOINT = "CHECKPOINT",
VSPLIT = "VSPLIT",
SPLIT = "SPLIT",
}
utils.command_map = {
[utils.actions.EDIT] = "edit",
[utils.actions.CHECKPOINT] = "edit",
[utils.actions.VSPLIT] = "vsplit",
[utils.actions.SPLIT] = "split",
}
utils.command_finder = function(command, min)
if min == nil then
min = 3
@ -28,7 +45,7 @@ utils.command_finder = function(command, min)
end
utils.vimgrep_action = function()
return function(item)
return function(item, action)
-- Match file and line form vimgrep style commands
local file = item:match "([^:]+):"
local line = item:match ":(%d+):"
@ -38,7 +55,7 @@ utils.vimgrep_action = function()
return
end
vim.cmd("edit " .. file)
utils.file_action()(file, action)
if line ~= nil then
vim.cmd(line)
end
@ -46,11 +63,18 @@ utils.vimgrep_action = function()
end
utils.file_action = function()
return function(file)
return function(file, action)
if file == nil then
return
end
vim.cmd("edit " .. file)
local command = utils.command_map[action]
if command == nil then
vim.api.nvim_err_writeln("[IVY] The file action is unable the handel the action " .. action)
return
end
vim.cmd(command .. " " .. file)
end
end

View file

@ -0,0 +1,39 @@
local utils = require "ivy.utils"
local line_action = utils.line_action()
local vim_mock = require "ivy.vim_mock"
before_each(function()
vim_mock.reset()
end)
it("will run the line command", function(t)
line_action " 4: Some text"
if #vim_mock.commands ~= 1 then
t.error "`line_action` command length should be 1"
end
if vim_mock.commands[1] ~= "4" then
t.error "`line_action` command should be 4"
end
end)
it("will run with more numbers", function(t)
line_action " 44: Some text"
if #vim_mock.commands ~= 1 then
t.error "`line_action` command length should be 1"
end
if vim_mock.commands[1] ~= "44" then
t.error "`line_action` command should be 44"
end
end)
it("dose not run any action if no line is found", function(t)
line_action "Some text"
if #vim_mock.commands ~= 0 then
t.error "`line_action` command length should be 1"
end
end)

View file

@ -0,0 +1,56 @@
local utils = require "ivy.utils"
local vimgrep_action = utils.vimgrep_action()
local vim_mock = require "ivy.vim_mock"
before_each(function()
vim_mock.reset()
end)
local test_data = {
{
it = "will edit some file and goto the line",
completion = "some/file.lua:2: This is some text",
action = utils.actions.EDIT,
commands = {
"edit some/file.lua",
"2",
},
},
{
it = "will skip the line if its not matched",
completion = "some/file.lua: This is some text",
action = utils.actions.EDIT,
commands = { "edit some/file.lua" },
},
{
it = "will run the vsplit command",
completion = "some/file.lua: This is some text",
action = utils.actions.VSPLIT,
commands = { "vsplit some/file.lua" },
},
{
it = "will run the split command",
completion = "some/file.lua: This is some text",
action = utils.actions.SPLIT,
commands = { "split some/file.lua" },
},
}
for i = 1, #test_data do
local data = test_data[i]
it(data.it, function(t)
vimgrep_action(data.completion, data.action)
if #vim_mock.commands ~= #data.commands then
t.error("Incorrect number of commands run expected " .. #data.commands .. " but found " .. #vim_mock.commands)
end
for j = 1, #data.commands do
if vim_mock.commands[j] ~= data.commands[j] then
t.error(
"Incorrect command run expected '" .. data.commands[j] .. "' but found '" .. vim_mock.commands[j] .. "'"
)
end
end
end)
end

30
lua/ivy/vim_mock.lua Normal file
View file

@ -0,0 +1,30 @@
local mock = {
commands = {},
}
mock.reset = function()
mock.commands = {}
_G.vim = {
notify = function() end,
cmd = function(cmd)
table.insert(mock.commands, cmd)
end,
api = {
nvim_echo = function() end,
nvim_get_current_win = function()
return 10
end,
nvim_command = function() end,
nvim_win_get_buf = function()
return 10
end,
nvim_win_set_option = function() end,
nvim_buf_set_option = function() end,
nvim_buf_set_var = function() end,
nvim_buf_set_keymap = function() end,
},
}
end
return mock

View file

@ -69,7 +69,9 @@ window.make_buffer = function()
"<cmd>lua vim.ivy.previous(); vim.ivy.checkpoint()<CR>",
opts
)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<CR>", "<cmd>lua vim.ivy.complete()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<CR>", "<cmd>lua vim.ivy.complete(vim.ivy.action.EDIT)<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-v>", "<cmd>lua vim.ivy.complete(vim.ivy.action.VSPLIT)<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-s>", "<cmd>lua vim.ivy.complete(vim.ivy.action.SPLIT)<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<BS>", "<cmd>lua vim.ivy.input('BACKSPACE')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<Left>", "<cmd>lua vim.ivy.input('LEFT')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<Right>", "<cmd>lua vim.ivy.input('RIGHT')<CR>", opts)

View file

@ -1,24 +1,8 @@
local vim_mock = require "ivy.vim_mock"
local window = require "ivy.window"
before_each(function()
-- Mock the global vim functions we are using in the prompt
_G.vim = {
notify = function() end,
api = {
nvim_echo = function() end,
nvim_get_current_win = function()
return 10
end,
nvim_command = function() end,
nvim_win_get_buf = function()
return 10
end,
nvim_win_set_option = function() end,
nvim_buf_set_option = function() end,
nvim_buf_set_var = function() end,
nvim_buf_set_keymap = function() end,
},
}
vim_mock.reset()
end)
it("can initialize", function(t)