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:
parent
ced6e5ae1e
commit
35e61885a5
9 changed files with 172 additions and 39 deletions
10
README.md
10
README.md
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
39
lua/ivy/utils_line_action_test.lua
Normal file
39
lua/ivy/utils_line_action_test.lua
Normal 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)
|
||||||
56
lua/ivy/utils_vimgrep_action_test.lua
Normal file
56
lua/ivy/utils_vimgrep_action_test.lua
Normal 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
30
lua/ivy/vim_mock.lua
Normal 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
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue