diff --git a/flake.lock b/flake.lock index 28e4bb4..f022169 100644 --- a/flake.lock +++ b/flake.lock @@ -518,6 +518,21 @@ "type": "github" } }, + "nixCats": { + "locked": { + "lastModified": 1745808494, + "narHash": "sha256-5Pr92pP0IaWaFCh6KLAzg+4PJ91HQGjnvvYAk8rxCL4=", + "owner": "BirdeeHub", + "repo": "nixCats-nvim", + "rev": "8b584f12aa289b00e653fe8a4e386109934d3a24", + "type": "github" + }, + "original": { + "owner": "BirdeeHub", + "repo": "nixCats-nvim", + "type": "github" + } + }, "nixos-hardware": { "locked": { "lastModified": 1745503349, @@ -727,6 +742,7 @@ "hyprland-plugins": "hyprland-plugins", "nix-darwin": "nix-darwin", "nix-on-droid": "nix-on-droid", + "nixCats": "nixCats", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixvim": "nixvim" diff --git a/flake.nix b/flake.nix index c0c286c..a44b07a 100644 --- a/flake.nix +++ b/flake.nix @@ -27,6 +27,9 @@ inputs.nixpkgs.follows = "nixpkgs"; inputs.home-manager.follows = "home-manager"; }; + nixCats = { + url = "github:BirdeeHub/nixCats-nvim"; + }; }; outputs = inputs @ { diff --git a/hosts/macbook/home.nix b/hosts/macbook/home.nix index 846159e..e2a66f6 100644 --- a/hosts/macbook/home.nix +++ b/hosts/macbook/home.nix @@ -5,7 +5,7 @@ }: { imports = [ ../../modules/home-manager/git.nix - ../../modules/home-manager/nixvim.nix + ../../modules/home-manager/nixcats ../../modules/home-manager/emacs ../../modules/home-manager/kitty.nix ../../modules/home-manager/zsh.nix diff --git a/modules/home-manager/nixcats/default.nix b/modules/home-manager/nixcats/default.nix new file mode 100644 index 0000000..3fa0cb2 --- /dev/null +++ b/modules/home-manager/nixcats/default.nix @@ -0,0 +1,158 @@ +{ config, lib, inputs, ... }: let + utils = inputs.nixCats.utils; +in { + imports = [ + inputs.nixCats.homeModule + ]; + config = { + nixCats = { + enable = true; + packageNames = [ "nvim" ]; + + luaPath = ./.; + + # for useage of this section, refer to :h nixCats.flake.outputs.categories + categoryDefinitions.replace = ({ pkgs, settings, categories, extra, name, mkPlugin, ... }@packageDef: { + # lspsAndRuntimeDeps: + # this section is for dependencies that should be available + # at RUN TIME for plugins. Will be available to PATH within neovim terminal + # this includes LSPs + lspsAndRuntimeDeps = { + general = with pkgs; [ + lazygit + ripgrep + fzf + ]; + lua = with pkgs; [ + lua-language-server + stylua + ]; + nix = with pkgs; [ + nixd + alejandra + ]; + go = with pkgs; [ + gopls + delve + golint + golangci-lint + gotools + go-tools + go + ]; + typescript = with pkgs; [ + typescript-language-server + vscode-langservers-extracted + vue-language-server + ]; + }; + + # This is for plugins that will load at startup without using packadd: + startupPlugins = { + general = with pkgs.vimPlugins; [ + # lazy loading isnt required with a config this small + # but as a demo, we do it anyway. + lze + lzextras + snacks-nvim + gruvbox-nvim + vim-sleuth + oil-nvim + plenary-nvim + ]; + }; + + # not loaded automatically at startup. + # use with packadd and an autocommand in config to achieve lazy loading + optionalPlugins = { + go = with pkgs.vimPlugins; [ + nvim-dap-go + ]; + lua = with pkgs.vimPlugins; [ + lazydev-nvim + ]; + general = with pkgs.vimPlugins; [ + mini-nvim + nvim-lspconfig + blink-cmp + nvim-treesitter.withAllGrammars + gitsigns-nvim + harpoon2 + which-key-nvim + nvim-lint + conform-nvim + nvim-dap + nvim-dap-ui + nvim-dap-virtual-text + ]; + }; + + # shared libraries to be added to LD_LIBRARY_PATH + # variable available to nvim runtime + sharedLibraries = { + general = with pkgs; [ ]; + }; + + # environmentVariables: + # this section is for environmentVariables that should be available + # at RUN TIME for plugins. Will be available to path within neovim terminal + environmentVariables = { + # test = { + # CATTESTVAR = "It worked!"; + # }; + }; + + # categories of the function you would have passed to withPackages + python3.libraries = { + # test = [ (_:[]) ]; + }; + + # If you know what these are, you can provide custom ones by category here. + # If you dont, check this link out: + # https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh + extraWrapperArgs = { + # test = [ + # '' --set CATTESTVAR2 "It worked again!"'' + # ]; + }; + }); + + # see :help nixCats.flake.outputs.packageDefinitions + packageDefinitions.replace = { + # These are the names of your packages + # you can include as many as you wish. + nvim = {pkgs, name, ... }: { + # they contain a settings set defined above + # see :help nixCats.flake.outputs.settings + settings = { + suffix-path = true; + suffix-LD = true; + wrapRc = true; + # unwrappedCfgPath = "/path/to/here"; + # IMPORTANT: + # your alias may not conflict with your other packages. + aliases = [ "vim" "homeVim" ]; + # neovim-unwrapped = inputs.neovim-nightly-overlay.packages.${pkgs.system}.neovim; + hosts.python3.enable = true; + hosts.node.enable = true; + }; + # and a set of categories that you want + # (and other information to pass to lua) + # and a set of categories that you want + categories = { + general = true; + lua = true; + nix = true; + go = true; + typescript = true; + }; + # anything else to pass and grab in lua with `nixCats.extra` + extra = { + nixdExtras.nixpkgs = ''import ${pkgs.path} {}''; + vueExtras.location = "${lib.getBin pkgs.vue-language-server}/lib/node_modules/@vue/language-server"; + }; + }; + }; + }; + }; +} diff --git a/modules/home-manager/nixcats/init.lua b/modules/home-manager/nixcats/init.lua new file mode 100644 index 0000000..4bbdd2a --- /dev/null +++ b/modules/home-manager/nixcats/init.lua @@ -0,0 +1,727 @@ +-- NOTE: These 2 need to be set up before any plugins are loaded. +vim.g.mapleader = ' ' +vim.g.maplocalleader = ' ' + +-- [[ Setting options ]] +-- See `:help vim.o` +-- NOTE: You can change these options as you wish! + +-- Sets how neovim will display certain whitespace characters in the editor. +-- See `:help 'list'` +-- and `:help 'listchars'` +vim.opt.list = true +vim.opt.listchars = { tab = '» ', trail = '·', nbsp = '␣' } + +-- Set highlight on search +vim.opt.hlsearch = true +vim.keymap.set('n', '', 'nohlsearch') + +-- Preview substitutions live, as you type! +vim.opt.inccommand = 'split' + +-- Minimal number of screen lines to keep above and below the cursor. +vim.opt.scrolloff = 10 + +-- Make line numbers default +vim.wo.number = true + +-- Enable mouse mode +vim.o.mouse = 'a' + +-- Indent +-- vim.o.smarttab = true +vim.opt.cpoptions:append('I') +vim.o.expandtab = true +-- vim.o.smartindent = true +-- vim.o.autoindent = true +-- vim.o.tabstop = 4 +-- vim.o.softtabstop = 4 +-- vim.o.shiftwidth = 4 + +-- stops line wrapping from being confusing +vim.o.breakindent = true + +-- Save undo history +vim.o.undofile = true + +-- Case-insensitive searching UNLESS \C or capital in search +vim.o.ignorecase = true +vim.o.smartcase = true + +-- Keep signcolumn on by default +vim.wo.signcolumn = 'yes' +vim.wo.relativenumber = true + +-- Decrease update time +vim.o.updatetime = 250 +vim.o.timeoutlen = 300 + +-- Set completeopt to have a better completion experience +vim.o.completeopt = 'menu,preview,noselect' + +-- NOTE: You should make sure your terminal supports this +vim.o.termguicolors = true + +-- [[ Disable auto comment on enter ]] +-- See :help formatoptions +vim.api.nvim_create_autocmd("FileType", { + desc = "remove formatoptions", + callback = function() + vim.opt.formatoptions:remove({ "c", "r", "o" }) + end, +}) + +-- [[ Highlight on yank ]] +-- See `:help vim.highlight.on_yank()` +local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true }) +vim.api.nvim_create_autocmd('TextYankPost', { + callback = function() + vim.highlight.on_yank() + end, + group = highlight_group, + pattern = '*', +}) + +vim.g.netrw_liststyle=0 +vim.g.netrw_banner=0 +-- [[ Basic Keymaps ]] + +-- Keymaps for better default experience +-- See `:help vim.keymap.set()` +vim.keymap.set("v", "J", ":m '>+1gv=gv", { desc = 'Moves Line Down' }) +vim.keymap.set("v", "K", ":m '<-2gv=gv", { desc = 'Moves Line Up' }) +vim.keymap.set("n", "", "zz", { desc = 'Scroll Down' }) +vim.keymap.set("n", "", "zz", { desc = 'Scroll Up' }) +vim.keymap.set("n", "n", "nzzzv", { desc = 'Next Search Result' }) +vim.keymap.set("n", "N", "Nzzzv", { desc = 'Previous Search Result' }) + +vim.keymap.set("n", "[", "bprev", { desc = 'Previous buffer' }) +vim.keymap.set("n", "]", "bnext", { desc = 'Next buffer' }) +vim.keymap.set("n", "l", "b#", { desc = 'Last buffer' }) +vim.keymap.set("n", "d", "bdelete", { desc = 'delete buffer' }) + +-- Remap for dealing with word wrap +vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) +vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) + +-- Diagnostic keymaps +vim.keymap.set('n', 'd', vim.diagnostic.open_float, { desc = 'Open floating diagnostic message' }) +vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostics list' }) + +-- kickstart.nvim starts you with this. +-- But it constantly clobbers your system clipboard whenever you delete anything. + +-- Sync clipboard between OS and Neovim. +-- Remove this option if you want your OS clipboard to remain independent. +-- See `:help 'clipboard'` +-- vim.o.clipboard = 'unnamedplus' + +-- You should instead use these keybindings so that they are still easy to use, but dont conflict +vim.keymap.set({"v", "x", "n"}, 'y', '"+y', { noremap = true, silent = true, desc = 'Yank to clipboard' }) +vim.keymap.set({"n", "v", "x"}, 'Y', '"+yy', { noremap = true, silent = true, desc = 'Yank line to clipboard' }) +vim.keymap.set({'n', 'v', 'x'}, 'p', '"+p', { noremap = true, silent = true, desc = 'Paste from clipboard' }) +vim.keymap.set('i', '', '+', { noremap = true, silent = true, desc = 'Paste from clipboard from within insert mode' }) +vim.keymap.set("x", "P", '"_dP', { noremap = true, silent = true, desc = 'Paste over selection without erasing unnamed register' }) + +vim.cmd.colorscheme('gruvbox') + +require("oil").setup() +vim.keymap.set("n", "fe", "Oil", { desc = 'Oil' }) + +require("snacks").setup({ + explorer = {}, + picker = {}, + bigfile = {}, + image = {}, + lazygit = {}, + rename = {}, + notifier = {}, + indent = { + enabled = true, + animate = { + enabled = false, + }, + }, + gitbrowse = {}, + scope = {}, +}) +vim.keymap.set("n", "gg", 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" }) +-- Grep +vim.keymap.set('n', "fg", function() Snacks.picker.grep() end, { desc = "Grep" }) +-- search +vim.keymap.set('n', "fd", function() Snacks.picker.diagnostics() end, { desc = "Diagnostics" }) +vim.keymap.set('n', "fh", function() Snacks.picker.help() end, { desc = "Help Pages" }) +vim.keymap.set('n', "fj", function() Snacks.picker.jumps() end, { desc = "Jumps" }) +vim.keymap.set('n', "fk", function() Snacks.picker.keymaps() end, { desc = "Keymaps" }) +vim.keymap.set('n', "fl", function() Snacks.picker.loclist() end, { desc = "Location List" }) +vim.keymap.set('n', "fM", function() Snacks.picker.man() end, { desc = "Man Pages" }) +vim.keymap.set('n', "fq", function() Snacks.picker.qflist() end, { desc = "Quickfix List" }) +vim.keymap.set('n', "fr", function() Snacks.picker.resume() end, { desc = "Resume" }) +vim.keymap.set('n', "fu", function() Snacks.picker.undo() end, { desc = "Undo History" }) +require('lze').load { + { + "blink.cmp", + enabled = nixCats('general') or false, + event = "DeferredUIEnter", + on_require = "blink", + after = function (plugin) + 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' }, + appearance = { + nerd_font_variant = 'mono' + }, + signature = { enabled = true, }, + sources = { + default = { 'lsp', 'path', 'snippets', 'buffer' }, + }, + }) + end, + }, + { + "nvim-treesitter", + enabled = nixCats('general') or false, + event = "DeferredUIEnter", + load = function (name) + vim.cmd.packadd(name) + vim.cmd.packadd("nvim-treesitter-textobjects") + end, + after = function (plugin) + require('nvim-treesitter.configs').setup { + highlight = { enable = true, }, + indent = { enable = false, }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = '', + node_incremental = '', + scope_incremental = '', + node_decremental = '', + }, + }, + textobjects = { + select = { + enable = true, + lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim + keymaps = { + -- You can use the capture groups defined in textobjects.scm + ['aa'] = '@parameter.outer', + ['ia'] = '@parameter.inner', + ['af'] = '@function.outer', + ['if'] = '@function.inner', + ['ac'] = '@class.outer', + ['ic'] = '@class.inner', + }, + }, + move = { + enable = true, + set_jumps = true, -- whether to set jumps in the jumplist + goto_next_start = { + [']m'] = '@function.outer', + [']]'] = '@class.outer', + }, + goto_next_end = { + [']M'] = '@function.outer', + [']['] = '@class.outer', + }, + goto_previous_start = { + ['[m'] = '@function.outer', + ['[['] = '@class.outer', + }, + goto_previous_end = { + ['[M'] = '@function.outer', + ['[]'] = '@class.outer', + }, + }, + swap = { + enable = true, + swap_next = { + ['a'] = '@parameter.inner', + }, + swap_previous = { + ['A'] = '@parameter.inner', + }, + }, + }, + } + end, + }, + { + "mini.nvim", + enabled = nixCats('general') or false, + event = "DeferredUIEnter", + after = function (plugin) + require('mini.pairs').setup() + require('mini.icons').setup() + require('mini.ai').setup() + end, + }, + { + "gitsigns.nvim", + enabled = nixCats('general') or false, + event = "DeferredUIEnter", + 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", + enabled = nixCats('general') or false, + event = "DeferredUIEnter", + after = function (plugin) + require('which-key').setup({}) + require('which-key').add { + { "b", group = "buffer commands" }, + { "c", group = "[c]ode" }, + { "c_", hidden = true }, + { "d", group = "[d]ocument" }, + { "d_", hidden = true }, + { "g", group = "[g]it" }, + { "g_", hidden = true }, + { "r", group = "[r]ename" }, + { "r_", hidden = true }, + { "f", group = "[f]ind" }, + { "f_", hidden = true }, + { "s", group = "[s]earch" }, + { "s_", hidden = true }, + { "t", group = "[t]oggles" }, + { "t_", hidden = true }, + { "w", group = "[w]orkspace" }, + { "w_", hidden = true }, + } + end, + }, + { + "nvim-lint", + enabled = nixCats('general') or false, + event = "FileType", + after = function (plugin) + require('lint').linters_by_ft = { + -- markdown = {'vale',}, + -- javascript = { 'eslint' }, + -- typescript = { 'eslint' }, + go = nixCats('go') and { 'golangcilint' } or nil, + } + + vim.api.nvim_create_autocmd({ "BufWritePost" }, { + callback = function() + require("lint").try_lint() + end, + }) + end, + }, + { + "conform.nvim", + enabled = nixCats('general') or false, + keys = { + { "FF", desc = "[F]ormat [F]ile" }, + }, + after = function (plugin) + local conform = require("conform") + + conform.setup({ + formatters_by_ft = { + -- NOTE: download some formatters in lspsAndRuntimeDeps + -- and configure them here + lua = nixCats('lua') and { "stylua" } or nil, + go = nixCats('go') and { "gofmt", "golint" } or nil, + -- 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-dap", + enabled = nixCats('general') or false, + keys = { + { "", desc = "Debug: Start/Continue" }, + { "", desc = "Debug: Step Into" }, + { "", desc = "Debug: Step Over" }, + { "", desc = "Debug: Step Out" }, + { "b", desc = "Debug: Toggle Breakpoint" }, + { "B", desc = "Debug: Set Breakpoint" }, + { "", desc = "Debug: See last session result." }, + }, + -- colorscheme = "", + load = function(name) + vim.cmd.packadd(name) + vim.cmd.packadd("nvim-dap-ui") + vim.cmd.packadd("nvim-dap-virtual-text") + end, + after = function (plugin) + local dap = require 'dap' + local dapui = require 'dapui' + + -- Basic debugging keymaps, feel free to change to your liking! + vim.keymap.set('n', '', dap.continue, { desc = 'Debug: Start/Continue' }) + vim.keymap.set('n', '', dap.step_into, { desc = 'Debug: Step Into' }) + vim.keymap.set('n', '', dap.step_over, { desc = 'Debug: Step Over' }) + vim.keymap.set('n', '', dap.step_out, { desc = 'Debug: Step Out' }) + vim.keymap.set('n', 'b', dap.toggle_breakpoint, { desc = 'Debug: Toggle Breakpoint' }) + vim.keymap.set('n', 'B', function() + dap.set_breakpoint(vim.fn.input 'Breakpoint condition: ') + end, { desc = 'Debug: Set Breakpoint' }) + + -- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception. + vim.keymap.set('n', '', dapui.toggle, { desc = 'Debug: See last session result.' }) + + dap.listeners.after.event_initialized['dapui_config'] = dapui.open + dap.listeners.before.event_terminated['dapui_config'] = dapui.close + dap.listeners.before.event_exited['dapui_config'] = dapui.close + + -- Dap UI setup + -- For more information, see |:help nvim-dap-ui| + dapui.setup { + -- Set icons to characters that are more likely to work in every terminal. + -- Feel free to remove or use ones that you like more! :) + -- Don't feel like these are good choices. + icons = { expanded = '▾', collapsed = '▸', current_frame = '*' }, + controls = { + icons = { + pause = '⏸', + play = '▶', + step_into = '⏎', + step_over = '⏭', + step_out = '⏮', + step_back = 'b', + run_last = '▶▶', + terminate = '⏹', + disconnect = '⏏', + }, + }, + } + + require("nvim-dap-virtual-text").setup { + enabled = true, -- enable this plugin (the default) + enabled_commands = true, -- create commands DapVirtualTextEnable, DapVirtualTextDisable, DapVirtualTextToggle, (DapVirtualTextForceRefresh for refreshing when debug adapter did not notify its termination) + highlight_changed_variables = true, -- highlight changed values with NvimDapVirtualTextChanged, else always NvimDapVirtualText + highlight_new_as_changed = false, -- highlight new variables in the same way as changed variables (if highlight_changed_variables) + show_stop_reason = true, -- show stop reason when stopped for exceptions + commented = false, -- prefix virtual text with comment string + only_first_definition = true, -- only show virtual text at first definition (if there are multiple) + all_references = false, -- show virtual text on all all references of the variable (not only definitions) + clear_on_continue = false, -- clear virtual text on "continue" (might cause flickering when stepping) + --- A callback that determines how a variable is displayed or whether it should be omitted + --- variable Variable https://microsoft.github.io/debug-adapter-protocol/specification#Types_Variable + --- buf number + --- stackframe dap.StackFrame https://microsoft.github.io/debug-adapter-protocol/specification#Types_StackFrame + --- node userdata tree-sitter node identified as variable definition of reference (see `:h tsnode`) + --- options nvim_dap_virtual_text_options Current options for nvim-dap-virtual-text + --- string|nil A text how the virtual text should be displayed or nil, if this variable shouldn't be displayed + display_callback = function(variable, buf, stackframe, node, options) + if options.virt_text_pos == 'inline' then + return ' = ' .. variable.value + else + return variable.name .. ' = ' .. variable.value + end + end, + -- position of virtual text, see `:h nvim_buf_set_extmark()`, default tries to inline the virtual text. Use 'eol' to set to end of line + virt_text_pos = vim.fn.has 'nvim-0.10' == 1 and 'inline' or 'eol', + + -- experimental features: + all_frames = false, -- show virtual text for all stack frames not only current. Only works for debugpy on my machine. + virt_lines = false, -- show virtual lines instead of virtual text (will flicker!) + virt_text_win_col = nil -- position the virtual text at a fixed window column (starting from the first text column) , + -- e.g. 80 to position at column 80, see `:h nvim_buf_set_extmark()` + } + + -- NOTE: Install lang specific config + -- either in here, or in a separate plugin spec as demonstrated for go below. + end, + }, + { + "nvim-dap-go", + enabled = nixCats('go') or false, + on_plugin = { "nvim-dap", }, + after = function(plugin) + require("dap-go").setup() + end, + }, + { + -- lazydev makes your lsp way better in your config without needing extra lsp configuration. + "lazydev.nvim", + enabled = nixCats('lua') or false, + cmd = { "LazyDev" }, + ft = "lua", + after = function(_) + require('lazydev').setup({ + library = { + { words = { "nixCats" }, path = (nixCats.nixCatsPath or "") .. '/lua' }, + }, + }) + end, + }, + { + "harpoon2", + enabled = nixCats('general') or false, + keys = { + { "a", desc = "[A]dd harpoon" }, + { "e", desc = "[E]dit harpoon" }, + { "k", desc = "Harpoon prev" }, + { "j", desc = "Harpoon next" }, + }, + after = function () + local harpoon = require("harpoon") + require("blink.cmp.sources.lsp.commands") + harpoon:setup() + + vim.keymap.set("n", "a", function() harpoon:list():add() end) + vim.keymap.set("n", "e", function() harpoon.ui:toggle_quick_menu(harpoon:list()) end) + + -- Toggle previous & next buffers stored within Harpoon list + vim.keymap.set("n", "k", function() harpoon:list():prev() end) + vim.keymap.set("n", "j", function() harpoon:list():next() end) + end + } +} + +local function lsp_on_attach(_, 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') + + if nixCats('general') then + 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') + end + + nmap('D', vim.lsp.buf.type_definition, 'Type [D]efinition') + + -- 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 + +-- NOTE: Register a handler from lzextras. This one makes it so that +-- you can set up lsps within lze specs, +-- and trigger vim.lsp.enable and the rtp config collection only on the correct filetypes +-- it adds the lsp field used below +-- (and must be registered before any load calls that use it!) +require('lze').register_handlers(require('lzextras').lsp) +-- also replace the fallback filetype list retrieval function with a slightly faster one +require('lze').h.lsp.set_ft_fallback(function(name) + return dofile(nixCats.pawsible({ "allPlugins", "opt", "nvim-lspconfig" }) .. "/lsp/" .. name .. ".lua").filetypes or {} +end) +require('lze').load { + { + "nvim-lspconfig", + enabled = nixCats("general") or false, + -- the on require handler will be needed here if you want to use the + -- fallback method of getting filetypes if you don't provide any + on_require = { "lspconfig" }, + -- define a function to run over all 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, + before = function(_) + vim.lsp.config('*', { + on_attach = lsp_on_attach, + }) + end, + }, + { + -- name of the lsp + "lua_ls", + enabled = nixCats('lua') or false, + -- 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. + lsp = { + -- if you provide the filetypes it doesn't ask lspconfig for the filetypes + filetypes = { 'lua' }, + settings = { + Lua = { + runtime = { version = 'LuaJIT' }, + formatters = { + ignoreComments = true, + }, + signatureHelp = { enabled = true }, + diagnostics = { + globals = { "nixCats", "vim", }, + disable = { 'missing-fields' }, + }, + telemetry = { enabled = false }, + }, + }, + }, + -- also these are regular specs and you can use before and after and all the other normal fields + }, + { + "ts_ls", + enabled = nixCats('typescript') or false, + lsp = { + filetypes = { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx", "vue" }, + init_options = { + plugins = { + { + name = "@vue/typescript-plugin", + languages = { "vue" }, + location = nixCats.extra("vueExtras.location"), + }, + }, + }, + }, + }, + { + "eslint", + enabled = nixCats('typescript') or false, + lsp = {}, + }, + { + "gopls", + enabled = nixCats("go") or false, + lsp = { + -- filetypes = { "go", "gomod", "gowork", "gotmpl" }, + }, + }, + { + "nixd", + enabled = nixCats('nix') or false, + lsp = { + filetypes = { 'nix' }, + settings = { + nixd = { + nixpkgs = { + expr = nixCats.extra("nixdExtras.nixpkgs") or [[import {}]], + }, + options = { + nixos = { + -- nixdExtras.nixos_options = ''(builtins.getFlake "path:${builtins.toString inputs.self.outPath}").nixosConfigurations.configname.options'' + expr = nixCats.extra("nixdExtras.nixos_options") + }, + ["home-manager"] = { + -- nixdExtras.home_manager_options = ''(builtins.getFlake "path:${builtins.toString inputs.self.outPath}").homeConfigurations.configname.options'' + expr = nixCats.extra("nixdExtras.home_manager_options") + } + }, + formatting = { + command = { "alejandra" } + }, + diagnostic = { + suppress = { + "sema-escaping-with" + } + } + } + }, + }, + }, +}