patch 9.1.0208: winfixbuf does not allow to re-edit current buffer

Commit: 
https://github.com/vim/vim/commit/65e580bd5610465bb6b9c1a546b7a8d00c76aa47
Author: Colin Kennedy <colin...@gmail.com>
Date:   Tue Mar 26 18:29:30 2024 +0100

    patch 9.1.0208: winfixbuf does not allow to re-edit current buffer
    
    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: #14237
    closes: #14286
    
    Signed-off-by: Colin Kennedy <colin...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 21ba0d5bc..981d270dc 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -460,6 +460,40 @@ restore_dbg_stuff(struct dbg_stuff *dsp)
 }
 #endif
 
+/*
+ * 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 int
+is_other_file(int fnum, char_u *ffname)
+{
+  if (fnum != 0)
+  {
+    if (fnum == curbuf->b_fnum)
+      return FALSE;
+
+    return TRUE;
+  }
+
+  if (ffname == NULL)
+    return TRUE;
+
+  if (*ffname == NUL)
+    return FALSE;
+
+  // TODO: Need a reliable way to know whether a buffer is meant to live 
on-disk
+  // !curbuf->b_dev_valid is not always available (example: missing on Windows)
+  if (curbuf->b_sfname != NULL
+      && *curbuf->b_sfname != NUL)
+    // This occurs with unsaved buffers. In which case `ffname`
+    // actually corresponds to curbuf->b_sfname
+    return fnamecmp(ffname, curbuf->b_sfname) != 0;
+
+  return otherfile(ffname);
+}
+
 /*
  * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi"
  * command is given.
@@ -7256,12 +7290,15 @@ ex_open(exarg_T *eap)
     static void
 ex_edit(exarg_T *eap)
 {
+    char_u *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;
 
     do_exedit(eap, NULL);
diff --git a/src/testdir/test_winfixbuf.vim b/src/testdir/test_winfixbuf.vim
index 04043f873..ba44b42cc 100644
--- a/src/testdir/test_winfixbuf.vim
+++ b/src/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()
diff --git a/src/version.c b/src/version.c
index 8ab595719..a9515d689 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    208,
 /**/
     207,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1rpAr9-007aCO-5V%40256bit.org.

Raspunde prin e-mail lui