diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 9f78179c61..ef6adb92d2 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -168,6 +168,8 @@ PERFORMANCE functions, which skips the Vimscript <=> Lua "bridge" (no data conversion/marshalling) entirely, if the `vim.fn` function is called from Lua. +• The table holding LSP data is now cleared using `table.clear`, + thus reducing GC and memory reallocation during each data reset. PLUGINS diff --git a/runtime/lua/vim/_core/table.lua b/runtime/lua/vim/_core/table.lua new file mode 100644 index 0000000000..58833b1c8d --- /dev/null +++ b/runtime/lua/vim/_core/table.lua @@ -0,0 +1,27 @@ +-- Basic shim for LuaJIT's table.new and table.clear. +local has_new, new = pcall(require, 'table.new') +local has_clear, clear = pcall(require, 'table.clear') + +local M = {} + +if not has_new then + ---@diagnostic disable-next-line: unused-local + new = function(narr, nrec) + return {} + end +end + +if not has_clear then + clear = function(tab) + ---@diagnostic disable-next-line: no-unknown + for k in pairs(tab) do + ---@diagnostic disable-next-line: no-unknown + tab[k] = nil + end + end +end + +M.new = new +M.clear = clear + +return M diff --git a/runtime/lua/vim/lsp/_folding_range.lua b/runtime/lua/vim/lsp/_folding_range.lua index e7ceee95db..b35fdfb1ea 100644 --- a/runtime/lua/vim/lsp/_folding_range.lua +++ b/runtime/lua/vim/lsp/_folding_range.lua @@ -1,5 +1,6 @@ local util = require('vim.lsp.util') local log = require('vim.lsp.log') +local tableclear = require('vim._core.table').clear local api = vim.api ---@type table @@ -51,12 +52,13 @@ Capability.all[State.name] = State --- Re-evaluate the cached foldinfo in the buffer. function State:evaluate() - ---@type table" | "<"?]?> - local row_level = {} - ---@type table?>> - local row_kinds = {} - ---@type table - local row_text = {} + local row_level, row_kinds, row_text, row_virt_text = + self.row_level, self.row_kinds, self.row_text, self.row_virt_text + + tableclear(row_level) + tableclear(row_kinds) + tableclear(row_text) + tableclear(row_virt_text) for client_id, ranges in pairs(self.client_state) do for _, range in ipairs(ranges) do @@ -88,11 +90,6 @@ function State:evaluate() end end end - - self.row_level = row_level - self.row_kinds = row_kinds - self.row_text = row_text - self.row_virt_text = {} end --- Force `foldexpr()` to be re-evaluated, without opening folds. @@ -190,10 +187,10 @@ end function State:reset() self.lang = vim.treesitter.language.get_lang(vim.bo[self.bufnr].filetype) - self.row_level = {} - self.row_kinds = {} - self.row_text = {} - self.row_virt_text = {} + tableclear(self.row_level) + tableclear(self.row_kinds) + tableclear(self.row_text) + tableclear(self.row_virt_text) end --- Initialize `state` and event hooks, then request folding ranges. @@ -201,7 +198,11 @@ end ---@return vim.lsp.folding_range.State function State:new(bufnr) self = Capability.new(self, bufnr) - self:reset() + self.lang = vim.treesitter.language.get_lang(vim.bo[self.bufnr].filetype) + self.row_level = {} + self.row_kinds = {} + self.row_text = {} + self.row_virt_text = {} api.nvim_buf_attach(bufnr, false, { -- Reset `bufstate` and request folding ranges. diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 07212e6554..1846d0f752 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -1,5 +1,6 @@ local util = require('vim.lsp.util') local log = require('vim.lsp.log') +local tableclear = require('vim._core.table').clear local api = vim.api local M = {} @@ -99,10 +100,10 @@ end function Provider:clear() self:reset_timer() self.version = nil - self.row_version = {} + tableclear(self.row_version) for _, state in pairs(self.client_state) do - state.row_lenses = {} + tableclear(state.row_lenses) api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1) end @@ -130,8 +131,8 @@ function Provider:handler(err, result, ctx) return end - ---@type table - local row_lenses = {} + local row_lenses = state.row_lenses + tableclear(row_lenses) -- Code lenses should only span a single line. for _, lens in ipairs(result or {}) do @@ -140,8 +141,6 @@ function Provider:handler(err, result, ctx) table.insert(lenses, lens) row_lenses[row] = lenses end - - state.row_lenses = row_lenses self.version = ctx.version api.nvim__redraw({ buf = self.bufnr, valid = true, flush = false }) @@ -516,7 +515,7 @@ function M.on_refresh(err, _, ctx) if not provider.timer then provider:request(client_id, function() if api.nvim_buf_is_valid(bufnr) then - provider.row_version = {} + tableclear(provider.row_version) vim.api.nvim__redraw({ buf = bufnr, valid = true, flush = false }) end end) diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index e95fe80343..b800aa5bf8 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -233,6 +233,7 @@ describe('vim._core', function() 'vim._core.shared', 'vim._core.stringbuffer', 'vim._core.system', + 'vim._core.table', 'vim._core.ui2', 'vim._core.util', 'vim._core.vimfn',