-- NOTE: You will likely want to break this up into more files. -- You can call this more than once. -- You can also include other files from within the specs via an `import` spec. -- see https://github.com/BirdeeHub/lze?tab=readme-ov-file#structuring-your-plugins nixInfo.lze.load { { -- lze specs need a name "trigger_colorscheme", -- lazy loaded colorscheme. -- This means you will need to add the colorscheme you want to lze sometime before VimEnter is done event = "VimEnter", -- Also, lze can load more than just plugins. -- The default load field contains vim.cmd.packadd -- Here we override it to schedule when our colorscheme is loaded load = function(_name) -- schedule so it runs after VimEnter vim.schedule(function() vim.cmd.colorscheme(nixInfo("onedark_dark", "settings", "colorscheme")) vim.schedule(function() -- I like this color. Use vim.schedule again to set it after the colorscheme is finished vim.cmd([[hi LineNr guifg=#bb9af7]]) end) end) end }, { -- NOTE: view these names in the info plugin! -- :lua nixInfo.lze.debug.display(nixInfo.plugins) -- The display function is from lzextras "onedarkpro.nvim", auto_enable = true, -- <- auto enable is useful here colorscheme = { "onedark", "onedark_dark", "onedark_vivid", "onelight" }, }, { "vim-moonfly-colors", auto_enable = true, colorscheme = "moonfly", }, { "snacks.nvim", auto_enable = true, -- snacks makes a global, and then lazily loads itself lazy = false, -- priority only affects startup plugins -- unless otherwise specified by a particular handler priority = 1000, after = function(plugin) -- I also like this color vim.api.nvim_set_hl(0, "MySnacksIndent", { fg = "#32a88f" }) require('snacks').setup({ explorer = { replace_netrw = true, }, picker = { sources = { explorer = { auto_close = true, }, }, }, git = {}, terminal = {}, scope = {}, indent = { scope = { hl = 'MySnacksIndent', }, chunk = { -- enabled = true, hl = 'MySnacksIndent', } }, statuscolumn = { left = { "mark", "git" }, -- priority of signs on the left (high to low) right = { "sign", "fold" }, -- priority of signs on the right (high to low) folds = { open = false, -- show open fold icons git_hl = false, -- use Git Signs hl for fold icons }, git = { -- patterns to match Git signs patterns = { "GitSign", "MiniDiffSign" }, }, refresh = 50, -- refresh at most every 50ms }, -- make sure lazygit always reopens the correct program -- hopefully this can be removed one day lazygit = { config = { os = { editPreset = "nvim-remote", edit = vim.v.progpath .. [=[ --server "$NVIM" --remote-send 'lua nixInfo.lazygit_fix({{filename}})']=], editAtLine = vim.v.progpath .. [=[ --server "$NVIM" --remote-send 'lua nixInfo.lazygit_fix({{filename}}, {{line}})']=], openDirInEditor = vim.v.progpath .. [=[ --server "$NVIM" --remote-send 'lua nixInfo.lazygit_fix({{dir}})']=], -- this one isnt a remote command, make sure it gets our config regardless of if we name it nvim or not editAtLineAndWait = nixInfo(vim.v.progpath, "progpath") .. " +{{line}} {{filename}}", }, }, }, }) -- Handle the backend of those remote commands. -- hopefully this can be removed one day nixInfo.lazygit_fix = function(path, line) local prev = vim.fn.bufnr("#") local prev_win = vim.fn.bufwinid(prev) vim.api.nvim_feedkeys("q", "n", false) if line then vim.api.nvim_buf_call(prev, function() vim.cmd.edit(path) local buf = vim.api.nvim_get_current_buf() vim.schedule(function() if buf then vim.api.nvim_win_set_buf(prev_win, buf) vim.api.nvim_win_set_cursor(0, { line or 0, 0}) end end) end) else vim.api.nvim_buf_call(prev, function() vim.cmd.edit(path) local buf = vim.api.nvim_get_current_buf() vim.schedule(function() if buf then vim.api.nvim_win_set_buf(prev_win, buf) end end) end) end end -- NOTE: we aren't loading this lazily, and the keybinds already are so it is fine to just set these here vim.keymap.set("n", "-", function() Snacks.explorer.open() end, { desc = 'Snacks file explorer' }) vim.keymap.set("n", "", function() Snacks.terminal.open() end, { desc = 'Snacks Terminal' }) vim.keymap.set("n", "_", function() Snacks.lazygit.open() end, { desc = 'Snacks LazyGit' }) vim.keymap.set('n', "sf", function() Snacks.picker.smart() end, { desc = "Smart Find Files" }) vim.keymap.set('n', "s", function() Snacks.picker.buffers() end, { desc = "Search Buffers" }) -- find vim.keymap.set('n', "ff", function() Snacks.picker.files() end, { desc = "Find Files" }) vim.keymap.set('n', "fg", function() Snacks.picker.git_files() end, { desc = "Find Git Files" }) -- Grep vim.keymap.set('n', "sb", function() Snacks.picker.lines() end, { desc = "Buffer Lines" }) vim.keymap.set('n', "sB", function() Snacks.picker.grep_buffers() end, { desc = "Grep Open Buffers" }) vim.keymap.set('n', "sg", function() Snacks.picker.grep() end, { desc = "Grep" }) vim.keymap.set({ "n", "x" }, "sw", function() Snacks.picker.grep_word() end, { desc = "Visual selection or ord" }) -- search vim.keymap.set('n', "sb", function() Snacks.picker.lines() end, { desc = "Buffer Lines" }) vim.keymap.set('n', "sd", function() Snacks.picker.diagnostics() end, { desc = "Diagnostics" }) vim.keymap.set('n', "sD", function() Snacks.picker.diagnostics_buffer() end, { desc = "Buffer Diagnostics" }) vim.keymap.set('n', "sh", function() Snacks.picker.help() end, { desc = "Help Pages" }) vim.keymap.set('n', "sj", function() Snacks.picker.jumps() end, { desc = "Jumps" }) vim.keymap.set('n', "sk", function() Snacks.picker.keymaps() end, { desc = "Keymaps" }) vim.keymap.set('n', "sl", function() Snacks.picker.loclist() end, { desc = "Location List" }) vim.keymap.set('n', "sm", function() Snacks.picker.marks() end, { desc = "Marks" }) vim.keymap.set('n', "sM", function() Snacks.picker.man() end, { desc = "Man Pages" }) vim.keymap.set('n', "sq", function() Snacks.picker.qflist() end, { desc = "Quickfix List" }) vim.keymap.set('n', "sR", function() Snacks.picker.resume() end, { desc = "Resume" }) vim.keymap.set('n', "su", function() Snacks.picker.undo() end, { desc = "Undo History" }) end }, { "nvim-lspconfig", auto_enable = true, -- NOTE: define a function for lsp, -- and it will run for all specs with type(plugin.lsp) == table -- when their filetype trigger loads them lsp = function(plugin) vim.lsp.config(plugin.name, plugin.lsp or {}) vim.lsp.enable(plugin.name) end, -- set up our on_attach function once before the spec loads before = function(_) vim.lsp.config('*', { on_attach = function(_, bufnr) -- we create a function that lets us more easily define mappings specific -- for LSP related items. It sets the mode, buffer and description for us each time. local nmap = function(keys, func, desc) if desc then desc = 'LSP: ' .. desc end vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) end nmap('rn', vim.lsp.buf.rename, '[R]e[n]ame') nmap('ca', vim.lsp.buf.code_action, '[C]ode [A]ction') nmap('gd', vim.lsp.buf.definition, '[G]oto [D]efinition') nmap('D', vim.lsp.buf.type_definition, 'Type [D]efinition') nmap('gr', function() Snacks.picker.lsp_references() end, '[G]oto [R]eferences') nmap('gI', function() Snacks.picker.lsp_implementations() end, '[G]oto [I]mplementation') nmap('ds', function() Snacks.picker.lsp_symbols() end, '[D]ocument [S]ymbols') nmap('ws', function() Snacks.picker.lsp_workspace_symbols() end, '[W]orkspace [S]ymbols') -- See `:help K` for why this keymap nmap('K', vim.lsp.buf.hover, 'Hover Documentation') nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') -- Lesser used LSP functionality nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') nmap('wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') nmap('wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') nmap('wl', function() print(vim.inspect(vim.lsp.buf.list_workspace_folders())) end, '[W]orkspace [L]ist Folders') -- Create a command `:Format` local to the LSP buffer vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_) vim.lsp.buf.format() end, { desc = 'Format current buffer with LSP' }) end }) end, }, { "mason.nvim", enabled = not nixInfo.isNix, priority = 100, -- <- run lsp hook before lspconfig's hook on_plugin = { "nvim-lspconfig" }, lsp = function(plugin) vim.cmd.MasonInstall(plugin.name) end, }, { -- lazydev makes your lua lsp load only the relevant definitions for a file. -- It also gives us a nice way to correlate globals we create with files. "lazydev.nvim", auto_enable = true, cmd = { "LazyDev" }, ft = "lua", after = function(_) require('lazydev').setup({ library = { { words = { "nixInfo%.lze" }, path = nixInfo("lze", "plugins", "start", "lze") .. '/lua', }, { words = { "nixInfo%.lze" }, path = nixInfo("lzextras", "plugins", "start", "lzextras") .. '/lua' }, }, }) end, }, { -- name of the lsp "lua_ls", for_cat = "lua", -- provide a table containing filetypes, -- and then whatever your functions defined in the function type specs expect. -- in our case, it just expects the normal lspconfig setup options, -- but with a default on_attach and capabilities lsp = { -- if you provide the filetypes it doesn't ask lspconfig for the filetypes -- (meaning it doesn't call the callback function we defined in the main init.lua) filetypes = { 'lua' }, settings = { Lua = { signatureHelp = { enabled = true }, diagnostics = { globals = { "nixInfo", "vim", }, disable = { 'missing-fields' }, }, }, }, }, -- also these are regular specs and you can use before and after and all the other normal fields }, { "nixd", enabled = nixInfo.isNix, -- mason doesn't have nixd for_cat = "nix", lsp = { filetypes = { "nix" }, settings = { nixd = { nixpkgs = { expr = [[import {}]], }, options = { }, formatting = { command = { "alejandra" } }, diagnostic = { suppress = { "sema-escaping-with" } } } }, }, }, { "nvim-treesitter", lazy = false, auto_enable = true, after = function(plugin) ---@param buf integer ---@param language string local function treesitter_try_attach(buf, language) -- check if parser exists and load it if not vim.treesitter.language.add(language) then return false end -- enables syntax highlighting and other treesitter features vim.treesitter.start(buf, language) -- enables treesitter based folds vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()" vim.wo.foldmethod = "expr" -- ensure folds are open to begin with vim.o.foldlevel = 99 -- enables treesitter based indentation vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" return true end local installable_parsers = require("nvim-treesitter").get_available() vim.api.nvim_create_autocmd("FileType", { callback = function(args) local buf, filetype = args.buf, args.match local language = vim.treesitter.language.get_lang(filetype) if not language then return end if not treesitter_try_attach(buf,language) then if vim.tbl_contains(installable_parsers, language) then -- not already installed, so try to install them via nvim-treesitter if possible require("nvim-treesitter").install(language):await(function() treesitter_try_attach(buf, language) end) end end end, }) end, }, { "nvim-treesitter-textobjects", auto_enable = true, lazy = false, before = function(plugin) -- https://github.com/nvim-treesitter/nvim-treesitter-textobjects/tree/main?tab=readme-ov-file#using-a-package-manager -- Disable entire built-in ftplugin mappings to avoid conflicts. -- See https://github.com/neovim/neovim/tree/master/runtime/ftplugin for built-in ftplugins. vim.g.no_plugin_maps = true -- Or, disable per filetype (add as you like) -- vim.g.no_python_maps = true -- vim.g.no_ruby_maps = true -- vim.g.no_rust_maps = true -- vim.g.no_go_maps = true end, after = function(plugin) require("nvim-treesitter-textobjects").setup { select = { -- Automatically jump forward to textobj, similar to targets.vim lookahead = true, -- You can choose the select mode (default is charwise 'v') -- -- Can also be a function which gets passed a table with the keys -- * query_string: eg '@function.inner' -- * method: eg 'v' or 'o' -- and should return the mode ('v', 'V', or '') or a table -- mapping query_strings to modes. selection_modes = { ['@parameter.outer'] = 'v', -- charwise ['@function.outer'] = 'V', -- linewise -- ['@class.outer'] = '', -- blockwise }, -- If you set this to `true` (default is `false`) then any textobject is -- extended to include preceding or succeeding whitespace. Succeeding -- whitespace has priority in order to act similarly to eg the built-in -- `ap`. -- -- Can also be a function which gets passed a table with the keys -- * query_string: eg '@function.inner' -- * selection_mode: eg 'v' -- and should return true of false include_surrounding_whitespace = false, }, } -- keymaps -- You can use the capture groups defined in `textobjects.scm` vim.keymap.set({ "x", "o" }, "am", function() require "nvim-treesitter-textobjects.select".select_textobject("@function.outer", "textobjects") end) vim.keymap.set({ "x", "o" }, "im", function() require "nvim-treesitter-textobjects.select".select_textobject("@function.inner", "textobjects") end) vim.keymap.set({ "x", "o" }, "ac", function() require "nvim-treesitter-textobjects.select".select_textobject("@class.outer", "textobjects") end) vim.keymap.set({ "x", "o" }, "ic", function() require "nvim-treesitter-textobjects.select".select_textobject("@class.inner", "textobjects") end) -- You can also use captures from other query groups like `locals.scm` vim.keymap.set({ "x", "o" }, "as", function() require "nvim-treesitter-textobjects.select".select_textobject("@local.scope", "locals") end) -- NOTE: for more textobjects options, see the following link. -- This template is using the new `main` branch of the repo. -- https://github.com/nvim-treesitter/nvim-treesitter-textobjects/tree/main end, }, { "conform.nvim", auto_enable = true, -- cmd = { "" }, -- event = "", -- ft = "", keys = { { "FF", desc = "[F]ormat [F]ile" }, }, -- colorscheme = "", after = function (plugin) local conform = require("conform") conform.setup({ formatters_by_ft = { -- NOTE: download some formatters -- and configure them here lua = nixInfo(nil, "settings", "cats", "lua") and { "stylua" } or nil, -- go = { "gofmt", "golint" }, -- templ = { "templ" }, -- Conform will run multiple formatters sequentially -- python = { "isort", "black" }, -- Use a sub-list to run only the first available formatter -- javascript = { { "prettierd", "prettier" } }, }, }) vim.keymap.set({ "n", "v" }, "FF", function() conform.format({ lsp_fallback = true, async = false, timeout_ms = 1000, }) end, { desc = "[F]ormat [F]ile" }) end, }, { "nvim-lint", auto_enable = true, -- cmd = { "" }, event = "FileType", -- ft = "", -- keys = "", -- colorscheme = "", after = function (plugin) require('lint').linters_by_ft = { -- NOTE: download some linters -- and configure them here -- markdown = {'vale',}, -- javascript = { 'eslint' }, -- typescript = { 'eslint' }, } vim.api.nvim_create_autocmd({ "BufWritePost" }, { callback = function() require("lint").try_lint() end, }) end, }, { "cmp-cmdline", auto_enable = true, on_plugin = { "blink.cmp" }, load = nixInfo.lze.loaders.with_after, }, { "blink.compat", auto_enable = true, dep_of = { "cmp-cmdline" }, }, { "colorful-menu.nvim", auto_enable = true, on_plugin = { "blink.cmp" }, }, { "blink.cmp", auto_enable = true, event = "DeferredUIEnter", after = function (_) require("blink.cmp").setup({ -- 'default' (recommended) for mappings similar to built-in completions (C-y to accept) -- See :h blink-cmp-config-keymap for configuring keymaps keymap = { preset = 'default', }, cmdline = { enabled = true, completion = { menu = { auto_show = true, }, }, sources = function() local type = vim.fn.getcmdtype() -- Search forward and backward if type == '/' or type == '?' then return { 'buffer' } end -- Commands if type == ':' or type == '@' then return { 'cmdline', 'cmp_cmdline' } end return {} end, }, fuzzy = { sorts = { 'exact', -- defaults 'score', 'sort_text', }, }, signature = { enabled = true, window = { show_documentation = true, }, }, completion = { menu = { draw = { treesitter = { 'lsp' }, components = { label = { text = function(ctx) return require("colorful-menu").blink_components_text(ctx) end, highlight = function(ctx) return require("colorful-menu").blink_components_highlight(ctx) end, }, }, }, }, documentation = { auto_show = true, }, }, sources = { default = { 'lsp', 'path', 'buffer', 'omni' }, providers = { path = { score_offset = 50, }, lsp = { score_offset = 40, }, cmp_cmdline = { name = 'cmp_cmdline', module = 'blink.compat.source', score_offset = -100, opts = { cmp_name = 'cmdline', }, }, }, }, }) end, }, { "nvim-surround", auto_enable = true, event = "DeferredUIEnter", -- keys = "", after = function(plugin) require('nvim-surround').setup() end, }, { "vim-startuptime", auto_enable = true, cmd = { "StartupTime" }, before = function(_) vim.g.startuptime_event_width = 0 vim.g.startuptime_tries = 10 vim.g.startuptime_exe_path = nixInfo(vim.v.progpath, "progpath") end, }, { "fidget.nvim", auto_enable = true, event = "DeferredUIEnter", -- keys = "", after = function(plugin) require('fidget').setup({}) end, }, { "lualine.nvim", auto_enable = true, -- cmd = { "" }, event = "DeferredUIEnter", -- ft = "", -- keys = "", -- colorscheme = "", after = function (plugin) require('lualine').setup({ options = { icons_enabled = false, theme = nixInfo("onedark_dark", "settings", "colorscheme"), component_separators = '|', section_separators = '', }, sections = { lualine_c = { { 'filename', path = 1, status = true, }, }, }, inactive_sections = { lualine_b = { { 'filename', path = 3, status = true, }, }, lualine_x = {'filetype'}, }, tabline = { lualine_a = { 'buffers' }, -- if you use lualine-lsp-progress, I have mine here instead of fidget -- lualine_b = { 'lsp_progress', }, lualine_z = { 'tabs' } }, }) end, }, { "gitsigns.nvim", auto_enable = true, event = "DeferredUIEnter", -- cmd = { "" }, -- ft = "", -- keys = "", -- colorscheme = "", after = function (plugin) require('gitsigns').setup({ -- See `:help gitsigns.txt` signs = { add = { text = '+' }, change = { text = '~' }, delete = { text = '_' }, topdelete = { text = '‾' }, changedelete = { text = '~' }, }, on_attach = function(bufnr) local gs = package.loaded.gitsigns local function map(mode, l, r, opts) opts = opts or {} opts.buffer = bufnr vim.keymap.set(mode, l, r, opts) end -- Navigation map({ 'n', 'v' }, ']c', function() if vim.wo.diff then return ']c' end vim.schedule(function() gs.next_hunk() end) return '' end, { expr = true, desc = 'Jump to next hunk' }) map({ 'n', 'v' }, '[c', function() if vim.wo.diff then return '[c' end vim.schedule(function() gs.prev_hunk() end) return '' end, { expr = true, desc = 'Jump to previous hunk' }) -- Actions -- visual mode map('v', 'hs', function() gs.stage_hunk { vim.fn.line '.', vim.fn.line 'v' } end, { desc = 'stage git hunk' }) map('v', 'hr', function() gs.reset_hunk { vim.fn.line '.', vim.fn.line 'v' } end, { desc = 'reset git hunk' }) -- normal mode map('n', 'gs', gs.stage_hunk, { desc = 'git stage hunk' }) map('n', 'gr', gs.reset_hunk, { desc = 'git reset hunk' }) map('n', 'gS', gs.stage_buffer, { desc = 'git Stage buffer' }) map('n', 'gu', gs.undo_stage_hunk, { desc = 'undo stage hunk' }) map('n', 'gR', gs.reset_buffer, { desc = 'git Reset buffer' }) map('n', 'gp', gs.preview_hunk, { desc = 'preview git hunk' }) map('n', 'gb', function() gs.blame_line { full = false } end, { desc = 'git blame line' }) map('n', 'gd', gs.diffthis, { desc = 'git diff against index' }) map('n', 'gD', function() gs.diffthis '~' end, { desc = 'git diff against last commit' }) -- Toggles map('n', 'gtb', gs.toggle_current_line_blame, { desc = 'toggle git blame line' }) map('n', 'gtd', gs.toggle_deleted, { desc = 'toggle git show deleted' }) -- Text object map({ 'o', 'x' }, 'ih', ':Gitsigns select_hunk', { desc = 'select git hunk' }) end, }) vim.cmd([[hi GitSignsAdd guifg=#04de21]]) vim.cmd([[hi GitSignsChange guifg=#83fce6]]) vim.cmd([[hi GitSignsDelete guifg=#fa2525]]) end, }, { "which-key.nvim", auto_enable = true, -- cmd = { "" }, event = "DeferredUIEnter", -- ft = "", -- keys = "", -- colorscheme = "", after = function (plugin) require('which-key').setup({ }) require('which-key').add { { "", group = "buffer commands" }, { "_", hidden = true }, { "c", group = "[c]ode" }, { "c_", hidden = true }, { "d", group = "[d]ocument" }, { "d_", hidden = true }, { "g", group = "[g]it" }, { "g_", hidden = true }, { "m", group = "[m]arkdown" }, { "m_", hidden = true }, { "r", group = "[r]ename" }, { "r_", hidden = true }, { "s", group = "[s]earch" }, { "s_", hidden = true }, { "t", group = "[t]oggles" }, { "t_", hidden = true }, { "w", group = "[w]orkspace" }, { "w_", hidden = true }, } end, }, }