---@tag telescope.mappings
---@brief [[
--- |telescope.mappings| is used to configure the keybindings within
--- a telescope picker. These keybinds are only local to the picker window
--- and will be cleared once you exit the picker.
---
--- We provide multiple different ways of configuring, as described below,
--- to provide an easy to use experience for changing the default behavior
--- of telescope or extending for your own purposes.
---
--- To see many of the builtin actions that you can use as values for this
--- table, see |telescope.actions|
---
--- Format is:
---
--- {
--- mode = { ..keys }
--- }
---
---
--- where {mode} is the one character letter for a mode ('i' for insert, 'n' for normal).
---
--- For example:
---
--- mappings = {
--- i = {
--- [""] = require('telescope.actions').close,
--- },
--- }
---
---
--- To disable a keymap, put `[map] = false`
--- For example:
---
--- {
--- ...,
--- [""] = false,
--- ...,
--- }
---
--- Into your config.
---
--- To override behavior of a key, simply set the value
--- to be a function (either by requiring an action or by writing
--- your own function)
---
--- {
--- ...,
--- [""] = require('telescope.actions').select_default,
--- ...,
--- }
---
---
--- If the function you want is part of `telescope.actions`, then you can
--- simply give a string.
--- For example, the previous option is equivalent to:
---
--- {
--- ...,
--- [""] = "select_default",
--- ...,
--- }
---
---
--- You can also add other mappings using tables with `type = "command"`.
--- For example:
---
--- {
--- ...,
--- ["jj"] = { "", type = "command" },
--- ["kk"] = { "echo \"Hello, World!\"", type = "command" },)
--- ...,
--- }
---
---
--- You can also add additional options for mappings of any type ("action" and "command").
--- For example:
---
--- {
--- ...,
--- [""] = {
--- actions.move_selection_next, type = "action",
--- opts = { nowait = true, silent = true }
--- },
--- ...,
--- }
---
---
--- There are three main places you can configure |telescope.mappings|. These are
--- ordered from the lowest priority to the highest priority.
---
--- 1. |telescope.defaults.mappings|
--- 2. In the |telescope.setup()| table, inside a picker with a given name, use the `mappings` key
---
--- require("telescope").setup {
--- pickers = {
--- find_files = {
--- mappings = {
--- n = {
--- ["kj"] = "close",
--- },
--- },
--- },
--- },
--- }
---
--- 3. `attach_mappings` function for a particular picker.
---
--- require("telescope.builtin").find_files {
--- attach_mappings = function(_, map)
--- map("i", "asdf", function(_prompt_bufnr)
--- print "You typed asdf"
--- end)
--- -- needs to return true if you want to map default_mappings and
--- -- false if not
--- return true
--- end,
--- }
---
---@brief ]]
local a = vim.api
local actions = require "telescope.actions"
local config = require "telescope.config"
local mappings = {}
mappings.default_mappings = config.values.default_mappings
or {
i = {
[""] = actions.move_selection_next,
[""] = actions.move_selection_previous,
[""] = actions.close,
[""] = actions.move_selection_next,
[""] = actions.move_selection_previous,
[""] = actions.select_default,
[""] = actions.select_horizontal,
[""] = actions.select_vertical,
[""] = actions.select_tab,
[""] = actions.preview_scrolling_up,
[""] = actions.preview_scrolling_down,
[""] = actions.results_scrolling_up,
[""] = actions.results_scrolling_down,
[""] = actions.toggle_selection + actions.move_selection_worse,
[""] = actions.toggle_selection + actions.move_selection_better,
[""] = actions.send_to_qflist + actions.open_qflist,
[""] = actions.send_selected_to_qflist + actions.open_qflist,
[""] = actions.complete_tag,
[""] = actions.which_key,
[""] = actions.which_key, -- keys from pressing
[""] = { "", type = "command" },
-- disable c-j because we dont want to allow new lines #2123
[""] = actions.nop,
},
n = {
[""] = actions.close,
[""] = actions.select_default,
[""] = actions.select_horizontal,
[""] = actions.select_vertical,
[""] = actions.select_tab,
[""] = actions.toggle_selection + actions.move_selection_worse,
[""] = actions.toggle_selection + actions.move_selection_better,
[""] = actions.send_to_qflist + actions.open_qflist,
[""] = actions.send_selected_to_qflist + actions.open_qflist,
-- TODO: This would be weird if we switch the ordering.
["j"] = actions.move_selection_next,
["k"] = actions.move_selection_previous,
["H"] = actions.move_to_top,
["M"] = actions.move_to_middle,
["L"] = actions.move_to_bottom,
[""] = actions.move_selection_next,
[""] = actions.move_selection_previous,
["gg"] = actions.move_to_top,
["G"] = actions.move_to_bottom,
[""] = actions.preview_scrolling_up,
[""] = actions.preview_scrolling_down,
[""] = actions.results_scrolling_up,
[""] = actions.results_scrolling_down,
["?"] = actions.which_key,
},
}
__TelescopeKeymapStore = __TelescopeKeymapStore
or setmetatable({}, {
__index = function(t, k)
rawset(t, k, {})
return rawget(t, k)
end,
})
local keymap_store = __TelescopeKeymapStore
local _mapping_key_id = 0
local get_next_id = function()
_mapping_key_id = _mapping_key_id + 1
return _mapping_key_id
end
local assign_function = function(prompt_bufnr, func)
local func_id = get_next_id()
keymap_store[prompt_bufnr][func_id] = func
return func_id
end
local telescope_map = function(prompt_bufnr, mode, key_bind, key_func, opts)
if not key_func then
return
end
opts = opts or {}
if opts.noremap == nil then
opts.noremap = true
end
if opts.silent == nil then
opts.silent = true
end
if type(key_func) == "string" then
key_func = actions[key_func]
elseif type(key_func) == "table" then
if key_func.type == "command" then
a.nvim_buf_set_keymap(prompt_bufnr, mode, key_bind, key_func[1], opts or {
silent = true,
})
return
elseif key_func.type == "action_key" then
key_func = actions[key_func[1]]
elseif key_func.type == "action" then
key_func = key_func[1]
end
end
local key_id = assign_function(prompt_bufnr, key_func)
local prefix
local map_string
if opts.expr then
map_string =
string.format([[luaeval("require('telescope.mappings').execute_keymap(%s, %s)")]], prompt_bufnr, key_id)
else
if mode == "i" and not opts.expr then
prefix = ""
elseif mode == "n" then
prefix = ":"
else
prefix = ":"
end
map_string =
string.format("%slua require('telescope.mappings').execute_keymap(%s, %s)", prefix, prompt_bufnr, key_id)
end
a.nvim_buf_set_keymap(prompt_bufnr, mode, key_bind, map_string, opts)
end
local extract_keymap_opts = function(key_func)
if type(key_func) == "table" and key_func.opts ~= nil then
-- we can't clear this because key_func could be a table from the config.
-- If we clear it the table ref would lose opts after the first bind
-- We need to copy it so noremap and silent won't be part of the table ref after the first bind
return vim.deepcopy(key_func.opts)
end
return {}
end
mappings.apply_keymap = function(prompt_bufnr, attach_mappings, buffer_keymap)
local applied_mappings = { n = {}, i = {} }
local map = function(mode, key_bind, key_func, opts)
mode = string.lower(mode)
local key_bind_internal = a.nvim_replace_termcodes(key_bind, true, true, true)
applied_mappings[mode][key_bind_internal] = true
telescope_map(prompt_bufnr, mode, key_bind, key_func, opts)
end
if attach_mappings then
local attach_results = attach_mappings(prompt_bufnr, map)
if attach_results == nil then
error(
"Attach mappings must always return a value. `true` means use default mappings, "
.. "`false` means only use attached mappings"
)
end
if not attach_results then
return
end
end
for mode, mode_map in pairs(buffer_keymap or {}) do
mode = string.lower(mode)
for key_bind, key_func in pairs(mode_map) do
local key_bind_internal = a.nvim_replace_termcodes(key_bind, true, true, true)
if not applied_mappings[mode][key_bind_internal] then
applied_mappings[mode][key_bind_internal] = true
telescope_map(prompt_bufnr, mode, key_bind, key_func, extract_keymap_opts(key_func))
end
end
end
-- TODO: Probably should not overwrite any keymaps
for mode, mode_map in pairs(mappings.default_mappings) do
mode = string.lower(mode)
for key_bind, key_func in pairs(mode_map) do
local key_bind_internal = a.nvim_replace_termcodes(key_bind, true, true, true)
if not applied_mappings[mode][key_bind_internal] then
applied_mappings[mode][key_bind_internal] = true
telescope_map(prompt_bufnr, mode, key_bind, key_func, extract_keymap_opts(key_func))
end
end
end
end
mappings.execute_keymap = function(prompt_bufnr, keymap_identifier)
local key_func = keymap_store[prompt_bufnr][keymap_identifier]
assert(key_func, string.format("Unsure of how we got this failure: %s %s", prompt_bufnr, keymap_identifier))
key_func(prompt_bufnr)
vim.api.nvim_exec_autocmds("User TelescopeKeymap", {})
end
mappings.clear = function(prompt_bufnr)
keymap_store[prompt_bufnr] = nil
end
return mappings