vim-patch:8.1.0815: dialog for file changed outside of Vim not tested (#28184)

Problem:    Dialog for file changed outside of Vim not tested.
Solution:   Add a test.  Move FileChangedShell test.  Add 'L' flag to
            feedkeys().

5e66b42aae

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2024-04-05 18:04:45 +08:00 committed by GitHub
parent 4add77ddbf
commit a500c5f808
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 30 additions and 234 deletions

View File

@ -1588,6 +1588,7 @@ feedkeys({string} [, {mode}]) *feedkeys()*
't' Handle keys as if typed; otherwise they are handled as
if coming from a mapping. This matters for undo,
opening folds, etc.
'L' Lowlevel input. Other flags are not used.
'i' Insert the string instead of appending (see above).
'x' Execute commands until typeahead is empty. This is
similar to using ":normal!". You can call feedkeys()

View File

@ -1959,6 +1959,7 @@ function vim.fn.extendnew(expr1, expr2, expr3) end
--- 't' Handle keys as if typed; otherwise they are handled as
--- if coming from a mapping. This matters for undo,
--- opening folds, etc.
--- 'L' Lowlevel input. Other flags are not used.
--- 'i' Insert the string instead of appending (see above).
--- 'x' Execute commands until typeahead is empty. This is
--- similar to using ":normal!". You can call feedkeys()

View File

@ -277,6 +277,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
bool typed = false;
bool execute = false;
bool dangerous = false;
bool lowlevel = false;
for (size_t i = 0; i < mode.size; i++) {
switch (mode.data[i]) {
@ -292,6 +293,8 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
execute = true; break;
case '!':
dangerous = true; break;
case 'L':
lowlevel = true; break;
}
}
@ -307,10 +310,14 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
} else {
keys_esc = keys.data;
}
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
insert ? 0 : typebuf.tb_len, !typed, false);
if (vgetc_busy) {
typebuf_was_filled = true;
if (lowlevel) {
input_enqueue_raw(cstr_as_string(keys_esc));
} else {
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
insert ? 0 : typebuf.tb_len, !typed, false);
if (vgetc_busy) {
typebuf_was_filled = true;
}
}
if (escape_ks) {

View File

@ -2481,6 +2481,7 @@ M.funcs = {
't' Handle keys as if typed; otherwise they are handled as
if coming from a mapping. This matters for undo,
opening folds, etc.
'L' Lowlevel input. Other flags are not used.
'i' Insert the string instead of appending (see above).
'x' Execute commands until typeahead is empty. This is
similar to using ":normal!". You can call feedkeys()

View File

@ -3395,9 +3395,7 @@ int do_dialog(int type, const char *title, const char *message, const char *butt
int retval = 0;
int i;
if (silent_mode // No dialogs in silent mode ("ex -s")
|| !ui_active() // Without a UI Nvim waits for input forever.
) {
if (silent_mode) { // No dialogs in silent mode ("ex -s")
return dfltbutton; // return default option
}
@ -3414,6 +3412,12 @@ int do_dialog(int type, const char *title, const char *message, const char *butt
char *hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
while (true) {
// Without a UI Nvim waits for input forever.
if (!ui_active() && !input_available()) {
retval = dfltbutton;
break;
}
// Get a typed character directly from the user.
int c = get_keystroke(NULL);
switch (c) {

View File

@ -247,6 +247,13 @@ bool os_isatty(int fd)
return uv_guess_handle(fd) == UV_TTY;
}
void input_enqueue_raw(String keys)
{
if (keys.size > 0) {
rbuffer_write(input_buffer, keys.data, keys.size);
}
}
size_t input_enqueue(String keys)
{
const char *ptr = keys.data;

View File

@ -1,59 +0,0 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, source = helpers.clear, helpers.source
local call, eq, api = helpers.call, helpers.eq, helpers.api
local function expected_empty()
eq({}, api.nvim_get_vvar('errors'))
end
describe('buffer', function()
before_each(function()
clear()
api.nvim_ui_attach(80, 24, {})
api.nvim_set_option_value('hidden', false, {})
end)
it('deleting a modified buffer with :confirm', function()
source([[
func Test_bdel_with_confirm()
new
call setline(1, 'test')
call assert_fails('bdel', 'E89:')
call nvim_input('c')
confirm bdel
call assert_equal(2, winnr('$'))
call assert_equal(1, &modified)
call nvim_input('n')
confirm bdel
call assert_equal(1, winnr('$'))
endfunc
]])
call('Test_bdel_with_confirm')
expected_empty()
end)
it('editing another buffer from a modified buffer with :confirm', function()
source([[
func Test_goto_buf_with_confirm()
new Xfile
enew
call setline(1, 'test')
call assert_fails('b Xfile', 'E37:')
call nvim_input('c')
call assert_fails('confirm b Xfile', 'E37:')
call assert_equal(1, &modified)
call assert_equal('', @%)
call nvim_input('y')
call assert_fails('confirm b Xfile', 'E37:')
call assert_equal(1, &modified)
call assert_equal('', @%)
call nvim_input('n')
confirm b Xfile
call assert_equal('Xfile', @%)
close!
endfunc
]])
call('Test_goto_buf_with_confirm')
expected_empty()
end)
end)

View File

@ -1,142 +0,0 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, source = helpers.clear, helpers.source
local call, eq, api = helpers.call, helpers.eq, helpers.api
local is_os = helpers.is_os
local skip = helpers.skip
local function expected_empty()
eq({}, api.nvim_get_vvar('errors'))
end
describe('file changed dialog', function()
before_each(function()
clear()
api.nvim_ui_attach(80, 24, {})
api.nvim_set_option_value('autoread', false, {})
api.nvim_set_option_value('fsync', true, {})
end)
it('works', function()
skip(is_os('win'))
source([[
func Test_file_changed_dialog()
au! FileChangedShell
new Xchanged_d
call setline(1, 'reload this')
write
" Need to wait until the timestamp would change by at least a second.
sleep 2
silent !echo 'extra line' >>Xchanged_d
call nvim_input('L')
checktime
call assert_match('W11:', v:warningmsg)
call assert_equal(2, line('$'))
call assert_equal('reload this', getline(1))
call assert_equal('extra line', getline(2))
" delete buffer, only shows an error, no prompt
silent !rm Xchanged_d
checktime
call assert_match('E211:', v:warningmsg)
call assert_equal(2, line('$'))
call assert_equal('extra line', getline(2))
let v:warningmsg = 'empty'
" change buffer, recreate the file and reload
call setline(1, 'buffer is changed')
silent !echo 'new line' >Xchanged_d
call nvim_input('L')
checktime
call assert_match('W12:', v:warningmsg)
call assert_equal(1, line('$'))
call assert_equal('new line', getline(1))
" Only mode changed, reload
silent !chmod +x Xchanged_d
call nvim_input('L')
checktime
call assert_match('W16:', v:warningmsg)
call assert_equal(1, line('$'))
call assert_equal('new line', getline(1))
" Only time changed, no prompt
sleep 2
silent !touch Xchanged_d
let v:warningmsg = ''
checktime Xchanged_d
call assert_equal('', v:warningmsg)
call assert_equal(1, line('$'))
call assert_equal('new line', getline(1))
" File created after starting to edit it
call delete('Xchanged_d')
new Xchanged_d
call writefile(['one'], 'Xchanged_d')
call nvim_input('L')
checktime Xchanged_d
call assert_equal(['one'], getline(1, '$'))
close!
bwipe!
call delete('Xchanged_d')
endfunc
]])
call('Test_file_changed_dialog')
expected_empty()
end)
it('works with FileChangedShell', function()
source([[
func Test_FileChangedShell_edit_dialog()
new Xchanged_r
call setline(1, 'reload this')
set fileformat=unix
silent write " Use :silent to prevent a hit-enter prompt
" File format changed, reload (content only) via prompt
augroup testreload
au!
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
augroup END
call assert_equal(&fileformat, 'unix')
sleep 10m " make the test less flaky in Nvim
call writefile(["line1\r", "line2\r"], 'Xchanged_r')
let g:reason = ''
call nvim_input('L') " load file content only
checktime
call assert_equal('changed', g:reason)
call assert_equal(&fileformat, 'unix')
call assert_equal("line1\r", getline(1))
call assert_equal("line2\r", getline(2))
%s/\r
silent write " Use :silent to prevent a hit-enter prompt
" File format changed, reload (file and options) via prompt
augroup testreload
au!
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
augroup END
call assert_equal(&fileformat, 'unix')
sleep 10m " make the test less flaky in Nvim
call writefile(["line1\r", "line2\r"], 'Xchanged_r')
let g:reason = ''
call nvim_input('a') " load file content and options
checktime
call assert_equal('changed', g:reason)
call assert_equal(&fileformat, 'dos')
call assert_equal("line1", getline(1))
call assert_equal("line2", getline(2))
set fileformat=unix
silent write " Use :silent to prevent a hit-enter prompt
au! testreload
bwipe!
call delete(undofile('Xchanged_r'))
call delete('Xchanged_r')
endfunc
]])
call('Test_FileChangedShell_edit_dialog')
expected_empty()
end)
end)

View File

@ -8,7 +8,6 @@ local clear = helpers.clear
local source = helpers.source
local command = helpers.command
local exc_exec = helpers.exc_exec
local pcall_err = helpers.pcall_err
local async_meths = helpers.async_meths
local NIL = vim.NIL
@ -407,7 +406,6 @@ describe('inputdialog()', function()
end)
describe('confirm()', function()
-- oldtest: Test_confirm()
it('works', function()
api.nvim_set_option_value('more', false, {}) -- Avoid hit-enter prompt
api.nvim_set_option_value('laststatus', 2, {})
@ -470,20 +468,6 @@ describe('confirm()', function()
screen:expect({ any = '%[No Name%]' })
eq(1, api.nvim_get_var('a'))
end
eq('Vim(call):E730: Using a List as a String', pcall_err(command, 'call confirm([])'))
eq(
'Vim(call):E730: Using a List as a String',
pcall_err(command, 'call confirm("Are you sure?", [])')
)
eq(
'Vim(call):E745: Using a List as a Number',
pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", [])')
)
eq(
'Vim(call):E730: Using a List as a String',
pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", 0, [])')
)
end)
it('shows dialog even if :silent #8788', function()

View File

@ -232,8 +232,6 @@ endfunc
" Test for deleting a modified buffer with :confirm
func Test_bdel_with_confirm()
" requires a UI to be active
throw 'Skipped: use test/functional/legacy/buffer_spec.lua'
CheckUnix
CheckNotGui
CheckFeature dialog_con
@ -251,8 +249,6 @@ endfunc
" Test for editing another buffer from a modified buffer with :confirm
func Test_goto_buf_with_confirm()
" requires a UI to be active
throw 'Skipped: use test/functional/legacy/buffer_spec.lua'
CheckUnix
CheckNotGui
CheckFeature dialog_con

View File

@ -140,8 +140,6 @@ func Test_FileChangedShell_edit()
endfunc
func Test_FileChangedShell_edit_dialog()
" requires a UI to be active
throw 'Skipped: use test/functional/legacy/filechanged_spec.lua'
CheckNotGui
CheckUnix " Using low level feedkeys() does not work on MS-Windows.
@ -156,6 +154,7 @@ func Test_FileChangedShell_edit_dialog()
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
augroup END
call assert_equal(&fileformat, 'unix')
sleep 10m " make the test less flaky in Nvim
call writefile(["line1\r", "line2\r"], 'Xchanged_r')
let g:reason = ''
call feedkeys('L', 'L') " load file content only
@ -173,6 +172,7 @@ func Test_FileChangedShell_edit_dialog()
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
augroup END
call assert_equal(&fileformat, 'unix')
sleep 10m " make the test less flaky in Nvim
call writefile(["line1\r", "line2\r"], 'Xchanged_r')
let g:reason = ''
call feedkeys('a', 'L') " load file content and options
@ -191,8 +191,6 @@ func Test_FileChangedShell_edit_dialog()
endfunc
func Test_file_changed_dialog()
" requires a UI to be active
throw 'Skipped: use test/functional/legacy/filechanged_spec.lua'
CheckUnix
CheckNotGui
au! FileChangedShell

View File

@ -2590,8 +2590,6 @@ endfunc
" Test confirm({msg} [, {choices} [, {default} [, {type}]]])
func Test_confirm()
" requires a UI to be active
throw 'Skipped: use test/functional/vimscript/input_spec.lua'
CheckUnix
CheckNotGui