]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0443: GUI: cancelling save dialog overwrites or discards unnamed buffer v9.2.0443
authorHirohito Higashi <h.east.727@gmail.com>
Tue, 5 May 2026 19:02:59 +0000 (19:02 +0000)
committerChristian Brabandt <cb@256bit.org>
Tue, 5 May 2026 19:02:59 +0000 (19:02 +0000)
Problem:  When closing gvim with an unsaved unnamed buffer, choosing
          "Yes" in the "Save changes?" dialog and then "Cancel" in the
          file selection dialog either silently writes the buffer to a
          file named "Untitled" (overwriting any existing file with
          that name) or discards the buffer altogether
          (vibs29, after v9.1.0265).
Solution: In dialog_changed(), if browse_save_fname() leaves the buffer
          without a file name, treat it as a cancel and return without
          saving.  Also stop clearing the modified flag in the restore
          path on write failure, so the unsaved changes are kept and
          the caller (e.g. gui_shell_closed()) can also cancel the
          close.  Pre-fill the file dialog with "Untitled" to match
          the preceding "Save changes to ..." prompt.  Add a test for
          the write-failure path (Hirohito Higashi).

fixes:  #20132
closes: #20143

Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/ex_cmds2.c
src/testdir/test_buffer.vim
src/version.c

index 7012c989626a7e15aca3dc9a4b6ebcbf1b3627e6..afe9c4b58ad1022758a6bba7cc257dab6bbd1df4 100644 (file)
@@ -141,7 +141,7 @@ browse_save_fname(buf_T *buf)
     char_u *fname;
 
     fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
-           NULL, NULL, NULL, NULL, buf);
+           (char_u *)"Untitled", NULL, NULL, NULL, buf);
     if (fname == NULL)
        return;
 
@@ -182,6 +182,10 @@ dialog_changed(
 # ifdef FEAT_BROWSE
        // May get file name, when there is none
        browse_save_fname(buf);
+
+       // User cancelled the file dialog; keep the buffer modified.
+       if (buf->b_fname == NULL)
+           return;
 # endif
        empty_bufname = buf->b_fname == NULL ? TRUE : FALSE;
        if (empty_bufname)
@@ -194,13 +198,12 @@ dialog_changed(
                return;
        }
 
-       // restore to empty when write failed
+       // restore to empty when write failed or was cancelled
        if (empty_bufname)
        {
            buf->b_fname = NULL;
            VIM_CLEAR(buf->b_ffname);
            VIM_CLEAR(buf->b_sfname);
-           unchanged(buf, TRUE, FALSE);
        }
     }
     else if (ret == VIM_NO)
index 934bc6fe1e8bd714ccae1ab1ada645417e517da6..4f0f1acb24f4c2365fc791cf07b812705497a80d 100644 (file)
@@ -342,6 +342,28 @@ func Test_goto_buf_with_confirm()
   close!
 endfunc
 
+" Test for issue #20132: when saving an unnamed buffer fails the modified
+" flag must be kept, otherwise the buffer is silently discarded.
+func Test_dialog_changed_keep_modified_on_write_fail()
+  CheckUnix
+  CheckNotGui
+  CheckFeature dialog_con
+  CheckNotFeature dialog_con_gui
+  CheckNotRoot
+
+  call writefile(['existing'], 'Untitled', 'D')
+  call setfperm('Untitled', 'r--r--r--')
+
+  new
+  call setline(1, 'test')
+  call feedkeys('y', 'L')
+  silent! confirm bdel
+  call assert_true(&modified)
+  call assert_equal(['existing'], readfile('Untitled'))
+
+  bw!
+endfunc
+
 " Test for splitting buffer with 'switchbuf'
 func Test_buffer_switchbuf()
   new Xswitchbuf
index 5dde38b7b4ca71c942ae4558c771a0f14bd320aa..61342e15f091a45e7c649f90e89d06aeb751c1f9 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    443,
 /**/
     442,
 /**/