Merge pull request #17394 from zeertzjq/vim-8.2.4343

vim-patch:8.2.4343: when reloading not all properties are detected
This commit is contained in:
zeertzjq 2022-02-15 08:10:21 +08:00 committed by GitHub
commit 8051fa1aff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 216 additions and 42 deletions

View File

@ -1450,6 +1450,11 @@ If you don't get warned often enough you can use the following command.
if it exists now. if it exists now.
Once a file has been checked the timestamp is reset, Once a file has been checked the timestamp is reset,
you will not be warned again. you will not be warned again.
Syntax highlighting, marks, diff status,
'fileencoding', 'fileformat' and 'binary' options
are not changed. See |v:fcs_choice| to reload these
too (for example, if a code formatting tools has
changed the file).
:[N]checkt[ime] {filename} :[N]checkt[ime] {filename}
:[N]checkt[ime] [N] :[N]checkt[ime] [N]

View File

@ -1882,6 +1882,11 @@ v:fcs_choice What should happen after a |FileChangedShell| event was
do with the affected buffer: do with the affected buffer:
reload Reload the buffer (does not work if reload Reload the buffer (does not work if
the file was deleted). the file was deleted).
edit Reload the buffer and detect the
values for options such as
'fileformat', 'fileencoding', 'binary'
(does not work if the file was
deleted).
ask Ask the user what to do, as if there ask Ask the user what to do, as if there
was no autocommand. Except that when was no autocommand. Except that when
only the timestamp changed nothing only the timestamp changed nothing

View File

@ -2013,10 +2013,8 @@ static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp)
return lnum; return lnum;
} }
/* /// Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary' to be
* Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be /// equal to the buffer "buf". Used for calling readfile().
* equal to the buffer "buf". Used for calling readfile().
*/
void prep_exarg(exarg_T *eap, const buf_T *buf) void prep_exarg(exarg_T *eap, const buf_T *buf)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
@ -4901,13 +4899,11 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
return retval; return retval;
} }
/* /// Check if buffer "buf" has been changed.
* Check if buffer "buf" has been changed. /// Also check if the file for a new buffer unexpectedly appeared.
* Also check if the file for a new buffer unexpectedly appeared. /// return 1 if a changed buffer was found.
* return 1 if a changed buffer was found. /// return 2 if a message has been displayed.
* return 2 if a message has been displayed. /// return 0 otherwise.
* return 0 otherwise.
*/
int buf_check_timestamp(buf_T *buf) int buf_check_timestamp(buf_T *buf)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
@ -4916,7 +4912,11 @@ int buf_check_timestamp(buf_T *buf)
char *mesg = NULL; char *mesg = NULL;
char *mesg2 = ""; char *mesg2 = "";
bool helpmesg = false; bool helpmesg = false;
bool reload = false; enum {
RELOAD_NONE,
RELOAD_NORMAL,
RELOAD_DETECT
} reload = RELOAD_NONE;
bool can_reload = false; bool can_reload = false;
uint64_t orig_size = buf->b_orig_size; uint64_t orig_size = buf->b_orig_size;
int orig_mode = buf->b_orig_mode; int orig_mode = buf->b_orig_mode;
@ -4969,7 +4969,7 @@ int buf_check_timestamp(buf_T *buf)
// If 'autoread' is set, the buffer has no changes and the file still // If 'autoread' is set, the buffer has no changes and the file still
// exists, reload the buffer. Use the buffer-local option value if it // exists, reload the buffer. Use the buffer-local option value if it
// was set, the global option value otherwise. // was set, the global option value otherwise.
reload = true; reload = RELOAD_NORMAL;
} else { } else {
if (!file_info_ok) { if (!file_info_ok) {
reason = "deleted"; reason = "deleted";
@ -5000,7 +5000,9 @@ int buf_check_timestamp(buf_T *buf)
} }
s = get_vim_var_str(VV_FCS_CHOICE); s = get_vim_var_str(VV_FCS_CHOICE);
if (STRCMP(s, "reload") == 0 && *reason != 'd') { if (STRCMP(s, "reload") == 0 && *reason != 'd') {
reload = true; reload = RELOAD_NORMAL;
} else if (STRCMP(s, "edit") == 0) {
reload = RELOAD_DETECT;
} else if (STRCMP(s, "ask") == 0) { } else if (STRCMP(s, "ask") == 0) {
n = false; n = false;
} else { } else {
@ -5064,9 +5066,15 @@ int buf_check_timestamp(buf_T *buf)
xstrlcat(tbuf, "\n", tbuf_len - 1); xstrlcat(tbuf, "\n", tbuf_len - 1);
xstrlcat(tbuf, mesg2, tbuf_len - 1); xstrlcat(tbuf, mesg2, tbuf_len - 1);
} }
if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), (char_u *)tbuf, switch (do_dialog(VIM_WARNING, (char_u *)_("Warning"), (char_u *)tbuf,
(char_u *)_("&OK\n&Load File"), 1, NULL, true) == 2) { (char_u *)_("&OK\n&Load File\nLoad File &and Options"),
reload = true; 1, NULL, true)) {
case 2:
reload = RELOAD_NORMAL;
break;
case 3:
reload = RELOAD_DETECT;
break;
} }
} else if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned) { } else if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned) {
if (*mesg2 != NUL) { if (*mesg2 != NUL) {
@ -5100,9 +5108,9 @@ int buf_check_timestamp(buf_T *buf)
xfree(tbuf); xfree(tbuf);
} }
if (reload) { if (reload != RELOAD_NONE) {
// Reload the buffer. // Reload the buffer.
buf_reload(buf, orig_mode); buf_reload(buf, orig_mode, reload == RELOAD_DETECT);
if (buf->b_p_udf && buf->b_ffname != NULL) { if (buf->b_p_udf && buf->b_ffname != NULL) {
char_u hash[UNDO_HASH_SIZE]; char_u hash[UNDO_HASH_SIZE];
@ -5120,13 +5128,11 @@ int buf_check_timestamp(buf_T *buf)
return retval; return retval;
} }
/* /// Reload a buffer that is already loaded.
* Reload a buffer that is already loaded. /// Used when the file was changed outside of Vim.
* Used when the file was changed outside of Vim. /// "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
* "orig_mode" is buf->b_orig_mode before the need for reloading was detected. /// buf->b_orig_mode may have been reset already.
* buf->b_orig_mode may have been reset already. void buf_reload(buf_T *buf, int orig_mode, bool reload_options)
*/
void buf_reload(buf_T *buf, int orig_mode)
{ {
exarg_T ea; exarg_T ea;
pos_T old_cursor; pos_T old_cursor;
@ -5141,11 +5147,15 @@ void buf_reload(buf_T *buf, int orig_mode)
// set curwin/curbuf for "buf" and save some things // set curwin/curbuf for "buf" and save some things
aucmd_prepbuf(&aco, buf); aucmd_prepbuf(&aco, buf);
// We only want to read the text from the file, not reset the syntax // Unless reload_options is set, we only want to read the text from the
// highlighting, clear marks, diff status, etc. Force the fileformat and // file, not reset the syntax highlighting, clear marks, diff status, etc.
// encoding to be the same. // Force the fileformat and encoding to be the same.
if (reload_options) {
memset(&ea, 0, sizeof(ea));
} else {
prep_exarg(&ea, buf);
}
prep_exarg(&ea, buf);
old_cursor = curwin->w_cursor; old_cursor = curwin->w_cursor;
old_topline = curwin->w_topline; old_topline = curwin->w_topline;

View File

@ -3464,6 +3464,7 @@ void msg_advance(int col)
/// ///
/// @param textfiel IObuff for inputdialog(), NULL otherwise /// @param textfiel IObuff for inputdialog(), NULL otherwise
/// @param ex_cmd when TRUE pressing : accepts default and starts Ex command /// @param ex_cmd when TRUE pressing : accepts default and starts Ex command
/// @returns 0 if cancelled, otherwise the nth button (1-indexed).
int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton,
char_u *textfield, int ex_cmd) char_u *textfield, int ex_cmd)
{ {

View File

@ -5654,7 +5654,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
// If the .add file is edited somewhere, reload it. // If the .add file is edited somewhere, reload it.
if (buf != NULL) { if (buf != NULL) {
buf_reload(buf, buf->b_orig_mode); buf_reload(buf, buf->b_orig_mode, false);
} }
redraw_all_later(SOME_VALID); redraw_all_later(SOME_VALID);

View File

@ -10,6 +10,7 @@ let s:did_load = 1
set backspace= set backspace=
set directory^=. set directory^=.
set fillchars=vert:\|,fold:- set fillchars=vert:\|,fold:-
set fsync
set laststatus=1 set laststatus=1
set listchars=eol:$ set listchars=eol:$
set joinspaces set joinspaces

View File

@ -1,9 +1,10 @@
" Tests for when a file was changed outside of Vim. " Tests for when a file was changed outside of Vim.
source check.vim
func Test_FileChangedShell_reload() func Test_FileChangedShell_reload()
if !has('unix') CheckUnix
return
endif
augroup testreload augroup testreload
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload' au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
augroup END augroup END
@ -90,11 +91,107 @@ func Test_FileChangedShell_reload()
call delete('Xchanged_r') call delete('Xchanged_r')
endfunc endfunc
func Test_FileChangedShell_edit()
CheckUnix
new Xchanged_r
call setline(1, 'reload this')
set fileformat=unix
write
" File format changed, reload (content only, no 'ff' etc)
augroup testreload
au!
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
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 = ''
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
write
" File format changed, reload with 'ff', etc
augroup testreload
au!
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'edit'
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 = ''
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
write
au! testreload
bwipe!
call delete(undofile('Xchanged_r'))
call delete('Xchanged_r')
endfunc
func Test_FileChangedShell_edit_dialog()
throw 'Skipped: requires a UI to be active'
CheckNotGui
new Xchanged_r
call setline(1, 'reload this')
set fileformat=unix
write
" 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')
call writefile(["line1\r", "line2\r"], 'Xchanged_r')
let g:reason = ''
call feedkeys('L', '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
write
" 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')
call writefile(["line1\r", "line2\r"], 'Xchanged_r')
let g:reason = ''
call feedkeys('a', 'L') " 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
write
au! testreload
bwipe!
call delete(undofile('Xchanged_r'))
call delete('Xchanged_r')
endfunc
func Test_file_changed_dialog() func Test_file_changed_dialog()
throw 'Skipped: requires a UI to a active' throw 'Skipped: requires a UI to be active'
if !has('unix') || has('gui_running') CheckUnix
return CheckNotGui
endif
au! FileChangedShell au! FileChangedShell
new Xchanged_d new Xchanged_d

View File

@ -11,6 +11,11 @@ describe('file changed dialog', function()
clear() clear()
meths.ui_attach(80, 24, {}) meths.ui_attach(80, 24, {})
meths.set_option('autoread', false) meths.set_option('autoread', false)
meths.set_option('fsync', true)
end)
it('works', function()
if helpers.pending_win32(pending) then return end
source([[ source([[
func Test_file_changed_dialog() func Test_file_changed_dialog()
au! FileChangedShell au! FileChangedShell
@ -66,11 +71,61 @@ describe('file changed dialog', function()
call delete('Xchanged_d') call delete('Xchanged_d')
endfunc endfunc
]]) ]])
end)
it('works', function()
if helpers.pending_win32(pending) then return end
call('Test_file_changed_dialog') call('Test_file_changed_dialog')
expected_empty() expected_empty()
end) 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) end)