ivy.nvim/lua/ivy/window.lua
Ade Attwood 6e45d75a1e
All checks were successful
CI / StyLua (pull_request) Successful in 31s
CI / Luacheck (pull_request) Successful in 52s
CI / Cargo Format (pull_request) Successful in 49s
Conventional Tools Commitlint / Commitlint (pull_request) Successful in 13s
CI / Build and test (pull_request) Successful in 2m50s
CI / StyLua (push) Successful in 44s
CI / Luacheck (push) Successful in 1m4s
CI / Cargo Format (push) Successful in 1m12s
Conventional Tools Commitlint / Commitlint (push) Successful in 17s
CI / Build and test (push) Successful in 6m4s
feat: allow users to configure the window keymaps
Summary:

Now you can use the setup configuration to overwrite and override the keymaps
in the ivy window. Each of the actions have now been givin a "key", you can use
the keys to run action on keymaps defined in the config. They will all be
registered in the buffer and run when pressed.

The readme has been updated to document how do this.

Test Plan:

We have the tests that still run. It has been tested manually and gone though
QA before getting merged.
2024-10-27 09:28:33 +00:00

177 lines
5 KiB
Lua

local config = require "ivy.config"
-- Constent options that will be used for the keymaps
local opts = { noremap = true, silent = true, nowait = true }
-- All of the base chars that will be used for an "input" operation on the
-- prompt
-- stylua: ignore
local chars = {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
"u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "<", ">", "`", "@", "#", "~", "!",
"\"", "$", "%", "^", "&", "/", "(", ")", "=", "+", "*", "-", "_", ".", ",", ";", ":", "?", "\\", "|", "'", "{", "}",
"[", "]", " ",
}
local function string_to_table(lines)
local matches = {}
for line in lines:gmatch "[^\r\n]+" do
table.insert(matches, { content = line })
end
return matches
end
local function get_items_length(items)
local mt = getmetatable(items)
if mt ~= nil and mt.__len ~= nil then
return mt.__len(items)
end
return #items
end
local function call_gc(items)
local mt = getmetatable(items)
if mt ~= nil and mt.__gc ~= nil then
return mt.__gc(items)
end
end
local callbacks = {
destroy = "<cmd>lua vim.ivy.destroy()<CR>",
clear = "<cmd>lua vim.ivy.search('')<CR>",
next = "<cmd>lua vim.ivy.next()<CR>",
previous = "<cmd>lua vim.ivy.previous()<CR>",
next_checkpoint = "<cmd>lua vim.ivy.next(); vim.ivy.checkpoint()<CR>",
previous_checkpoint = "<cmd>lua vim.ivy.previous(); vim.ivy.checkpoint()<CR>",
complete = "<cmd>lua vim.ivy.complete(vim.ivy.action.EDIT)<CR>",
vsplit = "<cmd>lua vim.ivy.complete(vim.ivy.action.VSPLIT)<CR>",
split = "<cmd>lua vim.ivy.complete(vim.ivy.action.SPLIT)<CR>",
backspace = "<cmd>lua vim.ivy.input('BACKSPACE')<CR>",
left = "<cmd>lua vim.ivy.input('LEFT')<CR>",
right = "<cmd>lua vim.ivy.input('RIGHT')<CR>",
delete_word = "<cmd>lua vim.ivy.input('DELETE_WORD')<CR>",
}
local window = {}
window.index = 0
window.origin = nil
window.window = nil
window.buffer = nil
window.origin_buffer = nil
window.initialize = function()
window.make_buffer()
end
window.make_buffer = function()
window.origin = vim.api.nvim_get_current_win()
window.origin_buffer = vim.api.nvim_win_get_buf(0)
vim.api.nvim_command "botright split new"
window.buffer = vim.api.nvim_win_get_buf(0)
window.window = vim.api.nvim_get_current_win()
vim.api.nvim_win_set_option(window.window, "number", false)
vim.api.nvim_win_set_option(window.window, "relativenumber", false)
vim.api.nvim_win_set_option(window.window, "signcolumn", "no")
vim.api.nvim_buf_set_option(window.buffer, "filetype", "ivy")
vim.api.nvim_buf_set_var(window.buffer, "bufftype", "nofile")
for index = 1, #chars do
local char = chars[index]
if char == "'" then
char = "\\'"
end
if char == "\\" then
char = "\\\\\\\\"
end
vim.api.nvim_buf_set_keymap(window.buffer, "n", chars[index], "<cmd>lua vim.ivy.input('" .. char .. "')<CR>", opts)
end
local mappings = config:get { "mappings" }
assert(mappings, "The mappings key is missing from the config, something has gone horribly wrong")
for key, value in pairs(mappings) do
if callbacks[value] == nil then
error("The mapping '" .. value .. "' is not a valid ivy callback")
end
vim.api.nvim_buf_set_keymap(window.buffer, "n", key, callbacks[value], opts)
end
end
window.get_current_selection = function()
local line = vim.api.nvim_buf_get_lines(window.buffer, window.index, window.index + 1, true)
if line == nil then
line = { "" }
end
return line[1]
end
window.get_buffer = function()
if window.buffer == nil then
window.make_buffer()
end
return window.buffer
end
window.update = function()
vim.api.nvim_win_set_cursor(window.window, { window.index + 1, 0 })
end
window.set_items = function(items)
if type(items) == "string" then
items = string_to_table(items)
end
local items_length = get_items_length(items)
-- TODO(ade): Validate the items are in the correct format. This also need to
-- come with some descriptive messages and possible help.
-- Display no items text if there are no items to dispaly
if items_length == 0 then
items_length = 1
items = { { content = "-- No Items --" } }
end
window.index = items_length - 1
for index = 1, items_length do
vim.api.nvim_buf_set_lines(window.buffer, index - 1, -1, false, { items[index].content })
end
-- Limit the results window size to 10 so when there are lots of results the
-- window does not take up the hole terminal
local line_count = items_length
if line_count > 10 then
line_count = 10
end
vim.api.nvim_win_set_height(window.window, line_count)
window.update()
call_gc(items)
end
window.destroy = function()
if type(window.buffer) == "number" then
vim.api.nvim_buf_delete(window.buffer, { force = true })
end
window.buffer = nil
window.window = nil
window.origin = nil
window.origin_buffer = nil
window.index = 0
end
return window