diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c37c711 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,63 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Architecture Overview + +This is a modern Neovim configuration built around the lazy.nvim plugin manager. The configuration follows a modular structure: + +- **Entry point**: `init.lua` loads core modules in sequence: options, mappings, lazy.nvim setup, and autocmds +- **Plugin management**: Uses lazy.nvim with plugins defined in `lua/plugins/` directory +- **LSP configuration**: Centralized in `lua/functions/lsp.lua` with server-specific settings in `lua/lsp/` +- **Shared utilities**: Common constants and tools in `lua/commons/init.lua` +- **Configuration modules**: Core settings split into separate files in `lua/configs/` + +## Key Components + +### LSP Setup +- Supports both Neovim 0.11+ new LSP config API and legacy setup +- LSP servers are defined in `commons.servers` array +- Server-specific settings live in `lua/lsp/{server}.lua` files +- Uses blink.cmp for completion capabilities +- Mason.nvim auto-installs: stylua, lua-language-server, gopls, pyright + +### Plugin Architecture +- All plugins defined as lazy.nvim specs in `lua/plugins/` +- Custom lazy file event handling in `utils/plugins.lua` +- Key plugins: blink.cmp (completion), conform.nvim (formatting), fzf-lua (fuzzy finding), treesitter, lspconfig + +### Formatting +- Conform.nvim handles formatting with `ff` keybind +- Format-on-save enabled with 500ms timeout +- Configured formatters: stylua (Lua), black (Python), rustfmt (Rust), prettier (JS), shfmt (shell) + +## Common Development Tasks + +### Adding New LSP Server +1. Add server name to `commons.servers` array in `lua/commons/init.lua` +2. Create server config file at `lua/lsp/{server}.lua` with settings table +3. Ensure server is installed via Mason or system package manager + +### Adding New Plugin +1. Create plugin spec file in `lua/plugins/{name}.lua` +2. Return lazy.nvim spec table with plugin URL and configuration +3. Plugin will be auto-loaded by lazy.nvim + +### Key Mappings +- Leader key: `` +- Save: `s` +- Buffer delete: `q` +- Quit: `qq` (force quit: `qqq`) +- Format code: `ff` +- Toggle comment: `mm` (normal/visual mode) + +### File Structure Conventions +- Plugin configs: `lua/plugins/{plugin-name}.lua` +- LSP server configs: `lua/lsp/{server-name}.lua` +- Shared utilities: `lua/commons/` and `lua/utils/` +- Core configuration: `lua/configs/` + +## Version Compatibility +- Uses `commons.tools.is_version_gte_0_11()` to detect Neovim 0.11+ for new LSP API +- Maintains backward compatibility with older Neovim versions +- Big file handling configured for files >50KB \ No newline at end of file diff --git a/lazy-lock.json b/lazy-lock.json index 612cf7d..70796e7 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -1,22 +1,22 @@ { "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, - "blink.cmp": { "branch": "main", "commit": "022521a8910a5543b0251b21c9e1a1e989745796" }, + "blink.cmp": { "branch": "main", "commit": "bae4bae0eedd1fa55f34b685862e94a222d5c6f8" }, "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" }, - "conform.nvim": { "branch": "master", "commit": "6feb2f28f9a9385e401857b21eeac3c1b66dd628" }, + "conform.nvim": { "branch": "master", "commit": "a0ab60ed666c56b37fd7ed1847d2ac52f2482ce0" }, "friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" }, - "fzf-lua": { "branch": "main", "commit": "97f665a38d73a6541d98b542c79b4bead8e85d4c" }, - "gitsigns.nvim": { "branch": "main", "commit": "8b729e489f1475615dc6c9737da917b3bc163605" }, - "gruvbox.nvim": { "branch": "main", "commit": "00e38a379bab3389e187b3953566d67d494dfddd" }, + "fzf-lua": { "branch": "main", "commit": "7d66cd81cf485fb17c22d82021cc166ce332a14c" }, + "gitsigns.nvim": { "branch": "main", "commit": "6e3c66548035e50db7bd8e360a29aec6620c3641" }, + "gruvbox.nvim": { "branch": "main", "commit": "12c2624287dc827edb5d72b2bc4c9619e692a554" }, "lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" }, - "lualine.nvim": { "branch": "master", "commit": "0c6cca9f2c63dadeb9225c45bc92bb95a151d4af" }, - "mason.nvim": { "branch": "main", "commit": "8024d64e1330b86044fed4c8494ef3dcd483a67c" }, - "nvim-autopairs": { "branch": "master", "commit": "4d74e75913832866aa7de35e4202463ddf6efd1b" }, + "lualine.nvim": { "branch": "master", "commit": "b8c23159c0161f4b89196f74ee3a6d02cdc3a955" }, + "mason.nvim": { "branch": "main", "commit": "7dc4facca9702f95353d5a1f87daf23d78e31c2a" }, + "nvim-autopairs": { "branch": "master", "commit": "23320e75953ac82e559c610bec5a90d9c6dfa743" }, "nvim-colorizer.lua": { "branch": "master", "commit": "a065833f35a3a7cc3ef137ac88b5381da2ba302e" }, - "nvim-lspconfig": { "branch": "master", "commit": "3ea99227e316c5028f57a4d86a1a7fd01dd876d0" }, + "nvim-lspconfig": { "branch": "master", "commit": "e844850b3143a1627437f811549fc7d70cfedf05" }, "nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" }, - "nvim-web-devicons": { "branch": "master", "commit": "1fb58cca9aebbc4fd32b086cb413548ce132c127" }, - "plenary.nvim": { "branch": "master", "commit": "857c5ac632080dba10aae49dba902ce3abf91b35" }, + "nvim-web-devicons": { "branch": "master", "commit": "81b37d7937953b50e5fd8d9d7dfe2c6d0088fde1" }, + "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, "snacks.nvim": { "branch": "main", "commit": "bc0630e43be5699bb94dadc302c0d21615421d93" }, - "tiny-code-action.nvim": { "branch": "main", "commit": "6bfecd218c617e125e69731033fb0d695b8b5144" }, + "tiny-code-action.nvim": { "branch": "main", "commit": "6f02cc30685c76812cdaa1bf1dc5f712d2265b14" }, "which-key.nvim": { "branch": "main", "commit": "370ec46f710e058c9c1646273e6b225acf47cbed" } } diff --git a/lua/functions/lsp.lua b/lua/functions/lsp.lua index c88454f..fccab5c 100644 --- a/lua/functions/lsp.lua +++ b/lua/functions/lsp.lua @@ -1,14 +1,61 @@ -local lspconfig = require("lspconfig") +-- Mason package name to LSP server name mapping +local mason_to_lsp = { + ["lua-language-server"] = "lua_ls", + ["typescript-language-server"] = "ts_ls", + ["rust-analyzer"] = "rust_analyzer", + ["gopls"] = "gopls", + ["pyright"] = "pyright", + ["clangd"] = "clangd", + ["bash-language-server"] = "bashls", + ["yaml-language-server"] = "yamlls", +} + +-- Get installed LSP servers from Mason +local function get_mason_installed_servers() + local mason_registry = require("mason-registry") + local installed_servers = {} + + for _, pkg in ipairs(mason_registry.get_installed_packages()) do + local lsp_name = mason_to_lsp[pkg.name] + if lsp_name then + table.insert(installed_servers, lsp_name) + end + end + + return installed_servers +end + if require("commons").tools.is_version_gte_0_11() then + -- Neovim 0.11+ native LSP configuration vim.lsp.config("*", { capabilities = require("blink.cmp").get_lsp_capabilities(), root_markers = { ".git" }, }) - for _, server in pairs(require("commons").servers) do + + -- Get installed servers from Mason + local installed_servers = get_mason_installed_servers() + + -- Configure and enable installed servers + for _, server in ipairs(installed_servers) do local ok, settings = pcall(require, "lsp." .. server) - if ok then vim.lsp.config(server, settings) end + if ok then + vim.lsp.config(server, settings) + else + -- Basic configuration for servers without custom config + vim.lsp.config(server, {}) + end vim.lsp.enable(server) end + + -- Also configure servers from commons.servers that have custom configs + for _, server in pairs(require("commons").servers) do + local ok, settings = pcall(require, "lsp." .. server) + if ok then + vim.lsp.config(server, settings) + vim.lsp.enable(server) + end + end + vim.diagnostic.config({ update_in_insert = true, severity_sort = true, @@ -16,7 +63,26 @@ if require("commons").tools.is_version_gte_0_11() then virtual_text = true, }) else + -- Legacy nvim-lspconfig setup for Neovim < 0.11 + local lspconfig = require("lspconfig") local capabilities = require("blink.cmp").get_lsp_capabilities() + + -- Get installed servers from Mason + local installed_servers = get_mason_installed_servers() + + -- Configure installed servers + for _, server in ipairs(installed_servers) do + local ok, settings = pcall(require, "lsp." .. server) + if ok then + settings.capabilities = capabilities + lspconfig[server].setup(settings) + else + -- Basic configuration for servers without custom config + lspconfig[server].setup({ capabilities = capabilities }) + end + end + + -- Also configure servers from commons.servers for _, server in pairs(require("commons").servers) do local ok, settings = pcall(require, "lsp." .. server) if ok then diff --git a/lua/lsp/example.lua b/lua/lsp/example.lua new file mode 100644 index 0000000..e8d2cfc --- /dev/null +++ b/lua/lsp/example.lua @@ -0,0 +1,84 @@ +---@type vim.lsp.Config +--[[ +Example LSP server configuration for Neovim 0.11+ native LSP API + +This file demonstrates the structure and common patterns for configuring +LSP servers in the new vim.lsp.Config format. Copy this file and modify +it for your specific language server. + +Key components: +- cmd: Command and arguments to start the server +- filetypes: File types that should trigger this LSP server +- root_markers: Files/directories that define project root (nested arrays = equal priority) +- settings: Server-specific configuration (schema varies by server) + +For server-specific settings schemas, check the server's documentation: +- Language servers often provide JSON schemas for their settings +- Many examples can be found at: https://github.com/neovim/nvim-lspconfig + +This configuration works with both Neovim 0.11+ (native vim.lsp.config) +and older versions (via nvim-lspconfig) thanks to the compatibility layer +in lua/functions/lsp.lua +--]] + +return { + -- Command to start the language server + -- This should match the executable name installed by Mason or system package manager + cmd = { "language-server-executable" }, + + -- File types that should automatically attach this LSP server + filetypes = { "javascript", "typescript", "javascriptreact", "typescriptreact" }, + + -- Root directory markers - LSP will search for these files/directories + -- to determine the project root. Nested arrays indicate equal priority. + -- The first match wins within each priority level. + root_markers = { + { "package.json", "tsconfig.json", "jsconfig.json" }, -- High priority + { ".git", ".hg" } -- Fallback markers + }, + + -- Server-specific settings (varies by language server) + -- Check your language server's documentation for available options + settings = { + -- Example: TypeScript server settings + typescript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + suggest = { + includeCompletionsForModuleExports = true, + }, + preferences = { + includePackageJsonAutoImports = "auto", + }, + }, + javascript = { + -- JavaScript-specific settings + suggest = { + includeCompletionsForModuleExports = true, + }, + }, + }, + + -- Optional: Additional capabilities (usually handled globally) + -- capabilities = require("blink.cmp").get_lsp_capabilities(), + + -- Optional: Custom initialization options + -- init_options = { + -- hostInfo = "neovim", + -- }, + + -- Optional: Custom handlers for LSP methods + -- handlers = { + -- ["textDocument/hover"] = vim.lsp.with( + -- vim.lsp.handlers.hover, + -- { border = "rounded" } + -- ), + -- }, +} \ No newline at end of file diff --git a/lua/lsp/lua_ls.lua b/lua/lsp/lua_ls.lua index 6db7f08..91746c9 100644 --- a/lua/lsp/lua_ls.lua +++ b/lua/lsp/lua_ls.lua @@ -1,9 +1,25 @@ +---@type vim.lsp.Config return { + cmd = { "lua-language-server" }, + filetypes = { "lua" }, + root_markers = { ".luarc.json", ".luarc.jsonc", ".git" }, settings = { Lua = { diagnostics = { globals = {'vim'}, - } + }, + runtime = { + version = 'LuaJIT', + }, + workspace = { + checkThirdParty = false, + library = { + vim.env.VIMRUNTIME, + }, + }, + telemetry = { + enable = false, + }, } } } diff --git a/lua/lsp/pyright.lua b/lua/lsp/pyright.lua new file mode 100644 index 0000000..616d86e --- /dev/null +++ b/lua/lsp/pyright.lua @@ -0,0 +1,44 @@ +return { + -- Command to start the language server + -- This should match the executable name installed by Mason or system package manager + cmd = { "pyright" }, + + -- File types that should automatically attach this LSP server + filetypes = { "python" }, + + -- Root directory markers - LSP will search for these files/directories + -- to determine the project root. Nested arrays indicate equal priority. + -- The first match wins within each priority level. + root_markers = { + { "pyprojtect.toml", "setup.py", "setup.cfg", "requirements.txt", "pyrightconfig.json" }, -- High priority + { ".git", ".hg" }, -- Fallback markers + }, + + -- Server-specific settings (varies by language server) + -- Check your language server's documentation for available options + settings = { + python = { + analysis = { + autoSearchPaths = true, + useLibraryCodeForTypes = true, + }, + }, + }, + + -- Optional: Additional capabilities (usually handled globally) + -- capabilities = require("blink.cmp").get_lsp_capabilities(), + + -- Optional: Custom initialization options + -- init_options = { + -- hostInfo = "neovim", + -- }, + + -- Optional: Custom handlers for LSP methods + -- handlers = { + -- ["textDocument/hover"] = vim.lsp.with( + -- vim.lsp.handlers.hover, + -- { border = "rounded" } + -- ), + -- }, +} + diff --git a/lua/lsp/rust-analyzer.lua b/lua/lsp/rust-analyzer.lua new file mode 100644 index 0000000..4ad3e97 --- /dev/null +++ b/lua/lsp/rust-analyzer.lua @@ -0,0 +1,32 @@ +---@type vim.lsp.Config +return { + cmd = { "rust-analyzer" }, + filetypes = { "rust" }, + root_markers = { + "Cargo.toml", + }, + settings = { + ["rust-analyzer"] = { + cargo = { + allFeatures = true, + loadOutDirsFromCheck = true, + }, + procMacro = { + enable = true, + }, + checkOnSave = { + command = "clippy", + extraArgs = { "--no-deps" }, + }, + diagnostics = { + enable = true, + enableExperimental = true, + }, + completion = { + postfix = { + enable = false, + }, + }, + }, + }, +} diff --git a/lua/plugins/bufferline.lua b/lua/plugins/bufferline.lua index 391a1cd..45cb5ce 100644 --- a/lua/plugins/bufferline.lua +++ b/lua/plugins/bufferline.lua @@ -2,6 +2,7 @@ return { "akinsho/bufferline.nvim", version = "*", dependencies = "nvim-tree/nvim-web-devicons", + event = "VeryLazy", config = function(_,opts) require("bufferline").setup({ options = { diff --git a/lua/plugins/lspconfig.lua b/lua/plugins/lspconfig.lua index 5e9dfb0..8c7ceec 100644 --- a/lua/plugins/lspconfig.lua +++ b/lua/plugins/lspconfig.lua @@ -1,7 +1,8 @@ return { "neovim/nvim-lspconfig", -- event = "InsertEnter", - -- cond = not require("commons").tools.is_version_gte_0_11(), + -- cond = not require("commons").tools.is_version_gte_0_11(), + event = { "BufReadPre", "BufNewFile" }, dependencies = { { "saghen/blink.cmp" }, { "williamboman/mason.nvim" } }, config = function() require("functions.lsp") diff --git a/lua/plugins/lualine.lua b/lua/plugins/lualine.lua index 4cea1b3..5cadba4 100644 --- a/lua/plugins/lualine.lua +++ b/lua/plugins/lualine.lua @@ -25,6 +25,7 @@ return { -- Config local config = { options = { + refresh = { statusline = 100 }, component_separators = "", section_separators = "", theme = "auto", diff --git a/lua/plugins/mason.lua b/lua/plugins/mason.lua index 4b9b630..0097194 100644 --- a/lua/plugins/mason.lua +++ b/lua/plugins/mason.lua @@ -4,6 +4,7 @@ return { build = ":MasonUpdate", opts_extend = { "ensure_installed" }, opts = { ensure_installed = { "stylua", "lua-language-server", "gopls", "pyright" } }, + event = "VeryLazy", config = function(_, opts) require("mason").setup(opts) local mr = require("mason-registry")