fix(progress): require "source" for progress-message #38514

Problem:
- Progress-events are filtered by "source". But "source" is not required by nvim_echo.
- Without "++nested" (force=false), nvim_echo in an event-handler does not trigger Progress events.
- vim.health does not declare a "source".

Solution:
- Make source mandatory for progress-messages
- Enable ++nested (force=true) by default when firing Progress event.
- Set "source" in vim.health module.
This commit is contained in:
Shadman
2026-03-28 19:22:22 +06:00
committed by GitHub
parent 5a7df03b42
commit 7bf83cc2a6
6 changed files with 128 additions and 80 deletions

View File

@@ -717,8 +717,9 @@ LspProgress *LspProgress*
vim.api.nvim_create_autocmd('LspProgress', { buffer = buf, callback = function(ev)
local value = ev.data.params.value
vim.api.nvim_echo({ { value.message or 'done' } }, false, {
id = 'lsp',
id = ev.data.id,
kind = 'progress',
source = 'vim.lsp',
title = value.title,
status = value.kind ~= 'end' and 'running' or 'success',
percent = value.percentage,

View File

@@ -375,7 +375,7 @@ end
---@param len integer
---@return fun(status: 'success'|'running', idx: integer, fmt: string, ...: any): nil
local function progress_report(len)
local progress = { kind = 'progress', title = 'checkhealth' }
local progress = { kind = 'progress', source = 'vim.health', title = 'checkhealth' }
return function(status, idx, fmt, ...)
progress.status = status

View File

@@ -870,6 +870,10 @@ Union(Integer, String) nvim_echo(ArrayOf(Tuple(String, *HLGroupID)) chunks, Bool
goto error;
});
VALIDATE_R((!is_progress || opts->source.size != 0), "opts.source", {
goto error;
});
// Message-id may be user-defined only if String, not Integer.
VALIDATE(opts->id.type != kObjectTypeInteger || msg_id_exists(opts->id.data.integer),
"Invalid 'id': %" PRId64, opts->id.data.integer, {

View File

@@ -1153,7 +1153,7 @@ void do_autocmd_progress(MsgID msg_id, HlMessage msg, MessageData *msg_data)
apply_autocmds_group(EVENT_PROGRESS,
(msg_data && msg_data->source.size > 0) ? msg_data->source.data : "", NULL,
false,
true,
AUGROUP_ALL, NULL, NULL, &DICT_OBJ(data));
kv_destroy(messages);
}

View File

@@ -3378,11 +3378,14 @@ describe('progress-message', function()
}, 'progress autocmd receives progress messages')
-- can update progress messages
api.nvim_echo(
{ { 'test-message-updated' } },
true,
{ id = id, kind = 'progress', title = 'TestSuit', percent = 50, status = 'running' }
)
api.nvim_echo({ { 'test-message-updated' } }, true, {
id = id,
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 50,
status = 'running',
})
screen:expect({
grid = [[
^ |
@@ -3406,7 +3409,7 @@ describe('progress-message', function()
assert_progress_autocmd({
text = { 'test-message-updated' },
percent = 50,
source = '',
source = 'tests',
status = 'running',
title = 'TestSuit',
id = 1,
@@ -3417,7 +3420,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message (success)' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 100, status = 'success' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 100, status = 'success' }
)
screen:expect({
grid = [[
@@ -3443,7 +3446,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message (fail)' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 35, status = 'failed' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 35, status = 'failed' }
)
screen:expect({
grid = [[
@@ -3469,7 +3472,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message (cancel)' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 30, status = 'cancel' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 30, status = 'cancel' }
)
screen:expect({
grid = [[
@@ -3495,7 +3498,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message (no-tile or percent)' } },
true,
{ kind = 'progress', status = 'cancel' }
{ kind = 'progress', source = 'tests', status = 'cancel' }
)
screen:expect({
grid = [[
@@ -3517,7 +3520,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message-updated' } },
true,
{ id = id, kind = 'progress', percent = 80, status = 'running' }
{ id = id, kind = 'progress', source = 'other_source', percent = 80, status = 'running' }
)
assert_progress_autocmd(nil, 'No progress message with Tests source yet')
@@ -3545,7 +3548,7 @@ describe('progress-message', function()
kind = 'progress',
title = 'TestSuit',
percent = 10,
source = '',
source = 'tests',
status = 'running',
data = { test_attribute = 1 },
})
@@ -3572,7 +3575,7 @@ describe('progress-message', function()
assert_progress_autocmd({
text = { 'test-message' },
percent = 10,
source = '',
source = 'tests',
status = 'running',
title = 'TestSuit',
id = 1,
@@ -3614,7 +3617,7 @@ describe('progress-message', function()
api.nvim_echo,
{ { 'test-message' } },
false,
{ kind = 'progress', status = 'live' }
{ kind = 'progress', source = 'tests', status = 'live' }
)
)
@@ -3625,7 +3628,7 @@ describe('progress-message', function()
api.nvim_echo,
{ { 'test-message' } },
false,
{ kind = 'progress', status = 'running', percent = -1 }
{ kind = 'progress', source = 'tests', status = 'running', percent = -1 }
)
)
@@ -3635,18 +3638,31 @@ describe('progress-message', function()
api.nvim_echo,
{ { 'test-message' } },
false,
{ kind = 'progress', status = 'running', percent = 101 }
{ kind = 'progress', source = 'tests', status = 'running', percent = 101 }
)
)
-- throws error if data is not a dictionary
eq(
"Invalid 'data': expected Dict, got String",
t.pcall_err(api.nvim_echo, { { 'test-message' } }, false, {
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 10,
status = 'running',
data = 'test',
})
)
-- throws error if source is not given
eq(
"Required: 'opts.source'",
t.pcall_err(
api.nvim_echo,
{ { 'test-message' } },
false,
{ kind = 'progress', title = 'TestSuit', percent = 10, status = 'running', data = 'test' }
{ kind = 'progress', status = 'running' }
)
)
end)
@@ -3655,15 +3671,18 @@ describe('progress-message', function()
local id = api.nvim_echo(
{ { 'test-message 10' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 10, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 10, status = 'running' }
)
eq('TestSuit: 10% test-message 10', exec_capture('messages'))
api.nvim_echo(
{ { 'test-message 20' } },
true,
{ id = id, kind = 'progress', title = 'TestSuit', percent = 20, status = 'running' }
)
api.nvim_echo({ { 'test-message 20' } }, true, {
id = id,
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 20,
status = 'running',
})
eq('TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20', exec_capture('messages'))
api.nvim_echo({ { 'middle msg' } }, true, {})
@@ -3671,21 +3690,27 @@ describe('progress-message', function()
'TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20\nmiddle msg',
exec_capture('messages')
)
api.nvim_echo(
{ { 'test-message 30' } },
true,
{ id = id, kind = 'progress', title = 'TestSuit', percent = 30, status = 'running' }
)
api.nvim_echo({ { 'test-message 30' } }, true, {
id = id,
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 30,
status = 'running',
})
eq(
'TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20\nmiddle msg\nTestSuit: 30% test-message 30',
exec_capture('messages')
)
api.nvim_echo(
{ { 'test-message 50' } },
true,
{ id = id, kind = 'progress', title = 'TestSuit', percent = 50, status = 'running' }
)
api.nvim_echo({ { 'test-message 50' } }, true, {
id = id,
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 50,
status = 'running',
})
eq(
'TestSuit: 10% test-message 10\nTestSuit: 20% test-message 20\nmiddle msg\nTestSuit: 30% test-message 30\nTestSuit: 50% test-message 50',
exec_capture('messages')
@@ -3696,14 +3721,14 @@ describe('progress-message', function()
local id1 = api.nvim_echo(
{ { 'test-message 10' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 10, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 10, status = 'running' }
)
eq(1, id1)
local id2 = api.nvim_echo(
{ { 'test-message 20' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 20, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 20, status = 'running' }
)
eq(2, id2)
@@ -3716,30 +3741,36 @@ describe('progress-message', function()
local id5 = api.nvim_echo(
{ { 'test-message 30' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 30, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 30, status = 'running' }
)
eq(5, id5)
-- updating progress message does not create new msg-id
local id5_update = api.nvim_echo(
{ { 'test-message 40' } },
true,
{ id = id5, kind = 'progress', title = 'TestSuit', percent = 40, status = 'running' }
)
local id5_update = api.nvim_echo({ { 'test-message 40' } }, true, {
id = id5,
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 40,
status = 'running',
})
eq(id5, id5_update)
local id6 = api.nvim_echo(
{ { 'test-message 30' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 30, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 30, status = 'running' }
)
eq(6, id6)
local id7 = api.nvim_echo(
{ { 'supports str-id' } },
true,
{ id = 'str-id', kind = 'progress', title = 'TestSuit', percent = 30, status = 'running' }
)
local id7 = api.nvim_echo({ { 'supports str-id' } }, true, {
id = 'str-id',
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 30,
status = 'running',
})
eq('str-id', id7)
-- internal messages are also assigned an ID (and thus advance the next progress ID)
@@ -3747,18 +3778,21 @@ describe('progress-message', function()
local id8 = api.nvim_echo(
{ { 'test-message 30' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 30, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 30, status = 'running' }
)
eq(8, id8)
end)
it('accepts caller-defined id (string)', function()
-- string id works
local id = api.nvim_echo(
{ { 'supports str-id' } },
true,
{ id = 'str-id', kind = 'progress', title = 'TestSuit', percent = 30, status = 'running' }
)
local id = api.nvim_echo({ { 'supports str-id' } }, true, {
id = 'str-id',
kind = 'progress',
source = 'tests',
title = 'TestSuit',
percent = 30,
status = 'running',
})
eq('str-id', id)
screen:expect({
@@ -3781,16 +3815,19 @@ describe('progress-message', function()
},
})
local id_update = api.nvim_echo(
{ { 'supports str-id updated' } },
true,
{ id = id, kind = 'progress', title = 'testsuit', percent = 40, status = 'running' }
)
local id_update = api.nvim_echo({ { 'supports str-id updated' } }, true, {
id = id,
kind = 'progress',
source = 'tests',
title = 'testsuit',
percent = 40,
status = 'running',
})
eq(id, id_update)
assert_progress_autocmd({
text = { 'supports str-id updated' },
percent = 40,
source = '',
source = 'tests',
status = 'running',
title = 'testsuit',
id = 'str-id',
@@ -3804,7 +3841,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message' } },
true,
{ kind = 'progress', title = 'TestSuit', percent = 10, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuit', percent = 10, status = 'running' }
)
screen:expect([[
^ |
@@ -3818,7 +3855,7 @@ describe('progress-message', function()
kind = 'progress',
title = 'TestSuit',
percent = 10,
source = '',
source = 'tests',
status = 'running',
})
@@ -3844,7 +3881,7 @@ describe('progress-message', function()
assert_progress_autocmd({
text = { 'test-message' },
percent = 10,
source = '',
source = 'tests',
status = 'running',
title = 'TestSuit',
id = 1,
@@ -3857,7 +3894,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message: not shown in cmdline' } },
true,
{ kind = 'progress', title = 'TestSuite', percent = 10, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuite', percent = 10, status = 'running' }
)
screen:expect([[
^ |
@@ -3867,7 +3904,7 @@ describe('progress-message', function()
assert_progress_autocmd({
text = { 'test-message: not shown in cmdline' },
percent = 10,
source = '',
source = 'tests',
status = 'running',
title = 'TestSuite',
id = 1,
@@ -3878,7 +3915,7 @@ describe('progress-message', function()
api.nvim_echo(
{ { 'test-message: shown in cmdline' } },
true,
{ kind = 'progress', title = 'TestSuite', percent = 10, status = 'running' }
{ kind = 'progress', source = 'tests', title = 'TestSuite', percent = 10, status = 'running' }
)
screen:expect({
grid = [[
@@ -3903,7 +3940,7 @@ describe('progress-message', function()
assert_progress_autocmd({
text = { 'test-message: shown in cmdline' },
percent = 10,
source = '',
source = 'tests',
status = 'running',
title = 'TestSuite',
id = 2,

View File

@@ -1057,27 +1057,33 @@ describe('default statusline', function()
local id1 = api.nvim_echo(
{ { 'searching...' } },
true,
{ kind = 'progress', title = 'test', status = 'running', percent = 10 }
{ kind = 'progress', source = 'tests', title = 'test', status = 'running', percent = 10 }
)
eq('10%(1) ', get_progress())
api.nvim_echo(
{ { 'searching' } },
true,
{ id = id1, kind = 'progress', percent = 50, status = 'running', title = 'terminal(ripgrep)' }
)
api.nvim_echo({ { 'searching' } }, true, {
id = id1,
kind = 'progress',
source = 'tests',
percent = 50,
status = 'running',
title = 'terminal(ripgrep)',
})
eq('50%(1) ', get_progress())
api.nvim_echo(
{ { 'searching...' } },
true,
{ kind = 'progress', title = 'second-item', status = 'running', percent = 20 }
)
api.nvim_echo({ { 'searching...' } }, true, {
kind = 'progress',
source = 'tests',
title = 'second-item',
status = 'running',
percent = 20,
})
eq('35%(2) ', get_progress())
api.nvim_echo({ { 'searching' } }, true, {
id = id1,
kind = 'progress',
source = 'tests',
percent = 100,
status = 'success',
title = 'terminal(ripgrep)',