diff options
author | Colin Kennedy <colinvfx@gmail.com> | 2024-03-27 08:22:33 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-27 16:22:33 +0800 |
commit | 61e25b7200a62d3f8c99ddd6196e124be6b6e3dc (patch) | |
tree | 0989367f86a04ed96e711e38d756caf31cc5ce7c | |
parent | 00e9c6955125fdbded208d4b5af59b94e96d7ea8 (diff) | |
download | rneovim-61e25b7200a62d3f8c99ddd6196e124be6b6e3dc.tar.gz rneovim-61e25b7200a62d3f8c99ddd6196e124be6b6e3dc.tar.bz2 rneovim-61e25b7200a62d3f8c99ddd6196e124be6b6e3dc.zip |
vim-patch:9.1.0208: winfixbuf does not allow to re-edit current buffer (#28054)
Problem: winfixbuf does not allow to re-edit current buffer
(Tim Pope, after v9.1.0147)
Solution: Explicitly allow :e even when 'winfixbuf' is set,
since it just re-loads the current buffer
(Colin Kennedy)
fixes: vim/vim#14237
closes: vim/vim#14286
https://github.com/vim/vim/commit/65e580bd5610465bb6b9c1a546b7a8d00c76aa47
-rw-r--r-- | src/nvim/ex_docmd.c | 36 | ||||
-rw-r--r-- | test/old/testdir/test_winfixbuf.vim | 140 |
2 files changed, 175 insertions, 1 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1009e25081..ee738d9e92 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -216,6 +216,38 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp) current_exception = dsp->current_exception; } +/// Check if ffname differs from fnum. +/// fnum is a buffer number. 0 == current buffer, 1-or-more must be a valid buffer ID. +/// ffname is a full path to where a buffer lives on-disk or would live on-disk. +static bool is_other_file(int fnum, char *ffname) +{ + if (fnum != 0) { + if (fnum == curbuf->b_fnum) { + return false; + } + + return true; + } + + if (ffname == NULL) { + return true; + } + + if (*ffname == NUL) { + return false; + } + + if (!curbuf->file_id_valid + && curbuf->b_sfname != NULL + && *curbuf->b_sfname != NUL) { + // This occurs with unsaved buffers. In which case `ffname` + // actually corresponds to curbuf->b_sfname + return path_fnamecmp(ffname, curbuf->b_sfname) != 0; + } + + return otherfile(ffname); +} + /// Repeatedly get commands for Ex mode, until the ":vi" command is given. void do_exmode(void) { @@ -5371,11 +5403,13 @@ static void ex_find(exarg_T *eap) /// ":edit", ":badd", ":balt", ":visual". static void ex_edit(exarg_T *eap) { + char *ffname = eap->cmdidx == CMD_enew ? NULL : eap->arg; + // Exclude commands which keep the window's current buffer if (eap->cmdidx != CMD_badd && eap->cmdidx != CMD_balt // All other commands must obey 'winfixbuf' / ! rules - && !check_can_set_curbuf_forceit(eap->forceit)) { + && (is_other_file(0, ffname) && !check_can_set_curbuf_forceit(eap->forceit))) { return; } diff --git a/test/old/testdir/test_winfixbuf.vim b/test/old/testdir/test_winfixbuf.vim index 320e73f378..d5e43cf33e 100644 --- a/test/old/testdir/test_winfixbuf.vim +++ b/test/old/testdir/test_winfixbuf.vim @@ -1125,6 +1125,146 @@ func Test_edit() call assert_equal(l:other, bufnr()) endfunc +" Fail :e when selecting a buffer from a relative path if in a different folder +" +" In this tests there's 2 buffers +" +" foo - lives on disk, in some folder. e.g. /tmp/foo +" foo - an in-memory buffer that has not been saved to disk. If saved, it +" would live in a different folder, /other/foo. +" +" The 'winfixbuf' is looking at the in-memory buffer and trying to switch to +" the buffer on-disk (and fails, because it's a different buffer) +func Test_edit_different_buffer_on_disk_and_relative_path_to_disk() + call s:reset_all_buffers() + + let l:file_on_disk = tempname() + let l:directory_on_disk1 = fnamemodify(l:file_on_disk, ":p:h") + let l:name = fnamemodify(l:file_on_disk, ":t") + execute "edit " . l:file_on_disk + write! + + let l:directory_on_disk2 = l:directory_on_disk1 . "_something_else" + + if !isdirectory(l:directory_on_disk2) + call mkdir(l:directory_on_disk2) + endif + + execute "cd " . l:directory_on_disk2 + execute "edit " l:name + + let l:current = bufnr() + + call assert_equal(l:current, bufnr()) + set winfixbuf + call assert_fails("edit " . l:file_on_disk, "E1513:") + call assert_equal(l:current, bufnr()) + + call delete(l:directory_on_disk1) + call delete(l:directory_on_disk2) +endfunc + +" Fail :e when selecting a buffer from a relative path if in a different folder +" +" In this tests there's 2 buffers +" +" foo - lives on disk, in some folder. e.g. /tmp/foo +" foo - an in-memory buffer that has not been saved to disk. If saved, it +" would live in a different folder, /other/foo. +" +" The 'winfixbuf' is looking at the on-disk buffer and trying to switch to +" the in-memory buffer (and fails, because it's a different buffer) +func Test_edit_different_buffer_on_disk_and_relative_path_to_memory() + call s:reset_all_buffers() + + let l:file_on_disk = tempname() + let l:directory_on_disk1 = fnamemodify(l:file_on_disk, ":p:h") + let l:name = fnamemodify(l:file_on_disk, ":t") + execute "edit " . l:file_on_disk + write! + + let l:directory_on_disk2 = l:directory_on_disk1 . "_something_else" + + if !isdirectory(l:directory_on_disk2) + call mkdir(l:directory_on_disk2) + endif + + execute "cd " . l:directory_on_disk2 + execute "edit " l:name + execute "cd " . l:directory_on_disk1 + execute "edit " l:file_on_disk + execute "cd " . l:directory_on_disk2 + + let l:current = bufnr() + + call assert_equal(l:current, bufnr()) + set winfixbuf + call assert_fails("edit " . l:name, "E1513:") + call assert_equal(l:current, bufnr()) + + call delete(l:directory_on_disk1) + call delete(l:directory_on_disk2) +endfunc + +" Fail to call `:e first` if called from a starting, in-memory buffer +func Test_edit_first_buffer() + call s:reset_all_buffers() + + set winfixbuf + let l:current = bufnr() + + call assert_fails("edit first", "E1513:") + call assert_equal(l:current, bufnr()) + + edit! first + call assert_equal(l:current, bufnr()) + edit! somewhere_else + call assert_notequal(l:current, bufnr()) +endfunc + +" Allow reloading a buffer using :e +func Test_edit_no_arguments() + call s:reset_all_buffers() + + let l:current = bufnr() + file some_buffer + + call assert_equal(l:current, bufnr()) + set winfixbuf + edit + call assert_equal(l:current, bufnr()) +endfunc + +" Allow :e selecting the current buffer +func Test_edit_same_buffer_in_memory() + call s:reset_all_buffers() + + let l:current = bufnr() + file same_buffer + + call assert_equal(l:current, bufnr()) + set winfixbuf + edit same_buffer + call assert_equal(l:current, bufnr()) +endfunc + +" Allow :e selecting the current buffer as a full path +func Test_edit_same_buffer_on_disk_absolute_path() + call s:reset_all_buffers() + + let l:file = tempname() + let l:current = bufnr() + execute "edit " . l:file + write! + + call assert_equal(l:current, bufnr()) + set winfixbuf + execute "edit " l:file + call assert_equal(l:current, bufnr()) + + call delete(l:file) +endfunc + " Fail :enew but :enew! is allowed func Test_enew() call s:reset_all_buffers() |