0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

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)
This commit is contained in:
Bram Moolenaar
2022-04-04 16:57:21 +01:00
parent cc766a85f4
commit 188639d75c
7 changed files with 105 additions and 62 deletions

View File

@@ -271,6 +271,11 @@ popup_create({what}, {options}) *popup_create()*
'buftype' set to "popup". That buffer will be wiped out once 'buftype' set to "popup". That buffer will be wiped out once
the popup closes. 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. {options} is a dictionary with many possible entries.
See |popup_create-arguments| for details. See |popup_create-arguments| for details.

View File

@@ -150,7 +150,8 @@ buffer_ensure_loaded(buf_T *buf)
aco_save_T aco; aco_save_T aco;
aucmd_prepbuf(&aco, buf); 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); open_buffer(FALSE, NULL, 0);
aucmd_restbuf(&aco); aucmd_restbuf(&aco);
} }
@@ -1053,10 +1054,12 @@ goto_buffer(
int count) int count)
{ {
bufref_T old_curbuf; bufref_T old_curbuf;
int save_sea = swap_exists_action;
set_bufref(&old_curbuf, curbuf); 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, (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
start, dir, count, eap->forceit); start, dir, count, eap->forceit);
if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
@@ -1071,7 +1074,7 @@ goto_buffer(
// Quitting means closing the split window, nothing else. // Quitting means closing the split window, nothing else.
win_close(curwin, TRUE); win_close(curwin, TRUE);
swap_exists_action = SEA_NONE; swap_exists_action = save_sea;
swap_exists_did_quit = TRUE; swap_exists_did_quit = TRUE;
#if defined(FEAT_EVAL) #if defined(FEAT_EVAL)

View File

@@ -4631,19 +4631,22 @@ attention_message(
--no_wait_return; --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) #if defined(FEAT_EVAL)
/* /*
* Trigger the SwapExists autocommands. * Trigger the SwapExists autocommands.
* Returns a value for equivalent to do_dialog() (see below): * Returns a value for equivalent to do_dialog().
* 0: still need to ask for a choice
* 1: open read-only
* 2: edit anyway
* 3: recover
* 4: delete it
* 5: quit
* 6: abort
*/ */
static int static sea_choice_T
do_swapexists(buf_T *buf, char_u *fname) do_swapexists(buf_T *buf, char_u *fname)
{ {
set_vim_var_string(VV_SWAPNAME, fname, -1); 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)) switch (*get_vim_var_str(VV_SWAPCHOICE))
{ {
case 'o': return 1; case 'o': return SEA_CHOICE_READONLY;
case 'e': return 2; case 'e': return SEA_CHOICE_EDIT;
case 'r': return 3; case 'r': return SEA_CHOICE_RECOVER;
case 'd': return 4; case 'd': return SEA_CHOICE_DELETE;
case 'q': return 5; case 'q': return SEA_CHOICE_QUIT;
case 'a': return 6; case 'a': return SEA_CHOICE_ABORT;
} }
return 0; return SEA_CHOICE_NONE;
} }
#endif #endif
@@ -4986,10 +4989,10 @@ findswapname(
if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED) if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
&& vim_strchr(p_shm, SHM_ATTENTION) == NULL) && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
{ {
int choice = 0; sea_choice_T choice = SEA_CHOICE_NONE;
stat_T st; stat_T st;
#ifdef CREATE_DUMMY_FILE #ifdef CREATE_DUMMY_FILE
int did_use_dummy = FALSE; int did_use_dummy = FALSE;
// Avoid getting a warning for the file being created // Avoid getting a warning for the file being created
// outside of Vim, it was created at the start of this // 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 if (mch_stat((char *)buf->b_fname, &st) == 0
&& swapfile_unchanged(fname)) && swapfile_unchanged(fname))
{ {
choice = 4; choice = SEA_CHOICE_DELETE;
if (p_verbose > 0) if (p_verbose > 0)
verb_msg(_("Found a swap file that is not useful, deleting it")); 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 * the response, trigger it. It may return 0 to ask the
* user anyway. * user anyway.
*/ */
if (choice == 0 if (choice == SEA_CHOICE_NONE
&& swap_exists_action != SEA_NONE && swap_exists_action != SEA_NONE
&& has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
choice = do_swapexists(buf, fname); choice = do_swapexists(buf, fname);
if (choice == 0)
#endif #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 #ifdef FEAT_GUI
// If we are supposed to start the GUI but it wasn't // 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 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; char_u *name;
int dialog_result;
name = alloc(STRLEN(fname) name = alloc(STRLEN(fname)
+ STRLEN(_("Swap file \"")) + STRLEN(_("Swap file \""))
@@ -5067,7 +5079,7 @@ findswapname(
1000, TRUE); 1000, TRUE);
STRCAT(name, _("\" already exists!")); STRCAT(name, _("\" already exists!"));
} }
choice = do_dialog(VIM_WARNING, dialog_result = do_dialog(VIM_WARNING,
(char_u *)_("VIM - ATTENTION"), (char_u *)_("VIM - ATTENTION"),
name == NULL name == NULL
? (char_u *)_("Swap file already exists!") ? (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); (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 # ifdef HAVE_PROCESS_STILL_RUNNING
if (process_still_running && choice >= 4) if (process_still_running && dialog_result >= 4)
choice++; // Skip missing "Delete it" button // compensate for missing "Delete it" button
dialog_result++;
# endif # endif
choice = dialog_result;
vim_free(name); vim_free(name);
// pretend screen didn't scroll, need redraw anyway // pretend screen didn't scroll, need redraw anyway
@@ -5090,41 +5104,37 @@ findswapname(
} }
#endif #endif
if (choice > 0) switch (choice)
{ {
switch (choice) case SEA_CHOICE_READONLY:
{ buf->b_p_ro = TRUE;
case 1: break;
buf->b_p_ro = TRUE; case SEA_CHOICE_EDIT:
break; break;
case 2: case SEA_CHOICE_RECOVER:
break; swap_exists_action = SEA_RECOVER;
case 3: break;
swap_exists_action = SEA_RECOVER; case SEA_CHOICE_DELETE:
break; mch_remove(fname);
case 4: break;
mch_remove(fname); case SEA_CHOICE_QUIT:
break; swap_exists_action = SEA_QUIT;
case 5: break;
swap_exists_action = SEA_QUIT; case SEA_CHOICE_ABORT:
break; swap_exists_action = SEA_QUIT;
case 6: got_int = TRUE;
swap_exists_action = SEA_QUIT; break;
got_int = TRUE; case SEA_CHOICE_NONE:
break; msg_puts("\n");
} if (msg_silent == 0)
// call wait_return() later
// If the file was deleted this fname can be used. need_wait_return = TRUE;
if (mch_getperm(fname) < 0)
break; break;
} }
else
{ // If the file was deleted this fname can be used.
msg_puts("\n"); if (choice != SEA_CHOICE_NONE && mch_getperm(fname) < 0)
if (msg_silent == 0) break;
// call wait_return() later
need_wait_return = TRUE;
}
#ifdef CREATE_DUMMY_FILE #ifdef CREATE_DUMMY_FILE
// Going to try another name, need the dummy file again. // Going to try another name, need the dummy file again.

View File

@@ -1989,7 +1989,9 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
new_buffer = FALSE; new_buffer = FALSE;
win_init_popup_win(wp, buf); win_init_popup_win(wp, buf);
set_local_options_default(wp, FALSE); set_local_options_default(wp, FALSE);
swap_exists_action = SEA_READONLY;
buffer_ensure_loaded(buf); buffer_ensure_loaded(buf);
swap_exists_action = SEA_NONE;
} }
else else
{ {

View File

@@ -2775,6 +2775,26 @@ func Test_popupwin_with_buffer()
call delete('XsomeFile') call delete('XsomeFile')
endfunc 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() func Test_popupwin_terminal_buffer()
CheckFeature terminal CheckFeature terminal
CheckUnix CheckUnix

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4685,
/**/ /**/
4684, 4684,
/**/ /**/

View File

@@ -1250,6 +1250,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define SEA_DIALOG 1 // use dialog when possible #define SEA_DIALOG 1 // use dialog when possible
#define SEA_QUIT 2 // quit editing the file #define SEA_QUIT 2 // quit editing the file
#define SEA_RECOVER 3 // recover 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. * Minimal size for block 0 of a swap file.