Skip to content

Commit 55dc87d

Browse files
committed
feat(statusline): Added progress component
1 parent b498c72 commit 55dc87d

File tree

3 files changed

+208
-7
lines changed

3 files changed

+208
-7
lines changed

lua/bars/components/statusline.lua

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
---@diagnostic disable: undefined-field
2+
13
local slC = {};
24
local utils = require("bars.utils");
35

@@ -244,6 +246,7 @@ slC.diagnostics = function (buffer, window, config)
244246
config = config or {};
245247

246248
local diagnostics_count = vim.diagnostic.count(buffer);
249+
---@diagnostic disable-next-line: deprecated
247250
local clients = vim.fn.has("nvim-0.11") == 1 and vim.lsp.get_clients({ bufnr = buffer }) or vim.lsp.buf_get_clients(buffer);
248251

249252
if #clients == 0 and config.auto_hide == true then
@@ -490,6 +493,104 @@ slC.macro = function (_, _, config)
490493
---|fE
491494
end
492495

496+
--- Ruler.
497+
---@param buffer integer
498+
---@param window integer
499+
---@param config statusline.components.progress
500+
---@return string?
501+
slC.progress = function (buffer, window, config)
502+
---|fS
503+
504+
---@type "start" | "progress" | "finish", "buffer" | "window"
505+
local state, src;
506+
local state_var = config.check or "progress_state";
507+
508+
if vim.w[window][state_var] then
509+
state = vim.w[window][state_var];
510+
src = "window";
511+
elseif vim.b[buffer][state_var] then
512+
state = vim.b[buffer][state_var];
513+
src = "buffer";
514+
else
515+
return;
516+
end
517+
518+
---@type "start" | "progress" | "finish", "buffer" | "window"
519+
local last_frame = src == "buffer" and vim.b[buffer].__loader_last_frame or vim.w[window].__loader_last_frame;
520+
last_frame = last_frame or 1;
521+
522+
---@type integer
523+
local last_tick = src == "buffer" and vim.b[buffer].__loader_last_tick or vim.w[window].__loader_last_tick;
524+
local now = vim.uv.hrtime() / 1e6; ---@diagnostic disable-line
525+
526+
--- Gets progress-bar state
527+
---@param from? string[]
528+
---@return string?
529+
local function get_state (from)
530+
---|fS
531+
532+
if not from or not vim.islist(from) then
533+
return;
534+
end
535+
536+
return from[last_frame] or from[#from] or "";
537+
538+
---|fE
539+
end
540+
541+
--- Updates frame count.
542+
---@param max integer
543+
local function update_frame (max)
544+
---|fS
545+
546+
if last_tick and now - last_tick < (config.update_delay or 250) then
547+
-- Not enough time has passed.
548+
return;
549+
end
550+
551+
if src == "buffer" then
552+
vim.b[buffer].__loader_last_tick = now;
553+
vim.b[buffer].__loader_last_frame = last_frame + 1 > max and 1 or last_frame + 1;
554+
else
555+
vim.w[window].__loader_last_tick = now;
556+
vim.w[window].__loader_last_frame = last_frame + 1 > max and 1 or last_frame + 1;
557+
end
558+
559+
---|fE
560+
end
561+
562+
local text, hl;
563+
564+
if state == "start" and config.start then
565+
text = config.start;
566+
hl = config.start_hl;
567+
568+
update_frame(1);
569+
elseif state == "progress" then
570+
text = get_state(config.progress);
571+
hl = get_state(config.progress_hl);
572+
573+
update_frame(
574+
vim.islist(config.progress) and #config.progress or 1
575+
);
576+
else
577+
text = config.finish;
578+
hl = config.finish_hl;
579+
580+
update_frame(1);
581+
end
582+
583+
local output = text or "";
584+
585+
if type(hl) == "string" then
586+
output = string.format("%%#%s#", hl) .. output;
587+
end
588+
589+
return output;
590+
591+
---|fE
592+
end
593+
493594
--- Custom section.
494595
---@param config statusline.components.custom
495596
---@return string

lua/definitions/statusline.lua

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,26 @@
443443
--- Highlight group for exec icon.
444444
---@field exec_hl? string
445445

446+
-----------------------------------------------------------------------------
447+
448+
---@class statusline.components.progress
449+
---
450+
--- Optional condition for this component.
451+
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
452+
---
453+
--- What kind of component is this?
454+
---@field kind "progress"
455+
---
456+
---@field check? string The variable that holds the progress state, default is "progress_state".
457+
---
458+
---@field finish string Text used as the indicator for progress finish.
459+
---@field finish_hl string Highlight group for the progress finish indicator.
460+
---
461+
---@field progress string[] Text used as the indicator for progress.
462+
---@field progress_hl string[] Highlight group for the progress indicator.
463+
---
464+
---@field start string Text used as the indicator for progress start.
465+
---@field start_hl string Highlight group for the progress start indicator.
466+
---
467+
---@field update_delay? integer Delay in milliseconds between state updates.
468+

plugin/bars.lua

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
---@diagnostic disable: undefined-field
2+
13
--- Update the tab list when opening new windows.
24
vim.api.nvim_create_autocmd({ "VimEnter" }, {
35
callback = function ()
@@ -180,17 +182,14 @@ vim.api.nvim_create_autocmd({ "ColorScheme" }, {
180182
end
181183
});
182184

183-
184-
-- ----------------------------------------------------------------------
185+
----------------------------------------------------------------------
185186

186187
--- Custom completion for the `?` operator.
187188
---@param before string
188189
---@return string[]
189190
_G.__bars_comp = function (before)
190191
---|fS
191192

192-
local bars = require("bars");
193-
194193
local tokens = vim.split(before, " ", { trimempty = true });
195194
local modules = { "statusline", "statuscolumn", "tabline", "winbar" };
196195
local _c = {};
@@ -318,9 +317,9 @@ end, {
318317
return vim.list_contains(tokens, tostring(val)) == false and string.match(tostring(val), arg_lead) ~= nil;
319318
end, vim.tbl_keys(module.state.attached_windows));
320319

321-
table.foreach(_c, function (key, value)
322-
_c[key] = tostring(value);
323-
end)
320+
for k, v in pairs(_c) do
321+
_c[k] = tostring(v);
322+
end
324323

325324
table.sort(_c);
326325
return _c;
@@ -330,3 +329,81 @@ end, {
330329
end
331330
});
332331

332+
----------------------------------------------------------------------
333+
334+
vim.api.nvim_create_autocmd("LspProgress", {
335+
callback = function (event)
336+
---|fS
337+
338+
local kind = event.data.params.value.kind;
339+
local attached = vim.lsp.get_buffers_by_client_id(event.data.client_id);
340+
341+
--- Sets buffer state
342+
---@param state "start" | "progress" | "finish" | nil
343+
local function set_state (state)
344+
---|fS
345+
346+
for _, buf in ipairs(attached) do
347+
vim.b[buf].lsp_loader_state = state;
348+
end
349+
350+
---|fE
351+
end
352+
353+
--- Gets the general state.
354+
---@return "start" | "progress" | "finish" | nil
355+
local function get_state ()
356+
---|fS
357+
358+
local states = {};
359+
360+
for _, buf in ipairs(attached) do
361+
table.insert(states, vim.b[buf].lsp_loader_state);
362+
end
363+
364+
local state = states[1];
365+
366+
for _, item in ipairs(states) do
367+
if item ~= state then
368+
return nil;
369+
end
370+
end
371+
372+
return state;
373+
374+
---|fE
375+
end
376+
377+
if kind == "begin" then
378+
set_state("start");
379+
380+
local lsp_timer = vim.uv.new_timer();
381+
382+
lsp_timer:start(0, 200, vim.schedule_wrap(function ()
383+
if get_state() == nil then
384+
timer:stop();
385+
return;
386+
end
387+
388+
vim.api.nvim__redraw({ statusline = true });
389+
end));
390+
391+
vim.api.nvim__redraw({ statusline = true });
392+
elseif kind == "report" then
393+
set_state("progress");
394+
else
395+
set_state("finish");
396+
397+
vim.defer_fn(function ()
398+
if get_state() == "finish" then
399+
set_state(nil);
400+
end
401+
402+
vim.api.nvim__redraw({ statusline = true });
403+
end, 500);
404+
end
405+
406+
---|fE
407+
end
408+
});
409+

0 commit comments

Comments
 (0)