diff options
-rw-r--r-- | runtime/lua/vim/lsp.lua | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 7df0064b6b..fb08e54dfc 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -306,7 +306,6 @@ local function once(fn) end end - local changetracking = {} do --@private @@ -327,6 +326,7 @@ do if not state then state = { pending_changes = {}; + last_flush = {}; use_incremental_sync = ( if_nil(client.config.flags.allow_incremental_sync, true) and client.resolved_capabilities.text_document_did_change == protocol.TextDocumentSyncKind.Incremental @@ -347,8 +347,11 @@ do function changetracking.reset_buf(client, bufnr) changetracking.flush(client) local state = state_by_client[client.id] - if state and state.buffers then - state.buffers[bufnr] = nil + if state then + if state.buffers then + state.buffers[bufnr] = nil + end + state.last_flush = {} end end @@ -362,6 +365,33 @@ do end ---@private + -- + -- Adjust debounce time by taking time of last didChange notification into + -- consideration. If the last didChange happened more than `debounce` time ago, + -- debounce can be skipped and otherwise maybe reduced. + -- + -- This turns the debounce into a kind of client rate limiting + local function next_debounce(debounce, state, bufnr) + if debounce == 0 then + return 0 + end + local ns_to_ms = 0.000001 + local last_flush = state.last_flush[bufnr] + if not last_flush then + return debounce + end + local now = uv.hrtime() + local ms_since_last_flush = (now - last_flush) * ns_to_ms + local remaining_debounce = debounce - ms_since_last_flush + if remaining_debounce > 0 then + return remaining_debounce + else + state.last_flush[bufnr] = now + return 0 + end + end + + ---@private function changetracking.prepare(bufnr, firstline, lastline, new_lastline) local incremental_changes = function(client) local cached_buffers = state_by_client[client.id].buffers @@ -383,7 +413,7 @@ do return end local state = state_by_client[client.id] - local debounce = client.config.flags.debounce_text_changes or 150 + local debounce = next_debounce(client.config.flags.debounce_text_changes or 150, state, bufnr) if debounce == 0 then local changes = state.use_incremental_sync and incremental_changes(client) or full_changes() client.notify("textDocument/didChange", { @@ -406,6 +436,7 @@ do end state.pending_change = function() state.pending_change = nil + state.last_flush[bufnr] = uv.hrtime() if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then return end |