aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Kennedy <colinvfx@gmail.com>2024-03-27 08:22:33 +0000
committerGitHub <noreply@github.com>2024-03-27 16:22:33 +0800
commit61e25b7200a62d3f8c99ddd6196e124be6b6e3dc (patch)
tree0989367f86a04ed96e711e38d756caf31cc5ce7c
parent00e9c6955125fdbded208d4b5af59b94e96d7ea8 (diff)
downloadrneovim-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.c36
-rw-r--r--test/old/testdir/test_winfixbuf.vim140
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()