aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp.lua
diff options
context:
space:
mode:
authorMathias Fußenegger <mfussenegger@users.noreply.github.com>2022-01-07 11:56:09 +0100
committerGitHub <noreply@github.com>2022-01-07 11:56:09 +0100
commitb680392687eeaee521b19d79a1e7effdc2dc1ed7 (patch)
tree03789e77eadb18e53a4a02a8887db292f31518e4 /runtime/lua/vim/lsp.lua
parentbba679c431069396ad28952620316e1f1fd97945 (diff)
downloadrneovim-b680392687eeaee521b19d79a1e7effdc2dc1ed7.tar.gz
rneovim-b680392687eeaee521b19d79a1e7effdc2dc1ed7.tar.bz2
rneovim-b680392687eeaee521b19d79a1e7effdc2dc1ed7.zip
feat(lsp): skip or reduce debounce after idle (#16881)
The idea of the debounce is to avoid overloading a server with didChange notifications. So far this used a constant value to group changes within an interval together and send a single notification. A side effect of this is that when you were idle, notifications are still delayed. This commit changes the logic to take the time the last notification happened into consideration, if it has been greater than the debounce interval, the debouncing is skipped or at least reduced.
Diffstat (limited to 'runtime/lua/vim/lsp.lua')
-rw-r--r--runtime/lua/vim/lsp.lua39
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