fix project settings regression
This commit is contained in:
parent
976949c6f4
commit
71beb0fb78
|
|
@ -29,23 +29,35 @@ Modern Lua-first Neovim configuration using lazy.nvim, currently in active migra
|
|||
### 1. LSP Configuration (Phase 3 Complete)
|
||||
**Modern API (Neovim 0.11+)**: Uses `vim.lsp.config()` + `vim.lsp.enable()`, NOT `require('lspconfig')[server].setup()`.
|
||||
|
||||
**CRITICAL (2025-12-07)**: Neovim 0.11+ does NOT support `on_new_config` callback. Use `LspAttach` autocmd instead.
|
||||
|
||||
```lua
|
||||
-- lua/plugins/lsp.lua pattern:
|
||||
-- Define config
|
||||
vim.lsp.config(server_name, {
|
||||
capabilities = capabilities,
|
||||
on_attach = on_attach,
|
||||
on_new_config = function(new_config, root_dir)
|
||||
-- Load project settings from root_dir/.nvim.lua
|
||||
-- NO on_attach here, NO on_new_config here
|
||||
})
|
||||
|
||||
-- Enable server
|
||||
vim.lsp.enable({ "lua_ls", "intelephense", ... })
|
||||
|
||||
-- Load project settings via LspAttach autocmd
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
callback = function(args)
|
||||
local client = vim.lsp.get_client_by_id(args.data.client_id)
|
||||
-- Load .nvim.lua from client.root_dir
|
||||
-- Merge into client.settings
|
||||
-- Send workspace/didChangeConfiguration notification
|
||||
end,
|
||||
})
|
||||
vim.lsp.enable({ "lua_ls", "intelephense", ... })
|
||||
```
|
||||
|
||||
**Key decisions**:
|
||||
- No neoconf (incompatible with Neovim 0.11+, issue #116)
|
||||
- Native `exrc` + `secure` for project config (see settings.lua)
|
||||
- `on_new_config` hook loads from actual `root_dir`, not cwd
|
||||
- `workspace/didChangeConfiguration` sent in `on_attach` for servers like intelephense
|
||||
- Project settings loaded via `LspAttach` autocmd (NOT `on_new_config` which is deprecated)
|
||||
- `workspace/didChangeConfiguration` sent after merging settings into `client.settings`
|
||||
|
||||
### 2. Project-Local Configuration
|
||||
**Format**: `.nvim.lua` at project root, returns:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ Record every decision here with a short rationale. Append new entries; do not re
|
|||
- 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.
|
||||
- 2025-12-07: **CRITICAL REGRESSION FIX**: Neovim 0.11+ does NOT support `on_new_config` callback in `vim.lsp.config()`. Project-local settings (`.nvim.lua`) must be loaded via `LspAttach` autocmd instead. The `on_new_config` hook was silently ignored, causing empty settings and breaking goto-definition for external includes. Solution: Use `LspAttach` to load project settings, merge into `client.settings`, and send `workspace/didChangeConfiguration` notification.
|
||||
- 2025-12-07: Native `exrc` + `.nvim.lua` finalized as project-local config approach (replaces neoconf, which is incompatible with Neovim 0.11+ native LSP API). Security via `vim.opt.secure = true`.
|
||||
|
||||
## Project-Local Configuration (design)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
# Critical Regression Fix: LSP Project Settings Not Loading (2025-12-07)
|
||||
|
||||
## Summary
|
||||
`gd` (goto definition) stopped working for external library references in `WORKSPACE_TEST/site/external.php`. Even restoring to a git commit where it previously worked didn't fix it, indicating an **environment change** rather than a code regression.
|
||||
|
||||
## Root Cause
|
||||
**Neovim 0.11+ removed support for the `on_new_config` callback in `vim.lsp.config()`.**
|
||||
|
||||
The previous implementation used `on_new_config` to load project-local settings from `.nvim.lua`:
|
||||
|
||||
```lua
|
||||
vim.lsp.config(server_name, {
|
||||
on_new_config = function(new_config, root_dir)
|
||||
-- Load project settings and merge into new_config.settings
|
||||
local project_settings = load_project_lsp_settings(server_name, root_dir)
|
||||
if project_settings.settings then
|
||||
new_config.settings = vim.tbl_deep_extend("force",
|
||||
new_config.settings or {},
|
||||
project_settings.settings)
|
||||
end
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
**Problem**: This callback was **silently ignored** in Neovim 0.11+, resulting in:
|
||||
- Empty `client.settings` (confirmed via `:LspInfo` showing `Settings: {}`)
|
||||
- No `includePaths` sent to intelephense
|
||||
- `gd` failing with "No locations found" for external library symbols
|
||||
|
||||
## Symptoms
|
||||
1. `:LspInfo` showed `Settings: {}` for intelephense
|
||||
2. `gd` on `\ExtLib\Src\Util::greetExternal()` returned "No locations found"
|
||||
3. Local (workspace) symbol navigation worked fine
|
||||
4. Git history restore didn't help (environment issue, not code issue)
|
||||
|
||||
## Solution
|
||||
Use the `LspAttach` autocmd instead of `on_new_config` to load and apply project settings:
|
||||
|
||||
```lua
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
group = vim.api.nvim_create_augroup('lsp_project_settings', { clear = true }),
|
||||
callback = function(args)
|
||||
local client = vim.lsp.get_client_by_id(args.data.client_id)
|
||||
if not client then return end
|
||||
|
||||
-- Load project-specific settings from .nvim.lua at client.root_dir
|
||||
local project_settings = load_project_lsp_settings(client.name, client.root_dir)
|
||||
if project_settings.settings then
|
||||
-- Merge into client.settings
|
||||
client.settings = vim.tbl_deep_extend("force",
|
||||
client.settings or {},
|
||||
project_settings.settings)
|
||||
|
||||
-- Notify server of updated settings
|
||||
vim.schedule(function()
|
||||
client.notify("workspace/didChangeConfiguration",
|
||||
{ settings = client.settings })
|
||||
end)
|
||||
end
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
## Validation
|
||||
After fix:
|
||||
```bash
|
||||
cd WORKSPACE_TEST
|
||||
nvim --headless +'e site/external.php' +'lua vim.wait(3000); local clients = vim.lsp.get_clients({name="intelephense"}); if clients[1] then print("Settings:", vim.inspect(clients[1].settings)) end' +quit
|
||||
```
|
||||
|
||||
Output:
|
||||
```lua
|
||||
Settings: {
|
||||
intelephense = {
|
||||
environment = {
|
||||
includePaths = { "/home/ray/.config/nvim/EXTERNAL_TEST" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
✅ Settings now correctly loaded and `gd` works for external symbols.
|
||||
|
||||
## Key Differences: Neovim 0.10 vs 0.11 LSP API
|
||||
|
||||
### Old API (lspconfig plugin, Neovim < 0.11)
|
||||
```lua
|
||||
require('lspconfig').intelephense.setup({
|
||||
on_new_config = function(new_config, root_dir)
|
||||
-- Called when creating new client
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
### New API (native vim.lsp.config, Neovim 0.11+)
|
||||
```lua
|
||||
-- Define config
|
||||
vim.lsp.config('intelephense', { ... })
|
||||
|
||||
-- Enable server
|
||||
vim.lsp.enable('intelephense')
|
||||
|
||||
-- Handle dynamic settings via autocmd
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
callback = function(args)
|
||||
-- Access client, load settings, notify server
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
## Documentation Updated
|
||||
- `README.md`: Added decision log entry for 2025-12-07
|
||||
- `.github/copilot-instructions.md`: Documents LspAttach pattern
|
||||
- `AGENTS.md`: Already notes "Native exrc + vim.lsp.config migration done"
|
||||
|
||||
## Prevention
|
||||
- Always test LSP functionality after Neovim version upgrades
|
||||
- Check `:help news` for API changes
|
||||
- Validate `:LspInfo` settings are populated correctly
|
||||
- Test with external library references, not just workspace files
|
||||
|
||||
## Files Modified
|
||||
- `lua/plugins/lsp.lua`: Replaced `on_new_config` with `LspAttach` autocmd
|
||||
|
||||
## Timeline
|
||||
- **Before 2025-12-07**: `on_new_config` worked in older Neovim version
|
||||
- **2025-12-07**: Neovim upgraded to 0.11.5, `on_new_config` silently ignored
|
||||
- **2025-12-07**: Diagnosed via `:LspInfo` showing empty settings
|
||||
- **2025-12-07**: Fixed with `LspAttach` pattern, verified working
|
||||
|
|
@ -9,6 +9,9 @@ return {
|
|||
|
||||
-- Load project-local LSP settings from .nvim.lua
|
||||
local function load_project_lsp_settings(server_name, root_dir)
|
||||
if not root_dir then
|
||||
return {}
|
||||
end
|
||||
local config_file = root_dir .. "/.nvim.lua"
|
||||
if vim.fn.filereadable(config_file) == 1 then
|
||||
local ok, project_config = pcall(dofile, config_file)
|
||||
|
|
@ -19,14 +22,8 @@ return {
|
|||
return {}
|
||||
end
|
||||
|
||||
local function on_attach(client, bufnr)
|
||||
-- Send settings to server after attach (many servers need didChangeConfiguration)
|
||||
if client.config.settings and next(client.config.settings) then
|
||||
vim.schedule(function()
|
||||
client.notify("workspace/didChangeConfiguration", { settings = client.config.settings })
|
||||
end)
|
||||
end
|
||||
|
||||
-- Setup keymaps on attach
|
||||
local function setup_keymaps(bufnr)
|
||||
local map = function(mode, lhs, rhs, desc)
|
||||
vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, noremap = true, desc = desc })
|
||||
end
|
||||
|
|
@ -37,6 +34,36 @@ return {
|
|||
map('n', 'K', vim.lsp.buf.hover, 'LSP: Hover')
|
||||
end
|
||||
|
||||
-- Global LspAttach handler to load project settings and setup keymaps
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
group = vim.api.nvim_create_augroup('lsp_project_settings', { clear = true }),
|
||||
callback = function(args)
|
||||
local client = vim.lsp.get_client_by_id(args.data.client_id)
|
||||
if not client then
|
||||
return
|
||||
end
|
||||
|
||||
-- Setup keymaps for this buffer
|
||||
setup_keymaps(args.buf)
|
||||
|
||||
-- Load and send project-specific settings
|
||||
local project_settings = load_project_lsp_settings(client.name, client.root_dir)
|
||||
if project_settings.settings then
|
||||
-- Merge with existing settings
|
||||
client.settings = vim.tbl_deep_extend(
|
||||
"force",
|
||||
client.settings or {},
|
||||
project_settings.settings
|
||||
)
|
||||
|
||||
-- Send didChangeConfiguration to update the server
|
||||
vim.schedule(function()
|
||||
client.notify("workspace/didChangeConfiguration", { settings = client.settings })
|
||||
end)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Configure servers using vim.lsp.config (Neovim 0.11+ API)
|
||||
local function configure(server_name, opts)
|
||||
opts = opts or {}
|
||||
|
|
@ -44,18 +71,6 @@ return {
|
|||
-- Merge with defaults
|
||||
local config = vim.tbl_deep_extend("force", {
|
||||
capabilities = capabilities,
|
||||
on_attach = on_attach,
|
||||
on_new_config = function(new_config, root_dir)
|
||||
-- Load project-specific settings based on actual root_dir
|
||||
local project_settings = load_project_lsp_settings(server_name, root_dir)
|
||||
if project_settings.settings then
|
||||
new_config.settings = vim.tbl_deep_extend(
|
||||
"force",
|
||||
new_config.settings or {},
|
||||
project_settings.settings
|
||||
)
|
||||
end
|
||||
end,
|
||||
}, opts)
|
||||
|
||||
-- Configure the server using the new API
|
||||
|
|
|
|||
Loading…
Reference in New Issue