diff --git a/.editorconfig b/.editorconfig index 69fc22b..79e89d1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,9 @@ trim_trailing_whitespace = true [*.md] max_line_length = 100 +[*.lua] +max_line_length = 120 + [*.php] indent_size = 4 diff --git a/config/nvim/init.lua b/config/nvim/init.lua index 3dff0bf..9103f03 100644 --- a/config/nvim/init.lua +++ b/config/nvim/init.lua @@ -18,7 +18,7 @@ if not vim.loop.fs_stat(lazypath) then if vim.v.shell_error ~= 0 then vim.api.nvim_echo({ { 'Failed to clone lazy.nvim:\n', 'ErrorMsg' }, - { out, 'WarningMsg' }, + { out, 'WarningMsg' }, { '\nPress any key to exit...' }, }, true, {}) vim.fn.getchar() @@ -38,7 +38,7 @@ require 'autogroups' -- ── Load plugins ──────────────────────────────────────────────────── require('lazy').setup( - -- Automatically load plugins from lua/plugins +-- Automatically load plugins from lua/plugins 'plugins', -- Lazy Configuration { diff --git a/config/nvim/lua/autogroups.lua b/config/nvim/lua/autogroups.lua index 97697b7..267edee 100644 --- a/config/nvim/lua/autogroups.lua +++ b/config/nvim/lua/autogroups.lua @@ -83,6 +83,8 @@ autocmd({ 'FileType' }, { }) -- Set filetype for SSH config directory +-- Pattern handles directories with files like: +-- .dotfiles/ssh/config.d/*, .ssh/config.local, .ssh/config.work autocmd({ 'BufRead', 'BufNewFile' }, { desc = 'Set filetype for SSH config directory', pattern = { '*/?.ssh/{config|shared}.d/*', '*/?.ssh/config.local', '*/?.ssh/config.work' }, diff --git a/config/nvim/lua/keymaps.lua b/config/nvim/lua/keymaps.lua index 1238c7a..db0315e 100644 --- a/config/nvim/lua/keymaps.lua +++ b/config/nvim/lua/keymaps.lua @@ -1,142 +1,91 @@ --- ╭─────────────────────────────────────────────────────────╮ --- │ Function shortcuts for keymap set │ --- ╰─────────────────────────────────────────────────────────╯ --- vim: set ft=lua ts=2 sw=2 tw=0 et cc=80 : +-- vim: set ft=lua ts=2 sw=2 tw=0 et cc=120 : --- Keymap set shortcut ---@type vim.keymap.set -local s = vim.keymap.set - --- Handle description ----@param desc string|table? Optional description. Can be a string or a table. ----@return table -- The description as a table. -local function handleDesc(desc) - if type(desc) == "string" then - -- Convert string to table with `desc` as a key - -- If the string is empty, just return as an empty description - return { desc = desc } - elseif type(desc) == "table" then - -- If desc doesn't have 'desc' key, combine it with - -- others with empty description - if not desc.desc then - desc.desc = '' - return desc - end - -- Use the table as is - return desc - else - -- Default to an empty table if `desc` is nil or an unsupported type - return { desc = '' } - end -end - --- Normal mode keymaps ----@param key string rhs, required ----@param cmd string|function lhs, required ----@param opts table? Options, optional -local n = function(key, cmd, opts) s('n', key, cmd, opts) end - --- Leader keymap shortcut function --- It prepends '' to the key ----@param key string rhs, required, but will be prepended with '' ----@param cmd string|function lhs, required ----@param opts table|string? Options (or just description), optional -local nl = function(key, cmd, opts) - opts = handleDesc(opts) - n('' .. key, cmd, opts) -end - --- Local leader keymap shortcut function --- It prepends '' to the key and uses desc from opts ----@param key string rhs, required, but will be prepended with '' ----@param cmd string|function lhs, required ----@param opts table|string description, required -local nld = function(key, cmd, opts) - opts = handleDesc(opts) - nl(key, cmd, opts) -end - --- Keymap shortcut function with mode defined, good for sorting by rhs ----@param key string rhs, required ----@param mode string|string[] one of n, v, x, or table of modes { 'n', 'v' } ----@param cmd string|function lhs, required ----@param opts string|table description, required -local d = function(key, mode, cmd, opts) - opts = handleDesc(opts) - s(mode, key, cmd, opts) -end - --- Leader based keymap shortcut function with mode defined ----@param key string rhs, required, but will be prepended with '' ----@param mode string|string[] one of n, v, x, or table of modes { 'n', 'v' } ----@param cmd string|function lhs, required ----@param opts string|table description (or opts), required -local ld = function(key, mode, cmd, opts) - opts = handleDesc(opts) - s(mode, '' .. key, cmd, opts) -end +require('utils') -- ╭─────────────────────────────────────────────────────────╮ -- │ Keymaps │ -- ╰─────────────────────────────────────────────────────────╯ --- Disable arrow keys in normal mode -n('', ':echo "Use h to move!!"') -n('', ':echo "Use l to move!!"') -n('', ':echo "Use k to move!!"') -n('', ':echo "Use j to move!!"') +-- ── Disable arrow keys in normal mode ─────────────────────────────── +K.n('', ':echo "Use h to move!!"') +K.n('', ':echo "Use l to move!!"') +K.n('', ':echo "Use k to move!!"') +K.n('', ':echo "Use j to move!!"') -n('', ':w!', { desc = 'Save', noremap = true }) -n('', ':nohlsearch', { desc = 'Clear Search Highlighting' }) +-- ── Splits ────────────────────────────────────────────────────────── +K.n(',', ':vertical resize -10', { desc = 'V Resize -' }) +K.n('.', ':vertical resize +10', { desc = 'V Resize +' }) +K.n('-', ':resize -10', { desc = 'H Resize -' }) +K.n('+', ':resize +10', { desc = 'H Resize +' }) +K.n('=', '=', { desc = 'Equal Size Splits' }) --- Buffer operations +-- ── Deal with word wrap ───────────────────────────────────────────── +K.n('k', "v:count == 0 ? 'gk' : 'k'", { desc = 'Move up', noremap = true, expr = true }) +K.n('j', "v:count == 0 ? 'gj' : 'j'", { desc = 'Move down', noremap = true, expr = true }) + +-- ── Text manipulation ─────────────────────────────────────────────── +K.d('<', { 'n', 'v' }, '', { 'n', 'v' }, '>gv', 'Indent Right') +K.d('', { 'n', 'v' }, ":m '<-2gv=gv", 'Move Block Up') +K.d('', { 'n', 'v' }, ":m '>+1gv=gv", 'Move Block Down') + +-- ── Other operations ──────────────────────────────────────────────── +K.nl('o', function() require('snacks').gitbrowse() end, 'Open repo in browser') +K.n('', ':w!', { desc = 'Save', noremap = true }) +K.n('', ':nohlsearch', { desc = 'Clear Search Highlighting' }) + +-- ── Buffer operations ─────────────────────────────────────────────── -- Mappings for buffer management operations like switching, deleting, etc. -- Convention: All mappings start with 'b' followed by the operation -nld('ba', ':%bd|e#|bd#', 'Close all except current') -nld('bd', ':lua MiniBufremove.delete()', 'Delete') -nld('bh', ':bprev', 'Prev') -nld('bj', ':bfirst', 'First') -nld('bk', ':blast', 'Last') -nld('bl', ':bnext', 'Next') -nld('bw', ':lua MiniBufremove.wipeout()', 'Wipeout') +K.nl('ba', ':%bd|e#|bd#', 'Close all except current') +K.nl('bd', ':lua MiniBufremove.delete()', 'Delete') +K.nl('bh', ':bprev', 'Prev') +K.nl('bj', ':bfirst', 'First') +K.nl('bk', ':blast', 'Last') +K.nl('bl', ':bnext', 'Next') +K.nl('bw', ':lua MiniBufremove.wipeout()', 'Wipeout') --- Code -nld('cg', ':lua require("neogen").generate()', 'Generate annotations') +-- ── Code & LSP operations ─────────────────────────────────────────── +-- Mappings for code and LSP operations like code actions, formatting, etc. +-- Convention: All mappings start with 'c' followed by the operation +-- unless it's a generic operation like signature help or hover +K.n('', ':lua vim.lsp.buf.signature_help()', { desc = 'Signature' }) +K.n('K', ':Lspsaga hover_doc', { desc = 'Hover Documentation' }) +K.ld('ca', 'n', ':Lspsaga code_action', 'Code Action') +K.ld('cci', 'n', ':Lspsaga incoming_calls', 'Incoming Calls') +K.ld('cco', 'n', ':Lspsaga outgoing_calls', 'Outgoing Calls') +K.ld('cd', 'n', ':Lspsaga show_line_diagnostics', 'Line Diagnostics') +K.ld('cf', { 'n', 'x' }, ':lua vim.lsp.buf.format()', 'Format') +K.ld('cg', 'n', ':lua require("neogen").generate()', 'Generate annotations') +K.ld('ci', 'n', ':Lspsaga implement', 'Implementations') +K.ld('cl', 'n', ':Lspsaga show_cursor_diagnostics', 'Cursor Diagnostics') +K.ld('cp', 'n', ':Lspsaga peek_definition', 'Peek Definition') +K.ld('cr', 'n', ':Lspsaga rename', 'Rename') +K.ld('cR', 'n', ':Lspsaga rename ++project', 'Rename Project wide') +K.ld('cs', 'n', ':Telescope lsp_document_symbols', 'LSP Document Symbols') +K.ld('ct', 'n', ':Lspsaga peek_type_definition', 'Peek Type Definition') +K.ld('cT', 'n', ':Telescope lsp_type_definitions', 'LSP Type Definitions') +K.ld('cu', 'n', ':Lspsaga preview_definition', 'Preview Definition') +K.ld('cv', 'n', ':Lspsaga diagnostic_jump_prev', 'Diagnostic Jump Prev') +K.ld('cw', 'n', ':Lspsaga diagnostic_jump_next', 'Diagnostic Jump Next') --- LSP -n('', ':lua vim.lsp.buf.signature_help()', { desc = 'Signature' }) -n('K', ':Lspsaga hover_doc', { desc = 'Hover Documentation' }) -ld('ca', 'n', ':Lspsaga code_action', 'Code Action') -ld('cci', 'n', ':Lspsaga incoming_calls', 'Incoming Calls') -ld('cco', 'n', ':Lspsaga outgoing_calls', 'Outgoing Calls') -ld('cd', 'n', ':Lspsaga show_line_diagnostics', 'Line Diagnostics') -ld('cf', { 'n', 'x' }, ':lua vim.lsp.buf.format()', 'Format') -ld('ci', 'n', ':Lspsaga implement', 'Implementations') -ld('cl', 'n', ':Lspsaga show_cursor_diagnostics', 'Cursor Diagnostics') -ld('cp', 'n', ':Lspsaga peek_definition', 'Peek Definition') -ld('cr', 'n', ':Lspsaga rename', 'Rename') -ld('cR', 'n', ':Lspsaga rename ++project', 'Rename Project wide') -ld('cs', 'n', ':Telescope lsp_document_symbols', 'LSP Document Symbols') -ld('ct', 'n', ':Lspsaga peek_type_definition', 'Peek Type Definition') -ld('cT', 'n', ':Telescope lsp_type_definitions', 'LSP Type Definitions') -ld('cu', 'n', ':Lspsaga preview_definition', 'Preview Definition') -ld('cv', 'n', ':Lspsaga diagnostic_jump_prev', 'Diagnostic Jump Prev') -ld('cw', 'n', ':Lspsaga diagnostic_jump_next', 'Diagnostic Jump Next') - --- CommentBox operations +-- ── CommentBox operations ─────────────────────────────────────────── -- Mappings for creating and managing comment boxes -- Convention: All mappings start with 'cb' followed by the box type -nld('cbb', 'CBccbox', 'CB: Box Title') -nld('cbd', 'CBd', 'CB: Remove a box') -nld('cbl', 'CBline', 'CB: Simple Line') -nld('cbm', 'CBllbox14', 'CB: Marked') -nld('cbt', 'CBllline', 'CB: Titled Line') +K.nl('cbb', 'CBccbox', 'CB: Box Title') +K.nl('cbd', 'CBd', 'CB: Remove a box') +K.nl('cbl', 'CBline', 'CB: Simple Line') +K.nl('cbm', 'CBllbox14', 'CB: Marked') +K.nl('cbt', 'CBllline', 'CB: Titled Line') --- Telescope -nld('f', ':Telescope find_files', 'Find Files') -nld(',', ':Telescope buffers', 'Find existing buffers') -nld('/', function() +-- ── Telescope operations ──────────────────────────────────────────── +-- Mappings for Telescope operations like finding files, buffers, etc. +-- Convention: All mappings start with 's' followed by the operation +-- unless it's a generic operation like searching or finding buffers +K.nl('f', ':Telescope find_files', 'Find Files') +K.nl(',', ':Telescope buffers', 'Find existing buffers') +K.nl('/', function() require('telescope.builtin').current_buffer_fuzzy_find( require('telescope.themes').get_dropdown { winblend = 20, @@ -145,75 +94,48 @@ nld('/', function() ) end, 'Fuzzily search in current buffer') -nld('sc', ':Telescope commands', 'Commands') -nld('sd', ':Telescope diagnostics', 'Search Diagnostics') -nld('sg', ':Telescope live_grep', 'Search by Grep') -nld('sh', ':Telescope highlights', 'List Highlights') -nld('sk', ':Telescope keymaps', 'Search Keymaps') -nld('sl', ':Telescope luasnip', 'Search LuaSnip') -nld('so', ':Telescope oldfiles', 'Old Files') -nld('sp', - ':lua require("telescope").extensions.lazy_plugins.lazy_plugins()', - 'Lazy Plugins') -nld('sq', ':Telescope quickfix', 'Quickfix') -nld('ss', ':Telescope treesitter', 'Treesitter') -nld('st', ':TodoTelescope', 'Search Todos') -nld('sw', ':Telescope grep_string', 'Grep String') -nld('sx', ':Telescope import', 'Telescope: Import') +K.nl('sc', ':Telescope commands', 'Commands') +K.nl('sd', ':Telescope diagnostics', 'Search Diagnostics') +K.nl('sg', ':Telescope live_grep', 'Search by Grep') +K.nl('sh', ':Telescope help_tags', 'Help tags') +K.nl('sk', ':Telescope keymaps', 'Search Keymaps') +K.nl('sl', ':Telescope luasnip', 'Search LuaSnip') +K.nl('so', ':Telescope oldfiles', 'Old Files') +K.nl('sp', ':lua require("telescope").extensions.lazy_plugins.lazy_plugins()', 'Lazy Plugins') +K.nl('sq', ':Telescope quickfix', 'Quickfix') +K.nl('ss', ':Telescope treesitter', 'Treesitter') +K.nl('st', ':TodoTelescope', 'Search Todos') +K.nl('sw', ':Telescope grep_string', 'Grep String') +K.nl('sx', ':Telescope import', 'Telescope: Import') --- Trouble -nld('xd', - ':Trouble document_diagnostics', 'Trouble: Document Diagnostics') -nld('xl', ':Trouble loclist', 'Trouble: Location List') -nld('xq', ':Trouble quickfix', 'Trouble: Quickfix') -nld('xw', - ':Trouble workspace_diagnostics', 'Trouble: Workspace Diagnostics') -nld('xx', ':Trouble diagnostics', 'Trouble: Diagnostic') +-- ── Trouble operations ────────────────────────────────────────────── +-- Convention is 'x' followed by the operation +K.nl('xd', ':Trouble document_diagnostics', 'Document Diagnostics') +K.nl('xl', ':Trouble loclist', 'Location List') +K.nl('xq', ':Trouble quickfix', 'Quickfix') +K.nl('xw', ':Trouble workspace_diagnostics', 'Workspace Diagnostics') +K.nl('xx', ':Trouble diagnostics', 'Diagnostic') --- Text manipulation -d('<', { 'n', 'v' }, '', { 'n', 'v' }, '>gv', 'Indent Right') -d('', { 'n', 'v' }, ":m '<-2gv=gv", 'Move Block Up') -d('', { 'n', 'v' }, ":m '>+1gv=gv", 'Move Block Down') +-- ── Toggle settings ───────────────────────────────────────────────── +-- Convention is 't' followed by the operation +K.nl('tc', ':CloakToggle', 'Cloak: Toggle') +K.nl('te', ':Neotree toggle', 'Toggle Neotree') +K.nl('tl', ToggleBackground, 'Toggle Light/Dark Mode') +K.nl('tn', ':Noice dismiss', 'Noice: Dismiss Notification') --- Other functionality -nld('o', function() require('snacks').gitbrowse() end, 'Open repo in browser') - --- Toggle settings -local function toggle_background() - vim.o.bg = vim.o.bg == "light" and "dark" or "light" -end - -nld('tc', ':CloakToggle', 'Cloak: Toggle') -nld('te', ':Neotree toggle', 'Toggle Neotree') -nld('tl', toggle_background, 'Toggle Light/Dark Mode') -nld('tn', ':Noice dismiss', 'Noice: Dismiss Notification') - --- Splits -n(',', ':vertical resize -10', { desc = 'V Resize -' }) -n('.', ':vertical resize +10', { desc = 'V Resize +' }) -n('-', ':resize -5', { desc = 'H Resize -' }) -n('+', ':resize +5', { desc = 'H Resize +' }) -n('=', '=', { desc = 'Equal Size Splits' }) - --- Deal with word wrap -n('k', - "v:count == 0 ? 'gk' : 'k'", - { desc = 'Move up', noremap = true, expr = true }) -n('j', - "v:count == 0 ? 'gj' : 'j'", - { desc = 'Move down', noremap = true, expr = true }) - --- Quit -nld('qf', ':q', 'Quicker close split') -nld('qq', function() +-- ── Quit operations ───────────────────────────────────────────────── +-- Convention is 'q' followed by the operation +K.nl('qf', ':q', 'Quicker close split') +K.nl('qq', function() if vim.fn.confirm("Force save and quit?", "&Yes\n&No", 2) == 1 then vim.cmd('wq!') end end, 'Quit with force saving') -nld('qw', ':wq', 'Write and quit') -nld('qQ', function() +K.nl('qw', ':wq', 'Write and quit') +K.nl('qQ', function() if vim.fn.confirm("Force quit without saving?", "&Yes\n&No", 2) == 1 then vim.cmd('q!') end end, 'Force quit without saving') + +-- That concludes the keymaps section of the config. diff --git a/config/nvim/lua/options.lua b/config/nvim/lua/options.lua index c856301..e80304c 100644 --- a/config/nvim/lua/options.lua +++ b/config/nvim/lua/options.lua @@ -33,7 +33,7 @@ o.numberwidth = 3 -- Set the width of the number column o.relativenumber = true -- Show relative line numbers o.scrolloff = 15 -- Show context around cursor o.showmode = false -- Don't show mode -o.signcolumn = 'yes:2' -- Keep signcolumn on by default +o.signcolumn = 'yes:3' -- Keep signcolumn on by default o.smartindent = true -- Insert indents automatically o.spell = true -- Enable spell checking o.spelllang = 'en_us' -- Set the spell checking language @@ -46,7 +46,7 @@ o.updatetime = 250 -- 250 ms = 2,5 seconds o.ignorecase = true -- Ignore case in search patterns o.smartcase = true -- Override 'ignorecase' if pattern contains upper case chars - +-- List options o.list = true -- Show some invisible characters o.listchars = { tab = '» ', trail = '·', nbsp = '␣' } -- Which invisible chars to show diff --git a/config/nvim/lua/plugins/blink.lua b/config/nvim/lua/plugins/blink.lua index d5296dd..82d41a1 100644 --- a/config/nvim/lua/plugins/blink.lua +++ b/config/nvim/lua/plugins/blink.lua @@ -18,9 +18,11 @@ return { impersonate_nvim_cmp = true, }, }, + -- Set of preconfigured snippets for different languages. -- https://github.com/rafamadriz/friendly-snippets { 'rafamadriz/friendly-snippets' }, + -- Lua plugin to turn github copilot into a cmp source -- https://github.com/giuxtaposition/blink-cmp-copilot { @@ -73,7 +75,10 @@ return { completion = { menu = { draw = { - columns = { { "label", "label_description", gap = 1 }, { "kind_icon", "kind", gap = 1 } }, + columns = { + { "label", "label_description", gap = 1 }, + { "kind_icon", "kind", gap = 1 } + }, }, }, documentation = { diff --git a/config/nvim/lua/plugins/folke.lua b/config/nvim/lua/plugins/folke.lua index 5274fdf..a119097 100644 --- a/config/nvim/lua/plugins/folke.lua +++ b/config/nvim/lua/plugins/folke.lua @@ -9,8 +9,11 @@ return { opts = { bigfile = { enabled = true }, gitbrowse = { enabled = true }, + notifier = { + enabled = true, + timeout = 3000, + }, notify = { enabled = true }, - notifier = { enabled = true }, quickfile = { enabled = true }, statuscolumn = { enabled = true, diff --git a/config/nvim/lua/plugins/mini.lua b/config/nvim/lua/plugins/mini.lua index b4425ac..560cfdf 100644 --- a/config/nvim/lua/plugins/mini.lua +++ b/config/nvim/lua/plugins/mini.lua @@ -4,6 +4,9 @@ return { -- Presets for common options and mappings { 'echasnovski/mini.basics', version = '*' }, + -- Extend and create a/i textobjects + { 'echasnovski/mini.ai', version = '*' }, + -- Animate common Neovim actions -- Replaced anuvyklack/windows.nvim { 'echasnovski/mini.animate', version = '*', opts = {} }, @@ -69,6 +72,7 @@ return { { mode = 'n', keys = 'b', desc = '+Buffers' }, { mode = 'n', keys = 'c', desc = '+Code' }, { mode = 'n', keys = 'cb', desc = '+CommentBox' }, + { mode = 'n', keys = 'cc', desc = '+Calls' }, { mode = 'n', keys = 'q', desc = '+Quit' }, { mode = 'n', keys = 's', desc = '+Telescope' }, { mode = 'n', keys = 't', desc = '+Toggle' }, @@ -104,7 +108,7 @@ return { version = '*', opts = { highlighters = { - -- Highlight standalone 'FIXME', 'HACK', 'TODO', 'NOTE' + -- Highlight standalone 'FIXME', 'HACK', 'TODO', 'NOTE', 'BUG', 'PERF' words fixme = { pattern = '%f[%w]()FIXME:?%s*()%f[%W]', group = 'MiniHipatternsFixme', @@ -182,15 +186,40 @@ return { { 'echasnovski/mini.operators', version = '*', opts = {} }, -- Session management (read, write, delete) - { 'echasnovski/mini.sessions', version = '*', opts = {} }, + { + 'echasnovski/mini.sessions', + version = '*', + opts = { + autoread = true, + autowrite = true, + } + }, -- Split and join arguments, lists, and other sequences -- Replaced Wansmer/treesj - { 'echasnovski/mini.splitjoin', version = '*', opts = {} }, + { 'echasnovski/mini.splitjoin', version = '*', opts = {} }, -- Fast and flexible start screen -- Replaced glepnir/dashboard-nvim - { 'echasnovski/mini.starter', version = '*', opts = {} }, + { + 'echasnovski/mini.starter', + version = '*', + config = function() + local starter = require('mini.starter') + starter.setup({ + items = { + starter.sections.telescope(), + starter.sections.builtin_actions(), + starter.sections.sessions(5, true), + }, + content_hooks = { + starter.gen_hook.adding_bullet(), + starter.gen_hook.indexing('all', { 'Builtin actions' }), + starter.gen_hook.aligning('center', 'center'), + }, + }) + end + }, -- Minimal and fast statusline module with opinionated default look -- Replaced nvim-lualine/lualine.nvim diff --git a/config/nvim/lua/plugins/telescope.lua b/config/nvim/lua/plugins/telescope.lua index 73cdcb0..bf6550a 100644 --- a/config/nvim/lua/plugins/telescope.lua +++ b/config/nvim/lua/plugins/telescope.lua @@ -8,6 +8,9 @@ return { { 'nvim-lua/plenary.nvim' }, { 'nvim-telescope/telescope-symbols.nvim' }, + -- Telescope plugin for file browsing + { 'nvim-telescope/telescope-file-browser.nvim' }, + -- A Telescope picker to quickly access configurations -- of plugins managed by lazy.nvim. -- https://github.com/polirritmico/telescope-lazy-plugins.nvim diff --git a/config/nvim/lua/utils.lua b/config/nvim/lua/utils.lua new file mode 100644 index 0000000..6915248 --- /dev/null +++ b/config/nvim/lua/utils.lua @@ -0,0 +1,84 @@ +-- These are my utility functions +-- I use to make my life bit easier + +-- ╭─────────────────────────────────────────────────────────╮ +-- │ Function shortcuts for keymap set │ +-- ╰─────────────────────────────────────────────────────────╯ + +-- Keymap set shortcut +--@type vim.keymap.set +local s = vim.keymap.set + +-- Keymap shortcut functions +K = {} + +-- Handle description +---@param desc string|table? Optional description. Can be a string or a table. +---@return table -- The description as a table. +local function handleDesc(desc) + if type(desc) == "string" then + -- Convert string to table with `desc` as a key + -- If the string is empty, just return as an empty description + return { desc = desc } + elseif type(desc) == "table" then + -- If desc doesn't have 'desc' key, combine it with + -- others with empty description + if not desc.desc then + desc.desc = '?' + return desc + end + -- Use the table as is + return desc + else + -- Default to an empty table if `desc` is nil or an unsupported type + return { desc = '?' } + end +end + +-- Normal mode keymaps +---@param key string rhs, required +---@param cmd string|function lhs, required +---@param opts table? Options, optional +K.n = function(key, cmd, opts) + opts = handleDesc(opts or {}) + s('n', key, cmd, opts) +end + +-- Leader keymap shortcut function +-- It prepends '' to the key +---@param key string rhs, required, but will be prepended with '' +---@param cmd string|function lhs, required +---@param opts table|string? Options (or just description), optional +K.nl = function(key, cmd, opts) + opts = handleDesc(opts) + K.n('' .. key, cmd, opts) +end + +-- Keymap shortcut function with mode defined, good for sorting by rhs +---@param key string rhs, required +---@param mode string|string[] one of n, v, x, or table of modes { 'n', 'v' } +---@param cmd string|function lhs, required +---@param opts string|table description, required +K.d = function(key, mode, cmd, opts) + opts = handleDesc(opts or {}) + s(mode, key, cmd, opts) +end + +-- Leader based keymap shortcut function with mode defined +---@param key string rhs, required, but will be prepended with '' +---@param mode string|string[] one of n, v, x, or table of modes { 'n', 'v' } +---@param cmd string|function lhs, required +---@param opts string|table description (or opts), required +K.ld = function(key, mode, cmd, opts) + opts = handleDesc(opts or {}) + s(mode, '' .. key, cmd, opts) +end + +-- ╭─────────────────────────────────────────────────────────╮ +-- │ Options related helper functions │ +-- ╰─────────────────────────────────────────────────────────╯ + +-- Toggle background between light and dark +function ToggleBackground() + vim.o.bg = vim.o.bg == "light" and "dark" or "light" +end