diff --git a/lua/keymaps.lua b/lua/keymaps.lua index 0e73647..ed26ad1 100644 --- a/lua/keymaps.lua +++ b/lua/keymaps.lua @@ -100,7 +100,15 @@ vim.keymap.set("n", "gao", function() Snacks.picker.lsp_outgoing_calls() end, { vim.keymap.set("n", "ss", function() Snacks.picker.lsp_symbols() end, { desc = "LSP Symbols" }) vim.keymap.set("n", "sS", function() Snacks.picker.lsp_workspace_symbols() end, { desc = "LSP Workspace Symbols" }) +-- Standard LSP +vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover Documentation" }) +vim.keymap.set("n", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) +vim.keymap.set("n", "cr", function() + return ":" .. require("inc_rename").config.cmd_name .. " " .. vim.fn.expand("") +end, { expr = true, desc = "Rename Symbol" }) + -- Other +vim.keymap.set("n", "sq", "nohlsearch", { desc = "Clear Search Highlights" }) vim.keymap.set("n", "z", function() Snacks.zen() end, { desc = "Toggle Zen Mode" }) vim.keymap.set("n", "Z", function() Snacks.zen.zoom() end, { desc = "Toggle Zoom" }) vim.keymap.set("n", ".", function() Snacks.scratch() end, { desc = "Toggle Scratch Buffer" }) @@ -111,8 +119,8 @@ vim.keymap.set("n", "cR", function() Snacks.rename.rename_file() end, { vim.keymap.set({ "n", "v" }, "gB", function() Snacks.gitbrowse() end, { desc = "Git Browse" }) vim.keymap.set("n", "gg", function() Snacks.lazygit() end, { desc = "Lazygit" }) vim.keymap.set("n", "un", function() Snacks.notifier.hide() end, { desc = "Dismiss All Notifications" }) -vim.keymap.set("n", "", function() Snacks.terminal() end, { desc = "Toggle Terminal" }) -vim.keymap.set("n", "", function() Snacks.terminal() end, { desc = "which_key_ignore" }) +vim.keymap.set({ "n", "t" }, "", function() Snacks.terminal() end, { desc = "Toggle Terminal" }) +vim.keymap.set({ "n", "t" }, "", function() Snacks.terminal() end, { desc = "which_key_ignore" }) vim.keymap.set({ "n", "t" }, "]]", function() Snacks.words.jump(vim.v.count1) end, { desc = "Next Reference" }) vim.keymap.set({ "n", "t" }, "[[", function() Snacks.words.jump(-vim.v.count1) end, { desc = "Prev Reference" }) vim.keymap.set("n", "N", function() @@ -132,6 +140,24 @@ end, { desc = "Neovim News" }) ---------------------------------------------------------- +-- Leap Keymaps +vim.keymap.set({ 'n', 'x', 'o' }, '', '(leap)') +vim.keymap.set('n', 'S', '(leap-from-window)') + +---------------------------------------------------------- + +-- Conform Keymaps +vim.keymap.set({ "n", "v" }, "cf", function() + require("conform").format({ lsp_format = "fallback" }) +end, { desc = "Format Buffer" }) + +---------------------------------------------------------- + +-- Undotree Keymaps +vim.keymap.set("n", "uu", "UndotreeToggle", { desc = "Toggle Undotree" }) + +---------------------------------------------------------- + -- Persistence Keymaps vim.keymap.set("n", "qs", function() require("persistence").load() end, { desc = "Restore Session" }) vim.keymap.set("n", "qS", function() require("persistence").select() end, { desc = "Select Session" }) diff --git a/lua/options.lua b/lua/options.lua index 53c2059..ee098ee 100644 --- a/lua/options.lua +++ b/lua/options.lua @@ -7,14 +7,14 @@ -- Autowrite/Autosave -- This ensures changes are saved on every buffer change or when leaving insert mode. vim.api.nvim_create_autocmd({ "InsertLeave", "TextChanged" }, { - group = vim.api.nvim_create_augroup("autosave", { clear = true }), - pattern = { "*" }, - callback = function() - local buftype = vim.api.nvim_get_option_value("buftype", { buf = 0 }) - if buftype == "" and vim.bo.modified then - vim.cmd("silent! update") - end - end, + group = vim.api.nvim_create_augroup("autosave", { clear = true }), + pattern = { "*" }, + callback = function() + local buftype = vim.api.nvim_get_option_value("buftype", { buf = 0 }) + if buftype == "" and vim.bo.modified then + vim.cmd("silent! update") + end + end, }) -- Performance and UI defaults @@ -22,3 +22,32 @@ vim.opt.updatetime = 200 -- Faster completion and CursorHold events vim.opt.autowrite = true -- Enable auto write vim.opt.number = true -- Show line numbers vim.opt.relativenumber = true -- Relative line numbers + +-- Persistent undo across sessions +vim.opt.undofile = true + +-- Indentation +vim.opt.tabstop = 2 -- Tab width in spaces +vim.opt.shiftwidth = 2 -- Indent width for >> and auto-indent +vim.opt.expandtab = true -- Use spaces instead of tabs + +-- FormatOnSave +vim.api.nvim_create_autocmd("BufWritePre", { + pattern = "*", + callback = function(args) + require("conform").format({ bufnr = args.buf }) + end, +}) + +-- Execute Format +vim.api.nvim_create_user_command("Format", function(args) + local range = nil + if args.count ~= -1 then + local end_line = vim.api.nvim_buf_get_lines(0, args.line2 - 1, args.line2, true)[1] + range = { + start = { args.line1, 0 }, + ["end"] = { args.line2, end_line:len() }, + } + end + require("conform").format({ async = true, lsp_format = "fallback", range = range }) +end, { range = true }) diff --git a/lua/plugins.lua b/lua/plugins.lua index 5158059..96e4f0c 100644 --- a/lua/plugins.lua +++ b/lua/plugins.lua @@ -6,39 +6,93 @@ -- Catppuccin.nvim -- Eagerly load the colorscheme plugin. -vim.pack.add { { src = "https://github.com/catppuccin/nvim", name = "catppuccin" } } +vim.pack.add({ { src = "https://github.com/catppuccin/nvim", name = "catppuccin" } }) -- Catppuccin Config Config.plugins.catppuccin = { - flavour = "mocha", + flavour = "mocha", } -vim.cmd.colorscheme "catppuccin" +vim.cmd.colorscheme("catppuccin") -- Snacks.nvim -- Eagerly load snacks for dashboard and performance features. -vim.pack.add { { src = "https://github.com/folke/snacks.nvim", name = "snacks" } } +vim.pack.add({ { src = "https://github.com/folke/snacks.nvim", name = "snacks" } }) -- Snacks Config -- Store opts in the registry first. Config.plugins.snacks = { - bigfile = { enabled = true }, - dashboard = { - enabled = true, - sections = { - { section = "header" }, - { section = "keys", gap = 1, padding = 1 }, - }, - }, - explorer = { enabled = true }, - indent = { enabled = true }, - input = { enabled = true }, - picker = { enabled = true }, - notifier = { enabled = true }, - quickfile = { enabled = true }, - scope = { enabled = true }, - scroll = { enabled = true }, - statuscolumn = { enabled = true }, - words = { enabled = true }, + bigfile = { enabled = true }, + dashboard = { + enabled = true, + sections = { + { section = "header" }, + { section = "keys", gap = 1, padding = 1 }, + }, + preset = { + header = require("data").header, + }, + }, + explorer = { enabled = true }, + indent = { enabled = true }, + input = { enabled = true }, + picker = { + enabled = true, + matcher = { + fuzzy = true, + smartcase = true, + ignorecase = true, + sort_empty = false, + filename_bonus = true, + file_pos = true, + cwd_bonus = true, + frecency = true, + history_bonus = true, + }, + win = { + input = { + keys = { + [""] = { "flash", mode = { "n", "i" } }, + ["s"] = { "flash" }, + }, + }, + }, + actions = { + flash = function(picker) + require("flash").jump({ + pattern = "^", + label = { after = { 0, 0 } }, + search = { + mode = "search", + exclude = { + function(win) + return vim.bo[vim.api.nvim_win_get_buf(win)].filetype ~= "snacks_picker_list" + end, + }, + }, + action = function(match) + local idx = picker.list:row2idx(match.pos[1]) + picker.list:_move(idx, true, true) + end, + }) + end, + }, + }, + notifier = { enabled = true }, + quickfile = { enabled = true }, + scope = { enabled = true }, + scratch = { enabled = true }, + scroll = { enabled = true }, + statuscolumn = { enabled = true }, + terminal = { + enabled = true, + win = { + keys = { + toggle = { "", function(self) self:hide() end, mode = "t", desc = "Toggle Terminal" }, + }, + }, + }, + words = { enabled = true }, + zen = { enabled = true }, } -- Setup Snacks with the registered opts. @@ -46,13 +100,13 @@ require("snacks").setup(Config.plugins.snacks) -- Persistence.nvim -- Simple session management. -vim.pack.add { { src = "https://github.com/folke/persistence.nvim", name = "persistence" } } +vim.pack.add({ { src = "https://github.com/folke/persistence.nvim", name = "persistence" } }) -- Persistence Config Config.plugins.persistence = { - dir = vim.fn.stdpath("state") .. "/sessions/", - need = 1, - branch = true, + dir = vim.fn.stdpath("state") .. "/sessions/", + need = 1, + branch = true, } require("persistence").setup(Config.plugins.persistence) @@ -60,76 +114,233 @@ require("persistence").setup(Config.plugins.persistence) local lazyload = require("lazyload") lazyload.on_vim_enter(function() - -- Gitsigns.nvim - vim.pack.add { { src = "https://github.com/lewis6991/gitsigns.nvim", name = "gitsigns" } } - require("gitsigns").setup({ - numhl = true, -- Enable line number highlighting - }) + -- Gitsigns.nvim + vim.pack.add({ { src = "https://github.com/lewis6991/gitsigns.nvim", name = "gitsigns" } }) + require("gitsigns").setup({ + numhl = false, + signcolumn = true, + current_line_blame = true, -- Required for the statusline variable to update + current_line_blame_opts = { + virt_text = false, -- Disable virtual text as we'll use the statusline + }, + }) - -- Grug-far.nvim - vim.pack.add { { src = "https://github.com/MagicDuck/grug-far.nvim", name = "grug-far" } } - require("grug-far").setup() + -- Treesitter Context + vim.pack.add({ + { src = "https://github.com/nvim-treesitter/nvim-treesitter-context", name = "nvim-treesitter-context" }, + }) + require("treesitter-context").setup({ + max_lines = 3, + trim_scope = "outer", + }) - -- Flash.nvim - vim.pack.add { { src = "https://github.com/folke/flash.nvim", name = "flash" } } - require("flash").setup() + -- Grug-far.nvim + vim.pack.add({ { src = "https://github.com/MagicDuck/grug-far.nvim", name = "grug-far" } }) + require("grug-far").setup() - -- Which-key.nvim - vim.pack.add { { src = "https://github.com/folke/which-key.nvim", name = "which-key" } } - require("which-key").setup() + -- Flash.nvim + vim.pack.add({ { src = "https://github.com/folke/flash.nvim", name = "flash" } }) + require("flash").setup({ + modes = { char = { keys = {} } }, + keys = {}, + }) - -- Mini.ai - vim.pack.add { { src = "https://github.com/echasnovski/mini.ai", name = "mini.ai" } } - - Config.plugins.mini_ai = { - custom_textobjects = { - g = function() - local n_lines = vim.api.nvim_buf_line_count(0) - return { - from = { line = 1, col = 1 }, - to = { line = n_lines, col = math.max(vim.fn.getline(n_lines):len(), 1) }, - } - end, - }, - } - require("mini.ai").setup(Config.plugins.mini_ai) + -- Leap.nvim + vim.pack.add({ { src = "https://git.disroot.org/andyg/leap.nvim", name = "leap" } }) + vim.api.nvim_set_hl(0, "LeapBackdrop", { link = "Comment" }) - -- Icons - vim.pack.add { { src = "https://github.com/nvim-tree/nvim-web-devicons", name = "nvim-web-devicons" } } + -- Mini.surround + vim.pack.add({ { src = "https://github.com/echasnovski/mini.surround", name = "mini.surround" } }) + require("mini.surround").setup() - -- Lualine - vim.pack.add { { src = "https://github.com/nvim-lualine/lualine.nvim", name = "lualine" } } - require("lualine").setup({ - options = { - theme = "auto", - globalstatus = true, - }, - sections = { - lualine_b = { "branch", "diff", "diagnostics" }, - } - }) + -- Undotree + vim.g.undotree_ShortIndicators = 0 + vim.g.undotree_SplitWidth = 32 + vim.g.undotree_SetFocusWhenToggle = 1 + vim.g.undotree_TreeNodeShape = "" + vim.g.undotree_TreeVertShape = "" + vim.g.undotree_TreeSplitShape = "" + vim.g.undotree_TreeReturnShape = "" + vim.g.undotree_HelpLine = 0 + vim.g.undotree_DiffAutoOpen = 0 + vim.pack.add({ { src = "https://github.com/mbbill/undotree", name = "undotree" } }) - -- Noice dependencies - vim.pack.add { { src = "https://github.com/MunifTanjim/nui.nvim", name = "nui" } } + -- Conform.nvim + vim.pack.add({ { src = "https://github.com/stevearc/conform.nvim", name = "conform" } }) + Config.plugins.conform = { + formatters_by_ft = { + lua = { "stylua" }, + c = { "clang-format" }, + cpp = { "clang-format" }, + rust = { "rustfmt" }, + python = { "ruff_format" }, + fish = { "fish_indent" }, + sh = { "shfmt" }, + bash = { "shfmt" }, + }, + format_on_save = function(bufnr) + -- Disable with a global or buffer-local variable + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + return + end + return { timeout_ms = 500, lsp_format = "fallback" } + end, + } + require("conform").setup(Config.plugins.conform) - -- Noice.nvim - vim.pack.add { { src = "https://github.com/folke/noice.nvim", name = "noice" } } - require("noice").setup({ - 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.set_autocmds"] = true, - ["vim.ui.codelens.display_inline"] = true, - }, - }, - -- 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 - }, - }) + -- Which-key.nvim + vim.pack.add({ { src = "https://github.com/folke/which-key.nvim", name = "which-key" } }) + require("which-key").setup() + + -- Lazydev.nvim (Neovim Lua type definitions for lua_ls) + vim.pack.add({ { src = "https://github.com/folke/lazydev.nvim", name = "lazydev" } }) + require("lazydev").setup({ + library = { + { path = "snacks.nvim", words = { "Snacks" } }, + }, + }) + + -- LSP Support + vim.pack.add({ { src = "https://github.com/williamboman/mason.nvim", name = "mason" } }) + vim.pack.add({ { src = "https://github.com/williamboman/mason-lspconfig.nvim", name = "mason-lspconfig" } }) + vim.pack.add({ { src = "https://github.com/neovim/nvim-lspconfig", name = "nvim-lspconfig" } }) + + -- Completion + vim.pack.add({ { src = "https://github.com/saghen/blink.cmp", name = "blink.cmp" } }) + vim.pack.add({ { src = "https://github.com/rafamadriz/friendly-snippets", name = "friendly-snippets" } }) + vim.pack.add({ { src = "https://github.com/fang2hou/blink-copilot", name = "blink-copilot" } }) + + require("mason").setup() + + -- Blink.cmp setup + require("blink.cmp").setup({ + keymap = { preset = "default" }, + appearance = { + use_nvim_cmp_as_default = true, + nerd_font_variant = "mono", + kind_icons = { + Copilot = "", + }, + }, + sources = { + default = { "lsp", "path", "snippets", "buffer", "copilot" }, + providers = { + copilot = { + name = "copilot", + module = "blink-copilot", + kind = "lsp", + server_name = "copilot", + score_offset = 100, + async = true, + opts = { + max_completions = 3, + max_attempts = 4, + }, + }, + }, + }, + signature = { enabled = true }, + }) + + local lspconfig = require("lspconfig") + local capabilities = require("blink.cmp").get_lsp_capabilities() + + require("mason-lspconfig").setup({ + ensure_installed = { + "lua_ls", + "clangd", + "rust_analyzer", + "pyright", + "fish_lsp", + "bashls", + "copilot", + }, + handlers = { + -- Default handler + function(server_name) + lspconfig[server_name].setup({ capabilities = capabilities }) + end, + -- Specific overrides + ["lua_ls"] = function() + lspconfig.lua_ls.setup({ + capabilities = capabilities, + settings = { + Lua = { + diagnostics = { globals = { "Config" } }, + }, + }, + }) + end, + }, + }) + + -- Mini.ai + vim.pack.add({ { src = "https://github.com/echasnovski/mini.ai", name = "mini.ai" } }) + + Config.plugins.mini_ai = { + custom_textobjects = { + g = function() + local n_lines = vim.api.nvim_buf_line_count(0) + return { + from = { line = 1, col = 1 }, + to = { line = n_lines, col = math.max(vim.fn.getline(n_lines):len(), 1) }, + } + end, + }, + } + require("mini.ai").setup(Config.plugins.mini_ai) + + -- Icons + vim.pack.add({ { src = "https://github.com/nvim-tree/nvim-web-devicons", name = "nvim-web-devicons" } }) + + -- Lualine + vim.pack.add({ { src = "https://github.com/nvim-lualine/lualine.nvim", name = "lualine" } }) + require("lualine").setup({ + options = { + theme = "auto", + globalstatus = true, + }, + sections = { + lualine_b = { "branch", "diff", "diagnostics" }, + lualine_c = { + { "filename" }, + { + function() + return vim.b.gitsigns_blame_line or "" + end, + cond = function() + return vim.b.gitsigns_blame_line ~= nil and vim.b.gitsigns_blame_line ~= "" + end, + }, + }, + }, + }) + + -- Inc-rename.nvim + vim.pack.add({ { src = "https://github.com/smjonas/inc-rename.nvim", name = "inc-rename" } }) + require("inc_rename").setup() + + -- Noice dependencies + vim.pack.add({ { src = "https://github.com/MunifTanjim/nui.nvim", name = "nui" } }) + + -- Noice.nvim + vim.pack.add({ { src = "https://github.com/folke/noice.nvim", name = "noice" } }) + require("noice").setup({ + 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.set_autocmds"] = true, + ["vim.ui.codelens.display_inline"] = true, + }, + }, + -- 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 = true, -- enables an input dialog for inc-rename.nvim + lsp_doc_border = false, -- add a border to hover docs and signature help + }, + }) end) diff --git a/nvim-pack-lock.json b/nvim-pack-lock.json index 26b01a1..a87f9f4 100644 --- a/nvim-pack-lock.json +++ b/nvim-pack-lock.json @@ -1,13 +1,33 @@ { "plugins": { + "blink-copilot": { + "rev": "7ad8209b2f880a2840c94cdcd80ab4dc511d4f39", + "src": "https://github.com/fang2hou/blink-copilot" + }, + "blink.cmp": { + "rev": "c573a15a62bd0bfd4006ee0849b24f5404395500", + "src": "https://github.com/saghen/blink.cmp" + }, "catppuccin": { "rev": "426dbebe06b5c69fd846ceb17b42e12f890aedf1", "src": "https://github.com/catppuccin/nvim" }, + "conform": { + "rev": "086a40dc7ed8242c03be9f47fbcee68699cc2395", + "src": "https://github.com/stevearc/conform.nvim" + }, "flash": { "rev": "fcea7ff883235d9024dc41e638f164a450c14ca2", "src": "https://github.com/folke/flash.nvim" }, + "friendly-snippets": { + "rev": "6cd7280adead7f586db6fccbd15d2cac7e2188b9", + "src": "https://github.com/rafamadriz/friendly-snippets" + }, + "git-blame": { + "rev": "5c536e2d4134d064aa3f41575280bc8a2a0e03d7", + "src": "https://github.com/f-person/git-blame.nvim" + }, "gitsigns": { "rev": "8d82c240f190fc33723d48c308ccc1ed8baad69d", "src": "https://github.com/lewis6991/gitsigns.nvim" @@ -16,14 +36,38 @@ "rev": "21604255d0e8f9968322f61f2b6c09e5efe1285a", "src": "https://github.com/MagicDuck/grug-far.nvim" }, + "inc-rename": { + "rev": "0074b551a17338ccdcd299bd86687cc651bcb33d", + "src": "https://github.com/smjonas/inc-rename.nvim" + }, + "lazydev": { + "rev": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d", + "src": "https://github.com/folke/lazydev.nvim" + }, + "leap": { + "rev": "b960d5038c5c505c52e56a54490f9bbb1f0e6ef6", + "src": "https://git.disroot.org/andyg/leap.nvim" + }, "lualine": { "rev": "a905eeebc4e63fdc48b5135d3bf8aea5618fb21c", "src": "https://github.com/nvim-lualine/lualine.nvim" }, + "mason": { + "rev": "b03fb0f20bc1d43daf558cda981a2be22e73ac42", + "src": "https://github.com/williamboman/mason.nvim" + }, + "mason-lspconfig": { + "rev": "0a3b42c3e503df87aef6d6513e13148381495c3a", + "src": "https://github.com/williamboman/mason-lspconfig.nvim" + }, "mini.ai": { "rev": "43eb2074843950a3a25aae56a5f41362ec043bfa", "src": "https://github.com/echasnovski/mini.ai" }, + "mini.surround": { + "rev": "2715e04bea3ec9244f15b421dc5b18c0fe326210", + "src": "https://github.com/echasnovski/mini.surround" + }, "noice": { "rev": "7bfd942445fb63089b59f97ca487d605e715f155", "src": "https://github.com/folke/noice.nvim" @@ -32,6 +76,18 @@ "rev": "de740991c12411b663994b2860f1a4fd0937c130", "src": "https://github.com/MunifTanjim/nui.nvim" }, + "nvim-lspconfig": { + "rev": "4b7fbaa239c5db6b36f424a4521ca9f1a401be33", + "src": "https://github.com/neovim/nvim-lspconfig" + }, + "nvim-treesitter": { + "rev": "4916d6592ede8c07973490d9322f187e07dfefac", + "src": "https://github.com/nvim-treesitter/nvim-treesitter" + }, + "nvim-treesitter-context": { + "rev": "b0c45cefe2c8f7b55fc46f34e563bc428ef99636", + "src": "https://github.com/nvim-treesitter/nvim-treesitter-context" + }, "nvim-web-devicons": { "rev": "c72328a5494b4502947a022fe69c0c47e53b6aa6", "src": "https://github.com/nvim-tree/nvim-web-devicons" @@ -44,6 +100,10 @@ "rev": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e", "src": "https://github.com/folke/snacks.nvim" }, + "undotree": { + "rev": "6fa6b57cda8459e1e4b2ca34df702f55242f4e4d", + "src": "https://github.com/mbbill/undotree" + }, "which-key": { "rev": "3aab2147e74890957785941f0c1ad87d0a44c15a", "src": "https://github.com/folke/which-key.nvim"