From 900a151bf541c7fa77a56b4881c4836a1cabcde6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 26 Aug 2022 19:04:20 +0800 Subject: [PATCH 1/4] vim-patch:9.0.0272: BufReadCmd not triggered when loading a "nofile" buffer Problem: BufReadCmd not triggered when loading a "nofile" buffer. (Maxim Kim) Solution: Call readfile() but bail out before reading a file. (closes vim/vim#10983) https://github.com/vim/vim/commit/b1d2c8116cb5577961ea109651fb888b5e58265f --- src/nvim/buffer.c | 13 ++++++++++--- src/nvim/fileio.c | 5 +++++ src/nvim/fileio.h | 1 + src/nvim/testdir/test_autocmd.vim | 12 ++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 24fd1b3022..3211b83dc7 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -165,11 +165,12 @@ static int read_buffer(int read_stdin, exarg_T *eap, int flags) /// /// @param read_stdin read file from stdin /// @param eap for forced 'ff' and 'fenc' or NULL -/// @param flags extra flags for readfile() +/// @param flags_arg extra flags for readfile() /// /// @return FAIL for failure, OK otherwise. -int open_buffer(int read_stdin, exarg_T *eap, int flags) +int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) { + int flags = flags_arg; int retval = OK; bufref_T old_curbuf; long old_tw = curbuf->b_p_tw; @@ -224,8 +225,14 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags) // mark cursor position as being invalid curwin->w_valid = 0; + // A buffer without an actual file should not use the buffer name to read a + // file. + if (bt_quickfix(curbuf) || bt_nofilename(curbuf)) { + flags |= READ_NOFILE; + } + // Read the file if there is one. - if (curbuf->b_ffname != NULL && !bt_quickfix(curbuf) && !bt_nofilename(curbuf)) { + if (curbuf->b_ffname != NULL) { #ifdef UNIX int save_bin = curbuf->b_p_bin; int perm; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 21c1549f42..fdba186200 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -167,6 +167,7 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) /// READ_STDIN read from stdin instead of a file /// READ_BUFFER read from curbuf instead of a file (converting after reading /// stdin) +/// READ_NOFILE do not read a file, only trigger BufReadCmd /// READ_DUMMY read into a dummy buffer (to check if file contents changed) /// READ_KEEP_UNDO don't clear undo info or read it from a file /// READ_FIFO read from fifo/socket instead of a file @@ -334,6 +335,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } curbuf->b_op_start = orig_start; + + if (flags & READ_NOFILE) { + return FAIL; + } } if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0) { diff --git a/src/nvim/fileio.h b/src/nvim/fileio.h index 650977deac..ae3c51f1bc 100644 --- a/src/nvim/fileio.h +++ b/src/nvim/fileio.h @@ -15,6 +15,7 @@ #define READ_KEEP_UNDO 0x20 // keep undo info #define READ_FIFO 0x40 // read from fifo or socket #define READ_NOWINENTER 0x80 // do not trigger BufWinEnter +#define READ_NOFILE 0x100 // do not read a file, do trigger BufReadCmd #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 5451dcf241..f21b958f1a 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -493,6 +493,18 @@ func Test_BufReadCmdHelpJump() au! BufReadCmd endfunc +" BufReadCmd is triggered for a "nofile" buffer +func Test_BufReadCmdNofile() + new somefile + set buftype=nofile + au BufReadCmd somefile call setline(1, 'triggered') + edit + call assert_equal('triggered', getline(1)) + + au! BufReadCmd + bwipe! +endfunc + func Test_augroup_deleted() " This caused a crash before E936 was introduced augroup x From 52f00a6c4d84a13a85ff265a5c59c92795d1b333 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 26 Aug 2022 20:03:08 +0800 Subject: [PATCH 2/4] vim-patch:9.0.0274: netrw plugin does not show remote files Problem: Netrw plugin does not show remote files. Solution: Do read a file when 'buftype' is "acwrite". (closes vim/vim#10983) https://github.com/vim/vim/commit/c312619f7c0cf590d96e0b2ed891d1f6c43d769b --- src/nvim/buffer.c | 40 +++++++++++++++++++---------- src/nvim/testdir/test_functions.vim | 7 +++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 3211b83dc7..514be4c56b 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -227,7 +227,7 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) // A buffer without an actual file should not use the buffer name to read a // file. - if (bt_quickfix(curbuf) || bt_nofilename(curbuf)) { + if (bt_nofileread(curbuf)) { flags |= READ_NOFILE; } @@ -812,6 +812,18 @@ static void free_buffer(buf_T *buf) } } +/// Free the b_wininfo list for buffer "buf". +static void clear_wininfo(buf_T *buf) +{ + wininfo_T *wip; + + while (buf->b_wininfo != NULL) { + wip = buf->b_wininfo; + buf->b_wininfo = wip->wi_next; + free_wininfo(wip, buf); + } +} + /// Free stuff in the buffer for ":bdel" and when wiping out the buffer. /// /// @param buf Buffer pointer @@ -846,18 +858,6 @@ static void free_buffer_stuff(buf_T *buf, int free_flags) buf_updates_unload(buf, false); } -/// Free the b_wininfo list for buffer "buf". -static void clear_wininfo(buf_T *buf) -{ - wininfo_T *wip; - - while (buf->b_wininfo != NULL) { - wip = buf->b_wininfo; - buf->b_wininfo = wip->wi_next; - free_wininfo(wip, buf); - } -} - /// Go to another buffer. Handles the result of the ATTENTION dialog. void goto_buffer(exarg_T *eap, int start, int dir, int count) { @@ -3834,7 +3834,8 @@ bool bt_terminal(const buf_T *const buf) } /// @return true if "buf" is a "nofile", "acwrite", "terminal" or "prompt" -/// buffer. This means the buffer name is not a file name. +/// buffer. This means the buffer name may not be a file name, +/// at least not for writing the buffer. bool bt_nofilename(const buf_T *const buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { @@ -3844,6 +3845,17 @@ bool bt_nofilename(const buf_T *const buf) || buf->b_p_bt[0] == 'p'); } +/// @return true if "buf" is a "nofile", "quickfix", "terminal" or "prompt" +/// buffer. This means the buffer is not to be read from a file. +static bool bt_nofileread(const buf_T *const buf) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') + || buf->b_p_bt[0] == 't' + || buf->b_p_bt[0] == 'q' + || buf->b_p_bt[0] == 'p'); +} + /// @return true if "buf" has 'buftype' set to "nofile". bool bt_nofile(const buf_T *const buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index b1f617ceda..555c4f58b7 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1887,6 +1887,13 @@ func Test_bufadd_bufload() call bufload(buf) call assert_equal([''], getbufline(buf, 1, '$')) + " when 'buftype' is "acwrite" then bufload() DOES read the file + bwipe! XotherName + let buf = bufadd('XotherName') + call setbufvar(buf, '&bt', 'acwrite') + call bufload(buf) + call assert_equal(['some', 'text'], getbufline(buf, 1, '$')) + bwipe someName bwipe XotherName call assert_equal(0, bufexists('someName')) From 45c23a757c6fc601a76a92f052f55eb3ed469364 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 26 Aug 2022 20:18:02 +0800 Subject: [PATCH 3/4] vim-patch:9.0.0275: BufEnter not triggered when using ":edit" in "nofile" buffer Problem: BufEnter not triggered when using ":edit" in "nofile" buffer. Solution: Let readfile() return NOTDONE. (closes vim/vim#10986) https://github.com/vim/vim/commit/a9b5b85068b2fcb1c01ea20524e227bcad579ceb --- src/nvim/fileio.c | 2 +- src/nvim/testdir/test_autocmd.vim | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fdba186200..0b66878103 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -337,7 +337,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_op_start = orig_start; if (flags & READ_NOFILE) { - return FAIL; + return NOTDONE; // so that BufEnter can be triggered } } diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index f21b958f1a..778e5f9b9f 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -599,9 +599,19 @@ func Test_BufEnter() " On MS-Windows we can't edit the directory, make sure we wipe the right " buffer. bwipe! Xdir - call delete('Xdir', 'd') au! BufEnter + + " Editing a "nofile" buffer doesn't read the file but does trigger BufEnter + " for historic reasons. + new somefile + set buftype=nofile + au BufEnter somefile call setline(1, 'some text') + edit + call assert_equal('some text', getline(1)) + + bwipe! + au! BufEnter endfunc " Closing a window might cause an endless loop From d813ef0097eb781baeba5d458dcb0507e2f61040 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 26 Aug 2022 22:39:13 +0800 Subject: [PATCH 4/4] vim-patch:9.0.0276: 'buftype' values not sufficiently tested Problem: 'buftype' values not sufficiently tested. Solution: Add and extend tests with 'buftype' values. (closes vim/vim#10988) https://github.com/vim/vim/commit/93f72cc119c796f1ccb75468ef9e446cbfb41e9b "terminal" and "popup" buffer types cannot be tested, and commenting them out causes an error, so just remove them. --- src/nvim/testdir/test_autocmd.vim | 49 +++++++++++++++++++---------- src/nvim/testdir/test_bufline.vim | 20 ++++++++++++ src/nvim/testdir/test_functions.vim | 28 +++++++++-------- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 778e5f9b9f..a249c2bf50 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -493,16 +493,24 @@ func Test_BufReadCmdHelpJump() au! BufReadCmd endfunc -" BufReadCmd is triggered for a "nofile" buffer +" BufReadCmd is triggered for a "nofile" buffer. Check all values. func Test_BufReadCmdNofile() - new somefile - set buftype=nofile - au BufReadCmd somefile call setline(1, 'triggered') - edit - call assert_equal('triggered', getline(1)) + for val in ['nofile', + \ 'nowrite', + \ 'acwrite', + \ 'quickfix', + \ 'help', + \ 'prompt', + \ ] + new somefile + exe 'set buftype=' .. val + au BufReadCmd somefile call setline(1, 'triggered') + edit + call assert_equal('triggered', getline(1)) - au! BufReadCmd - bwipe! + au! BufReadCmd + bwipe! + endfor endfunc func Test_augroup_deleted() @@ -603,15 +611,22 @@ func Test_BufEnter() au! BufEnter " Editing a "nofile" buffer doesn't read the file but does trigger BufEnter - " for historic reasons. - new somefile - set buftype=nofile - au BufEnter somefile call setline(1, 'some text') - edit - call assert_equal('some text', getline(1)) - - bwipe! - au! BufEnter + " for historic reasons. Also test other 'buftype' values. + for val in ['nofile', + \ 'nowrite', + \ 'acwrite', + \ 'quickfix', + \ 'help', + \ 'prompt', + \ ] + new somefile + exe 'set buftype=' .. val + au BufEnter somefile call setline(1, 'some text') + edit + call assert_equal('some text', getline(1)) + bwipe! + au! BufEnter + endfor endfunc " Closing a window might cause an endless loop diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim index 939147b83b..3b5bcbce89 100644 --- a/src/nvim/testdir/test_bufline.vim +++ b/src/nvim/testdir/test_bufline.vim @@ -187,4 +187,24 @@ func Test_deletebufline_select_mode() bwipe! endfunc +func Test_setbufline_startup_nofile() + let before =<< trim [CODE] + set shortmess+=F + file Xresult + set buftype=nofile + call setbufline('', 1, 'success') + [CODE] + let after =<< trim [CODE] + set buftype= + write + quit + [CODE] + + if !RunVim(before, after, '--clean') + return + endif + call assert_equal(['success'], readfile('Xresult')) + call delete('Xresult') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 555c4f58b7..147eda5b0a 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1880,19 +1880,21 @@ func Test_bufadd_bufload() exe 'bwipe ' .. buf2 call assert_equal(0, bufexists(buf2)) - " when 'buftype' is "nofile" then bufload() does not read the file - bwipe! XotherName - let buf = bufadd('XotherName') - call setbufvar(buf, '&bt', 'nofile') - call bufload(buf) - call assert_equal([''], getbufline(buf, 1, '$')) - - " when 'buftype' is "acwrite" then bufload() DOES read the file - bwipe! XotherName - let buf = bufadd('XotherName') - call setbufvar(buf, '&bt', 'acwrite') - call bufload(buf) - call assert_equal(['some', 'text'], getbufline(buf, 1, '$')) + " When 'buftype' is "nofile" then bufload() does not read the file. + " Other values too. + for val in [['nofile', 0], + \ ['nowrite', 1], + \ ['acwrite', 1], + \ ['quickfix', 0], + \ ['help', 1], + \ ['prompt', 0], + \ ] + bwipe! XotherName + let buf = bufadd('XotherName') + call setbufvar(buf, '&bt', val[0]) + call bufload(buf) + call assert_equal(val[1] ? ['some', 'text'] : [''], getbufline(buf, 1, '$'), val[0]) + endfor bwipe someName bwipe XotherName