This commit is contained in:
Mathias Fußenegger 2024-09-11 09:34:36 +02:00 committed by GitHub
commit 5840d7cb39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 124 additions and 27 deletions

View File

@ -38,7 +38,7 @@ local M = {}
--- @field refs integer how many clients are using this group
---
--- @class vim.lsp.CTGroupState
--- @field buffers table<integer,vim.lsp.CTBufferState>
--- @field buffers vim.Buflocal
--- @field debounce integer debounce duration in ms
--- @field clients table<integer, table> clients using this state. {client_id, client}
@ -138,7 +138,20 @@ function M.init(client, bufnr)
state.clients[client.id] = client
else
state = {
buffers = {},
buffers = vim.buflocal(function(b)
local bufstate = {
name = api.nvim_buf_get_name(b),
lines = {},
lines_tmp = {},
pending_changes = {},
needs_flush = false,
refs = 0,
}
if group.sync_kind == protocol.TextDocumentSyncKind.Incremental then
bufstate.lines = api.nvim_buf_get_lines(b, 0, -1, true)
end
return bufstate
end),
debounce = client.flags.debounce_text_changes or 150,
clients = {
[client.id] = client,
@ -146,23 +159,8 @@ function M.init(client, bufnr)
}
state_by_group[group] = state
end
local buf_state = state.buffers[bufnr]
if buf_state then
buf_state.refs = buf_state.refs + 1
else
buf_state = {
name = api.nvim_buf_get_name(bufnr),
lines = {},
lines_tmp = {},
pending_changes = {},
needs_flush = false,
refs = 1,
}
state.buffers[bufnr] = buf_state
if group.sync_kind == protocol.TextDocumentSyncKind.Incremental then
buf_state.lines = api.nvim_buf_get_lines(bufnr, 0, -1, true)
end
end
local buf_state = state.buffers:get(bufnr)
buf_state.refs = buf_state.refs + 1
end
--- @param client vim.lsp.Client
@ -171,7 +169,7 @@ end
--- @return string
function M._get_and_set_name(client, bufnr, name)
local state = state_by_group[get_group(client)] or {}
local buf_state = (state.buffers or {})[bufnr]
local buf_state = state.buffers:get(bufnr)
local old_name = buf_state.name
buf_state.name = name
return old_name
@ -198,11 +196,11 @@ function M.reset_buf(client, bufnr)
return
end
assert(state.buffers, 'CTGroupState must have buffers')
local buf_state = state.buffers[bufnr]
local buf_state = state.buffers:get(bufnr)
buf_state.refs = buf_state.refs - 1
assert(buf_state.refs >= 0, 'refcount on buffer state must not get negative')
if buf_state.refs == 0 then
state.buffers[bufnr] = nil
state.buffers:clear(bufnr)
reset_timer(buf_state)
end
end
@ -215,10 +213,10 @@ function M.reset(client)
end
state.clients[client.id] = nil
if vim.tbl_count(state.clients) == 0 then
for _, buf_state in pairs(state.buffers) do
for _, buf_state in state.buffers:pairs() do
reset_timer(buf_state)
end
state.buffers = {}
state.buffers:clear()
end
end
@ -301,7 +299,7 @@ local function send_changes_for_group(bufnr, firstline, lastline, new_lastline,
)
)
end
local buf_state = state.buffers[bufnr]
local buf_state = state.buffers:get(bufnr)
buf_state.needs_flush = true
reset_timer(buf_state)
local debounce = next_debounce(state.debounce, buf_state)
@ -359,11 +357,11 @@ function M.flush(client, bufnr)
return
end
if bufnr then
local buf_state = state.buffers[bufnr] or {}
local buf_state = state.buffers:get(bufnr)
reset_timer(buf_state)
send_changes(bufnr, group.sync_kind, state, buf_state)
else
for buf, buf_state in pairs(state.buffers) do
for buf, buf_state in state.buffers:pairs() do
reset_timer(buf_state)
send_changes(buf, group.sync_kind, state, buf_state)
end

View File

@ -1137,6 +1137,73 @@ do
end
end
do
---@class vim.Buflocal<T>
---@field private _values table<integer, any>
---@field private _default any|fun(b: integer):any
---@class vim.Buflocal<T>
local Buflocal = {}
local buflocal_mt = {
__index = Buflocal,
}
---@generic T : any
---@param bufnr integer
---@return T
function Buflocal:get(bufnr)
bufnr = assert(bufnr) == 0 and vim.api.nvim_get_current_buf() or bufnr
local value = self._values[bufnr]
if not value then
if type(self._default) == "function" then
value = self._default(bufnr)
else
value = self._default or {}
end
self._values[bufnr] = value
vim.api.nvim_buf_attach(bufnr, false, {
on_detach = function(_, b)
self._values[b] = nil
end,
})
vim.api.nvim_create_autocmd("BufWipeout", {
buffer = bufnr,
callback = function(args)
self._values[args.buf] = nil
end
})
end
return value
end
function Buflocal:pairs()
return pairs(self._values)
end
---@param bufnr integer?
function Buflocal:clear(bufnr)
if bufnr == nil then
self._values = {}
else
self._values[bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr] = nil
end
end
---@generic T
---@param default? T|fun(b: integer):T
---@return vim.Buflocal
function vim.buflocal(default)
local state = {
_values = {},
_default = default,
}
return setmetatable(state, buflocal_mt)
end
end
--- @private
--- @generic T
--- @param root string

View File

@ -3977,6 +3977,38 @@ describe('lua stdlib', function()
}
eq(expected, results)
end)
it("vim.buflocal", function()
local result = exec_lua([[
local buflocal = vim.buflocal()
local buf1 = vim.api.nvim_create_buf(true, true)
local buf2 = vim.api.nvim_create_buf(true, true)
local state1 = buflocal:get(buf1)
state1.x = 10
local state2 = buflocal:get(buf2)
state2.x = 20
local results = {}
results.values = {}
results.x1 = buflocal:get(buf1).x
results.x2 = buflocal:get(buf2).x
for _, value in buflocal:pairs() do
table.insert(results.values, value)
end
vim.api.nvim_buf_delete(buf1, { force = true })
local ok, err = pcall(buflocal.get, buflocal, buf1)
results.deleted_buf = {ok, err}
return results
]])
eq(10, result.x1)
eq(20, result.x2)
eq(false, result.deleted_buf[1])
eq(true, vim.startswith(result.deleted_buf[2], "vim/shared.lua:0: Invalid buffer id: "))
end)
end)
describe('lua: builtin modules', function()