diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2019-04-29 17:41:17 +0200 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2019-04-29 21:22:55 +0200 |
commit | 3033b5a70a1a9f1fdce1a772541fec9722825298 (patch) | |
tree | d75910dd59df01772559b8327e88939744c19793 | |
parent | 04f0bc97b732c395dbfcc9411910ab58b9346f58 (diff) | |
download | rneovim-3033b5a70a1a9f1fdce1a772541fec9722825298.tar.gz rneovim-3033b5a70a1a9f1fdce1a772541fec9722825298.tar.bz2 rneovim-3033b5a70a1a9f1fdce1a772541fec9722825298.zip |
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)
https://github.com/vim/vim/commit/67cf86bfff5fd5224d557d81cb146f46e33b831c
N/A:
vim-patch:8.1.1232
vim-patch:8.1.1233
vim-patch:8.1.1236
-rw-r--r-- | runtime/doc/usr_11.txt | 7 | ||||
-rw-r--r-- | src/nvim/fileio.c | 2 | ||||
-rw-r--r-- | src/nvim/main.c | 7 | ||||
-rw-r--r-- | src/nvim/memline.c | 86 | ||||
-rw-r--r-- | src/nvim/os/process.c | 6 | ||||
-rw-r--r-- | src/nvim/testdir/test_swap.vim | 56 |
6 files changed, 140 insertions, 24 deletions
diff --git a/runtime/doc/usr_11.txt b/runtime/doc/usr_11.txt index e5591ac1d1..42b564e962 100644 --- a/runtime/doc/usr_11.txt +++ b/runtime/doc/usr_11.txt @@ -205,6 +205,13 @@ something wrong. It may be one of these two situations. 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 Sometimes the line diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index b2840c9402..7abc75916c 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -633,7 +633,7 @@ readfile ( #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 (!read_buffer && !read_stdin) close(fd); diff --git a/src/nvim/main.c b/src/nvim/main.c index 27e2abe1ad..4e1c7dff57 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1520,10 +1520,11 @@ static void create_windows(mparm_T *parmp) dorewind = FALSE; curbuf = curwin->w_buffer; if (curbuf->b_ml.ml_mfp == NULL) { - /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */ - if (p_fdls >= 0) + // Set 'foldlevel' to 'foldlevelstart' if it's not negative.. + if (p_fdls >= 0) { 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; set_buflisted(TRUE); diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 7e15627292..23f223fcac 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -71,6 +71,7 @@ #include "nvim/undo.h" #include "nvim/window.h" #include "nvim/os/os.h" +#include "nvim/os/process.h" #include "nvim/os/input.h" #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; } -#ifdef UNIX static bool process_still_running; -#endif /// Return information found in swapfile "fname" in dictionary "d". /// 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) { MSG_PUTS(_("\n process ID: ")); msg_outnum(char_to_long(b0.b0_pid)); -#if defined(UNIX) - if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0) { + if (os_proc_running((int)char_to_long(b0.b0_pid))) { MSG_PUTS(_(" (STILL RUNNING)")); process_still_running = true; } -#endif } if (b0_magic_wrong(&b0)) { @@ -1588,6 +1585,51 @@ static time_t swapfile_info(char_u *fname) 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) 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) { int choice = 0; -#ifdef UNIX process_still_running = false; -#endif - /* - * If there is a SwapExists autocommand and we can handle - * the response, trigger it. It may return 0 to ask the - * user anyway. - */ - if (swap_exists_action != SEA_NONE - && has_autocmd(EVENT_SWAPEXISTS, (char_u *) buf_fname, buf)) + // It's safe to delete the swap file if all these are true: + // - the edited file exists + // - the swap file has no changes and looks OK + if (os_path_exists(buf->b_fname) && swapfile_unchanged(fname)) { + choice = 4; + if (p_verbose > 0) { + verb_msg(_("Found a swap file that is not useful, deleting it")); + } + } + + // 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); + } if (choice == 0) { // 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); choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"), (char_u *)name, -# if defined(UNIX) process_still_running ? (char_u *)_( "&Open Read-Only\n&Edit anyway\n&Recover" "\n&Quit\n&Abort") : -# endif (char_u *)_( "&Open Read-Only\n&Edit anyway\n&Recover" "\n&Delete it\n&Quit\n&Abort"), 1, NULL, false); -# if defined(UNIX) - if (process_still_running && choice >= 4) - choice++; /* Skip missing "Delete it" button */ -# endif + if (process_still_running && choice >= 4) { + choice++; // Skip missing "Delete it" button. + } xfree(name); // pretend screen didn't scroll, need redraw anyway diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c index a67e7487eb..a1020be215 100644 --- a/src/nvim/os/process.c +++ b/src/nvim/os/process.c @@ -265,3 +265,9 @@ Dictionary os_proc_info(int pid) return pinfo; } #endif + +/// Return true if process `pid` is running. +bool os_proc_running(int pid) +{ + return uv_kill(pid, 0) == 0; +} diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim index 1bd73707a8..1000422813 100644 --- a/src/nvim/testdir/test_swap.vim +++ b/src/nvim/testdir/test_swap.vim @@ -125,3 +125,59 @@ func Test_swapname() call delete('Xtest2') call delete('Xtest3') 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 |