mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 03:48:18 +00:00
fix(lsp): on detach, cancel pending foldingRange requests #31509
Problem: 1. Open a relatively large file (so the server needs some time to process the request). 2. Then immediately execute `:bdelete`. 3. Once the request is completed, the handler will obtain the bufstate of a buffer already unloaded. Error executing vim.schedule lua callback: ...7841_1/share/nvim/runtime/lua/vim/lsp/_folding_range.lua:119: assertion failed! stack traceback: [C]: in function 'assert' ...7841_1/share/nvim/runtime/lua/vim/lsp/_folding_range.lua:119: in function 'multi_handler' ...7841_1/share/nvim/runtime/lua/vim/lsp/_folding_range.lua:140: in function 'handler' ...HEAD-c137841_1/share/nvim/runtime/lua/vim/lsp/client.lua:669: in function '' vim/_editor.lua: in function <vim/_editor.lua:0> Solution: On detach, cancel all pending textDocument_foldingRange requests.
This commit is contained in:
@@ -197,6 +197,11 @@ local function setup(bufnr)
|
|||||||
-- `on_detach` also runs on buffer reload (`:e`).
|
-- `on_detach` also runs on buffer reload (`:e`).
|
||||||
-- Ensure `bufstate` and hooks are cleared to avoid duplication or leftover states.
|
-- Ensure `bufstate` and hooks are cleared to avoid duplication or leftover states.
|
||||||
on_detach = function()
|
on_detach = function()
|
||||||
|
util._cancel_requests({
|
||||||
|
bufnr = bufnr,
|
||||||
|
method = ms.textDocument_foldingRange,
|
||||||
|
type = 'pending',
|
||||||
|
})
|
||||||
bufstates[bufnr] = nil
|
bufstates[bufnr] = nil
|
||||||
api.nvim_clear_autocmds({ buffer = bufnr, group = augroup_setup })
|
api.nvim_clear_autocmds({ buffer = bufnr, group = augroup_setup })
|
||||||
end,
|
end,
|
||||||
|
@@ -2153,6 +2153,41 @@ local function make_line_range_params(bufnr, start_line, end_line, position_enco
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@class (private) vim.lsp.util._cancel_requests.Filter
|
||||||
|
---@field bufnr? integer
|
||||||
|
---@field clients? vim.lsp.Client[]
|
||||||
|
---@field method? string
|
||||||
|
---@field type? string
|
||||||
|
|
||||||
|
---@private
|
||||||
|
--- Cancel all {filter}ed requests.
|
||||||
|
---
|
||||||
|
---@param filter? vim.lsp.util._cancel_requests.Filter
|
||||||
|
function M._cancel_requests(filter)
|
||||||
|
filter = filter or {}
|
||||||
|
local bufnr = filter.bufnr and vim._resolve_bufnr(filter.bufnr) or nil
|
||||||
|
local clients = filter.clients
|
||||||
|
local method = filter.method
|
||||||
|
local type = filter.type
|
||||||
|
|
||||||
|
for _, client in
|
||||||
|
ipairs(clients or vim.lsp.get_clients({
|
||||||
|
bufnr = bufnr,
|
||||||
|
method = method,
|
||||||
|
}))
|
||||||
|
do
|
||||||
|
for id, request in pairs(client.requests) do
|
||||||
|
if
|
||||||
|
(bufnr == nil or bufnr == request.bufnr)
|
||||||
|
and (method == nil or method == request.method)
|
||||||
|
and (type == nil or type == request.type)
|
||||||
|
then
|
||||||
|
client:cancel_request(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---@class (private) vim.lsp.util._refresh.Opts
|
---@class (private) vim.lsp.util._refresh.Opts
|
||||||
---@field bufnr integer? Buffer to refresh (default: 0)
|
---@field bufnr integer? Buffer to refresh (default: 0)
|
||||||
---@field only_visible? boolean Whether to only refresh for the visible regions of the buffer (default: false)
|
---@field only_visible? boolean Whether to only refresh for the visible regions of the buffer (default: false)
|
||||||
@@ -2180,12 +2215,12 @@ function M._refresh(method, opts)
|
|||||||
if api.nvim_win_get_buf(window) == bufnr then
|
if api.nvim_win_get_buf(window) == bufnr then
|
||||||
local first = vim.fn.line('w0', window)
|
local first = vim.fn.line('w0', window)
|
||||||
local last = vim.fn.line('w$', window)
|
local last = vim.fn.line('w$', window)
|
||||||
|
M._cancel_requests({
|
||||||
|
bufnr = bufnr,
|
||||||
|
clients = clients,
|
||||||
|
type = 'pending',
|
||||||
|
})
|
||||||
for _, client in ipairs(clients) do
|
for _, client in ipairs(clients) do
|
||||||
for rid, req in pairs(client.requests) do
|
|
||||||
if req.method == method and req.type == 'pending' and req.bufnr == bufnr then
|
|
||||||
client:cancel_request(rid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
client:request(method, {
|
client:request(method, {
|
||||||
textDocument = textDocument,
|
textDocument = textDocument,
|
||||||
range = make_line_range_params(bufnr, first - 1, last - 1, client.offset_encoding),
|
range = make_line_range_params(bufnr, first - 1, last - 1, client.offset_encoding),
|
||||||
|
Reference in New Issue
Block a user