Compare commits

...

1 commit

Author SHA1 Message Date
35e61885a5 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.
2022-09-07 21:11:49 +01:00
9 changed files with 172 additions and 39 deletions

View file

@ -58,10 +58,12 @@ A command can be run that will launch the completion UI
Action can be run on selected candidates provide functionality Action can be run on selected candidates provide functionality
| Action | Description | | Action | Description |
| -------- | ------------------------------------------------------------------------------ | | -------------- | ------------------------------------------------------------------------------ |
| Complete | Run the completion function, usually this will be opening a file | | 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 | | 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 ## API

View file

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

View file

@ -1,14 +1,8 @@
local prompt = require "ivy.prompt" local prompt = require "ivy.prompt"
local vim_mock = require "ivy.vim_mock"
before_each(function() before_each(function()
-- Mock the global vim functions we are using in the prompt vim_mock.reset()
_G.vim = {
notify = function() end,
api = {
nvim_echo = function() end,
},
}
prompt.destroy() prompt.destroy()
end) end)
@ -23,7 +17,7 @@ end
local assert_prompt = function(t, expected) local assert_prompt = function(t, expected)
local text = prompt.text() local text = prompt.text()
if text ~= expected then 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
end end

View file

@ -1,5 +1,22 @@
local utils = {} 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) utils.command_finder = function(command, min)
if min == nil then if min == nil then
min = 3 min = 3
@ -28,7 +45,7 @@ utils.command_finder = function(command, min)
end end
utils.vimgrep_action = function() utils.vimgrep_action = function()
return function(item) return function(item, action)
-- Match file and line form vimgrep style commands -- Match file and line form vimgrep style commands
local file = item:match "([^:]+):" local file = item:match "([^:]+):"
local line = item:match ":(%d+):" local line = item:match ":(%d+):"
@ -38,7 +55,7 @@ utils.vimgrep_action = function()
return return
end end
vim.cmd("edit " .. file) utils.file_action()(file, action)
if line ~= nil then if line ~= nil then
vim.cmd(line) vim.cmd(line)
end end
@ -46,11 +63,18 @@ utils.vimgrep_action = function()
end end
utils.file_action = function() utils.file_action = function()
return function(file) return function(file, action)
if file == nil then if file == nil then
return return
end 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
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>", "<cmd>lua vim.ivy.previous(); vim.ivy.checkpoint()<CR>",
opts 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", "<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", "<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) 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" local window = require "ivy.window"
before_each(function() before_each(function()
-- Mock the global vim functions we are using in the prompt vim_mock.reset()
_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,
},
}
end) end)
it("can initialize", function(t) it("can initialize", function(t)