]> granicus.if.org Git - vim/commitdiff
patch 8.2.4685: when a swap file is found for a popup there is no dialog v8.2.4685
authorBram Moolenaar <Bram@vim.org>
Mon, 4 Apr 2022 15:57:21 +0000 (16:57 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 4 Apr 2022 15:57:21 +0000 (16:57 +0100)
Problem:    When a swap file is found for a popup there is no dialog and the
            buffer is loaded anyway.
Solution:   Silently load the buffer read-only. (closes #10073)

runtime/doc/popup.txt
src/buffer.c
src/memline.c
src/popupwin.c
src/testdir/test_popupwin.vim
src/version.c
src/vim.h

index 6645a7b2d9e551538a3d194ad549d94940327fbd..dcde185e918a8a872c109fd9d086fbf3595322a0 100644 (file)
@@ -271,6 +271,11 @@ popup_create({what}, {options})                            *popup_create()*
                'buftype' set to "popup".  That buffer will be wiped out once
                the popup closes.
 
+               if {what} is a buffer number and loading the buffer runs into
+               an existing swap file, it is silently opened read-only, as if
+               a |SwapExists| autocommand had set |v:swapchoice| to 'o'.
+               This is because we assume the buffer is only used for viewing.
+
                {options} is a dictionary with many possible entries.
                See |popup_create-arguments| for details.
 
index 8b50540e4e5ac01a4080e3f39fd1dd3f79e0f4b8..bd378302cd1d1cf3f727033867f9cf6f3b2b740a 100644 (file)
@@ -150,7 +150,8 @@ buffer_ensure_loaded(buf_T *buf)
        aco_save_T      aco;
 
        aucmd_prepbuf(&aco, buf);
-       swap_exists_action = SEA_NONE;
+       if (swap_exists_action != SEA_READONLY)
+           swap_exists_action = SEA_NONE;
        open_buffer(FALSE, NULL, 0);
        aucmd_restbuf(&aco);
     }
@@ -1053,10 +1054,12 @@ goto_buffer(
     int                count)
 {
     bufref_T   old_curbuf;
+    int                save_sea = swap_exists_action;
 
     set_bufref(&old_curbuf, curbuf);
 
-    swap_exists_action = SEA_DIALOG;
+    if (swap_exists_action == SEA_NONE)
+       swap_exists_action = SEA_DIALOG;
     (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
                                             start, dir, count, eap->forceit);
     if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
@@ -1071,7 +1074,7 @@ goto_buffer(
 
        // Quitting means closing the split window, nothing else.
        win_close(curwin, TRUE);
-       swap_exists_action = SEA_NONE;
+       swap_exists_action = save_sea;
        swap_exists_did_quit = TRUE;
 
 #if defined(FEAT_EVAL)
index 7b453cd474dcb9a7af20a41f4cb3e0f01f385a9b..abd2360ae8aa65148b6a8d61668b8b4721cccbef 100644 (file)
@@ -4631,19 +4631,22 @@ attention_message(
     --no_wait_return;
 }
 
+typedef enum {
+    SEA_CHOICE_NONE = 0,
+    SEA_CHOICE_READONLY = 1,
+    SEA_CHOICE_EDIT = 2,
+    SEA_CHOICE_RECOVER = 3,
+    SEA_CHOICE_DELETE = 4,
+    SEA_CHOICE_QUIT = 5,
+    SEA_CHOICE_ABORT = 6
+} sea_choice_T;
+
 #if defined(FEAT_EVAL)
 /*
  * Trigger the SwapExists autocommands.
- * Returns a value for equivalent to do_dialog() (see below):
- * 0: still need to ask for a choice
- * 1: open read-only
- * 2: edit anyway
- * 3: recover
- * 4: delete it
- * 5: quit
- * 6: abort
+ * Returns a value for equivalent to do_dialog().
  */
-    static int
+    static sea_choice_T
 do_swapexists(buf_T *buf, char_u *fname)
 {
     set_vim_var_string(VV_SWAPNAME, fname, -1);
@@ -4659,15 +4662,15 @@ do_swapexists(buf_T *buf, char_u *fname)
 
     switch (*get_vim_var_str(VV_SWAPCHOICE))
     {
-       case 'o': return 1;
-       case 'e': return 2;
-       case 'r': return 3;
-       case 'd': return 4;
-       case 'q': return 5;
-       case 'a': return 6;
+       case 'o': return SEA_CHOICE_READONLY;
+       case 'e': return SEA_CHOICE_EDIT;
+       case 'r': return SEA_CHOICE_RECOVER;
+       case 'd': return SEA_CHOICE_DELETE;
+       case 'q': return SEA_CHOICE_QUIT;
+       case 'a': return SEA_CHOICE_ABORT;
     }
 
-    return 0;
+    return SEA_CHOICE_NONE;
 }
 #endif
 
@@ -4986,10 +4989,10 @@ findswapname(
                if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
                        && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
                {
-                   int         choice = 0;
-                   stat_T      st;
+                   sea_choice_T choice = SEA_CHOICE_NONE;
+                   stat_T       st;
 #ifdef CREATE_DUMMY_FILE
-                   int         did_use_dummy = FALSE;
+                   int          did_use_dummy = FALSE;
 
                    // Avoid getting a warning for the file being created
                    // outside of Vim, it was created at the start of this
@@ -5013,7 +5016,7 @@ findswapname(
                    if (mch_stat((char *)buf->b_fname, &st) == 0
                                                  && swapfile_unchanged(fname))
                    {
-                       choice = 4;
+                       choice = SEA_CHOICE_DELETE;
                        if (p_verbose > 0)
                            verb_msg(_("Found a swap file that is not useful, deleting it"));
                    }
@@ -5024,13 +5027,20 @@ findswapname(
                     * the response, trigger it.  It may return 0 to ask the
                     * user anyway.
                     */
-                   if (choice == 0
+                   if (choice == SEA_CHOICE_NONE
                            && swap_exists_action != SEA_NONE
                            && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
                        choice = do_swapexists(buf, fname);
-
-                   if (choice == 0)
 #endif
+
+                   if (choice == SEA_CHOICE_NONE
+                                        && swap_exists_action == SEA_READONLY)
+                   {
+                       // always open readonly.
+                       choice = SEA_CHOICE_READONLY;
+                   }
+
+                   if (choice == SEA_CHOICE_NONE)
                    {
 #ifdef FEAT_GUI
                        // If we are supposed to start the GUI but it wasn't
@@ -5053,9 +5063,11 @@ findswapname(
                    }
 
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-                   if (swap_exists_action != SEA_NONE && choice == 0)
+                   if (swap_exists_action != SEA_NONE
+                                                 && choice == SEA_CHOICE_NONE)
                    {
                        char_u  *name;
+                       int     dialog_result;
 
                        name = alloc(STRLEN(fname)
                                + STRLEN(_("Swap file \""))
@@ -5067,7 +5079,7 @@ findswapname(
                                                                  1000, TRUE);
                            STRCAT(name, _("\" already exists!"));
                        }
-                       choice = do_dialog(VIM_WARNING,
+                       dialog_result = do_dialog(VIM_WARNING,
                                    (char_u *)_("VIM - ATTENTION"),
                                    name == NULL
                                        ?  (char_u *)_("Swap file already exists!")
@@ -5079,9 +5091,11 @@ findswapname(
                                        (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, FALSE);
 
 # ifdef HAVE_PROCESS_STILL_RUNNING
-                       if (process_still_running && choice >= 4)
-                           choice++;   // Skip missing "Delete it" button
+                       if (process_still_running && dialog_result >= 4)
+                           // compensate for missing "Delete it" button
+                           dialog_result++;
 # endif
+                       choice = dialog_result;
                        vim_free(name);
 
                        // pretend screen didn't scroll, need redraw anyway
@@ -5090,41 +5104,37 @@ findswapname(
                    }
 #endif
 
-                   if (choice > 0)
+                   switch (choice)
                    {
-                       switch (choice)
-                       {
-                           case 1:
-                               buf->b_p_ro = TRUE;
-                               break;
-                           case 2:
-                               break;
-                           case 3:
-                               swap_exists_action = SEA_RECOVER;
-                               break;
-                           case 4:
-                               mch_remove(fname);
-                               break;
-                           case 5:
-                               swap_exists_action = SEA_QUIT;
-                               break;
-                           case 6:
-                               swap_exists_action = SEA_QUIT;
-                               got_int = TRUE;
-                               break;
-                       }
-
-                       // If the file was deleted this fname can be used.
-                       if (mch_getperm(fname) < 0)
+                       case SEA_CHOICE_READONLY:
+                           buf->b_p_ro = TRUE;
+                           break;
+                       case SEA_CHOICE_EDIT:
+                           break;
+                       case SEA_CHOICE_RECOVER:
+                           swap_exists_action = SEA_RECOVER;
+                           break;
+                       case SEA_CHOICE_DELETE:
+                           mch_remove(fname);
+                           break;
+                       case SEA_CHOICE_QUIT:
+                           swap_exists_action = SEA_QUIT;
+                           break;
+                       case SEA_CHOICE_ABORT:
+                           swap_exists_action = SEA_QUIT;
+                           got_int = TRUE;
+                           break;
+                       case SEA_CHOICE_NONE:
+                           msg_puts("\n");
+                           if (msg_silent == 0)
+                               // call wait_return() later
+                               need_wait_return = TRUE;
                            break;
                    }
-                   else
-                   {
-                       msg_puts("\n");
-                       if (msg_silent == 0)
-                           // call wait_return() later
-                           need_wait_return = TRUE;
-                   }
+
+                   // If the file was deleted this fname can be used.
+                   if (choice != SEA_CHOICE_NONE && mch_getperm(fname) < 0)
+                       break;
 
 #ifdef CREATE_DUMMY_FILE
                    // Going to try another name, need the dummy file again.
index 9c0cade2da1d645ab686e971643f147f685b666d..e6792c8528f22b21ca50e4228e845c11d615fded 100644 (file)
@@ -1989,7 +1989,9 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
        new_buffer = FALSE;
        win_init_popup_win(wp, buf);
        set_local_options_default(wp, FALSE);
+       swap_exists_action = SEA_READONLY;
        buffer_ensure_loaded(buf);
+       swap_exists_action = SEA_NONE;
     }
     else
     {
index 08f45ae22e79afac89d8b0c21fd703d4b6ed4d2c..b91689e50ca47666bf089c0453a92e3e6020202b 100644 (file)
@@ -2775,6 +2775,26 @@ func Test_popupwin_with_buffer()
   call delete('XsomeFile')
 endfunc
 
+func Test_popupwin_buffer_with_swapfile()
+  call writefile(['some text', 'in a buffer'], 'XopenFile')
+  call writefile([''], '.XopenFile.swp')
+  let g:ignoreSwapExists = 1
+
+  let bufnr = bufadd('XopenFile')
+  call assert_equal(0, bufloaded(bufnr))
+  let winid = popup_create(bufnr, {'hidden': 1})
+  call assert_equal(1, bufloaded(bufnr))
+  call popup_close(winid)
+
+  exe 'buffer ' .. bufnr
+  call assert_equal(1, &readonly)
+  bwipe!
+
+  call delete('XopenFile')
+  call delete('.XopenFile.swp')
+  unlet g:ignoreSwapExists
+endfunc
+
 func Test_popupwin_terminal_buffer()
   CheckFeature terminal
   CheckUnix
index a7df559c58c1adb337fd93ba43fdbcf0216789cb..930f92ec4302cc416b8474b65c0c70a8fc2bd8a9 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4685,
 /**/
     4684,
 /**/
index 91ef5ccfcbbc46e8fd7a1aeb9a367417bff416a3..4174fa0d7e2ef3cbd478c46ef258b7329d8315ad 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -1250,6 +1250,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 #define SEA_DIALOG     1       // use dialog when possible
 #define SEA_QUIT       2       // quit editing the file
 #define SEA_RECOVER    3       // recover the file
+#define SEA_READONLY   4       // no dialog, mark buffer as read-only
 
 /*
  * Minimal size for block 0 of a swap file.