if vim.g.did_load_keymaps_plugin then return end vim.g.did_load_keymaps_plugin = true local api = vim.api local fn = vim.fn local keymap = vim.keymap local diagnostic = vim.diagnostic -- Yank from current position till end of current line keymap.set('n', 'Y', 'y$', { silent = true, desc = '[Y]ank to end of line' }) require('which-key').add({ -- Buffer list navigation, ordering, ... { "", "BufferLineTogglePin", desc = '[p]in buffer' }, { "gB", "BufferLinePick", desc = '[g]o to [b]uffer' }, { '>b', "BufferLineMoveNext", desc = 'move [b]uffer right' }, { 'BufferLineMovePrev", desc = 'move [b]uffer left' }, { '[b', "BufferLineCyclePrev", desc = 'previous [b]uffer' }, { ']b', "BufferLineCycleNext", desc = 'next [b]uffer' }, { '[B', vim.cmd.bfirst, desc = 'first [B]uffer' }, { ']B', vim.cmd.blast, desc = 'last [B]uffer' }, { 'tn', vim.cmd.tabnew, desc = '[t]ab: [n]ew' }, { 'tq', "bd", desc = '[t]ab: [q]uit/close' }, { 'c', "bd", desc = '[c]lose tab' }, -- Window resizing { "", "resize -2", desc = "resize split up" }, { "", "resize +2", desc = "resize split down" }, { "", "vertical resize +2", desc = "resize split left" }, { "", "vertical resize -2", desc = "resize split right" }, -- ToggleTerm { "Tf", "ToggleTerm direction=float", desc = "[T]oggleterm [f]loat" }, { "Th", "ToggleTerm size=10 direction=horizontal", desc = "[T]oggleterm [h]orizontal split" }, { "Tv", "ToggleTerm size=80 direction=vertical", desc = "[T]oggleterm [v]ertical split" }, { "", 'execute v:count . "ToggleTerm"', desc = "Toggle terminal" }, { mode = "t", "", "ToggleTerm", desc = "Toggle terminal" }, { mode = "i", "", "ToggleTerm", desc = "Toggle terminal" }, { "", 'execute v:count . "ToggleTerm"', desc = "Toggle terminal" }, -- requires terminal that supports binding { "", "ToggleTerm", desc = "Toggle terminal" }, -- requires terminal that supports binding { "", "ToggleTerm", desc = "Toggle terminal" }, -- requires terminal that supports binding ` -- Trouble { "x", group = "trouble" }, { "xt", "Trouble diagnostics toggle", desc = "trouble: [t]oggle", }, { "xX", "Trouble diagnostics toggle filter.buf=0", desc = "trouble: [b]uffer diagnostics", }, { "xs", "Trouble symbols toggle focus=false", desc = "trouble: [s]ymbols (Trouble)", }, { "xl", "Trouble lsp toggle focus=false win.position=right", desc = "trouble: [l]sp definitions / references / ...", }, { "xL", "Trouble loclist toggle", desc = "trouble: [L]ocation list", }, { "xQ", "Trouble qflist toggle", desc = "trouble: [q]uickfix list", }, { "xw", noremap = true, callback = function() for _, client in ipairs(vim.lsp.buf_get_clients()) do require("workspace-diagnostics").populate_workspace_diagnostics(client, 0) end end, desc = "trouble: load [w]orkspace" }, }) -- Toggle the quickfix list (only opens if it is populated) local function toggle_qf_list() local qf_exists = false for _, win in pairs(fn.getwininfo() or {}) do if win['quickfix'] == 1 then qf_exists = true end end if qf_exists == true then vim.cmd.cclose() return end if not vim.tbl_isempty(vim.fn.getqflist()) then vim.cmd.copen() end end keymap.set('n', '', toggle_qf_list, { desc = 'toggle quickfix list' }) keymap.set({ "v", "n" }, "gf", require("actions-preview").code_actions, { desc = '[l]sp [f]ix' }) keymap.set({ "v", "n" }, "lf", require("actions-preview").code_actions, { desc = '[l]sp [f]ix' }) local function try_fallback_notify(opts) local success, _ = pcall(opts.try) if success then return end success, _ = pcall(opts.fallback) if success then return end vim.notify(opts.notify, vim.log.levels.INFO) end -- Cycle the quickfix and location lists local function cleft() try_fallback_notify { try = vim.cmd.cprev, fallback = vim.cmd.clast, notify = 'Quickfix list is empty!', } end local function cright() try_fallback_notify { try = vim.cmd.cnext, fallback = vim.cmd.cfirst, notify = 'Quickfix list is empty!', } end keymap.set('n', '[c', cleft, { silent = true, desc = '[c]ycle quickfix left' }) keymap.set('n', ']c', cright, { silent = true, desc = '[c]ycle quickfix right' }) keymap.set('n', '[C', vim.cmd.cfirst, { silent = true, desc = 'first quickfix entry' }) keymap.set('n', ']C', vim.cmd.clast, { silent = true, desc = 'last quickfix entry' }) local function lleft() try_fallback_notify { try = vim.cmd.lprev, fallback = vim.cmd.llast, notify = 'Location list is empty!', } end local function lright() try_fallback_notify { try = vim.cmd.lnext, fallback = vim.cmd.lfirst, notify = 'Location list is empty!', } end keymap.set('n', '[l', lleft, { silent = true, desc = 'cycle [l]oclist left' }) keymap.set('n', ']l', lright, { silent = true, desc = 'cycle [l]oclist right' }) keymap.set('n', '[L', vim.cmd.lfirst, { silent = true, desc = 'first [L]oclist entry' }) keymap.set('n', ']L', vim.cmd.llast, { silent = true, desc = 'last [L]oclist entry' }) -- Resize vertical splits local toIntegral = math.ceil keymap.set('n', 'w+', function() local curWinWidth = api.nvim_win_get_width(0) api.nvim_win_set_width(0, toIntegral(curWinWidth * 3 / 2)) end, { silent = true, desc = 'inc window [w]idth' }) keymap.set('n', 'w-', function() local curWinWidth = api.nvim_win_get_width(0) api.nvim_win_set_width(0, toIntegral(curWinWidth * 2 / 3)) end, { silent = true, desc = 'dec window [w]idth' }) keymap.set('n', 'h+', function() local curWinHeight = api.nvim_win_get_height(0) api.nvim_win_set_height(0, toIntegral(curWinHeight * 3 / 2)) end, { silent = true, desc = 'inc window [h]eight' }) keymap.set('n', 'h-', function() local curWinHeight = api.nvim_win_get_height(0) api.nvim_win_set_height(0, toIntegral(curWinHeight * 2 / 3)) end, { silent = true, desc = 'dec window [h]eight' }) -- Close floating windows [Neovim 0.10 and above] keymap.set('n', 'fq', function() vim.cmd('fclose!') end, { silent = true, desc = '[f]loating windows: [q]uit/close all' }) -- Remap Esc to switch to normal mode and Ctrl-Esc to pass Esc to terminal keymap.set('t', '', '', { desc = 'switch to normal mode' }) keymap.set('t', '', '', { desc = 'send Esc to terminal' }) -- Shortcut for expanding to current buffer's directory in command mode keymap.set('c', '%%', function() if fn.getcmdtype() == ':' then return fn.expand('%:h') .. '/' else return '%%' end end, { expr = true, desc = "expand to current buffer's directory" }) local severity = diagnostic.severity keymap.set('n', 'le', function() local _, winid = diagnostic.open_float(nil, { scope = 'line' }) if not winid then vim.notify('no diagnostics found', vim.log.levels.INFO) return end vim.api.nvim_win_set_config(winid or 0, { focusable = true }) end, { noremap = true, silent = true, desc = 'diagnostics floating window' }) keymap.set('n', '[d', diagnostic.goto_prev, { noremap = true, silent = true, desc = 'previous [d]iagnostic' }) keymap.set('n', ']d', diagnostic.goto_next, { noremap = true, silent = true, desc = 'next [d]iagnostic' }) keymap.set('n', '[e', function() diagnostic.goto_prev { severity = severity.ERROR, } end, { noremap = true, silent = true, desc = 'previous [e]rror diagnostic' }) keymap.set('n', ']e', function() diagnostic.goto_next { severity = severity.ERROR, } end, { noremap = true, silent = true, desc = 'next [e]rror diagnostic' }) keymap.set('n', '[w', function() diagnostic.goto_prev { severity = severity.WARN, } end, { noremap = true, silent = true, desc = 'previous [w]arning diagnostic' }) keymap.set('n', ']w', function() diagnostic.goto_next { severity = severity.WARN, } end, { noremap = true, silent = true, desc = 'next [w]arning diagnostic' }) keymap.set('n', '[h', function() diagnostic.goto_prev { severity = severity.HINT, } end, { noremap = true, silent = true, desc = 'previous [h]int diagnostic' }) keymap.set('n', ']h', function() diagnostic.goto_next { severity = severity.HINT, } end, { noremap = true, silent = true, desc = 'next [h]int diagnostic' }) local function toggle_spell_check() ---@diagnostic disable-next-line: param-type-mismatch vim.opt.spell = not (vim.opt.spell:get()) end keymap.set('n', 'S', toggle_spell_check, { noremap = true, silent = true, desc = 'toggle [S]pell' }) keymap.set('n', '', 'zz', { desc = 'move [d]own half-page and center' }) keymap.set('n', '', 'zz', { desc = 'move [u]p half-page and center' }) keymap.set('n', '', 'zz', { desc = 'move DOWN [f]ull-page and center' }) keymap.set('n', '', 'zz', { desc = 'move UP full-page and center' }) keymap.set('n', '', 'wincmd h', { desc = 'focus left window' }) keymap.set('n', '', 'wincmd j', { desc = 'focus bottom window' }) keymap.set('n', '', 'wincmd k', { desc = 'focus top window' }) keymap.set('n', '', 'wincmd l', { desc = 'focus right window' }) keymap.set('n', 'tt', 'TodoTelescope', { desc = '[t]elescope [t]odo comments' }) --- Disabled keymaps [enable at your own risk] -- Automatic management of search highlight -- XXX: This is not so nice if you use j/k for navigation -- (you should be using / and relative line numbers instead ;) -- -- local auto_hlsearch_namespace = vim.api.nvim_create_namespace('auto_hlsearch') -- vim.on_key(function(char) -- if vim.fn.mode() == 'n' then -- vim.opt.hlsearch = vim.tbl_contains({ '', 'n', 'N', '*', '#', '?', '/' }, vim.fn.keytrans(char)) -- end -- end, auto_hlsearch_namespace)