aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-02-14 11:35:25 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-02-14 11:35:25 +0800
commit5220891571a799fd630cbcbe836d1f9e3d2dc1fa (patch)
treebe2ab5557a3b1aa02f0ad7b5c52d3441ed225a02
parent5d6bef0f6e5e6fc2daa12a0d7e1f5d63df59926e (diff)
downloadrneovim-5220891571a799fd630cbcbe836d1f9e3d2dc1fa.tar.gz
rneovim-5220891571a799fd630cbcbe836d1f9e3d2dc1fa.tar.bz2
rneovim-5220891571a799fd630cbcbe836d1f9e3d2dc1fa.zip
vim-patch:8.2.4343: when reloading not all properties are detected
Problem: When reloading not all properties are detected. Solution: Add the "edit" value to v:fcs_choice. (Rob Pilling, closes vim/vim#9579) https://github.com/vim/vim/commit/8196e94a8b72ed8618605cb66615571313097d78 Cherry-pick some test changes from patch 8.1.1826.
-rw-r--r--runtime/doc/editing.txt5
-rw-r--r--runtime/doc/eval.txt5
-rw-r--r--src/nvim/fileio.c70
-rw-r--r--src/nvim/message.c1
-rw-r--r--src/nvim/spellfile.c2
-rw-r--r--src/nvim/testdir/setup.vim1
-rw-r--r--src/nvim/testdir/test_filechanged.vim111
-rw-r--r--test/functional/legacy/filechanged_spec.lua61
8 files changed, 215 insertions, 41 deletions
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 3d0287b0cd..8ddc661c0e 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1450,6 +1450,11 @@ If you don't get warned often enough you can use the following command.
if it exists now.
Once a file has been checked the timestamp is reset,
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] [N]
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index fc788fba59..fc422f13e5 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1882,6 +1882,11 @@ v:fcs_choice What should happen after a |FileChangedShell| event was
do with the affected buffer:
reload Reload the buffer (does not work if
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
was no autocommand. Except that when
only the timestamp changed nothing
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 110981159f..f5824d83be 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -2013,10 +2013,8 @@ static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp)
return lnum;
}
-/*
- * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
- * equal to the buffer "buf". Used for calling readfile().
- */
+/// Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary' to be
+/// equal to the buffer "buf". Used for calling readfile().
void prep_exarg(exarg_T *eap, const buf_T *buf)
FUNC_ATTR_NONNULL_ALL
{
@@ -4901,13 +4899,11 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
return retval;
}
-/*
- * Check if buffer "buf" has been changed.
- * Also check if the file for a new buffer unexpectedly appeared.
- * return 1 if a changed buffer was found.
- * return 2 if a message has been displayed.
- * return 0 otherwise.
- */
+/// Check if buffer "buf" has been changed.
+/// Also check if the file for a new buffer unexpectedly appeared.
+/// return 1 if a changed buffer was found.
+/// return 2 if a message has been displayed.
+/// return 0 otherwise.
int buf_check_timestamp(buf_T *buf)
FUNC_ATTR_NONNULL_ALL
{
@@ -4916,7 +4912,11 @@ int buf_check_timestamp(buf_T *buf)
char *mesg = NULL;
char *mesg2 = "";
bool helpmesg = false;
- bool reload = false;
+ enum {
+ RELOAD_NONE,
+ RELOAD_NORMAL,
+ RELOAD_DETECT
+ } reload = RELOAD_NONE;
bool can_reload = false;
uint64_t orig_size = buf->b_orig_size;
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
// exists, reload the buffer. Use the buffer-local option value if it
// was set, the global option value otherwise.
- reload = true;
+ reload = RELOAD_NORMAL;
} else {
if (!file_info_ok) {
reason = "deleted";
@@ -5000,7 +5000,9 @@ int buf_check_timestamp(buf_T *buf)
}
s = get_vim_var_str(VV_FCS_CHOICE);
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) {
n = false;
} else {
@@ -5064,9 +5066,15 @@ int buf_check_timestamp(buf_T *buf)
xstrlcat(tbuf, "\n", tbuf_len - 1);
xstrlcat(tbuf, mesg2, tbuf_len - 1);
}
- if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), (char_u *)tbuf,
- (char_u *)_("&OK\n&Load File"), 1, NULL, true) == 2) {
- reload = true;
+ switch (do_dialog(VIM_WARNING, (char_u *)_("Warning"), (char_u *)tbuf,
+ (char_u *)_("&OK\n&Load File\nLoad File &and Options"),
+ 1, NULL, true)) {
+ case 2:
+ reload = RELOAD_NORMAL;
+ break;
+ case 3:
+ reload = RELOAD_DETECT;
+ break;
}
} else if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned) {
if (*mesg2 != NUL) {
@@ -5100,9 +5108,9 @@ int buf_check_timestamp(buf_T *buf)
xfree(tbuf);
}
- if (reload) {
+ if (reload != RELOAD_NONE) {
// 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) {
char_u hash[UNDO_HASH_SIZE];
@@ -5120,13 +5128,11 @@ int buf_check_timestamp(buf_T *buf)
return retval;
}
-/*
- * Reload a buffer that is already loaded.
- * Used when the file was changed outside of Vim.
- * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
- * buf->b_orig_mode may have been reset already.
- */
-void buf_reload(buf_T *buf, int orig_mode)
+/// Reload a buffer that is already loaded.
+/// Used when the file was changed outside of Vim.
+/// "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
+/// buf->b_orig_mode may have been reset already.
+void buf_reload(buf_T *buf, int orig_mode, bool reload_options)
{
exarg_T ea;
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
aucmd_prepbuf(&aco, buf);
- // We only want to read the text from the file, not reset the syntax
- // highlighting, clear marks, diff status, etc. Force the fileformat and
- // encoding to be the same.
+ // Unless reload_options is set, we only want to read the text from the
+ // file, not reset the syntax highlighting, clear marks, diff status, etc.
+ // 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_topline = curwin->w_topline;
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 93742ccbdb..b39450cdc6 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -3464,6 +3464,7 @@ void msg_advance(int col)
///
/// @param textfiel IObuff for inputdialog(), NULL otherwise
/// @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,
char_u *textfield, int ex_cmd)
{
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index f6b95f37b1..d7b220b3f6 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -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 (buf != NULL) {
- buf_reload(buf, buf->b_orig_mode);
+ buf_reload(buf, buf->b_orig_mode, false);
}
redraw_all_later(SOME_VALID);
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index fdae0697c3..15e3b31498 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -10,6 +10,7 @@ let s:did_load = 1
set backspace=
set directory^=.
set fillchars=vert:\|,fold:-
+set fsync
set laststatus=1
set listchars=eol:$
set joinspaces
diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim
index b4c32fcc16..06ccd6e85f 100644
--- a/src/nvim/testdir/test_filechanged.vim
+++ b/src/nvim/testdir/test_filechanged.vim
@@ -1,9 +1,10 @@
" Tests for when a file was changed outside of Vim.
+source check.vim
+
func Test_FileChangedShell_reload()
- if !has('unix')
- return
- endif
+ CheckUnix
+
augroup testreload
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
augroup END
@@ -90,11 +91,107 @@ func Test_FileChangedShell_reload()
call delete('Xchanged_r')
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()
- throw 'Skipped: requires a UI to a active'
- if !has('unix') || has('gui_running')
- return
- endif
+ throw 'Skipped: requires a UI to be active'
+ CheckUnix
+ CheckNotGui
au! FileChangedShell
new Xchanged_d
diff --git a/test/functional/legacy/filechanged_spec.lua b/test/functional/legacy/filechanged_spec.lua
index fed7b27b0c..6eb853d630 100644
--- a/test/functional/legacy/filechanged_spec.lua
+++ b/test/functional/legacy/filechanged_spec.lua
@@ -11,6 +11,11 @@ describe('file changed dialog', function()
clear()
meths.ui_attach(80, 24, {})
meths.set_option('autoread', false)
+ meths.set_option('fsync', true)
+ end)
+
+ it('works', function()
+ if helpers.pending_win32(pending) then return end
source([[
func Test_file_changed_dialog()
au! FileChangedShell
@@ -66,11 +71,61 @@ describe('file changed dialog', function()
call delete('Xchanged_d')
endfunc
]])
+ call('Test_file_changed_dialog')
+ expected_empty()
end)
- it('works', function()
- if helpers.pending_win32(pending) then return end
- call('Test_file_changed_dialog')
+ 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)