Files
telescope.nvim/lua/telescope/mappings.lua
Hannu Hartikainen 4626aaa2bc fix(scrolling): enhance and simplify scrolling (#3028)
The previous scrolling implementation (#2687) moved the result selection
by one item at a time, which isn't technically scrolling (ie. moving the
view) and feels quite slow.

Let the neovim builtin scrolling do its thing, so using the scroll wheel
feels like scrolling and is functionally scrolling, too. Scrolling does
not move the selection so after scrolling it typically makes sense to
click. Moving the selection with keyboard takes you back to where you
were. This is in line with typical desktop user interfaces.
2024-04-02 13:36:54 +00:00

365 lines
11 KiB
Lua

---@tag telescope.mappings
---@brief [[
--- |telescope.mappings| is used to configure the keybindings within
--- a telescope picker. These key binds are only local to the picker window
--- and will be cleared once you exit the picker.
---
--- We provide multiple configuration options to make it easy for you to adjust
--- telescope's default key bindings and create your own custom key binds.
---
--- To see many of the builtin actions that you can use as values for this
--- table, see |telescope.actions|
---
--- Format is:
--- <code>
--- {
--- mode = { ..keys }
--- }
--- </code>
---
--- where {mode} is the one character letter for a mode ('i' for insert, 'n' for normal).
---
--- For example:
--- <code>
--- mappings = {
--- i = {
--- ["<esc>"] = require('telescope.actions').close,
--- },
--- }
--- </code>
---
--- To disable a keymap, put `[map] = false`<br>
--- For example:
--- <code>
--- {
--- ...,
--- ["<C-n>"] = false,
--- ...,
--- }
--- </code>
---
--- 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)
--- <code>
--- {
--- ...,
--- ["<C-i>"] = require('telescope.actions').select_default,
--- ...,
--- }
--- </code>
---
--- If the function you want is part of `telescope.actions`, then you can
--- simply supply the function name as a string.
--- For example, the previous option is equivalent to:
--- <code>
--- {
--- ...,
--- ["<C-i>"] = "select_default",
--- ...,
--- }
--- </code>
---
--- You can also add other mappings using tables with `type = "command"`.
--- For example:
--- <code>
--- {
--- ...,
--- ["jj"] = { "<esc>", type = "command" },
--- ["kk"] = { "<cmd>echo \"Hello, World!\"<cr>", type = "command" },)
--- ...,
--- }
--- </code>
---
--- You can also add additional options for mappings of any type ("action" and "command").
--- For example:
--- <code>
--- {
--- ...,
--- ["<C-j>"] = {
--- actions.move_selection_next, type = "action",
--- opts = { nowait = true, silent = true }
--- },
--- ...,
--- }
--- </code>
---
--- 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
--- <code>
--- require("telescope").setup {
--- pickers = {
--- find_files = {
--- mappings = {
--- n = {
--- ["kj"] = "close",
--- },
--- },
--- },
--- },
--- }
--- </code>
--- 3. `attach_mappings` function for a particular picker.
--- <code>
--- require("telescope.builtin").find_files {
--- attach_mappings = function(_, map)
--- map("i", "asdf", function(_prompt_bufnr)
--- print "You typed asdf"
--- end)
---
--- map({"i", "n"}, "<C-r>", function(_prompt_bufnr)
--- print "You typed <C-r>"
--- end, { desc = "desc for which key"})
---
--- -- needs to return true if you want to map default_mappings and
--- -- false if not
--- return true
--- end,
--- }
--- </code>
---@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 = {
["<LeftMouse>"] = {
actions.mouse_click,
type = "action",
opts = { expr = true },
},
["<2-LeftMouse>"] = {
actions.double_mouse_click,
type = "action",
opts = { expr = true },
},
["<C-n>"] = actions.move_selection_next,
["<C-p>"] = actions.move_selection_previous,
["<C-c>"] = actions.close,
["<Down>"] = actions.move_selection_next,
["<Up>"] = actions.move_selection_previous,
["<CR>"] = actions.select_default,
["<C-x>"] = actions.select_horizontal,
["<C-v>"] = actions.select_vertical,
["<C-t>"] = actions.select_tab,
["<C-u>"] = actions.preview_scrolling_up,
["<C-d>"] = actions.preview_scrolling_down,
["<C-f>"] = actions.preview_scrolling_left,
["<C-k>"] = actions.preview_scrolling_right,
["<PageUp>"] = actions.results_scrolling_up,
["<PageDown>"] = actions.results_scrolling_down,
["<M-f>"] = actions.results_scrolling_left,
["<M-k>"] = actions.results_scrolling_right,
["<Tab>"] = actions.toggle_selection + actions.move_selection_worse,
["<S-Tab>"] = actions.toggle_selection + actions.move_selection_better,
["<C-q>"] = actions.send_to_qflist + actions.open_qflist,
["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
["<C-l>"] = actions.complete_tag,
["<C-/>"] = actions.which_key,
["<C-_>"] = actions.which_key, -- keys from pressing <C-/>
["<C-w>"] = { "<c-s-w>", type = "command" },
["<C-r><C-w>"] = actions.insert_original_cword,
-- disable c-j because we dont want to allow new lines #2123
["<C-j>"] = actions.nop,
},
n = {
["<LeftMouse>"] = {
actions.mouse_click,
type = "action",
opts = { expr = true },
},
["<2-LeftMouse>"] = {
actions.double_mouse_click,
type = "action",
opts = { expr = true },
},
["<esc>"] = actions.close,
["<CR>"] = actions.select_default,
["<C-x>"] = actions.select_horizontal,
["<C-v>"] = actions.select_vertical,
["<C-t>"] = actions.select_tab,
["<Tab>"] = actions.toggle_selection + actions.move_selection_worse,
["<S-Tab>"] = actions.toggle_selection + actions.move_selection_better,
["<C-q>"] = actions.send_to_qflist + actions.open_qflist,
["<M-q>"] = 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,
["<Down>"] = actions.move_selection_next,
["<Up>"] = actions.move_selection_previous,
["gg"] = actions.move_to_top,
["G"] = actions.move_to_bottom,
["<C-u>"] = actions.preview_scrolling_up,
["<C-d>"] = actions.preview_scrolling_down,
["<C-f>"] = actions.preview_scrolling_left,
["<C-k>"] = actions.preview_scrolling_right,
["<PageUp>"] = actions.results_scrolling_up,
["<PageDown>"] = actions.results_scrolling_down,
["<M-f>"] = actions.results_scrolling_left,
["<M-k>"] = actions.results_scrolling_right,
["?"] = actions.which_key,
},
}
-- normal names are prefixed with telescope|
-- encoded objects are prefixed with telescopej|
---@param key_func table|fun()
---@param opts table
---@return string?
local get_desc_for_keyfunc = function(key_func, opts)
if opts and opts.desc then
return "telescope|" .. opts.desc
end
if type(key_func) == "table" then
local name = ""
for _, action in ipairs(key_func) do
if type(action) == "string" then
name = name == "" and action or name .. " + " .. action
end
end
return "telescope|" .. name
elseif type(key_func) == "function" then
local info = debug.getinfo(key_func)
return "telescopej|" .. vim.json.encode { source = info.source, linedefined = info.linedefined }
end
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
vim.keymap.set(
mode,
key_bind,
key_func[1],
vim.tbl_extend("force", opts or {
silent = true,
}, { buffer = prompt_bufnr })
)
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
vim.keymap.set(mode, key_bind, function()
local ret = key_func(prompt_bufnr)
vim.api.nvim_exec_autocmds("User", { pattern = "TelescopeKeymap" })
return ret
end, vim.tbl_extend("force", opts, { buffer = prompt_bufnr, desc = get_desc_for_keyfunc(key_func, 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(modes, key_bind, key_func, opts)
if type(modes) == "string" then
modes = { modes }
end
for _, mode in pairs(modes) do
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
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
return mappings