summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-04-04 16:57:21 +0100
committerBram Moolenaar <Bram@vim.org>2022-04-04 16:57:21 +0100
commit188639d75c363dffaf813e8e2209f7350ad1e871 (patch)
tree5ad1a2954a8a4a821125a7f20e9667a85f3a6196
parentcc766a85f460ebb7f8c915508447548b5f5b99bc (diff)
patch 8.2.4685: when a swap file is found for a popup there is no dialogv8.2.4685
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)
-rw-r--r--runtime/doc/popup.txt5
-rw-r--r--src/buffer.c9
-rw-r--r--src/memline.c128
-rw-r--r--src/popupwin.c2
-rw-r--r--src/testdir/test_popupwin.vim20
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
7 files changed, 105 insertions, 62 deletions
diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt
index 6645a7b2d9..dcde185e91 100644
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -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.
diff --git a/src/buffer.c b/src/buffer.c
index 8b50540e4e..bd378302cd 100644
--- 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)
diff --git a/src/memline.c b/src/memline.c
index 7b453cd474..abd2360ae8 100644
--- 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.
diff --git a/src/popupwin.c b/src/popupwin.c
index 9c0cade2da..e6792c8528 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -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
{
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index 08f45ae22e..b91689e50c 100644
--- 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
diff --git a/src/version.c b/src/version.c
index a7df559c58..930f92ec43 100644
--- 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,
diff --git a/src/vim.h b/src/vim.h
index 91ef5ccfcb..4174fa0d7e 100644
--- 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.