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:
@@ -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.
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
128
src/memline.c
128
src/memline.c
@@ -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.
|
||||||
|
@@ -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
|
||||||
{
|
{
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -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.
|
||||||
|
Reference in New Issue
Block a user