mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge #9956 from justinmk/vim-8.1.1231
vim-patch:8.1.1231, swap-related patches
This commit is contained in:
commit
63526f2eee
@ -2321,6 +2321,8 @@ submatch({nr} [, {list}]) String or List
|
||||
specific match in ":s" or substitute()
|
||||
substitute({expr}, {pat}, {sub}, {flags})
|
||||
String all {pat} in {expr} replaced with {sub}
|
||||
swapinfo({fname}) Dict information about swap file {fname}
|
||||
swapname({expr}) String swap file of buffer {expr}
|
||||
synID({lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col}
|
||||
synIDattr({synID}, {what} [, {mode}])
|
||||
String attribute {what} of syntax ID {synID}
|
||||
@ -7758,6 +7760,31 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
|
||||
|submatch()| returns. Example: >
|
||||
:echo substitute(s, '\(\x\x\)', {m -> '0x' . m[1]}, 'g')
|
||||
|
||||
swapinfo({fname}) swapinfo()
|
||||
The result is a dictionary, which holds information about the
|
||||
swapfile {fname}. The available fields are:
|
||||
version VIM version
|
||||
user user name
|
||||
host host name
|
||||
fname original file name
|
||||
pid PID of the VIM process that created the swap
|
||||
file
|
||||
mtime last modification time in seconds
|
||||
inode Optional: INODE number of the file
|
||||
dirty 1 if file was modified, 0 if not
|
||||
In case of failure an "error" item is added with the reason:
|
||||
Cannot open file: file not found or in accessible
|
||||
Cannot read file: cannot read first block
|
||||
Not a swap file: does not contain correct block ID
|
||||
Magic number mismatch: Info in first block is invalid
|
||||
|
||||
swapname({expr}) *swapname()*
|
||||
The result is the swap file path of the buffer {expr}.
|
||||
For the use of {expr}, see |bufname()| above.
|
||||
If buffer {expr} is the current buffer, the result is equal to
|
||||
|:swapname| (unless no swap file).
|
||||
If buffer {expr} has no swap file, returns an empty string.
|
||||
|
||||
synID({lnum}, {col}, {trans}) *synID()*
|
||||
The result is a Number, which is the syntax ID at the position
|
||||
{lnum} and {col} in the current window.
|
||||
|
@ -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
|
||||
|
@ -5221,7 +5221,7 @@ bool garbage_collect(bool testing)
|
||||
(void)garbage_collect(testing);
|
||||
}
|
||||
} else if (p_verbose > 0) {
|
||||
verb_msg((char_u *)_(
|
||||
verb_msg(_(
|
||||
"Not enough memory to set references, garbage collection aborted!"));
|
||||
}
|
||||
#undef ABORTING
|
||||
@ -11474,25 +11474,21 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
|
||||
static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
|
||||
|
||||
/*
|
||||
* "inputrestore()" function
|
||||
*/
|
||||
/// "inputrestore()" function
|
||||
static void f_inputrestore(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
if (!GA_EMPTY(&ga_userinput)) {
|
||||
--ga_userinput.ga_len;
|
||||
ga_userinput.ga_len--;
|
||||
restore_typeahead((tasave_T *)(ga_userinput.ga_data)
|
||||
+ ga_userinput.ga_len);
|
||||
/* default return is zero == OK */
|
||||
+ ga_userinput.ga_len);
|
||||
// default return is zero == OK
|
||||
} else if (p_verbose > 1) {
|
||||
verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
|
||||
rettv->vval.v_number = 1; /* Failed */
|
||||
verb_msg(_("called inputrestore() more often than inputsave()"));
|
||||
rettv->vval.v_number = 1; // Failed
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "inputsave()" function
|
||||
*/
|
||||
/// "inputsave()" function
|
||||
static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
// Add an entry to the stack of typeahead storage.
|
||||
@ -11500,9 +11496,7 @@ static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
save_typeahead(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* "inputsecret()" function
|
||||
*/
|
||||
/// "inputsecret()" function
|
||||
static void f_inputsecret(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
cmdline_star++;
|
||||
@ -16423,6 +16417,27 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// "swapinfo(swap_filename)" function
|
||||
static void f_swapinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
tv_dict_alloc_ret(rettv);
|
||||
get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
|
||||
}
|
||||
|
||||
/// "swapname(expr)" function
|
||||
static void f_swapname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
rettv->v_type = VAR_STRING;
|
||||
buf_T *buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL
|
||||
|| buf->b_ml.ml_mfp == NULL
|
||||
|| buf->b_ml.ml_mfp->mf_fname == NULL) {
|
||||
rettv->vval.v_string = NULL;
|
||||
} else {
|
||||
rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
|
||||
}
|
||||
}
|
||||
|
||||
/// "synID(lnum, col, trans)" function
|
||||
static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
|
@ -301,6 +301,8 @@ return {
|
||||
strwidth={args=1},
|
||||
submatch={args={1, 2}},
|
||||
substitute={args=4},
|
||||
swapinfo={args={1}},
|
||||
swapname={args={1}},
|
||||
synID={args=3},
|
||||
synIDattr={args={2, 3}},
|
||||
synIDtrans={args=1},
|
||||
|
@ -1656,12 +1656,7 @@ int tv_dict_add_special(dict_T *const d, const char *const key,
|
||||
|
||||
/// Add a string entry to dictionary
|
||||
///
|
||||
/// @param[out] d Dictionary to add entry to.
|
||||
/// @param[in] key Key to add.
|
||||
/// @param[in] key_len Key length.
|
||||
/// @param[in] val String to add.
|
||||
///
|
||||
/// @return OK in case of success, FAIL when key already exists.
|
||||
/// @see tv_dict_add_allocated_str
|
||||
int tv_dict_add_str(dict_T *const d,
|
||||
const char *const key, const size_t key_len,
|
||||
const char *const val)
|
||||
@ -1670,6 +1665,27 @@ int tv_dict_add_str(dict_T *const d,
|
||||
return tv_dict_add_allocated_str(d, key, key_len, xstrdup(val));
|
||||
}
|
||||
|
||||
/// Add a string entry to dictionary
|
||||
///
|
||||
/// @param[out] d Dictionary to add entry to.
|
||||
/// @param[in] key Key to add.
|
||||
/// @param[in] key_len Key length.
|
||||
/// @param[in] val String to add. NULL adds empty string.
|
||||
/// @param[in] len Use this many bytes from `val`, or -1 for whole string.
|
||||
///
|
||||
/// @return OK in case of success, FAIL when key already exists.
|
||||
int tv_dict_add_str_len(dict_T *const d,
|
||||
const char *const key, const size_t key_len,
|
||||
char *const val, int len)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||
{
|
||||
char *s = val ? val : "";
|
||||
if (val != NULL) {
|
||||
s = (len < 0) ? xstrdup(val) : xstrndup(val, (size_t)len);
|
||||
}
|
||||
return tv_dict_add_allocated_str(d, key, key_len, s);
|
||||
}
|
||||
|
||||
/// Add a string entry to dictionary
|
||||
///
|
||||
/// Unlike tv_dict_add_str() saves val to the new dictionary item in place of
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,14 +1454,47 @@ static char *make_percent_swname(const char *dir, char *name)
|
||||
return d;
|
||||
}
|
||||
|
||||
#ifdef UNIX
|
||||
static bool process_still_running;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Give information about an existing swap file.
|
||||
* Returns timestamp (0 when unknown).
|
||||
*/
|
||||
/// Return information found in swapfile "fname" in dictionary "d".
|
||||
/// This is used by the swapinfo() function.
|
||||
void get_b0_dict(const char *fname, dict_T *d)
|
||||
{
|
||||
int fd;
|
||||
struct block0 b0;
|
||||
|
||||
if ((fd = os_open(fname, O_RDONLY, 0)) >= 0) {
|
||||
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) {
|
||||
if (ml_check_b0_id(&b0) == FAIL) {
|
||||
tv_dict_add_str(d, S_LEN("error"), "Not a swap file");
|
||||
} else if (b0_magic_wrong(&b0)) {
|
||||
tv_dict_add_str(d, S_LEN("error"), "Magic number mismatch");
|
||||
} else {
|
||||
// We have swap information.
|
||||
tv_dict_add_str_len(d, S_LEN("version"), (char *)b0.b0_version, 10);
|
||||
tv_dict_add_str_len(d, S_LEN("user"), (char *)b0.b0_uname,
|
||||
B0_UNAME_SIZE);
|
||||
tv_dict_add_str_len(d, S_LEN("host"), (char *)b0.b0_hname,
|
||||
B0_HNAME_SIZE);
|
||||
tv_dict_add_str_len(d, S_LEN("fname"), (char *)b0.b0_fname,
|
||||
B0_FNAME_SIZE_ORG);
|
||||
|
||||
tv_dict_add_nr(d, S_LEN("pid"), char_to_long(b0.b0_pid));
|
||||
tv_dict_add_nr(d, S_LEN("mtime"), char_to_long(b0.b0_mtime));
|
||||
tv_dict_add_nr(d, S_LEN("dirty"), b0.b0_dirty ? 1 : 0);
|
||||
tv_dict_add_nr(d, S_LEN("inode"), char_to_long(b0.b0_ino));
|
||||
}
|
||||
} else {
|
||||
tv_dict_add_str(d, S_LEN("error"), "Cannot read file");
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
tv_dict_add_str(d, S_LEN("error"), "Cannot open file");
|
||||
}
|
||||
}
|
||||
|
||||
/// Give information about an existing swap file.
|
||||
/// Returns timestamp (0 when unknown).
|
||||
static time_t swapfile_info(char_u *fname)
|
||||
{
|
||||
assert(fname != NULL);
|
||||
@ -1530,12 +1564,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)) {
|
||||
@ -1552,6 +1584,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(bram): 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
|
||||
{
|
||||
@ -3353,17 +3430,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))
|
||||
choice = do_swapexists(buf, (char_u *) fname);
|
||||
// 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.
|
||||
@ -3395,21 +3479,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
|
||||
|
@ -133,15 +133,11 @@ int msg(char_u *s)
|
||||
return msg_attr_keep(s, 0, false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like msg() but keep it silent when 'verbosefile' is set.
|
||||
*/
|
||||
int verb_msg(char_u *s)
|
||||
/// Like msg() but keep it silent when 'verbosefile' is set.
|
||||
int verb_msg(char *s)
|
||||
{
|
||||
int n;
|
||||
|
||||
verbose_enter();
|
||||
n = msg_attr_keep(s, 0, false, false);
|
||||
int n = msg_attr_keep((char_u *)s, 0, false, false);
|
||||
verbose_leave();
|
||||
|
||||
return n;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
" Tests for the swap feature
|
||||
|
||||
func s:swapname()
|
||||
return trim(execute('swapname'))
|
||||
endfunc
|
||||
|
||||
" Tests for 'directory' option.
|
||||
func Test_swap_directory()
|
||||
if !has("unix")
|
||||
@ -17,7 +21,7 @@ func Test_swap_directory()
|
||||
" Verify that the swap file doesn't exist in the current directory
|
||||
call assert_equal([], glob(".Xtest1*.swp", 1, 1, 1))
|
||||
edit Xtest1
|
||||
let swfname = split(execute("swapname"))[0]
|
||||
let swfname = s:swapname()
|
||||
call assert_equal([swfname], glob(swfname, 1, 1, 1))
|
||||
|
||||
" './dir', swap file in a directory relative to the file
|
||||
@ -27,7 +31,7 @@ func Test_swap_directory()
|
||||
edit Xtest1
|
||||
call assert_equal([], glob(swfname, 1, 1, 1))
|
||||
let swfname = "Xtest2/Xtest1.swp"
|
||||
call assert_equal(swfname, split(execute("swapname"))[0])
|
||||
call assert_equal(swfname, s:swapname())
|
||||
call assert_equal([swfname], glob("Xtest2/*", 1, 1, 1))
|
||||
|
||||
" 'dir', swap file in directory relative to the current dir
|
||||
@ -38,7 +42,7 @@ func Test_swap_directory()
|
||||
edit Xtest2/Xtest3
|
||||
call assert_equal(["Xtest2/Xtest3"], glob("Xtest2/*", 1, 1, 1))
|
||||
let swfname = "Xtest.je/Xtest3.swp"
|
||||
call assert_equal(swfname, split(execute("swapname"))[0])
|
||||
call assert_equal(swfname, s:swapname())
|
||||
call assert_equal([swfname], glob("Xtest.je/*", 1, 1, 1))
|
||||
|
||||
set dir&
|
||||
@ -61,3 +65,120 @@ func Test_missing_dir()
|
||||
set directory&
|
||||
call delete('Xswapdir', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_swapinfo()
|
||||
new Xswapinfo
|
||||
call setline(1, ['one', 'two', 'three'])
|
||||
w
|
||||
let fname = s:swapname()
|
||||
call assert_match('Xswapinfo', fname)
|
||||
let info = swapinfo(fname)
|
||||
|
||||
let ver = printf('VIM %d.%d', v:version / 100, v:version % 100)
|
||||
call assert_equal(ver, info.version)
|
||||
|
||||
call assert_match('\w', info.user)
|
||||
" host name is truncated to 39 bytes in the swap file
|
||||
call assert_equal(hostname()[:38], info.host)
|
||||
call assert_match('Xswapinfo', info.fname)
|
||||
call assert_match(0, info.dirty)
|
||||
call assert_equal(getpid(), info.pid)
|
||||
call assert_match('^\d*$', info.mtime)
|
||||
if has_key(info, 'inode')
|
||||
call assert_match('\d', info.inode)
|
||||
endif
|
||||
bwipe!
|
||||
call delete(fname)
|
||||
call delete('Xswapinfo')
|
||||
|
||||
let info = swapinfo('doesnotexist')
|
||||
call assert_equal('Cannot open file', info.error)
|
||||
|
||||
call writefile(['burp'], 'Xnotaswapfile')
|
||||
let info = swapinfo('Xnotaswapfile')
|
||||
call assert_equal('Cannot read file', info.error)
|
||||
call delete('Xnotaswapfile')
|
||||
|
||||
call writefile([repeat('x', 10000)], 'Xnotaswapfile')
|
||||
let info = swapinfo('Xnotaswapfile')
|
||||
call assert_equal('Not a swap file', info.error)
|
||||
call delete('Xnotaswapfile')
|
||||
endfunc
|
||||
|
||||
func Test_swapname()
|
||||
edit Xtest1
|
||||
let expected = s:swapname()
|
||||
call assert_equal(expected, swapname('%'))
|
||||
|
||||
new Xtest2
|
||||
let buf = bufnr('%')
|
||||
let expected = s:swapname()
|
||||
wincmd p
|
||||
call assert_equal(expected, swapname(buf))
|
||||
|
||||
new Xtest3
|
||||
setlocal noswapfile
|
||||
call assert_equal('', swapname('%'))
|
||||
|
||||
bwipe!
|
||||
call delete('Xtest1')
|
||||
call delete('Xtest2')
|
||||
call delete('Xtest3')
|
||||
endfunc
|
||||
|
||||
func Test_swapfile_delete()
|
||||
throw 'skipped: need the "blob" feature for this test'
|
||||
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(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t'))
|
||||
|
||||
" 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(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t'))
|
||||
|
||||
call delete('XswapfileText')
|
||||
call delete(swapfile_name)
|
||||
augroup test_swapfile_delete
|
||||
autocmd!
|
||||
augroup END
|
||||
augroup! test_swapfile_delete
|
||||
endfunc
|
||||
|
@ -1131,8 +1131,9 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
|
||||
/* If there is no undo information at all, quit here after deleting any
|
||||
* existing undo file. */
|
||||
if (buf->b_u_numhead == 0 && buf->b_u_line_ptr == NULL) {
|
||||
if (p_verbose > 0)
|
||||
verb_msg((char_u *)_("Skipping undo file write, nothing to undo"));
|
||||
if (p_verbose > 0) {
|
||||
verb_msg(_("Skipping undo file write, nothing to undo"));
|
||||
}
|
||||
goto theend;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user