diff --git a/nvim/lua/keymaps.lua b/nvim/lua/keymaps.lua index 2568ca2..8ab4647 100644 --- a/nvim/lua/keymaps.lua +++ b/nvim/lua/keymaps.lua @@ -1,4 +1,205 @@ local g = vim.g +local set = vim.keymap.set +local f = string.format g.mapleader = ' ' g.maplocalleader = '\\' + +-- Disable arrow key movement -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for _, key in ipairs({ '', '', '', '' }) do + set({ 'n', 'i' }, key, '') +end + +-- Better up/down -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for dir, key in pairs({ Down = 'j', Up = 'k' }) do + set( + { 'n', 'x' }, + key, + f("v:count == 0 ? 'g%s' : '%s'", dir, dir), + { desc = dir, expr = true, silent = true } + ) +end + +-- Resize windows -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for key, dir in pairs({ + Up = 'Increase', + Down = 'Decrease', + Left = 'Decrease', + Right = 'Increase', +}) do + local sign = (dir == 'Increase') and '+' or '-' + + set( + { 'n' }, + f('', key), + f('resize %s4', sign), + { desc = f('%s window height', dir) } + ) +end + +-- Buffers -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for key, dir in pairs({ + [''] = 'previous', + [''] = 'next', + ['[b'] = 'previous', + [']b'] = 'next', +}) do + -- previous -> Prev + local prettyDir = (dir:gsub('^%l', string.upper)):sub(1, 4) + + set( + { 'n' }, + key, + f('b%s', dir), + { desc = f('%s buffer', prettyDir) } + ) +end + +set({ 'n' }, 'bD', 'bd', { desc = 'Delete buffer and window' }) + +-- Clear search & refresh -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +set( + { 'n', 'i' }, + '', + 'noh', + { desc = 'Escape and clear hlsearch' } +) + +set( + { 'n' }, + 'ur', + 'nohlsearchdiffupdatenormal! ', + { desc = 'Redraw / clear hlsearch / diff update' } +) + +-- Better n & N -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for _, mode in ipairs({ 'n', 'x', 'o' }) do + local zv = (mode == 'n') and ".'zv'" or '' + + set( + { mode }, + 'n', + f("'Nn'[v:searchforward]%s", zv), + { desc = 'Next search result', expr = true } + ) + + set( + { mode }, + 'N', + f("'nN'[v:searchforward]%s", zv), + { desc = 'Previous search result', expr = true } + ) +end + +-- Undo break-points -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for _, char in ipairs({ ',', '.', ';' }) do + set({ 'i' }, char, f('%su', char)) +end + +-- Search docs (keywordprog) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +-- https://til.codeinthehole.com/posts/about-how-to-use-keywordprg-effectively/ +set( + { 'n' }, + 'K', + 'norm! K', + { desc = 'Search for word' } +) + +-- Better indenting -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for _, char in ipairs({ '<', '>' }) do + set({ 'v' }, char, f('%sgv', char)) +end + +-- Commenting -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for key, dir in pairs({ o = 'Below', O = 'Above' }) do + set( + { 'n' }, + f('gc%s', key), + f('%sVcxnormal gccfxa', key), + { desc = f('Add comment %s', dir) } + ) +end + +-- New files -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +set({ 'n' }, 'fn', 'enew', { desc = 'New file' }) + +-- Locations/quickfixes -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +set({ 'n' }, 'xl', 'lopen', { desc = 'Location list' }) +set({ 'n' }, 'xq', 'copen', { desc = 'Quickfix list' }) + +for key, dir in pairs({ ['['] = 'Previous', [']'] = 'Next' }) do + -- Previous -> prev + local cmd = (dir:gsub('^%l', string.lower)):sub(1, 4) + + set( + { 'n' }, + f('%sq', key), + f('c%s', cmd), + { desc = f('%s quickfix', dir) } + ) +end + +-- Diagnostics -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +set({ 'n' }, 'cd', function() + vim.diagnostic.open_float() +end, { desc = 'Line diagnostics' }) + +local function goto_diagnostic(next, severity) + local go = next and vim.diagnostic.goto_next or vim.diagnostic.goto_prev + severity = severity and vim.diagnostic.severity[severity] or nil + return function() + go({ severity = severity }) + end +end + +for key, sev in pairs({ + d = { nil, 'Diagnostic' }, + e = { 'ERROR', 'Error' }, + w = { 'WARN', 'Warning' }, +}) do + set( + { 'n' }, + f(']%s', key), + goto_diagnostic(true, sev[1]), + { desc = f('Next %s', sev[2]) } + ) + + set( + { 'n' }, + f('[%s', key), + goto_diagnostic(false, sev[1]), + { desc = f('Previous %s', sev[2]) } + ) +end + +-- Quit -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +set({ 'n' }, 'qq', 'qa', { desc = 'Quit all' }) + +-- Inspect -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +set({ 'n' }, 'ui', vim.show_pos, { desc = 'Inspect position' }) + +-- Window management -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +set({ 'n' }, 'w', '', { desc = 'Windows', remap = true }) +set({ 'n' }, '-', 's', { desc = 'Split below', remap = true }) +set({ 'n' }, '|', 'v', { desc = 'Split right', remap = true }) +set({ 'n' }, 'wd', 'c', { desc = 'Delete window', remap = true }) + +-- Tab management -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +for key, act in pairs({ + l = 'Last', + o = 'Only', + f = 'First', + [''] = 'New', + [']'] = 'Next', + d = 'Close', + ['['] = 'Previous', +}) do + local desc = (act == 'Only') and 'Close other tabs' or f('%s tab', act) + + set( + { 'n' }, + f('%s', key), + f('tab%s', act:lower()), + { desc = desc } + ) +end