changeset 28319:427600f3b1c5 v8.2.4685

patch 8.2.4685: when a swap file is found for a popup there is no dialog Commit: https://github.com/vim/vim/commit/188639d75c363dffaf813e8e2209f7350ad1e871 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Apr 4 16:57:21 2022 +0100 patch 8.2.4685: when a swap file is found for a popup there is no dialog 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)
author Bram Moolenaar <Bram@vim.org>
date Mon, 04 Apr 2022 18:00:04 +0200
parents 0a9769423ce4
children e96740baf1b4
files runtime/doc/popup.txt src/buffer.c src/memline.c src/popupwin.c src/testdir/test_popupwin.vim src/version.c src/vim.h
diffstat 7 files changed, 105 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -271,6 +271,11 @@ popup_create({what}, {options})				*popu
 		'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.
 
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -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)
--- a/src/memline.c
+++ b/src/memline.c
@@ -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.
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -1989,7 +1989,9 @@ popup_create(typval_T *argvars, typval_T
 	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
     {
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -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
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4685,
+/**/
     4684,
 /**/
     4683,
--- a/src/vim.h
+++ b/src/vim.h
@@ -1250,6 +1250,7 @@ extern int (*dyn_libintl_wputenv)(const 
 #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.