From 319c66bc0ab2331b37aa75c9d4ec17fac996615a Mon Sep 17 00:00:00 2001 From: ray Date: Sat, 6 Dec 2025 23:16:03 +0000 Subject: [PATCH] mason + lsp config working --- .gitignore | 1 + MIGRATION_PLAN.md | 24 +++++++++++++ README.md | 2 ++ lazy-lock.json | 2 ++ lua/keymaps.lua | 40 ++++++++++++++++++++-- lua/plugins/lsp.lua | 60 +++++++++++++++++++++------------ lua/plugins/mason-lspconfig.lua | 20 +++++++++++ lua/plugins/mason.lua | 8 +++++ lua/plugins/neoconf.lua | 11 ++++-- 9 files changed, 142 insertions(+), 26 deletions(-) create mode 100644 lua/plugins/mason-lspconfig.lua create mode 100644 lua/plugins/mason.lua diff --git a/.gitignore b/.gitignore index d204dc8..93e30e5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ view/* tmpdir WORKSPACE_TEST/ EXTERNAL_TEST/ +WORKSPACE_SIMPLE/ diff --git a/MIGRATION_PLAN.md b/MIGRATION_PLAN.md index 251609d..fc3859b 100644 --- a/MIGRATION_PLAN.md +++ b/MIGRATION_PLAN.md @@ -66,9 +66,27 @@ Source of truth for the step-by-step rebuild. Keep this concise and up to date. - [ ] Verify neoconf merges settings into lspconfig - [x] Wire `intelephense.environment.includePaths` via `.neoconf.json` - [x] Create validation workspaces: `WORKSPACE_TEST/` and `EXTERNAL_TEST/` with sample PHP files +- [x] Enable LSP debug notifications during validation and remove them after verifying roots + +## Phase 3.7 — Clean LSP config +- [x] Remove debug/helper logic from LSP config +- [x] Use non-deprecated per-server setup (no top-level lspconfig table access) + +## Phase 3.8 — Validate Neoconf includePaths (temporary) +- [x] Temporarily inject `intelephense.environment.includePaths` via lspconfig for `WORKSPACE_SIMPLE` to validate goto-definition +- [x] After validation, remove the temporary injection and rely on neoconf ## Phase 3.5 — LSP minimal defaults - [x] Add `nvim-lspconfig` with minimal defaults (no over-configuration) +- [x] Add minimal LSP on-attach keymaps (gd, gr, K, gD, gI) +- [x] Add global LSP keymaps with fallback in `lua/keymaps.lua` + +## Phase 3.6 — LSP server management (Mason) +- [x] Confirm scope and priorities for this subphase +- [x] Add `williamboman/mason.nvim` and `williamboman/mason-lspconfig.nvim` +- [x] Ensure servers installed: `lua_ls`, `tsserver`, `html`, `cssls`, `jsonls`, `bashls`, `marksman`, `intelephense` +- [x] Keep our custom per-server setup; use Mason only for installation +- [x] Improve root detection to include `.neoconf.json` ## Phase 4 — Navigation @@ -182,3 +200,9 @@ Notes: - Avoid adding plugins not listed in the guide unless explicitly requested. - Prefer simple defaults; only add settings that clearly improve workflow. - Plugin approval policy: unlisted plugins may be proposed, but must be explicitly confirmed before installation. + +Known Issues / Follow-ups: +- lua-language-server (lua_ls) from Mason failed to start due to missing shared library `libbfd-2.38-system.so`. Options: + - Install lua-language-server via system package manager compatible with your distro. + - Provide the required `libbfd` or adjust symlink to match expected soname. + - Skip lua_ls for now; neoconf validation can be done with other servers (e.g., jsonls) and PHP (intelephense). diff --git a/README.md b/README.md index 83ee0b0..4b2b07e 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Record every decision here with a short rationale. Append new entries; do not re - 2025-12-06: No direnv fallback for local config (keep setup simple and repo-driven). - 2025-12-06: Project-local config = layered JSON `.nvim.json` + `.nvim.local.json` with `.nvimroot` as workspace boundary marker (multi-repo friendly). - 2025-12-06: Switch to `folke/neoconf.nvim` for project-local configuration (supersedes custom layered JSON loader); use `.neoconf.json` at workspace root. +- 2025-12-06: Use `mason.nvim` + `mason-lspconfig.nvim` to install/manage LSP servers; keep custom lspconfig setup; include `.neoconf.json` in root detection. + - For PHP validation inside this repo: we require `.neoconf.json` to attach `intelephense` to avoid the repo’s `.git` being chosen as the LSP root. - 2025-12-06: Plugin approval policy — other plugins are allowed, but do not install any plugin not listed without explicit confirmation. ## Project-Local Configuration (design) diff --git a/lazy-lock.json b/lazy-lock.json index ffcc549..40720b6 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -4,6 +4,8 @@ "cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" }, "cmp-path": { "branch": "main", "commit": "c642487086dbd9a93160e1679a1327be111cbc25" }, "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "0b9bb925c000ae649ff7e7149c8cd00031f4b539" }, + "mason.nvim": { "branch": "main", "commit": "57e5a8addb8c71fb063ee4acda466c7cf6ad2800" }, "neoconf.nvim": { "branch": "main", "commit": "fbf01840998b9f0e6b05a5c3811a882fcbcaf563" }, "nvim-cmp": { "branch": "main", "commit": "d97d85e01339f01b842e6ec1502f639b080cb0fc" }, "nvim-lspconfig": { "branch": "master", "commit": "9c923997123ff9071198ea3b594d4c1931fab169" } diff --git a/lua/keymaps.lua b/lua/keymaps.lua index e61a45b..c017f72 100644 --- a/lua/keymaps.lua +++ b/lua/keymaps.lua @@ -1,8 +1,42 @@ --- Non-plugin keymaps (kept intentionally minimal for bootstrap) +-- Non-plugin and global helper keymaps local map = vim.keymap.set local opts = { noremap = true, silent = true } --- Add non-plugin keymaps during Phase 3 when porting settings +-- LSP-aware helpers with graceful fallback to built-ins +local function lsp_has(bufnr, capability) + for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do + if client.server_capabilities[capability] then return true end + end + return false +end + +local function lsp_or_builtin(bufnr, capability, lsp_fn, builtin_normal) + if lsp_has(bufnr, capability) then + lsp_fn() + else + vim.cmd("normal! " .. builtin_normal) + end +end + +-- Global LSP-keymaps with fallback so they work reliably +map('n', 'gd', function() + lsp_or_builtin(0, 'definitionProvider', vim.lsp.buf.definition, 'gd') +end, { desc = 'Go to definition (LSP or built-in)' }) + +map('n', 'gr', function() + if lsp_has(0, 'referencesProvider') then vim.lsp.buf.references() end +end, { desc = 'References (LSP)', silent = true }) + +map('n', 'gD', function() + lsp_or_builtin(0, 'declarationProvider', vim.lsp.buf.declaration, 'gD') +end, { desc = 'Go to declaration (LSP or built-in)' }) + +map('n', 'gI', function() + if lsp_has(0, 'implementationProvider') then vim.lsp.buf.implementation() end +end, { desc = 'Go to implementation (LSP)', silent = true }) + +map('n', 'K', function() + if lsp_has(0, 'hoverProvider') then vim.lsp.buf.hover() end +end, { desc = 'Hover (LSP)', silent = true }) return {} - diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index 1b56eab..726fe41 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -7,30 +7,48 @@ return { }, config = function() local capabilities = require("cmp_nvim_lsp").default_capabilities() + local util = require("lspconfig.util") - local servers = { - lua_ls = { - settings = { - Lua = { - diagnostics = { globals = { "vim" } }, - }, + local function on_attach(_, bufnr) + local map = function(mode, lhs, rhs, desc) + vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, noremap = true, desc = desc }) + end + map('n', 'gd', vim.lsp.buf.definition, 'LSP: Go to definition') + map('n', 'gr', vim.lsp.buf.references, 'LSP: References') + map('n', 'gD', vim.lsp.buf.declaration, 'LSP: Go to declaration') + map('n', 'gI', vim.lsp.buf.implementation, 'LSP: Go to implementation') + map('n', 'K', vim.lsp.buf.hover, 'LSP: Hover') + end + + local function setup(server, opts) + local ok, mod = pcall(require, "lspconfig." .. server) + if not ok or type(mod.setup) ~= "function" then return end + mod.setup(vim.tbl_deep_extend("force", { + capabilities = capabilities, + on_attach = on_attach, + root_dir = util.root_pattern( + ".neoconf.json", + ".git", + "composer.json", + "package.json" + ), + }, opts or {})) + end + + setup("lua_ls", { + settings = { + Lua = { + diagnostics = { globals = { "vim" } }, }, }, - ts_ls = {}, - html = {}, - cssls = {}, - jsonls = {}, - bashls = {}, - marksman = {}, - intelephense = {}, - } + }) - for name, opts in pairs(servers) do - local ok, mod = pcall(require, "lspconfig." .. name) - if ok and mod and type(mod.setup) == "function" then - opts = vim.tbl_deep_extend("force", { capabilities = capabilities }, opts or {}) - mod.setup(opts) - end - end + setup("ts_ls") + setup("html") + setup("cssls") + setup("jsonls") + setup("bashls") + setup("marksman") + setup("intelephense") end, } diff --git a/lua/plugins/mason-lspconfig.lua b/lua/plugins/mason-lspconfig.lua new file mode 100644 index 0000000..e8cba44 --- /dev/null +++ b/lua/plugins/mason-lspconfig.lua @@ -0,0 +1,20 @@ +return { + "williamboman/mason-lspconfig.nvim", + dependencies = { "williamboman/mason.nvim" }, + config = function() + require("mason-lspconfig").setup({ + -- mason-lspconfig currently expects the legacy name "tsserver" + ensure_installed = { + "lua_ls", + "ts_ls", + "html", + "cssls", + "jsonls", + "bashls", + "marksman", + "intelephense", + }, + automatic_installation = true, + }) + end, +} diff --git a/lua/plugins/mason.lua b/lua/plugins/mason.lua new file mode 100644 index 0000000..58290fc --- /dev/null +++ b/lua/plugins/mason.lua @@ -0,0 +1,8 @@ +return { + "williamboman/mason.nvim", + build = ":MasonUpdate", + config = function() + require("mason").setup({}) + end, +} + diff --git a/lua/plugins/neoconf.lua b/lua/plugins/neoconf.lua index f6514ef..2a5f9b1 100644 --- a/lua/plugins/neoconf.lua +++ b/lua/plugins/neoconf.lua @@ -2,9 +2,16 @@ return { "folke/neoconf.nvim", lazy = false, -- load early so it can influence lspconfig later priority = 1000, - opts = {}, + opts = { + live_reload = true, + filetype_jsonc = true, + plugins = { + lspconfig = { enabled = true }, + jsonls = { enabled = true, configured_servers_only = false }, + lua_ls = { enabled_for_neovim_config = true }, + }, + }, config = function(_, opts) require("neoconf").setup(opts) end, } -