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
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 't' Handle keys as if typed; otherwise they are handled as
if coming from a mapping. This matters for undo, if coming from a mapping. This matters for undo,
opening folds, etc. opening folds, etc.
'L' Lowlevel input. Other flags are not used.
'i' Insert the string instead of appending (see above). 'i' Insert the string instead of appending (see above).
'x' Execute commands until typeahead is empty. This is 'x' Execute commands until typeahead is empty. This is
similar to using ":normal!". You can call feedkeys() 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 --- 't' Handle keys as if typed; otherwise they are handled as
--- if coming from a mapping. This matters for undo, --- if coming from a mapping. This matters for undo,
--- opening folds, etc. --- opening folds, etc.
--- 'L' Lowlevel input. Other flags are not used.
--- 'i' Insert the string instead of appending (see above). --- 'i' Insert the string instead of appending (see above).
--- 'x' Execute commands until typeahead is empty. This is --- 'x' Execute commands until typeahead is empty. This is
--- similar to using ":normal!". You can call feedkeys() --- 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 typed = false;
bool execute = false; bool execute = false;
bool dangerous = false; bool dangerous = false;
bool lowlevel = false;
for (size_t i = 0; i < mode.size; i++) { for (size_t i = 0; i < mode.size; i++) {
switch (mode.data[i]) { switch (mode.data[i]) {
@@ -292,6 +293,8 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
execute = true; break; execute = true; break;
case '!': case '!':
dangerous = true; break; dangerous = true; break;
case 'L':
lowlevel = true; break;
} }
} }
@@ -307,10 +310,14 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
} else { } else {
keys_esc = keys.data; keys_esc = keys.data;
} }
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), if (lowlevel) {
insert ? 0 : typebuf.tb_len, !typed, false); input_enqueue_raw(cstr_as_string(keys_esc));
if (vgetc_busy) { } else {
typebuf_was_filled = true; 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) { if (escape_ks) {

View File

@@ -2481,6 +2481,7 @@ M.funcs = {
't' Handle keys as if typed; otherwise they are handled as 't' Handle keys as if typed; otherwise they are handled as
if coming from a mapping. This matters for undo, if coming from a mapping. This matters for undo,
opening folds, etc. opening folds, etc.
'L' Lowlevel input. Other flags are not used.
'i' Insert the string instead of appending (see above). 'i' Insert the string instead of appending (see above).
'x' Execute commands until typeahead is empty. This is 'x' Execute commands until typeahead is empty. This is
similar to using ":normal!". You can call feedkeys() 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 retval = 0;
int i; int i;
if (silent_mode // No dialogs in silent mode ("ex -s") if (silent_mode) { // No dialogs in silent mode ("ex -s")
|| !ui_active() // Without a UI Nvim waits for input forever.
) {
return dfltbutton; // return default option 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); char *hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
while (true) { 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. // Get a typed character directly from the user.
int c = get_keystroke(NULL); int c = get_keystroke(NULL);
switch (c) { switch (c) {

View File

@@ -247,6 +247,13 @@ bool os_isatty(int fd)
return uv_guess_handle(fd) == UV_TTY; 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) size_t input_enqueue(String keys)
{ {
const char *ptr = keys.data; 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 source = helpers.source
local command = helpers.command local command = helpers.command
local exc_exec = helpers.exc_exec local exc_exec = helpers.exc_exec
local pcall_err = helpers.pcall_err
local async_meths = helpers.async_meths local async_meths = helpers.async_meths
local NIL = vim.NIL local NIL = vim.NIL
@@ -407,7 +406,6 @@ describe('inputdialog()', function()
end) end)
describe('confirm()', function() describe('confirm()', function()
-- oldtest: Test_confirm()
it('works', function() it('works', function()
api.nvim_set_option_value('more', false, {}) -- Avoid hit-enter prompt api.nvim_set_option_value('more', false, {}) -- Avoid hit-enter prompt
api.nvim_set_option_value('laststatus', 2, {}) api.nvim_set_option_value('laststatus', 2, {})
@@ -470,20 +468,6 @@ describe('confirm()', function()
screen:expect({ any = '%[No Name%]' }) screen:expect({ any = '%[No Name%]' })
eq(1, api.nvim_get_var('a')) eq(1, api.nvim_get_var('a'))
end 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) end)
it('shows dialog even if :silent #8788', function() it('shows dialog even if :silent #8788', function()

View File

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

View File

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

View File

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