diff options
Diffstat (limited to 'runtime/lua/vim/lsp.lua')
-rw-r--r-- | runtime/lua/vim/lsp.lua | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 7df0064b6b..fc9c991c05 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,8 +413,12 @@ do return end local state = state_by_client[client.id] - local debounce = client.config.flags.debounce_text_changes or 150 + changetracking._reset_timer(state) + local debounce = next_debounce(client.config.flags.debounce_text_changes or 150, state, bufnr) if debounce == 0 then + if state.pending_change then + state.pending_change() + end local changes = state.use_incremental_sync and incremental_changes(client) or full_changes() client.notify("textDocument/didChange", { textDocument = { @@ -395,7 +429,6 @@ do }) return end - changetracking._reset_timer(state) if state.use_incremental_sync then -- This must be done immediately and cannot be delayed -- The contents would further change and startline/endline may no longer fit @@ -406,6 +439,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 |