-- Bootstrap lazy.nvim local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not (vim.uv or vim.loop).fs_stat(lazypath) then local lazyrepo = "https://github.com/folke/lazy.nvim.git" vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) end vim.opt.rtp:prepend(lazypath) -- === NIXOS HELPER (Simplified) === local function get_tsserver_path() -- 1. Try to find 'tsserver' in the current shell (direnv/nix-shell) local bin = vim.fn.exepath("tsserver") if bin == "" then vim.notify("WARN: tsserver not found in PATH. Are you in a nix-shell?", vim.log.levels.WARN) return nil end -- 2. Follow the Nix symlinks to find the actual .js file -- On NixOS, 'bin/tsserver' is a shell script wrapper. We need the .js file it points to. local resolved = vim.fn.resolve(bin) -- Logic: Check if the resolved path is already the js file or needs traversal if resolved:match("%.js$") then return resolved end -- Common NixOS pattern: /nix/store/.../bin/tsserver -> points near lib/node_modules return vim.fn.fnamemodify(resolved, ":h") .. "/../lib/node_modules/typescript/lib/tsserver.js" end require("lazy").setup({ ------------------------------ UI ------------------------------ { "catppuccin/nvim", name = "catppuccin", priority = 1000 }, { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", opts = {} }, "nvim-tree/nvim-web-devicons", { "nvim-tree/nvim-tree.lua", opts = {} }, "romgrk/barbar.nvim", { "nvim-lualine/lualine.nvim", opts = {} }, { 'windwp/nvim-autopairs', event = "InsertEnter", opts = {} }, -- DIRENV (Crucial for NixOS shells) { "direnv/direnv.vim" }, ------------------------------ DIAGNOSTICS & UI ------------------------------ { "folke/trouble.nvim", cmd = "Trouble", opts = {}, keys = { { "xx", "Trouble diagnostics toggle", desc = "Diagnostics" } }, }, { "rachartier/tiny-inline-diagnostic.nvim", event = "VeryLazy", priority = 1000, config = function() require("tiny-inline-diagnostic").setup() vim.diagnostic.config({ virtual_text = false }) end, }, { "nvimdev/lspsaga.nvim", opts = { lightbulb = { enable = true, virtual_text = false, sign = true, } } }, ------------------------------ COMPLETION ------------------------------ { "saghen/blink.cmp", version = "*", opts = { keymap = { preset = "default" }, sources = { default = { "lsp", "path", "snippets", "buffer" } }, signature = { enabled = true } }, }, ------------------------------ FORMATTING ------------------------------ { "stevearc/conform.nvim", event = { "BufWritePre" }, opts = { formatters_by_ft = { lua = { "stylua" }, python = { "ruff_format" }, javascript = { "prettierd", "prettier", stop_after_first = true }, typescript = { "prettierd", "prettier", stop_after_first = true }, vue = { "prettierd" }, }, format_on_save = { timeout_ms = 500, lsp_fallback = true }, }, }, ------------------------------ SPECIALISTS ------------------------------ { "mrcjkb/rustaceanvim", version = '^5', lazy = false }, { "pmizio/typescript-tools.nvim", dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" } }, "esmuellert/nvim-eslint", "neovim/nvim-lspconfig", }) ------------------------------ CONFIGURATION ------------------------------ vim.o.tabstop = 2 vim.o.shiftwidth = 2 vim.o.expandtab = true vim.o.number = true vim.o.signcolumn = "yes" vim.o.cursorline = true vim.cmd.colorscheme "catppuccin-mocha" ------------------------------ NATIVE LSP SETUP ------------------------------ local capabilities = require('blink.cmp').get_lsp_capabilities() -- 1. TYPESCRIPT TOOLS (Specialist) require("typescript-tools").setup({ capabilities = capabilities, -- CRITICAL: This must be a string. If nil, the plugin defaults to internal logic. tsserver_path = get_tsserver_path(), settings = { -- Remove the 'tsserver_plugins' block for now. -- It causes the "table at index 1" crash if the paths are wrong. tsserver_file_preferences = { includeCompletionsForModuleExports = true, quotePreference = "auto", importModuleSpecifierPreference = "non-relative", }, }, -- Only run on standard JS/TS files for now filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact" }, }) -- 2. ESLINT (Specialist) require("nvim-eslint").setup({ capabilities = capabilities, }) -- 3. RUST (Specialist) vim.g.rustaceanvim = { server = { capabilities = capabilities, default_settings = { ['rust-analyzer'] = { checkOnSave = { command = "clippy" } } } } } -- 4. GENERICS (Native Loop) -- NOTE: "vue_ls" is the new name for Volar. local generic_servers = { "basedpyright", "ruff", "lua_ls", "html", "svelte", "vue_ls", "nil_ls" } for _, name in ipairs(generic_servers) do -- Apply caps vim.lsp.config(name, { capabilities = capabilities, -- NixOS Tip: This prevents Neovim from yelling if a server is missing from your shell on_init = function(client) -- Optional: logic to check if root_dir is valid end }) -- Enable vim.lsp.enable(name) end vim.keymap.set({ "n", "v" }, "ca", "Lspsaga code_action", { desc = "Code Action" })