mirror of
https://github.com/neovim/neovim.git
synced 2025-11-26 20:20:42 +00:00
vim-patch:8.1.1231: asking about existing swap file unnecessarily
Problem: Asking about existing swap file unnecessarily.
Solution: When it is safe, delete the swap file. Remove
HAS_SWAP_EXISTS_ACTION, it is always defined. (closes vim/vim#1237)
67cf86bfff
N/A:
vim-patch:8.1.1232
vim-patch:8.1.1233
vim-patch:8.1.1236
This commit is contained in:
@@ -205,6 +205,13 @@ something wrong. It may be one of these two situations.
|
|||||||
NEWER than swap file! ~
|
NEWER than swap file! ~
|
||||||
|
|
||||||
|
|
||||||
|
NOTE that in the following situation Vim knows the swap file is not useful and
|
||||||
|
will automatically delete it:
|
||||||
|
- The file is a valid swap file (Magic number is correct).
|
||||||
|
- The flag that the file was modified is not set.
|
||||||
|
- The process is not running.
|
||||||
|
|
||||||
|
|
||||||
UNREADABLE SWAP FILE
|
UNREADABLE SWAP FILE
|
||||||
|
|
||||||
Sometimes the line
|
Sometimes the line
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ readfile (
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If "Quit" selected at ATTENTION dialog, don't load the file */
|
// If "Quit" selected at ATTENTION dialog, don't load the file.
|
||||||
if (swap_exists_action == SEA_QUIT) {
|
if (swap_exists_action == SEA_QUIT) {
|
||||||
if (!read_buffer && !read_stdin)
|
if (!read_buffer && !read_stdin)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|||||||
@@ -1520,10 +1520,11 @@ static void create_windows(mparm_T *parmp)
|
|||||||
dorewind = FALSE;
|
dorewind = FALSE;
|
||||||
curbuf = curwin->w_buffer;
|
curbuf = curwin->w_buffer;
|
||||||
if (curbuf->b_ml.ml_mfp == NULL) {
|
if (curbuf->b_ml.ml_mfp == NULL) {
|
||||||
/* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
|
// Set 'foldlevel' to 'foldlevelstart' if it's not negative..
|
||||||
if (p_fdls >= 0)
|
if (p_fdls >= 0) {
|
||||||
curwin->w_p_fdl = p_fdls;
|
curwin->w_p_fdl = p_fdls;
|
||||||
/* When getting the ATTENTION prompt here, use a dialog */
|
}
|
||||||
|
// When getting the ATTENTION prompt here, use a dialog.
|
||||||
swap_exists_action = SEA_DIALOG;
|
swap_exists_action = SEA_DIALOG;
|
||||||
set_buflisted(TRUE);
|
set_buflisted(TRUE);
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
|
#include "nvim/os/process.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
|
|
||||||
#ifndef UNIX /* it's in os/unix_defs.h for Unix */
|
#ifndef UNIX /* it's in os/unix_defs.h for Unix */
|
||||||
@@ -1453,9 +1454,7 @@ static char *make_percent_swname(const char *dir, char *name)
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNIX
|
|
||||||
static bool process_still_running;
|
static bool process_still_running;
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Return information found in swapfile "fname" in dictionary "d".
|
/// Return information found in swapfile "fname" in dictionary "d".
|
||||||
/// This is used by the swapinfo() function.
|
/// This is used by the swapinfo() function.
|
||||||
@@ -1566,12 +1565,10 @@ static time_t swapfile_info(char_u *fname)
|
|||||||
if (char_to_long(b0.b0_pid) != 0L) {
|
if (char_to_long(b0.b0_pid) != 0L) {
|
||||||
MSG_PUTS(_("\n process ID: "));
|
MSG_PUTS(_("\n process ID: "));
|
||||||
msg_outnum(char_to_long(b0.b0_pid));
|
msg_outnum(char_to_long(b0.b0_pid));
|
||||||
#if defined(UNIX)
|
if (os_proc_running((int)char_to_long(b0.b0_pid))) {
|
||||||
if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0) {
|
|
||||||
MSG_PUTS(_(" (STILL RUNNING)"));
|
MSG_PUTS(_(" (STILL RUNNING)"));
|
||||||
process_still_running = true;
|
process_still_running = true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b0_magic_wrong(&b0)) {
|
if (b0_magic_wrong(&b0)) {
|
||||||
@@ -1588,6 +1585,51 @@ static time_t swapfile_info(char_u *fname)
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns TRUE if the swap file looks OK and there are no changes, thus it
|
||||||
|
/// can be safely deleted.
|
||||||
|
static time_t swapfile_unchanged(char *fname)
|
||||||
|
{
|
||||||
|
struct block0 b0;
|
||||||
|
int ret = true;
|
||||||
|
|
||||||
|
// Swap file must exist.
|
||||||
|
if (!os_path_exists((char_u *)fname)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be able to read the first block
|
||||||
|
int fd = os_open(fname, O_RDONLY, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (read_eintr(fd, &b0, sizeof(b0)) != sizeof(b0)) {
|
||||||
|
close(fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the ID and magic number must be correct
|
||||||
|
if (ml_check_b0_id(&b0) == FAIL|| b0_magic_wrong(&b0)) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be unchanged
|
||||||
|
if (b0.b0_dirty) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process must be known and not running.
|
||||||
|
long pid = char_to_long(b0.b0_pid);
|
||||||
|
if (pid == 0L || os_proc_running((int)pid)) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Should we check if the swap file was created on the current
|
||||||
|
// system? And the current user?
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
|
static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
@@ -3389,17 +3431,24 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
|
|||||||
&& vim_strchr(p_shm, SHM_ATTENTION) == NULL) {
|
&& vim_strchr(p_shm, SHM_ATTENTION) == NULL) {
|
||||||
int choice = 0;
|
int choice = 0;
|
||||||
|
|
||||||
#ifdef UNIX
|
|
||||||
process_still_running = false;
|
process_still_running = false;
|
||||||
#endif
|
// It's safe to delete the swap file if all these are true:
|
||||||
/*
|
// - the edited file exists
|
||||||
* If there is a SwapExists autocommand and we can handle
|
// - the swap file has no changes and looks OK
|
||||||
* the response, trigger it. It may return 0 to ask the
|
if (os_path_exists(buf->b_fname) && swapfile_unchanged(fname)) {
|
||||||
* user anyway.
|
choice = 4;
|
||||||
*/
|
if (p_verbose > 0) {
|
||||||
if (swap_exists_action != SEA_NONE
|
verb_msg(_("Found a swap file that is not useful, deleting it"));
|
||||||
&& has_autocmd(EVENT_SWAPEXISTS, (char_u *) buf_fname, buf))
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a SwapExists autocommand and we can handle the
|
||||||
|
// response, trigger it. It may return 0 to ask the user anyway.
|
||||||
|
if (choice == 0
|
||||||
|
&& swap_exists_action != SEA_NONE
|
||||||
|
&& has_autocmd(EVENT_SWAPEXISTS, (char_u *) buf_fname, buf)) {
|
||||||
choice = do_swapexists(buf, (char_u *) fname);
|
choice = do_swapexists(buf, (char_u *) fname);
|
||||||
|
}
|
||||||
|
|
||||||
if (choice == 0) {
|
if (choice == 0) {
|
||||||
// Show info about the existing swap file.
|
// Show info about the existing swap file.
|
||||||
@@ -3431,21 +3480,18 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
|
|||||||
xstrlcat(name, sw_msg_2, name_len);
|
xstrlcat(name, sw_msg_2, name_len);
|
||||||
choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"),
|
choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"),
|
||||||
(char_u *)name,
|
(char_u *)name,
|
||||||
# if defined(UNIX)
|
|
||||||
process_still_running
|
process_still_running
|
||||||
? (char_u *)_(
|
? (char_u *)_(
|
||||||
"&Open Read-Only\n&Edit anyway\n&Recover"
|
"&Open Read-Only\n&Edit anyway\n&Recover"
|
||||||
"\n&Quit\n&Abort") :
|
"\n&Quit\n&Abort") :
|
||||||
# endif
|
|
||||||
(char_u *)_(
|
(char_u *)_(
|
||||||
"&Open Read-Only\n&Edit anyway\n&Recover"
|
"&Open Read-Only\n&Edit anyway\n&Recover"
|
||||||
"\n&Delete it\n&Quit\n&Abort"),
|
"\n&Delete it\n&Quit\n&Abort"),
|
||||||
1, NULL, false);
|
1, NULL, false);
|
||||||
|
|
||||||
# if defined(UNIX)
|
if (process_still_running && choice >= 4) {
|
||||||
if (process_still_running && choice >= 4)
|
choice++; // Skip missing "Delete it" button.
|
||||||
choice++; /* Skip missing "Delete it" button */
|
}
|
||||||
# endif
|
|
||||||
xfree(name);
|
xfree(name);
|
||||||
|
|
||||||
// pretend screen didn't scroll, need redraw anyway
|
// pretend screen didn't scroll, need redraw anyway
|
||||||
|
|||||||
@@ -265,3 +265,9 @@ Dictionary os_proc_info(int pid)
|
|||||||
return pinfo;
|
return pinfo;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Return true if process `pid` is running.
|
||||||
|
bool os_proc_running(int pid)
|
||||||
|
{
|
||||||
|
return uv_kill(pid, 0) == 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -125,3 +125,59 @@ func Test_swapname()
|
|||||||
call delete('Xtest2')
|
call delete('Xtest2')
|
||||||
call delete('Xtest3')
|
call delete('Xtest3')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_swapfile_delete()
|
||||||
|
autocmd! SwapExists
|
||||||
|
function s:swap_exists()
|
||||||
|
let v:swapchoice = s:swap_choice
|
||||||
|
let s:swapname = v:swapname
|
||||||
|
let s:filename = expand('<afile>')
|
||||||
|
endfunc
|
||||||
|
augroup test_swapfile_delete
|
||||||
|
autocmd!
|
||||||
|
autocmd SwapExists * call s:swap_exists()
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
|
||||||
|
" Create a valid swapfile by editing a file.
|
||||||
|
split XswapfileText
|
||||||
|
call setline(1, ['one', 'two', 'three'])
|
||||||
|
write " file is written, not modified
|
||||||
|
" read the swapfile as a Blob
|
||||||
|
let swapfile_name = swapname('%')
|
||||||
|
let swapfile_bytes = readfile(swapfile_name, 'B')
|
||||||
|
|
||||||
|
" Close the file and recreate the swap file.
|
||||||
|
" Now editing the file will run into the process still existing
|
||||||
|
quit
|
||||||
|
call writefile(swapfile_bytes, swapfile_name)
|
||||||
|
let s:swap_choice = 'e'
|
||||||
|
let s:swapname = ''
|
||||||
|
split XswapfileText
|
||||||
|
quit
|
||||||
|
call assert_equal(swapfile_name, s:swapname)
|
||||||
|
|
||||||
|
" Write the swapfile with a modified PID, now it will be automatically
|
||||||
|
" deleted. Process one should never be Vim.
|
||||||
|
let swapfile_bytes[24:27] = 0z01000000
|
||||||
|
call writefile(swapfile_bytes, swapfile_name)
|
||||||
|
let s:swapname = ''
|
||||||
|
split XswapfileText
|
||||||
|
quit
|
||||||
|
call assert_equal('', s:swapname)
|
||||||
|
|
||||||
|
" Now set the modified flag, the swap file will not be deleted
|
||||||
|
let swapfile_bytes[28 + 80 + 899] = 0x55
|
||||||
|
call writefile(swapfile_bytes, swapfile_name)
|
||||||
|
let s:swapname = ''
|
||||||
|
split XswapfileText
|
||||||
|
quit
|
||||||
|
call assert_equal(swapfile_name, s:swapname)
|
||||||
|
|
||||||
|
call delete('XswapfileText')
|
||||||
|
call delete(swapfile_name)
|
||||||
|
augroup test_swapfile_delete
|
||||||
|
autocmd!
|
||||||
|
augroup END
|
||||||
|
augroup! test_swapfile_delete
|
||||||
|
endfunc
|
||||||
|
|||||||
Reference in New Issue
Block a user