commit 5973328edaedb04425e2f6cb63b2efab4aeb5fcb
parent 6fd2a3040f7d6b522d403b66ad34e0710235052a
Author: Shadman <shadmansaleh3@gmail.com>
Date: Mon, 7 Jul 2025 05:17:06 +0600
feat(options): per-buffer 'busy' status #34493
Problem:
Plugins cannot mark a buffer as "busy".
Solution:
- Add a buffer-local 'busy' option.
- Show a busy indicator in the default 'statusline'.
Diffstat:
10 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
@@ -224,6 +224,7 @@ OPTIONS
• 'pummaxwidth' sets maximum width for the completion popup menu.
• 'winborder' "bold" style.
• |g:clipboard| accepts a string name to force any builtin clipboard tool.
+• 'busy' sets a buffer "busy" status. Indicated in the default statusline.
PERFORMANCE
@@ -265,6 +266,7 @@ UI
• Error messages are more concise:
• "Error detected while processing:" changed to "Error in:".
• "Error executing Lua:" changed to "Lua:".
+• 'busy' status is shown in default statusline with symbol ◐
VIMSCRIPT
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
@@ -1217,6 +1217,13 @@ A jump table for the options with a short description can be found at |Q_op|.
without saving. For writing there must be matching |BufWriteCmd|,
|FileWriteCmd| or |FileAppendCmd| autocommands.
+ *'busy'*
+'busy' number (default 0)
+ local to buffer
+ Sets a buffer "busy" status. Indicated in the default statusline.
+ When busy status is larger then 0 busy flag is shown in statusline.
+ The semantics of "busy" are arbitrary, typically decided by the plugin that owns the buffer.
+
*'casemap'* *'cmp'*
'casemap' 'cmp' string (default "internal,keepascii")
global
@@ -6184,7 +6191,7 @@ A jump table for the options with a short description can be found at |Q_op|.
an expensive expression can negatively affect render performance.
*'statusline'* *'stl'* *E540* *E542*
-'statusline' 'stl' string (default "%<%f %h%w%m%r %=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}")
+'statusline' 'stl' string (default "%<%f %h%w%m%r %=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &busy > 0 ? '◐ ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}")
global or local to window |global-local|
Sets the |status-line|.
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
@@ -404,6 +404,7 @@ Options:
- 'ttimeout', 'ttimeoutlen' behavior was simplified
- 'winblend' pseudo-transparency in floating windows |api-floatwin|
- 'winhighlight' window-local highlights
+- 'busy' busy status for buffers
Performance:
- Signs are implemented using Nvim's internal "marktree" (btree) structure.
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
@@ -664,6 +664,14 @@ vim.o.bt = vim.o.buftype
vim.bo.buftype = vim.o.buftype
vim.bo.bt = vim.bo.buftype
+--- Sets a buffer "busy" status. Indicated in the default statusline.
+--- When busy status is larger then 0 busy flag is shown in statusline.
+--- The semantics of "busy" are arbitrary, typically decided by the plugin that owns the buffer.
+---
+--- @type integer
+vim.o.busy = 0
+vim.bo.busy = vim.o.busy
+
--- Specifies details about changing the case of letters. It may contain
--- these words, separated by a comma:
--- internal Use internal case mapping functions, the current
@@ -6853,7 +6861,7 @@ vim.wo.stc = vim.wo.statuscolumn
---
---
--- @type string
-vim.o.statusline = "%<%f %h%w%m%r %=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}"
+vim.o.statusline = "%<%f %h%w%m%r %=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &busy > 0 ? '◐ ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}"
vim.o.stl = vim.o.statusline
vim.wo.statusline = vim.o.statusline
vim.wo.stl = vim.wo.statusline
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
@@ -12,6 +12,7 @@
#include "nvim/option_defs.h"
#include "nvim/os/fs_defs.h"
#include "nvim/statusline_defs.h"
+#include "nvim/types_defs.h"
#include "nvim/undo_defs.h"
/// Reference to a buffer that stores the value of buf_free_count.
@@ -522,6 +523,7 @@ struct file_buffer {
int b_p_bomb; ///< 'bomb'
char *b_p_bh; ///< 'bufhidden'
char *b_p_bt; ///< 'buftype'
+ OptInt b_p_busy; ///< 'busy'
int b_has_qf_entry; ///< quickfix exists for buffer
int b_p_bl; ///< 'buflisted'
OptInt b_p_channel; ///< 'channel'
diff --git a/src/nvim/option.c b/src/nvim/option.c
@@ -4681,6 +4681,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
return &(buf->b_p_bt);
case kOptBuflisted:
return &(buf->b_p_bl);
+ case kOptBusy:
+ return &(buf->b_p_busy);
case kOptChannel:
return &(buf->b_p_channel);
case kOptCopyindent:
diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h
@@ -280,6 +280,7 @@ EXTERN char *p_bsk; ///< 'backupskip'
EXTERN char *p_breakat; ///< 'breakat'
EXTERN char *p_bh; ///< 'bufhidden'
EXTERN char *p_bt; ///< 'buftype'
+EXTERN OptInt p_busy; ///< 'busy'
EXTERN char *p_cmp; ///< 'casemap'
EXTERN unsigned cmp_flags;
EXTERN char *p_enc; ///< 'encoding'
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
@@ -951,6 +951,21 @@ local options = {
varname = 'p_bt',
},
{
+ defaults = 0,
+ desc = [=[
+ Sets a buffer "busy" status. Indicated in the default statusline.
+ When busy status is larger then 0 busy flag is shown in statusline.
+ The semantics of "busy" are arbitrary, typically decided by the plugin that owns the buffer.
+ ]=],
+ full_name = 'busy',
+ redraw = { 'statuslines' },
+ noglob = true,
+ scope = { 'buf' },
+ short_desc = N_('buffer is busy'),
+ type = 'number',
+ varname = 'p_busy',
+ },
+ {
abbreviation = 'cmp',
defaults = 'internal,keepascii',
values = { 'internal', 'keepascii' },
@@ -8640,6 +8655,7 @@ local options = {
'%=',
"%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}",
"%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}",
+ "%{% &busy > 0 ? '◐ ' : '' %}",
"%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}",
}),
desc = [=[
diff --git a/test/functional/legacy/autocmd_option_spec.lua b/test/functional/legacy/autocmd_option_spec.lua
@@ -355,8 +355,7 @@ describe('au OptionSet', function()
it('with string global-local (to window) option', function()
local oldval = eval('&statusline')
- local default_statusline =
- "%<%f %h%w%m%r %=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}"
+ local default_statusline = api.nvim_get_option_info2('statusline', {}).default
command('set statusline=foo')
expected_combination({
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
@@ -785,8 +785,15 @@ describe('default statusline', function()
exec_lua("vim.o.statusline = 'asdf'")
eq('asdf', eval('&statusline'))
- local default_statusline =
- "%<%f %h%w%m%r %=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}"
+ local default_statusline = table.concat({
+ '%<',
+ '%f %h%w%m%r ',
+ '%=',
+ "%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}",
+ "%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}",
+ "%{% &busy > 0 ? '◐ ' : '' %}",
+ "%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}",
+ })
exec_lua("vim.o.statusline = ''")
@@ -799,4 +806,30 @@ describe('default statusline', function()
|
]])
end)
+
+ it('shows busy status when buffer is set to be busy', function()
+ exec_lua("vim.o.statusline = ''")
+
+ screen:expect([[
+ ^ |
+ {1:~ }|*13
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]])
+ exec_lua('vim.o.busy = 1')
+ screen:expect([[
+ ^ |
+ {1:~ }|*13
+ {3:[No Name] ◐ 0,0-1 All}|
+ |
+ ]])
+
+ exec_lua('vim.o.busy = 0')
+ screen:expect([[
+ ^ |
+ {1:~ }|*13
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]])
+ end)
end)