Skip to content

Commit 0321c5f

Browse files
authored
Refactor throttle messaging (#43)
* Refactor code to improve performance Changed the status line function to just get a buffer variable for the status line and delegate the update of this variable to the lsp_handlers * Implemented a timer base update instead of autocmd Using the libuv loop to schedule a timer base interval to update the statusline. This will schedule the tasks to redraw the statusline every 100ms and if the statusline is different. NOTE: There is an issue with the status text not updating that needs to be fixed * Fixed timer functionality Now the timer function work but the last message is still displayed on the screen. * Cleanup unused variables * Fix missing status update This will redraw one more time after the last LSP update * Fix return value from global to buffer
1 parent 0aaf6a6 commit 0321c5f

File tree

8 files changed

+83
-23
lines changed

8 files changed

+83
-23
lines changed

doc/lsp-status.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ update_current_function() *lsp-status.update_current_function()*
194194
Module: lsp-status.clangd *lsp-status-api-clangd*
195195

196196
setup() *lsp-status.extensions.clangd.setup()*
197-
Return the handler {LSP Method: handler} table for `clangd` 's `fileStatus` extension
197+
Return the handler {LSP Method: handler} table for `clangd` 's
198+
`fileStatus` extension
198199

199200
Return: ~
200201
Table of extension method handlers, to be added to your
@@ -205,7 +206,8 @@ setup() *lsp-status.extensions.clangd.setup()*
205206
Module: lsp-status.pyls_ms *lsp-status-api-pyls_ms*
206207

207208
setup() *lsp-status.extensions.pyls_ms.setup()*
208-
Return the handler {LSP Method: handler} table for `MPLS` 's progress and statusbar message extensions
209+
Return the handler {LSP Method: handler} table for `MPLS` 's
210+
progress and statusbar message extensions
209211

210212
Return: ~
211213
Table of extension method handlers, to be added to your

lua/lsp-status.lua

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
local _config = {}
21
local default_config = {
32
kind_labels = {},
43
current_function = true,
@@ -12,8 +11,8 @@ local default_config = {
1211
status_symbol = ' 🇻',
1312
select_symbol = nil
1413
}
14+
local _config = vim.deepcopy(default_config)
1515

16-
_config = vim.deepcopy(default_config)
1716
local messages = {}
1817

1918
-- Diagnostics
@@ -23,6 +22,7 @@ local messages = {}
2322
local function diagnostics() -- luacheck: no unused
2423
error() -- Stub for docs
2524
end
25+
2626
local diagnostics = require('lsp-status/diagnostics')
2727

2828
-- Messaging
@@ -79,14 +79,6 @@ local function on_attach(client)
7979
-- Register the client for messages
8080
messaging.register_client(client.id, client.name)
8181

82-
-- Set up autocommands to refresh the statusline when information changes
83-
vim.api.nvim_command('augroup lsp_aucmds')
84-
vim.api.nvim_command('au! * <buffer>')
85-
vim.api.nvim_command('au User LspDiagnosticsChanged redrawstatus!')
86-
vim.api.nvim_command('au User LspMessageUpdate redrawstatus!')
87-
vim.api.nvim_command('au User LspStatusUpdate redrawstatus!')
88-
vim.api.nvim_command('augroup END')
89-
9082
-- If the client is a documentSymbolProvider, set up an autocommand
9183
-- to update the containing symbol
9284
if _config.current_function and client.resolved_capabilities.document_symbol then
@@ -96,6 +88,8 @@ local function on_attach(client)
9688
)
9789
vim.api.nvim_command('augroup END')
9890
end
91+
92+
require('lsp-status/timer').register_timer()
9993
end
10094

10195
config(_config)

lua/lsp-status/current_function.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ local function current_function_callback(_, _, result, _, _)
2121
end)
2222

2323
if not function_symbols or #function_symbols == 0 then
24-
vim.api.nvim_command('doautocmd <nomodeline> User LspStatusUpdate')
24+
vim.b.lsp_status_redraw = true
2525
return
2626
end
2727

@@ -38,7 +38,7 @@ local function current_function_callback(_, _, result, _, _)
3838
end
3939

4040
vim.b.lsp_current_function = fn_name
41-
vim.api.nvim_command('doautocmd <nomodeline> User LspStatusUpdate')
41+
vim.b.lsp_status_redraw = true
4242
return
4343
end
4444
end

lua/lsp-status/extensions/clangd.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ local handlers = {
1616
['textDocument/clangd.fileStatus'] = function(_, _, statusMessage, client_id)
1717
ensure_init(client_id)
1818
messages[client_id].status = { uri = statusMessage.uri, content = statusMessage.state }
19-
vim.api.nvim_command('doautocmd <nomodeline> User LspMessageUpdate')
19+
vim.b.lsp_status_redraw = true
2020
end,
2121
}
2222

lua/lsp-status/extensions/pyls_ms.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local util = require('lsp-status/util')
2+
local statusline = require('lsp-status/statusline')
23

34
local messages = {}
45
---@private
@@ -15,7 +16,7 @@ local handlers = {
1516
['python/setStatusBarMessage'] = function(_, _, message, client_id)
1617
ensure_init(client_id)
1718
messages[client_id].static_message = { content = message[1] }
18-
vim.api.nvim_command('doautocmd <nomodeline> User LspMessageUpdate')
19+
vim.b.lsp_status_redraw = true
1920
end,
2021
['python/beginProgress'] = function(_, _, _, client_id)
2122
ensure_init(client_id)
@@ -26,11 +27,11 @@ local handlers = {
2627
['python/reportProgress'] = function(_, _, message, client_id)
2728
messages[client_id].progress[1].spinner = messages[client_id].progress[1].spinner + 1
2829
messages[client_id].progress[1].title = message[1]
29-
vim.api.nvim_command('doautocmd <nomodeline> User LspMessageUpdate')
30+
vim.b.lsp_status_redraw = true
3031
end,
3132
['python/endProgress'] = function(_, _, _, client_id)
3233
messages[client_id].progress[1] = nil
33-
vim.api.nvim_command('doautocmd <nomodeline> User LspMessageUpdate')
34+
vim.b.lsp_status_redraw = true
3435
end,
3536
}
3637

lua/lsp-status/messaging.lua

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ local function progress_callback(_, _, msg, client_id)
4343
table.insert(messages[client_id], {content = val, show_once = true, shown = 0})
4444
end
4545

46-
vim.api.nvim_command('doautocmd <nomodeline> User LspMessageUpdate')
46+
vim.b.lsp_status_redraw = true
4747
end
4848

4949
-- Process messages
@@ -95,7 +95,9 @@ local function get_messages()
9595
return new_messages
9696
end
9797

98-
local function register_progress() vim.lsp.handlers['$/progress'] = progress_callback end
98+
local function register_progress()
99+
vim.lsp.handlers['$/progress'] = progress_callback
100+
end
99101

100102
-- Client registration for messages
101103
local function register_client(id, name)

lua/lsp-status/statusline.lua

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ local function init(_, _config)
3636
_info = make_statusline_component('info')
3737
end
3838

39-
local function statusline_lsp(bufnr)
39+
local function get_lsp_statusline(bufnr)
4040
bufnr = bufnr or 0
4141
if #vim.lsp.buf_get_clients(bufnr) == 0 then
4242
return ''
@@ -74,7 +74,7 @@ local function statusline_lsp(bufnr)
7474
for _, msg in ipairs(buf_messages) do
7575
local name = aliases[msg.name] or msg.name
7676
local client_name = '[' .. name .. ']'
77-
local contents = ''
77+
local contents
7878
if msg.progress then
7979
contents = msg.title
8080
if msg.message then
@@ -132,9 +132,15 @@ local function get_component_functions()
132132
}
133133
end
134134

135+
-- Status line component for nvim-lsp
136+
local function lsp_status()
137+
return vim.b.lsp_status_statusline or ''
138+
end
139+
135140
local M = {
136141
_init = init,
137-
status = statusline_lsp,
142+
status = lsp_status,
143+
get_lsp_statusline = get_lsp_statusline,
138144
_get_component_functions = get_component_functions
139145
}
140146

lua/lsp-status/timer.lua

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--- Timer instance
2+
local timer = nil
3+
--- This flag is used to redraw one more time after the las LSP update.
4+
-- NOTE: This is achieved by setting the redraw_flag to true if
5+
-- vim.b.lsp_status_redraw is true and there has been an update. Next time if
6+
-- vim.b.lsp_status_redraw is false (no update) it will still redraw the
7+
-- statusline and this flag will be set to false.
8+
local redraw_flag = false
9+
10+
--- Timer callback function
11+
-- NOTE: This function uses get_lsp_statusline so that needs nvim api functions
12+
-- so it should call in the vim.schedule_wrap()
13+
local function timer_callback()
14+
-- Check if need to redraw
15+
local update_flag = vim.b.lsp_status_redraw
16+
if update_flag or redraw_flag then
17+
vim.b.lsp_status_redraw = false
18+
-- Schedule the command when it's safe to call it
19+
local new_state = require('lsp-status/statusline').get_lsp_statusline()
20+
if new_state ~= vim.b.lsp_status_statusline then
21+
vim.b.lsp_status_statusline = new_state
22+
vim.api.nvim_command('redrawstatus!')
23+
-- If this was an lsp update (update_flag is true) redraw also next time
24+
-- by setting redraw_flag
25+
redraw_flag = update_flag
26+
end
27+
end
28+
end
29+
30+
--- Function to register a timer to update statusline
31+
-- This function is called on attach of a LSP Server and will pull updates for
32+
-- status line on a specific every interval of time. It will also schedule the
33+
-- redraw of the status line on the main loop. This will reduce the lag for
34+
-- servers that constantly update the messages like `rust-analyzer`. It will
35+
-- set use the variable timer to schedule the updates.
36+
-- TODO: This could error if the lsp is disconnected, the timer should be
37+
-- stopped
38+
local function register_timer()
39+
-- Guard the for an already defined timer
40+
if timer ~= nil then
41+
return
42+
end
43+
timer = vim.loop.new_timer()
44+
-- Execute the timer every 100 milliseconds
45+
-- NOTE: This could be 30 to get a 30 updates per seconds, but set to 100 to
46+
-- copy coc.nvim status interval
47+
timer:start(0, 100, vim.schedule_wrap(timer_callback))
48+
end
49+
50+
local M = {
51+
timer = timer,
52+
register_timer = register_timer,
53+
}
54+
55+
return M

0 commit comments

Comments
 (0)