diff options
Diffstat (limited to 'config/nvim/lua')
| -rw-r--r-- | config/nvim/lua/.gitignore | 1 | ||||
| -rw-r--r-- | config/nvim/lua/config/lazy.lua | 37 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/colorschemes.lua | 23 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/completion.lua | 159 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/editing.lua | 127 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/editor.lua | 29 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/fzf.lua | 148 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/git.lua | 63 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/lsp.lua | 281 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/reload.lua | 28 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/testing.lua | 41 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/ui.lua | 335 | ||||
| -rw-r--r-- | config/nvim/lua/plugins/which-key.lua | 30 |
13 files changed, 1302 insertions, 0 deletions
diff --git a/config/nvim/lua/.gitignore b/config/nvim/lua/.gitignore new file mode 100644 index 0000000..8ad8db1 --- /dev/null +++ b/config/nvim/lua/.gitignore @@ -0,0 +1 @@ +local.lua diff --git a/config/nvim/lua/config/lazy.lua b/config/nvim/lua/config/lazy.lua new file mode 100644 index 0000000..58636f9 --- /dev/null +++ b/config/nvim/lua/config/lazy.lua @@ -0,0 +1,37 @@ +-- Check if Lazy.nvim is installed, if not, install it +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" -- Lazy.nvim install path +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { out, "WarningMsg" }, + { "\nPress any key to exit..." }, + }, true, {}) + vim.fn.getchar() + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) + +-- Load Lazy.nvim and install plugins if necessary +require("lazy").setup({ + spec = { + -- import plugins from ~/.config/nvim/lua/plugins/ + -- eg ~/.config/nvim/lua/plugins/completion.lua + { import = "plugins" }, + }, + install = { + -- install missing plugins on startup. This doesn't increase startup time. + missing = true, + }, + -- automatically check for plugin updates + checker = { + enabled = true, -- automatically check for plugin updates + concurrency = nil, -- set to 1 to check for updates very slowly + notify = false, -- get a notification when new updates are found + frequency = 6 * 30 * 24 * 3600, -- check for updates every 6 months + check_pinned = false, -- check for pinned packages that can't be updated + }, +}) diff --git a/config/nvim/lua/plugins/colorschemes.lua b/config/nvim/lua/plugins/colorschemes.lua new file mode 100644 index 0000000..005403d --- /dev/null +++ b/config/nvim/lua/plugins/colorschemes.lua @@ -0,0 +1,23 @@ +local plugins = { + { "sonph/onehalf", rtp = "vim/" }, + { "altercation/vim-colors-solarized" }, + { "nlknguyen/papercolor-theme" }, + { "tanvirtin/monokai.nvim" }, + { "tomasr/molokai" }, + { "cohlin/vim-colorschemes" }, + { "reedes/vim-colors-pencil" }, + { "ayu-theme/ayu-vim" }, + { "overcache/NeoSolarized" }, + { "cormacrelf/vim-colors-github" }, + { "rafi/awesome-vim-colorschemes" }, +} + +-- These are lazy-loaded: cfg-watch (lua/plugins/reload.lua) lists them as +-- dependencies, so they are loaded right before ~/.local/share/nvim/colors.lua +-- runs `:colorscheme`. Keeping them lazy keeps them off the startup path while +-- still letting the dynamic light/dark theme switcher reach any of them. +for _, plugin in ipairs(plugins) do + plugin.lazy = true +end + +return plugins diff --git a/config/nvim/lua/plugins/completion.lua b/config/nvim/lua/plugins/completion.lua new file mode 100644 index 0000000..fa037cd --- /dev/null +++ b/config/nvim/lua/plugins/completion.lua @@ -0,0 +1,159 @@ +local plugins = { + -- Autocompletion and Snippets + { + "Saghen/blink.cmp", + version = "1.*", -- Use a stable release version + main = "blink.cmp", + opts = { + keymap = { -- https://cmp.saghen.dev/configuration/keymap.html + preset = "default", + ["<Tab>"] = { "accept", "fallback" }, + }, + sources = { + -- Enable completion from lazydev, LSP, filesystem paths, snippets, buffer + -- (and optionally supermaven) + -- default = { "lazydev", "lsp", "path", "snippets", "buffer", "supermaven" }, + default = { "lazydev", "lsp", "path", "snippets", "buffer" }, + providers = { + -- Neovim Lua API / plugin spec completions (folke/lazydev.nvim) + lazydev = { + name = "LazyDev", + module = "lazydev.integrations.blink", + score_offset = 100, -- show lazydev items above LSP + }, + buffer = { + -- Optional: Configure buffer-specific settings + -- max_async_buffer_size = 200000, -- 200KB default + -- use_cache = true, -- Cache words for better performance + }, + -- lsp = { fallbacks = {} }, -- always show the buffer source + supermaven = { + enabled = false, + name = "supermaven", + module = "blink-cmp-supermaven", + async = true, + + }, + }, + }, + completion = { + -- Enable ghost text to show completions inline + ghost_text = { + -- enabled = true, + enabled = false, + }, + -- Configure the completion menu + menu = { + auto_show = true, -- Automatically show the menu + }, + list = { + selection = { + preselect = true, + auto_insert = false, + }, + }, + -- Avoid unnecessary requests for performance + trigger = { + -- prefetch_on_insert = true, -- When true, will prefetch the completion items when entering insert mode + show_in_snippet = false, -- When false, will not show the completion window automatically when in a snippet + show_on_backspace = false, -- When true, will show completion window after backspacing + show_on_backspace_in_keyword = false, -- When true, will show completion window after backspacing into a keyword + show_on_backspace_after_accept = false, -- When true, will show the completion window after accepting a completion and then backspacing into a keyword + show_on_backspace_after_insert_enter = false, -- When true, will show the completion window after entering insert mode and backspacing into keyword + show_on_keyword = false, -- When true, will show the completion window after typing any of alphanumerics, `-` or `_` + show_on_trigger_character = false, -- When true, will show the completion window after typing a trigger character + show_on_insert = false, -- When true, will show the completion window after entering insert mode + -- LSPs can indicate when to show the completion window via trigger characters + -- however, some LSPs (i.e. tsserver) return characters that would essentially + -- always show the window. We block these by default. + -- show_on_blocked_trigger_characters = { " ", "\n", "\t" }, + -- You can also block per filetype with a function: + -- show_on_blocked_trigger_characters = function(ctx) + -- if vim.bo.filetype == 'markdown' then return { ' ', '\n', '\t', '.', '/', '(', '[' } end + -- return { ' ', '\n', '\t' } + -- end, + -- When both this and show_on_trigger_character are true, will show the completion window + -- when the cursor comes after a trigger character after accepting an item + show_on_accept_on_trigger_character = false, + -- When both this and show_on_trigger_character are true, will show the completion window + -- when the cursor comes after a trigger character when entering insert mode + show_on_insert_on_trigger_character = false, + -- List of trigger characters (on top of `show_on_blocked_trigger_characters`) that won't trigger + -- the completion window when the cursor comes after a trigger character when + -- entering insert mode/accepting an item + -- show_on_x_blocked_trigger_characters = { "'", '"', "(" }, + -- or a function, similar to show_on_blocked_trigger_character + }, + }, + signature = { + enabled = true, + window = { + show_documentation = false, + }, + }, + -- Disable blink.cmp for command-line mode to let native wildmenu work + cmdline = { + enabled = false, + }, + }, + }, + + -- Supermaven was acquired (and killed) by Cursor + { + "supermaven-inc/supermaven-nvim", + event = "InsertEnter", + opts = { + keymaps = { + accept_suggestion = "<Tab>", + clear_suggestion = "<C-]>", + accept_word = "<C-j>", + }, + ignore_filetypes = {}, + disable_inline_completion = false, + disable_keymaps = false, + condition = function() + return false + end, + log_level = "info", + }, + config = function(_, opts) + require("supermaven-nvim").setup(opts) + -- Clear supermaven ghost text when entering command-line mode + -- to prevent interference with wildmenu completion + vim.api.nvim_create_autocmd("CmdlineEnter", { + callback = function() + local ok, preview = pcall(require, "supermaven-nvim.completion_preview") + if ok and preview.on_dispose_inlay then + preview.on_dispose_inlay() + end + end, + }) + end, + }, + { + "huijiro/blink-cmp-supermaven", + }, + + -- Lua LSP completion + types for the Neovim API and lazy plugin specs. + -- Replaces the old lua_ls `globals` hack for editing this config. + { + "folke/lazydev.nvim", + ft = "lua", + opts = { + library = { + -- Load luvit types when the `vim.uv` word is found + { path = "${3rd}/luv/library", words = { "vim%.uv" } }, + -- Types for snacks.nvim (used throughout this config) + { path = "snacks.nvim", words = { "Snacks" } }, + }, + }, + }, +} + +for _, plugin in ipairs(plugins) do + if not plugin.priority then + plugin.priority = 2000 + end +end + +return plugins diff --git a/config/nvim/lua/plugins/editing.lua b/config/nvim/lua/plugins/editing.lua new file mode 100644 index 0000000..af7a867 --- /dev/null +++ b/config/nvim/lua/plugins/editing.lua @@ -0,0 +1,127 @@ +local plugins = { + { "godlygeek/tabular" }, -- text filtering and alignment + { + "Wansmer/treesj", -- splitting/joining blocks of code + dependencies = { "nvim-treesitter/nvim-treesitter" }, + config = function() + require("treesj").setup({ + -- use_default_keymaps = false, + }) + vim.keymap.set("n", "<leader>jj", require("treesj").join) + vim.keymap.set("n", "<leader>js", require("treesj").split) + vim.keymap.set("n", "<leader>jm", require("treesj").toggle) + vim.keymap.set("n", "<leader>jM", function() + require("treesj").toggle({ split = { recursive = true } }) + end) + end, + }, + { "tpope/vim-repeat" }, -- enable plugins to repeat actions + { "tpope/vim-sleuth" }, -- heuristically set buffer options + -- Add/delete/replace surrounding pairs: sa (add), sd (delete), sr (replace). + -- Replaces tpope/vim-surround; consolidates onto mini.* with built-in + -- dot-repeat. NOTE: the `s` prefix shadows native `s` (substitute) — use `cl`. + { + "nvim-mini/mini.surround", + event = "VeryLazy", + opts = {}, + }, + -- Auto close/rename HTML/JSX/TSX/Astro tags + { + "windwp/nvim-ts-autotag", + ft = { + "html", "xml", "markdown", "svelte", "vue", + "javascript", "javascriptreact", "typescript", "typescriptreact", "astro", + }, + opts = {}, + }, + -- Context-aware commentstring (e.g. {/* */} inside JSX, not //) + { + "folke/ts-comments.nvim", + event = "VeryLazy", + opts = {}, + }, + -- Extended text objects: af/if (function), ac/ic (class), + -- ao/io (block/conditional/loop), plus args/quotes/brackets. + -- Takes over the old fold if/af mappings. + { + "nvim-mini/mini.ai", + event = "VeryLazy", + dependencies = { + "nvim-treesitter/nvim-treesitter-textobjects", + }, + opts = function() + local ai = require("mini.ai") + return { + n_lines = 500, + custom_textobjects = { + f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }), + c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }), + o = ai.gen_spec.treesitter({ + a = { "@block.outer", "@conditional.outer", "@loop.outer" }, + i = { "@block.inner", "@conditional.inner", "@loop.inner" }, + }), + }, + } + end, + }, + -- Treesitter textobjects (main): move between and swap functions/classes/args, + -- and make ; , (and f F t T) repeat the last move. + { + "nvim-treesitter/nvim-treesitter-textobjects", + branch = "main", + event = "VeryLazy", + config = function() + require("nvim-treesitter-textobjects").setup({ + move = { set_jumps = true }, -- record moves in the jumplist + }) + + local move = require("nvim-treesitter-textobjects.move") + local swap = require("nvim-treesitter-textobjects.swap") + local rep = require("nvim-treesitter-textobjects.repeatable_move") + + -- Repeat the last textobject move with ; and , ... + vim.keymap.set({ "n", "x", "o" }, ";", rep.repeat_last_move) + vim.keymap.set({ "n", "x", "o" }, ",", rep.repeat_last_move_opposite) + -- ... and upgrade f/F/t/T to repeat with the same ; , + vim.keymap.set({ "n", "x", "o" }, "f", rep.builtin_f_expr, { expr = true }) + vim.keymap.set({ "n", "x", "o" }, "F", rep.builtin_F_expr, { expr = true }) + vim.keymap.set({ "n", "x", "o" }, "t", rep.builtin_t_expr, { expr = true }) + vim.keymap.set({ "n", "x", "o" }, "T", rep.builtin_T_expr, { expr = true }) + + -- Jump between functions / classes ( ]] [[ are taken by quickfix ). + -- Note: ]c / [c shadow diff-mode change navigation; swap to ]C/[C if + -- you'd rather keep that. + local jumps = { + ["]f"] = { move.goto_next_start, "@function.outer", "Next function start" }, + ["[f"] = { move.goto_previous_start, "@function.outer", "Prev function start" }, + ["]F"] = { move.goto_next_end, "@function.outer", "Next function end" }, + ["[F"] = { move.goto_previous_end, "@function.outer", "Prev function end" }, + ["]c"] = { move.goto_next_start, "@class.outer", "Next class start" }, + ["[c"] = { move.goto_previous_start, "@class.outer", "Prev class start" }, + } + for lhs, m in pairs(jumps) do + vim.keymap.set({ "n", "x", "o" }, lhs, function() + m[1](m[2], "textobjects") + end, { desc = m[3] }) + end + + -- Swap the argument under the cursor with the next / previous one + vim.keymap.set("n", "<leader>sa", function() + swap.swap_next("@parameter.inner") + end, { desc = "Swap argument with next" }) + vim.keymap.set("n", "<leader>sA", function() + swap.swap_previous("@parameter.inner") + end, { desc = "Swap argument with previous" }) + end, + }, + -- Comment.nvim and nvim-ts-context-commentstring removed + -- Neovim 0.10+ has built-in gc/gcc commenting with native treesitter commentstring support +} + +for _, plugin in ipairs(plugins) do + if not plugin.priority then + plugin.priority = 2000 + end +end + +return plugins diff --git a/config/nvim/lua/plugins/editor.lua b/config/nvim/lua/plugins/editor.lua new file mode 100644 index 0000000..4e1cb4d --- /dev/null +++ b/config/nvim/lua/plugins/editor.lua @@ -0,0 +1,29 @@ +return { + -- Highlight and navigate TODO / FIXME / HACK / BUG comments + { + "folke/todo-comments.nvim", + event = "VeryLazy", + dependencies = { "nvim-lua/plenary.nvim" }, + opts = {}, + keys = { + { "]t", function() require("todo-comments").jump_next() end, desc = "Next todo comment" }, + { "[t", function() require("todo-comments").jump_prev() end, desc = "Previous todo comment" }, + { "<leader>qt", "<cmd>TodoTrouble<cr>", desc = "Todo (Trouble)" }, + }, + }, + -- Pretty, navigable lists for diagnostics, references, symbols, quickfix. + -- Lives under <leader>q ("lists") to avoid the <leader>x buffer-close prefix. + { + "folke/trouble.nvim", + cmd = "Trouble", + dependencies = { "nvim-tree/nvim-web-devicons" }, + opts = {}, + keys = { + { "<leader>qd", "<cmd>Trouble diagnostics toggle<cr>", desc = "Diagnostics (Trouble)" }, + { "<leader>qb", "<cmd>Trouble diagnostics toggle filter.buf=0<cr>", desc = "Buffer diagnostics (Trouble)" }, + { "<leader>qs", "<cmd>Trouble symbols toggle<cr>", desc = "Symbols (Trouble)" }, + { "<leader>ql", "<cmd>Trouble lsp toggle<cr>", desc = "LSP defs/refs (Trouble)" }, + { "<leader>qq", "<cmd>Trouble qflist toggle<cr>", desc = "Quickfix list (Trouble)" }, + }, + }, +} diff --git a/config/nvim/lua/plugins/fzf.lua b/config/nvim/lua/plugins/fzf.lua new file mode 100644 index 0000000..8ef0104 --- /dev/null +++ b/config/nvim/lua/plugins/fzf.lua @@ -0,0 +1,148 @@ +return { + { + "ibhagwan/fzf-lua", + dependencies = { "nvim-tree/nvim-web-devicons" }, + config = function() + local fzf = require("fzf-lua") + fzf.setup({ + defaults = { + file_icons = true, + }, + grep = { + rg_opts = table.concat({ + "--color=never", + "--no-heading", + "--with-filename", + "--line-number", + "--column", + "--smart-case", + "--glob=!.git/**", + "--glob=!package-lock.json", + "--glob=!lazy-lock.json", + "--glob=!node_modules/**", + }, " "), + }, + keymap = { + builtin = { + ["<C-h>"] = "toggle-help", + }, + fzf = { + ["ctrl-q"] = "select-all+accept", + }, + }, + }) + + -- General pickers + vim.keymap.set("n", "<Leader>f", fzf.resume, { desc = "Resume search" }) + vim.keymap.set("n", "<C-p>", fzf.files, { desc = "Find file" }) + vim.keymap.set("n", "<Leader>a", fzf.live_grep, { desc = "Find text" }) + vim.keymap.set("n", "\\b", fzf.buffers, { desc = "Find buffer" }) + vim.keymap.set("n", "\\h", fzf.help_tags, { desc = "Find help" }) + vim.keymap.set("n", "\\k", fzf.keymaps, { desc = "Find keymaps" }) + vim.keymap.set("n", "<Leader><Leader>t", fzf.colorschemes, { desc = "Select colorscheme" }) + + -- Git + vim.keymap.set("n", "\\g", fzf.git_status, { desc = "Find changed file" }) + + -- LSP pickers + vim.keymap.set("n", "\\r", function() + fzf.lsp_references({ includeDeclaration = false }) + end, { desc = "Find references" }) + vim.keymap.set("n", "\\c", fzf.lsp_incoming_calls, { desc = "Find incoming calls" }) + vim.keymap.set("n", "\\o", fzf.lsp_outgoing_calls, { desc = "Find outgoing calls" }) + vim.keymap.set("n", "\\d", fzf.lsp_definitions, { desc = "Find definitions" }) + vim.keymap.set("n", "\\t", fzf.lsp_typedefs, { desc = "Find type definitions" }) + vim.keymap.set("n", "\\i", fzf.lsp_implementations, { desc = "Find implementations" }) + vim.keymap.set("n", "\\s", fzf.lsp_document_symbols, { desc = "Find document symbols" }) + vim.keymap.set("n", "\\S", fzf.lsp_live_workspace_symbols, { desc = "Find workspace symbols" }) + + -- Search nvim config + vim.keymap.set("n", "\\C", function() + fzf.live_grep({ + cwd = vim.fn.expand("~/.config/nvim"), + rg_opts = "--follow " .. table.concat({ + "--color=never", + "--no-heading", + "--with-filename", + "--line-number", + "--column", + "--smart-case", + }, " "), + }) + end, { desc = "Search config" }) + + -- Custom directory picker + local function reset_lsp_workspace_folders() + local clients = vim.lsp.get_clients() + if #clients == 0 then + vim.notify("No active LSP clients found", vim.log.levels.WARN) + return + end + for _, client in ipairs(clients) do + local current_folders = client.workspace_folders or {} + for _, folder in ipairs(current_folders) do + vim.lsp.buf.remove_workspace_folder(folder.name) + end + vim.lsp.buf.add_workspace_folder(vim.fn.getcwd()) + vim.notify( + string.format("Reset workspace folders for %s to: %s", client.name, vim.fn.getcwd()), + vim.log.levels.INFO + ) + end + end + + local function build_find_dir_cmd() + local home = vim.fn.expand("~") + local homeSrc = vim.fn.expand("~/src") + local sense = "/Volumes/Sense" + local cmd = "find" + local search_paths = {} + local excluded_dirs = { + "*/cloud-copy*", + "*/node_modules*", + "*/.venv*", + "*/venv*", + } + if vim.fn.isdirectory(sense) == 1 then + table.insert(search_paths, sense) + table.insert(excluded_dirs, homeSrc) + else + table.insert(search_paths, homeSrc) + end + table.insert(search_paths, vim.fn.expand("~/.local/share/nvim")) + + local args = { cmd } + for _, path in ipairs(search_paths) do + table.insert(args, path) + end + table.insert(args, "-type") + table.insert(args, "d") + table.insert(args, "-maxdepth") + table.insert(args, "4") + for _, dir in ipairs(excluded_dirs) do + table.insert(args, "-not") + table.insert(args, "-path") + table.insert(args, dir) + end + return table.concat(args, " ") + end + + vim.keymap.set("n", "<Leader>p", function() + fzf.fzf_exec(build_find_dir_cmd(), { + prompt = "Change Directory> ", + actions = { + ["default"] = function(selected) + local dir = selected[1] + vim.cmd("cd " .. vim.fn.fnameescape(dir)) + vim.opt.titlestring = vim.fn.fnamemodify(dir, ":t") + vim.opt.title = true + reset_lsp_workspace_folders() + vim.cmd("LspRestart") + print("Changed directory to: " .. dir) + end, + }, + }) + end, { desc = "Change working directory" }) + end, + }, +} diff --git a/config/nvim/lua/plugins/git.lua b/config/nvim/lua/plugins/git.lua new file mode 100644 index 0000000..ad120f4 --- /dev/null +++ b/config/nvim/lua/plugins/git.lua @@ -0,0 +1,63 @@ +return { + { + "lewis6991/gitsigns.nvim", + config = function() + -- Git hunk navigation + local gs = require("gitsigns") + gs.setup({ + signs_staged_enable = true, + signcolumn = true, -- Toggle with `:Gitsigns toggle_signs` + numhl = true, -- Toggle with `:Gitsigns toggle_numhl` + linehl = false, -- Toggle with `:Gitsigns toggle_linehl` + word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff` + current_line_blame_opts = { + virt_text_pos = 'right_align', -- 'eol' | 'overlay' | 'right_align' + }, + -- current_line_blame = true, + -- current_line_blame_formatter = '<author>, <author_time:%R> - <summary>', + }) + vim.keymap.set("n", "[g", gs.prev_hunk, { desc = "Goto previous git hunk" }) + vim.keymap.set("n", "]g", gs.next_hunk, { desc = "Goto next git hunk" }) + + -- vim.keymap.set("n", "<Leader>cg", gitsigns.preview_hunk, { desc = "Preview git hunk" }) + vim.keymap.set("n", "<Leader>gd", function() gs.preview_hunk_inline() end, { desc = "Preview hunk inline" }) + vim.keymap.set("n", "<Leader>gD", function() gs.preview_hunk() end, { desc = "Preview hunk popup" }) + vim.keymap.set("n", "<Leader>gf", function() gs.diffthis() end, { desc = "Diff file" }) + vim.keymap.set("n", "<Leader>gr", function() gs.reset_hunk() end, { desc = "Revert hunk" }) + vim.keymap.set("n", "<Leader>gs", function() gs.stage_hunk() end, { desc = "Stage hunk" }) + vim.keymap.set("n", "<Leader>ga", function() gs.stage_buffer() end, { desc = "Stage buffer" }) + vim.keymap.set("n", "<Leader>gB", function() gs.toggle_current_line_blame() end, { desc = "Toggle current line blame (virtual text)" }) + vim.keymap.set("n", "<Leader>gb", function() gs.blame() end, { desc = "Open blame" }) + + -- Select hunks as a text object. + vim.keymap.set({'o', 'x'}, 'ih', '<Cmd>Gitsigns select_hunk<CR>') + + -- Open current file/line (or visual selection) on the git remote + vim.keymap.set({ "n", "x" }, "<Leader>go", function() Snacks.gitbrowse() end, { desc = "Open in remote (browser)" }) + end, + }, + -- Lazy-loaded: kept only for its `:Git <arbitrary>` escape hatch and :Gblame, + -- since neogit + diffview + gitsigns cover day-to-day staging/diff/blame. + { + "tpope/vim-fugitive", + cmd = { "Git", "G", "Gdiffsplit", "Gread", "Gwrite", "Gedit", "Gblame", "Gclog" }, + }, + { + "NeogitOrg/neogit", + lazy = true, + dependencies = { + "nvim-lua/plenary.nvim", -- required + "sindrets/diffview.nvim", -- optional - Diff integration + + -- Only one of these is needed. + "ibhagwan/fzf-lua", -- optional + -- "nvim-telescope/telescope.nvim", -- optional + -- "nvim-mini/mini.pick", -- optional + -- "folke/snacks.nvim", -- optional + }, + cmd = "Neogit", + keys = { + { "<leader>gg", "<cmd>Neogit<cr>", desc = "Show Neogit UI" } + } + }, +} diff --git a/config/nvim/lua/plugins/lsp.lua b/config/nvim/lua/plugins/lsp.lua new file mode 100644 index 0000000..c3853b3 --- /dev/null +++ b/config/nvim/lua/plugins/lsp.lua @@ -0,0 +1,281 @@ +-- LSP attach handler using LspAttach autocmd (NeoVim 0.11+ recommended pattern) +vim.api.nvim_create_autocmd('LspAttach', { + callback = function(args) + local client = vim.lsp.get_client_by_id(args.data.client_id) + local bufnr = args.buf + + -- Enable completion triggered by <c-x><c-o> + vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc" + + vim.keymap.set("n", "K", function() vim.lsp.buf.hover() end, { buffer = bufnr, desc = "Hover info" }) + vim.keymap.set("n", "<c-k>", function() vim.lsp.buf.signature_help() end, { buffer = bufnr, desc = "Signature help" }) + vim.keymap.set("n", "<Leader>L", function() vim.lsp.buf.format({ async = true }) end, { buffer = bufnr, desc = "LSP format" }) + + -- TypeScript/JavaScript specific: organize imports + if client and client.name == "ts_ls" then + vim.keymap.set("n", "gro", function() + client:exec_cmd({ + command = "_typescript.organizeImports", + arguments = { vim.api.nvim_buf_get_name(0) }, + title = "", + }) + end, { buffer = bufnr, desc = "Organize imports" }) + end + end, +}) + +local function configure_lsp() -- Setup LSP configurations using vim.lsp.config (NeoVim 0.11+) + -- Completion capabilities from blink.cmp (extends Neovim's defaults with the + -- snippet/resolve/tag support that the hand-rolled table used to set). + local capabilities = require("blink.cmp").get_lsp_capabilities() + + -- Global config for all LSP servers + vim.lsp.config('*', { + capabilities = capabilities, + }) + + -- Configure lua-language-server + vim.lsp.config('lua_ls', { + settings = { + Lua = { + diagnostics = { + -- `vim`/`require` are covered by lazydev.nvim + LuaLS defaults. + -- `hs` is the Hammerspoon global, which lazydev doesn't know about. + globals = { + "hs", + }, + disable = { + "unused-local", + }, + }, + }, + }, + }) + + -- Configure bash-language-server + vim.lsp.config('bashls', { + settings = { + bashIde = { + enableExplainshellEndpoint = false, + explainshellEndpoint = "", + globPattern = "*@(.sh|.bash|.zsh|bash*|zsh*)", + shfmt = { + path = "shfmt", + args = { "-i", "2", "-ci", "-sr" }, + }, + }, + }, + }) + + -- Configure typescript-language-server + vim.lsp.config('ts_ls', {}) + + -- Configure astro-language-server + vim.lsp.config('astro', {}) + + -- Configure gopls (Go language server) + vim.lsp.config('gopls', { + settings = { + gopls = { + analyses = { + unusedparams = true, + }, + staticcheck = true, + gofumpt = true, + }, + }, + }) + + -- Configure pyright (Python language server) + vim.lsp.config('pyright', { + settings = { + python = { + analysis = { + autoSearchPaths = true, + useLibraryCodeForTypes = true, + diagnosticMode = "workspace", + }, + }, + }, + }) + + -- Configure jdtls (Java language server) + vim.lsp.config('jdtls', {}) + + -- Enable all configured servers + -- Note: This doesn't force installation, it just enables them if installed + vim.lsp.enable({ 'lua_ls', 'bashls', 'ts_ls', 'astro', 'gopls', 'pyright', 'jdtls' }) + + -- ESLint LSP is temporarily disabled (causes errors with call hierarchy) + -- To re-enable, remove the line below and add 'eslint' to vim.lsp.enable() + vim.lsp.enable('eslint', false) +end + +return { + { + "nvim-treesitter/nvim-treesitter", + branch = "main", -- Use main branch for Neovim 0.12+ compatibility + build = ":TSUpdate", + config = function() + -- Add nvim-treesitter's runtime directory to runtimepath for queries (folds, indents, etc.) + local ts_runtime = vim.fn.stdpath("data") .. "/lazy/nvim-treesitter/runtime" + if vim.fn.isdirectory(ts_runtime) == 1 then + vim.opt.runtimepath:prepend(ts_runtime) + end + + -- The `main` branch has no `ensure_installed` option, so we install any + -- missing parsers ourselves. Add/remove languages here as needed. + local TS = require("nvim-treesitter") + local ensure_installed = { + "astro", "go", "html", "javascript", "lua", "python", "tsx", "typescript", + } + local installed = TS.get_installed("parsers") + local to_install = vim.tbl_filter(function(lang) + return not vim.tbl_contains(installed, lang) + end, ensure_installed) + if #to_install > 0 then + TS.install(to_install, { summary = true }) + end + + -- On the `main` branch, treesitter highlighting must be started per + -- buffer (it is NOT automatic). Start it whenever a parser is available. + vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("sz_treesitter_start", { clear = true }), + callback = function(args) + pcall(vim.treesitter.start, args.buf) + end, + }) + + -- Show all available code actions (including organize imports) + vim.keymap.set( + "n", + "<leader>ca", + vim.lsp.buf.code_action, + { noremap = true, silent = true, desc = "Show code actions" } + ) + vim.keymap.set("v", "<C-k>", vim.lsp.buf.code_action, + { noremap = true, silent = true, desc = "Show code actions" }) + end, + }, + { + "williamboman/mason.nvim", + main = "mason", + opts = { + registries = { + "github:mason-org/mason-registry", + "github:Crashdummyy/mason-registry", -- Roslyn LSP + }, + }, + }, + { + "williamboman/mason-lspconfig.nvim", + main = "mason-lspconfig", + opts = { + -- Only ensure core language servers are installed on ALL machines + -- Other servers will be auto-installed when you open a file of that type + ensure_installed = { "lua_ls", "bashls" }, + }, + }, + { + "WhoIsSethDaniel/mason-tool-installer.nvim", + dependencies = { "williamboman/mason.nvim" }, + config = function() + require("mason-tool-installer").setup({ + -- Core tools - always installed + ensure_installed = { + "stylua", -- Lua formatting + "shfmt", -- Bash formatting + "prettier", -- JS/TS/Astro formatting + }, + -- Optional tools - install with: :MasonToolsInstall + -- Or add them here when working on those projects + -- "black", -- Python formatting + -- "isort", -- Python imports sorting + -- "gofumpt", -- Go formatting (stricter than gofmt) + -- "goimports", -- Go imports formatting + -- "csharpier", -- C# formatting + -- "netcoredbg", -- C#/.NET debugging + -- "google-java-format", -- Java formatting + }) + end, + }, + { + "neovim/nvim-lspconfig", + config = configure_lsp, + }, + { + "seblj/roslyn.nvim", + ft = "cs", + dependencies = { + "nvim-lua/plenary.nvim", + }, + opts = { + filewatching = "roslyn", + -- Disable Razor extension (only needed for Blazor) + razor = { + enabled = false, + }, + config = { + settings = { + ["csharp|inlay_hints"] = { + csharp_enable_inlay_hints_for_implicit_object_creation = true, + csharp_enable_inlay_hints_for_implicit_variable_types = true, + csharp_enable_inlay_hints_for_lambda_parameter_types = true, + csharp_enable_inlay_hints_for_types = true, + dotnet_enable_inlay_hints_for_indexer_parameters = true, + dotnet_enable_inlay_hints_for_literal_parameters = true, + dotnet_enable_inlay_hints_for_object_creation_parameters = true, + dotnet_enable_inlay_hints_for_other_parameters = true, + dotnet_enable_inlay_hints_for_parameters = true, + dotnet_suppress_inlay_hints_for_parameters_that_differ_only_by_suffix = true, + dotnet_suppress_inlay_hints_for_parameters_that_match_argument_name = true, + dotnet_suppress_inlay_hints_for_parameters_that_match_method_intent = true, + }, + ["csharp|completion"] = { + dotnet_show_completion_items_from_unimported_namespaces = true, + dotnet_show_name_completion_suggestions = true, + }, + ["csharp|code_lens"] = { + dotnet_enable_references_code_lens = true, + dotnet_enable_tests_code_lens = true, + }, + }, + }, + }, + }, + { + "stevearc/conform.nvim", + event = { "BufReadPre", "BufNewFile" }, + config = function() + local conform = require("conform") + conform.setup({ + formatters_by_ft = { + astro = { "prettier" }, + bash = { "shfmt" }, + cs = { "csharpier" }, + css = { "prettier" }, + go = { "goimports", "gofumpt" }, -- Run goimports then gofumpt + html = { "prettier" }, + java = { "google-java-format" }, + javascript = { "prettier" }, + javascriptreact = { "prettier" }, + json = { "prettier" }, + lua = { "stylua" }, + markdown = { "prettier" }, + python = { "isort", "black" }, -- Run isort then black + typescript = { "prettier" }, + typescriptreact = { "prettier" }, + }, + -- Set to `true` to format on save, or provide a function for conditional formatting + -- format_on_save = { + -- timeout_ms = 500, + -- lsp_fallback = true, -- Use LSP formatting as a fallback if no external formatter is found + -- }, + }) + + vim.keymap.set({ "n", "v" }, "<leader>l", function() + conform.format({ async = true, lsp_format = "fallback" }) + end, { desc = "Format file or range" }) + end, + }, +} diff --git a/config/nvim/lua/plugins/reload.lua b/config/nvim/lua/plugins/reload.lua new file mode 100644 index 0000000..6bd1366 --- /dev/null +++ b/config/nvim/lua/plugins/reload.lua @@ -0,0 +1,28 @@ +return { + { + dir = vim.fn.stdpath("config") .. "/local-plugins/cfg-watch", + name = "cfg-watch", + event = "VeryLazy", -- fires after init.lua finishes and UI is ready + -- Colorscheme plugins (defined in lua/plugins/colorschemes.lua as lazy=true) + -- are listed here so they load before load_colors() runs `:colorscheme`. + dependencies = { + { "rktjmp/fwatch.nvim" }, + "sonph/onehalf", + "altercation/vim-colors-solarized", + "nlknguyen/papercolor-theme", + "tanvirtin/monokai.nvim", + "tomasr/molokai", + "cohlin/vim-colorschemes", + "reedes/vim-colors-pencil", + "ayu-theme/ayu-vim", + "overcache/NeoSolarized", + "cormacrelf/vim-colors-github", + "rafi/awesome-vim-colorschemes", + }, + config = function() + local lc = require("cfg_watch") + lc.load_colors() + lc.load_config("local") + end, + }, +} diff --git a/config/nvim/lua/plugins/testing.lua b/config/nvim/lua/plugins/testing.lua new file mode 100644 index 0000000..c402bb1 --- /dev/null +++ b/config/nvim/lua/plugins/testing.lua @@ -0,0 +1,41 @@ +return { + { + "nvim-neotest/neotest", + dependencies = { + "nvim-neotest/nvim-nio", + "nvim-lua/plenary.nvim", + "nvim-treesitter/nvim-treesitter", + "nvim-neotest/neotest-jest", + -- "marilari88/neotest-vitest", + }, + cmd = { "Neotest" }, + keys = { + { "<Leader>ta", function() require("neotest").run.run(vim.fn.getcwd()) end, desc = "Run all tests" }, + { "<Leader>tf", function() require("neotest").run.run(vim.fn.expand("%")) end, desc = "Run tests in file" }, + { "<Leader>tn", function() require("neotest").run.run() end, desc = "Run nearest test" }, + { "<Leader>to", function() require("neotest").output.open({ enter = true }) end, desc = "Show test output" }, + { "<Leader>tS", function() require("neotest").summary.toggle() end, desc = "Toggle test summary" }, + }, + config = function() + require("neotest").setup({ + adapters = { + require("neotest-jest")({ + jestCommand = "npm test --", + jestArguments = function(defaultArguments, context) + return defaultArguments + end, + -- jestConfigFile = "custom.jest.config.ts", + -- env = { CI = true }, + cwd = function(path) + return vim.fn.getcwd() + end, + filter_dir = function(name, rel_path, root) + return name ~= "node_modules" and name ~= "dist" and name ~= "build" + end, + }), + -- require("neotest-vitest"), + }, + }) + end, + }, +} diff --git a/config/nvim/lua/plugins/ui.lua b/config/nvim/lua/plugins/ui.lua new file mode 100644 index 0000000..d035789 --- /dev/null +++ b/config/nvim/lua/plugins/ui.lua @@ -0,0 +1,335 @@ +return { + { + "folke/snacks.nvim", + priority = 1000, + lazy = false, + ---@type snacks.Config + opts = { + indent = { + enabled = true, + animate = { + enabled = false, + }, + }, + -- Disable expensive features on very large / minified files + bigfile = { enabled = true }, + -- Render a file before plugins fully load, for faster opening + quickfile = { enabled = true }, + -- LSP reference highlighting under the cursor (CursorHold-based); + -- replaces the hand-rolled CursorMoved autocmd in init.lua + words = { enabled = true }, + -- Treesitter scope detection: ii/ai indent text-objects + [i/]i jumps + scope = { enabled = true }, + -- Unified gutter (signs+number+fold+git). The statuscolumn option + -- itself is set in init.lua. + statuscolumn = { enabled = true }, + }, + keys = { + { "<Leader>it", function() + if Snacks.indent.enabled then + Snacks.indent.disable() + else + Snacks.indent.enable() + end + end, desc = "Toggle indent guides" }, + }, + }, + { + "nvim-lualine/lualine.nvim", + config = function() + local enable_web_dev_icons = vim.g.enable_web_dev_icons ~= 0 + local lualine_custom_theme = require("lualine.themes.auto") + lualine_custom_theme.normal.c.bg = "none" + require("lualine").setup({ + options = { + icons_enabled = enable_web_dev_icons, + theme = lualine_custom_theme, + component_separators = "|", + section_separators = { left = "", right = "" }, + disabled_filetypes = {}, + always_divide_middle = true, + globalstatus = true, + }, + sections = { + lualine_a = { "mode" }, + lualine_b = { "branch", "diff", "diagnostics" }, + lualine_c = { "filename" }, + lualine_x = { "encoding", "fileformat", "filetype" }, + lualine_y = { + function() + return vim.fn.fnamemodify(vim.fn.getcwd(), ":t") + end, + }, + lualine_z = { "progress", "location" }, + }, + inactive_sections = { + lualine_a = {}, + lualine_b = {}, + lualine_c = { "filename" }, + lualine_x = { "location" }, + lualine_y = {}, + lualine_z = {}, + }, + tabline = {}, + extensions = {}, + }) + end, + }, + { "nvim-tree/nvim-web-devicons" }, + { "nvim-mini/mini.icons", version = false }, + { + "j-hui/fidget.nvim", + main = "fidget", + opts = {}, + }, + { + "romgrk/barbar.nvim", + version = "^1.0.0", + dependencies = { + "nvim-tree/nvim-web-devicons", -- for file icons + "lewis6991/gitsigns.nvim", -- optional for git status + }, + init = function() + vim.g.barbar_auto_setup = false + end, + config = function() + require("barbar").setup({ + -- Enable/disable animations + animation = true, + -- Enable/disable auto-hiding the tab bar when there is a single buffer + auto_hide = true, + -- Enable/disable current/total tabpages indicator (top right corner) + tabpages = true, + -- Enables/disable clickable tabs + clickable = true, + -- Configure icons on the bufferline + icons = { + -- Configure the base icons on the bufferline + buffer_index = false, + buffer_number = false, + button = "", -- Empty string disables close button + -- Enables / disables diagnostic symbols + diagnostics = { + [vim.diagnostic.severity.ERROR] = { enabled = true }, + [vim.diagnostic.severity.WARN] = { enabled = true }, + [vim.diagnostic.severity.INFO] = { enabled = false }, + [vim.diagnostic.severity.HINT] = { enabled = false }, + }, + gitsigns = { + added = { enabled = true, icon = "+" }, + changed = { enabled = true, icon = "~" }, + deleted = { enabled = true, icon = "-" }, + }, + filetype = { + -- Sets the icon's highlight group. + -- If false, will use nvim-web-devicons colors + custom_colors = false, + -- Requires `nvim-web-devicons` if `true` + enabled = false, + }, + separator = { left = "▎", right = "" }, + -- Configure the icons on the bufferline when modified + modified = { button = "" }, + -- Configure the icons on the bufferline based on the visibility of a buffer + pinned = { button = "📌" }, + -- Configure the icons on the bufferline for various kinds of tabs + preset = "default", + -- Configure the icons on the bufferline for alternate layout + alternate = { filetype = { enabled = false } }, + -- Configure the icons on the bufferline when the buffer is currently active + current = { buffer_index = false }, + -- Configure the icons on the bufferline for inactive tabs + -- inactive = { button = "×" }, + inactive = {}, + -- Configure the icons on the bufferline for visible tabs + visible = { modified = { buffer_number = false } }, + }, + -- If true, new buffers will be inserted at the start/end of the list. + -- Default is to insert after current buffer. + insert_at_end = false, + insert_at_start = false, + -- Sets the maximum padding width with which to surround each tab + maximum_padding = 1, + -- Sets the minimum padding width with which to surround each tab + minimum_padding = 1, + -- Sets the maximum buffer name length + maximum_length = 30, + -- Sets the minimum buffer name length + minimum_length = 0, + -- If set, the letters for each buffer in buffer-pick mode will be + -- assigned based on their name. Otherwise or in case all letters are + -- already assigned, the behavior is to assign letters in order of + -- usability (see order below) + semantic_letters = true, + -- Sets the name of unnamed buffers. By default format is "[Buffer X]" + -- where X is the buffer number. But only a static string is accepted here. + no_name_title = nil, + -- Set the filetypes which barbar will offset itself for + sidebar_filetypes = { + NvimTree = { text = "Files", align = "left" }, + }, + }) + + -- Buffer navigation with <Leader> + number + for i = 1, 8 do + vim.keymap.set("n", "<Leader>" .. i, ":BufferGoto " .. i .. "<CR>") + end + vim.keymap.set("n", "<Leader>9", ":BufferLast<CR>", { desc = "Go to last buffer" }) + vim.keymap.set("n", "<Leader>]", ":BufferNext<CR>") + vim.keymap.set("n", "<Leader>[", ":BufferPrevious<CR>") + -- vim.keymap.set("n", "<A-<>", ":BufferMovePrevious<CR>") + -- vim.keymap.set("n", "<A->>", ":BufferMoveNext<CR>") + -- vim.keymap.set("n", "<A-p>", ":BufferPin<CR>") + vim.keymap.set("n", "<Leader>x", ":BufferClose<CR>", { desc = "Close buffer" }) + vim.keymap.set("n", "<Leader>X", ":BufferCloseAllButCurrent<CR>", { desc = "Close other buffers" }) + end, + }, + { "fweep/vim-zsh-path-completion" }, + { + "nvim-tree/nvim-tree.lua", + cmd = { "NvimTreeToggle", "NvimTreeFindFile" }, + keys = { + { "<Leader>/", ":NvimTreeToggle .<CR>", desc = "Toggle file tree" }, + { "<Leader>?", ":NvimTreeFindFile<CR>", desc = "Find current file in tree" }, + }, + config = function() + vim.g.enable_web_dev_icons = true + local enable_web_dev_icons = vim.g.enable_web_dev_icons ~= 0 + require("nvim-tree").setup({ + actions = { + open_file = { + window_picker = { + enable = false, + }, + }, + }, + renderer = { + highlight_git = true, + root_folder_label = false, -- Set to false to hide the root folder name, or a function to customize display + icons = { + show = { + file = enable_web_dev_icons, + folder = enable_web_dev_icons, + folder_arrow = enable_web_dev_icons, + git = false, + }, + }, + -- special_files = {}, + }, + view = { + -- signcolumn = 'no', + }, + }) + end, + }, + { + "folke/noice.nvim", + event = "VeryLazy", + dependencies = { + -- if you lazy-load any plugin below, make sure to add proper `module="..."` entries + "MunifTanjim/nui.nvim", + -- OPTIONAL: + -- `nvim-notify` is only needed, if you want to use the notification view. + -- If not available, we use `mini` as the fallback + "rcarriga/nvim-notify", + }, + config = function() + require("notify").setup({ + background_colour = "#000000", + }) + + local noice = require("noice") + noice.setup({ + messages = { + view = "mini", + view_error = "mini", -- view for errors + view_warn = "mini", -- view for warnings + view_search = false, + }, + lsp = { + -- override markdown rendering so that **cmp** and other plugins use **Treesitter** + override = { + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + ["cmp.entry.get_documentation"] = true, -- requires hrsh7th/nvim-cmp + }, + }, + -- you can enable a preset for easier configuration + presets = { + -- bottom_search = true, -- use a classic bottom cmdline for search + command_palette = true, -- position the cmdline and popupmenu together + long_message_to_split = true, -- long messages will be sent to a split + inc_rename = false, -- enables an input dialog for inc-rename.nvim + lsp_doc_border = false, -- add a border to hover docs and signature help + }, + routes = { + -- <C-g> buffer path → mini view, kept visible for 10s. + -- Must come first so it wins (and stops) before the generic + -- notify route below; route opts.timeout sets autohide. + { + view = "cmdline_popup", + filter = { + event = "notify", + cond = function(m) + return m.opts ~= nil and m.opts.buffer_path == true + end, + }, + opts = { timeout = 10000 }, + }, + + { view = "mini", filter = { event = "notify", find = "^Register" } }, + + -- 1) all normal Vim messages → mini + -- { filter = { event = "msg_show" }, view = "mini" }, + -- 2) mode/recording messages → mini + -- { filter = { event = "msg_showmode" }, view = "mini" }, + -- 3) anything sent via vim.notify() → mini + { filter = { event = "notify" }, view = "mini" }, + -- 4) LSP progress to mini (leave hover/signature in their own views) + -- { filter = { event = "lsp", kind = "progress" }, view = "mini" }, + }, + }) + + vim.api.nvim_create_autocmd("RecordingEnter", { + group = vim.api.nvim_create_augroup("NoiceMacroNotification", { clear = true }), + callback = function() + _MACRO_RECORDING_STATUS = true + noice.notify(string.format("Register: %s", vim.fn.reg_recording()), vim.log.levels.INFO, { + title = "Recording macro", + view = "mini", + keep = function() + return _MACRO_RECORDING_STATUS + end, + }) + end, + }) + vim.api.nvim_create_autocmd("RecordingLeave", { + group = vim.api.nvim_create_augroup("NoiceMacroNotificationDismiss", { clear = true }), + callback = function() + _MACRO_RECORDING_STATUS = false + noice.notify(string.format("Register: %s", vim.fn.reg_recording()), vim.log.levels.INFO, { + title = "Saved macro", + view = "mini", + timeout = 2000, + }) + end, + }) + + -- setup :Noice dismiss + vim.keymap.set("n", "<Leader>nd", ":Noice dismiss<CR>", { desc = "Dismiss notifications" }) + + -- <C-g>: show full buffer path. Emit a notify (instead of the native + -- msg_show) so noice's msg_show dedup can't drop repeated presses, and + -- tag it so the route below sends it to the mini view with a long timeout. + vim.keymap.set("n", "<C-g>", function() + local path = vim.fn.expand("%:p") + if path == "" then + path = "[No Name]" + end + vim.notify(path, vim.log.levels.INFO, { buffer_path = true }) + end, { desc = "Show full buffer path" }) + end, + }, + -- Inlay hints are toggled natively via <Leader>dh (see init.lua); the + -- MysticalDevil/inlay-hints.nvim plugin is no longer needed on 0.10+. +} diff --git a/config/nvim/lua/plugins/which-key.lua b/config/nvim/lua/plugins/which-key.lua new file mode 100644 index 0000000..8462cbf --- /dev/null +++ b/config/nvim/lua/plugins/which-key.lua @@ -0,0 +1,30 @@ +return { + { + "folke/which-key.nvim", + event = "VeryLazy", + keys = { + { + "<leader>@", + function() + local which_key = require("which-key") + which_key.show({ global = false }) + end, + desc = "Buffer Local Keymaps (which-key)", + }, + }, + config = function() + local wk = require("which-key") + wk.add({ + { "<leader>c", group = "Code actions" }, + { "<leader>g", group = "Git actions" }, + { "<leader>d", group = "Diagnostics" }, + { "<leader>t", group = "Tests" }, + { "<leader>;", group = "Terminal" }, + { "<leader>n", group = "Run" }, + { "<leader>j", group = "Split/Join" }, + { "<leader>q", group = "Lists (Trouble)" }, + { "<leader>s", group = "Swap args" }, + }) + end, + }, +} |
