mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
commit
ecc28fb2dd
@ -824,7 +824,7 @@ void ml_recover(void)
|
|||||||
(void)recover_names(fname, FALSE, i, &fname_used);
|
(void)recover_names(fname, FALSE, i, &fname_used);
|
||||||
}
|
}
|
||||||
if (fname_used == NULL)
|
if (fname_used == NULL)
|
||||||
goto theend; /* out of memory */
|
goto theend; // user chose invalid number.
|
||||||
|
|
||||||
/* When called from main() still need to initialize storage structure */
|
/* When called from main() still need to initialize storage structure */
|
||||||
if (called_from_main && ml_open(curbuf) == FAIL)
|
if (called_from_main && ml_open(curbuf) == FAIL)
|
||||||
@ -1244,8 +1244,10 @@ theend:
|
|||||||
mf_put(mfp, hp, false, false);
|
mf_put(mfp, hp, false, false);
|
||||||
mf_close(mfp, false); /* will also free(mfp->mf_fname) */
|
mf_close(mfp, false); /* will also free(mfp->mf_fname) */
|
||||||
}
|
}
|
||||||
free(buf->b_ml.ml_stack);
|
if (buf != NULL) { //may be NULL if swap file not found.
|
||||||
free(buf);
|
free(buf->b_ml.ml_stack);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
if (serious_error && called_from_main)
|
if (serious_error && called_from_main)
|
||||||
ml_close(curbuf, TRUE);
|
ml_close(curbuf, TRUE);
|
||||||
else {
|
else {
|
||||||
@ -1321,53 +1323,35 @@ recover_names (
|
|||||||
if (dir_name[0] == '.' && dir_name[1] == NUL) { /* check current dir */
|
if (dir_name[0] == '.' && dir_name[1] == NUL) { /* check current dir */
|
||||||
if (fname == NULL) {
|
if (fname == NULL) {
|
||||||
names[0] = vim_strsave((char_u *)"*.sw?");
|
names[0] = vim_strsave((char_u *)"*.sw?");
|
||||||
#if defined(UNIX) || defined(WIN3264)
|
|
||||||
/* For Unix names starting with a dot are special. MS-Windows
|
/* For Unix names starting with a dot are special. MS-Windows
|
||||||
* supports this too, on some file systems. */
|
* supports this too, on some file systems. */
|
||||||
names[1] = vim_strsave((char_u *)".*.sw?");
|
names[1] = vim_strsave((char_u *)".*.sw?");
|
||||||
names[2] = vim_strsave((char_u *)".sw?");
|
names[2] = vim_strsave((char_u *)".sw?");
|
||||||
num_names = 3;
|
num_names = 3;
|
||||||
#else
|
|
||||||
num_names = 1;
|
|
||||||
#endif
|
|
||||||
} else
|
} else
|
||||||
num_names = recov_file_names(names, fname_res, TRUE);
|
num_names = recov_file_names(names, fname_res, TRUE);
|
||||||
} else { /* check directory dir_name */
|
} else { /* check directory dir_name */
|
||||||
if (fname == NULL) {
|
if (fname == NULL) {
|
||||||
names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
|
names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
|
||||||
#if defined(UNIX) || defined(WIN3264)
|
|
||||||
/* For Unix names starting with a dot are special. MS-Windows
|
/* For Unix names starting with a dot are special. MS-Windows
|
||||||
* supports this too, on some file systems. */
|
* supports this too, on some file systems. */
|
||||||
names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
|
names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
|
||||||
names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
|
names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
|
||||||
num_names = 3;
|
num_names = 3;
|
||||||
#else
|
|
||||||
num_names = 1;
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
#if defined(UNIX) || defined(WIN3264)
|
|
||||||
p = dir_name + STRLEN(dir_name);
|
p = dir_name + STRLEN(dir_name);
|
||||||
if (after_pathsep(dir_name, p) && p[-1] == p[-2]) {
|
if (after_pathsep(dir_name, p) && p[-1] == p[-2]) {
|
||||||
/* Ends with '//', Use Full path for swap name */
|
/* Ends with '//', Use Full path for swap name */
|
||||||
tail = make_percent_swname(dir_name, fname_res);
|
tail = make_percent_swname(dir_name, fname_res);
|
||||||
} else
|
} else {
|
||||||
#endif
|
tail = path_tail(fname_res);
|
||||||
tail = path_tail(fname_res);
|
tail = concat_fnames(dir_name, tail, TRUE);
|
||||||
tail = concat_fnames(dir_name, tail, TRUE);
|
}
|
||||||
num_names = recov_file_names(names, tail, FALSE);
|
num_names = recov_file_names(names, tail, FALSE);
|
||||||
free(tail);
|
free(tail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for out-of-memory
|
|
||||||
for (int i = 0; i < num_names; ++i) {
|
|
||||||
if (names[i] == NULL) {
|
|
||||||
for (int j = 0; j < num_names; ++j)
|
|
||||||
free(names[j]);
|
|
||||||
num_names = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (num_names == 0)
|
if (num_names == 0)
|
||||||
num_files = 0;
|
num_files = 0;
|
||||||
else if (expand_wildcards(num_names, names, &num_files, &files,
|
else if (expand_wildcards(num_names, names, &num_files, &files,
|
||||||
@ -1453,7 +1437,6 @@ recover_names (
|
|||||||
return file_count;
|
return file_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
|
|
||||||
/*
|
/*
|
||||||
* Append the full path to name with path separators made into percent
|
* Append the full path to name with path separators made into percent
|
||||||
* signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
|
* signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
|
||||||
@ -1475,7 +1458,6 @@ static char_u *make_percent_swname(char_u *dir, char_u *name)
|
|||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
static int process_still_running;
|
static int process_still_running;
|
||||||
@ -1576,17 +1558,12 @@ static time_t swapfile_info(char_u *fname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
int num_names;
|
int num_names = 0;
|
||||||
char_u *p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
num_names = 0;
|
// May also add the file name with a dot prepended, for swap file in same
|
||||||
|
// dir as original file.
|
||||||
/*
|
|
||||||
* May also add the file name with a dot prepended, for swap file in same
|
|
||||||
* dir as original file.
|
|
||||||
*/
|
|
||||||
if (prepend_dot) {
|
if (prepend_dot) {
|
||||||
names[num_names] = modname(path, (char_u *)".sw?", TRUE);
|
names[num_names] = modname(path, (char_u *)".sw?", TRUE);
|
||||||
if (names[num_names] == NULL)
|
if (names[num_names] == NULL)
|
||||||
@ -1597,8 +1574,8 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
|
|||||||
// Form the normal swap file name pattern by appending ".sw?".
|
// Form the normal swap file name pattern by appending ".sw?".
|
||||||
names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
|
names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
|
||||||
if (num_names >= 1) { /* check if we have the same name twice */
|
if (num_names >= 1) { /* check if we have the same name twice */
|
||||||
p = names[num_names - 1];
|
char_u *p = names[num_names - 1];
|
||||||
i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
|
int i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
p += i; /* file name has been expanded to full path */
|
p += i; /* file name has been expanded to full path */
|
||||||
|
|
||||||
@ -3088,7 +3065,6 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
|
|||||||
char_u fname_buf[MAXPATHL];
|
char_u fname_buf[MAXPATHL];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
|
|
||||||
s = dir_name + STRLEN(dir_name);
|
s = dir_name + STRLEN(dir_name);
|
||||||
if (after_pathsep(dir_name, s) && s[-1] == s[-2]) { /* Ends with '//', Use Full path */
|
if (after_pathsep(dir_name, s) && s[-1] == s[-2]) { /* Ends with '//', Use Full path */
|
||||||
r = NULL;
|
r = NULL;
|
||||||
@ -3098,7 +3074,6 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
|
|||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_READLINK
|
#ifdef HAVE_READLINK
|
||||||
/* Expand symlink in the file name, so that we put the swap file with the
|
/* Expand symlink in the file name, so that we put the swap file with the
|
||||||
|
@ -83,15 +83,12 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
|
|||||||
return kDifferentFiles;
|
return kDifferentFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the tail of a path: the file name.
|
/// Gets the tail (i.e., the filename segment) of a path `fname`.
|
||||||
///
|
///
|
||||||
/// @param fname A file path.
|
/// @return pointer just past the last path separator (empty string, if fname
|
||||||
/// @return
|
/// ends in a slash), or empty string if fname is NULL.
|
||||||
/// - Empty string, if fname is NULL.
|
|
||||||
/// - The position of the last path separator + 1. (i.e. empty string, if
|
|
||||||
/// fname ends in a slash).
|
|
||||||
/// - Never NULL.
|
|
||||||
char_u *path_tail(char_u *fname)
|
char_u *path_tail(char_u *fname)
|
||||||
|
FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
if (fname == NULL) {
|
if (fname == NULL) {
|
||||||
return (char_u *)"";
|
return (char_u *)"";
|
||||||
|
@ -24,7 +24,7 @@ SCRIPTS := test_autoformat_join.out \
|
|||||||
test61.out test62.out test63.out test64.out test65.out \
|
test61.out test62.out test63.out test64.out test65.out \
|
||||||
test68.out test69.out \
|
test68.out test69.out \
|
||||||
test71.out test73.out test74.out \
|
test71.out test73.out test74.out \
|
||||||
test76.out test78.out test79.out test80.out \
|
test76.out test79.out test80.out \
|
||||||
test82.out test83.out \
|
test82.out test83.out \
|
||||||
test86.out test87.out test88.out \
|
test86.out test87.out test88.out \
|
||||||
test96.out \
|
test96.out \
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
Inserts 10000 lines with text to fill the swap file with two levels of pointer
|
|
||||||
blocks. Then recovers from the swap file and checks all text is restored.
|
|
||||||
|
|
||||||
We need about 10000 lines of 100 characters to get two levels of pointer
|
|
||||||
blocks.
|
|
||||||
|
|
||||||
STARTTEST
|
|
||||||
:so small.vim
|
|
||||||
:set fileformat=unix undolevels=-1
|
|
||||||
:e! Xtest
|
|
||||||
ggdG
|
|
||||||
:let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
|
|
||||||
:let i = 1
|
|
||||||
:let linecount = 10000
|
|
||||||
:while i <= linecount | call append(i - 1, i . text) | let i += 1 | endwhile
|
|
||||||
:preserve
|
|
||||||
:" get the name of the swap file
|
|
||||||
:redir => swapname
|
|
||||||
:swapname
|
|
||||||
:redir END
|
|
||||||
:let swapname = substitute(swapname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
|
|
||||||
:" make a copy of the swap file in Xswap
|
|
||||||
:set bin
|
|
||||||
:exe 'sp ' . swapname
|
|
||||||
:w! Xswap
|
|
||||||
:echo swapname
|
|
||||||
:set nobin
|
|
||||||
:new
|
|
||||||
:only!
|
|
||||||
:bwipe! Xtest
|
|
||||||
:call rename('Xswap', swapname)
|
|
||||||
:recover Xtest
|
|
||||||
:call delete(swapname)
|
|
||||||
:new
|
|
||||||
:call append(0, 'recovery start')
|
|
||||||
:wincmd w
|
|
||||||
:let linedollar = line('$')
|
|
||||||
:if linedollar < linecount | exe 'wincmd w' | call append(line('$'), "expected " . linecount . " lines but found only " . linedollar) | exe 'wincmd w' | let linecount = linedollar | endif
|
|
||||||
:let i = 1
|
|
||||||
:while i <= linecount | if getline(i) != i . text | exe 'wincmd w' | call append(line('$'), i . ' differs') | exe 'wincmd w' | endif | let i += 1 | endwhile
|
|
||||||
:q!
|
|
||||||
:call append(line('$'), 'recovery end')
|
|
||||||
:w! test.out
|
|
||||||
:qa!
|
|
||||||
ENDTEST
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
recovery start
|
|
||||||
|
|
||||||
recovery end
|
|
71
test/functional/ex_cmds/recover_spec.lua
Normal file
71
test/functional/ex_cmds/recover_spec.lua
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
-- Tests for :recover
|
||||||
|
|
||||||
|
local helpers = require('test.functional.helpers')
|
||||||
|
local execute, eq, clear, eval, feed, expect, source =
|
||||||
|
helpers.execute, helpers.eq, helpers.clear, helpers.eval, helpers.feed,
|
||||||
|
helpers.expect, helpers.source
|
||||||
|
|
||||||
|
describe(':recover', function()
|
||||||
|
before_each(clear)
|
||||||
|
|
||||||
|
it('fails if given a non-existent swapfile', function()
|
||||||
|
local swapname = 'bogus-swapfile'
|
||||||
|
execute('recover '..swapname) -- This should not segfault. #2117
|
||||||
|
eq('E305: No swap file found for '..swapname, eval('v:errmsg'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe(':preserve', function()
|
||||||
|
local swapdir = lfs.currentdir()..'/testdir_recover_spec'
|
||||||
|
before_each(function()
|
||||||
|
clear()
|
||||||
|
os.remove(swapdir)
|
||||||
|
lfs.mkdir(swapdir)
|
||||||
|
end)
|
||||||
|
after_each(function()
|
||||||
|
os.remove(swapdir)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("saves to custom 'directory' and (R)ecovers (issue #1836)", function()
|
||||||
|
local testfile = 'testfile_recover_spec'
|
||||||
|
local init = [[
|
||||||
|
set swapfile fileformat=unix undolevels=-1
|
||||||
|
set directory^=]]..swapdir..[[//
|
||||||
|
]]
|
||||||
|
|
||||||
|
source(init)
|
||||||
|
execute('set swapfile fileformat=unix undolevels=-1')
|
||||||
|
-- Put swapdir at the start of the 'directory' list. #1836
|
||||||
|
execute('set directory^='..swapdir..'//')
|
||||||
|
execute('edit '..testfile)
|
||||||
|
feed('isometext<esc>')
|
||||||
|
execute('preserve')
|
||||||
|
source('redir => g:swapname | swapname | redir END')
|
||||||
|
|
||||||
|
local swappath1 = eval('g:swapname')
|
||||||
|
|
||||||
|
--TODO(justinmk): this is an ugly hack to force `helpers` to support
|
||||||
|
--multiple sessions.
|
||||||
|
local nvim2 = helpers.spawn({helpers.nvim_prog, '-u', 'NONE', '--embed'})
|
||||||
|
helpers.set_session(nvim2)
|
||||||
|
|
||||||
|
source(init)
|
||||||
|
|
||||||
|
-- Use the "SwapExists" event to choose the (R)ecover choice at the dialog.
|
||||||
|
execute('autocmd SwapExists * let v:swapchoice = "r"')
|
||||||
|
execute('silent edit '..testfile)
|
||||||
|
source('redir => g:swapname | swapname | redir END')
|
||||||
|
|
||||||
|
local swappath2 = eval('g:swapname')
|
||||||
|
|
||||||
|
-- swapfile from session 1 should end in .swp
|
||||||
|
assert(testfile..'.swp' == string.match(swappath1, '[^%%]+$'))
|
||||||
|
|
||||||
|
-- swapfile from session 2 should end in .swo
|
||||||
|
assert(testfile..'.swo' == string.match(swappath2, '[^%%]+$'))
|
||||||
|
|
||||||
|
expect('sometext')
|
||||||
|
end)
|
||||||
|
|
||||||
|
end)
|
@ -18,6 +18,10 @@ if nvim_dir == nvim_prog then
|
|||||||
nvim_dir = "."
|
nvim_dir = "."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Nvim "Unit Under Test" http://en.wikipedia.org/wiki/Device_under_test
|
||||||
|
local NvimUUT = {}
|
||||||
|
NvimUUT.__index = NvimUUT
|
||||||
|
|
||||||
local prepend_argv
|
local prepend_argv
|
||||||
|
|
||||||
if os.getenv('VALGRIND') then
|
if os.getenv('VALGRIND') then
|
||||||
@ -49,6 +53,10 @@ end
|
|||||||
|
|
||||||
local session, loop_running, loop_stopped, last_error
|
local session, loop_running, loop_stopped, last_error
|
||||||
|
|
||||||
|
local function set_session(s)
|
||||||
|
session = s
|
||||||
|
end
|
||||||
|
|
||||||
local function request(method, ...)
|
local function request(method, ...)
|
||||||
local status, rv = session:request(method, ...)
|
local status, rv = session:request(method, ...)
|
||||||
if not status then
|
if not status then
|
||||||
@ -305,5 +313,6 @@ return {
|
|||||||
curwin = curwin,
|
curwin = curwin,
|
||||||
curtab = curtab,
|
curtab = curtab,
|
||||||
curbuf_contents = curbuf_contents,
|
curbuf_contents = curbuf_contents,
|
||||||
wait = wait
|
wait = wait,
|
||||||
|
set_session = set_session
|
||||||
}
|
}
|
||||||
|
80
test/functional/legacy/078_swapfile_recover_spec.lua
Normal file
80
test/functional/legacy/078_swapfile_recover_spec.lua
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
-- Inserts 10000 lines with text to fill the swap file with two levels of
|
||||||
|
-- pointer blocks. Then recovers from the swap file and checks all text is
|
||||||
|
-- restored. We need about 10000 lines of 100 characters to get two levels of
|
||||||
|
-- pointer blocks.
|
||||||
|
|
||||||
|
local helpers = require('test.functional.helpers')
|
||||||
|
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
|
||||||
|
local clear, execute, expect, source = helpers.clear, helpers.execute, helpers.expect, helpers.source
|
||||||
|
local eval = helpers.eval
|
||||||
|
|
||||||
|
describe('78', function()
|
||||||
|
setup(clear)
|
||||||
|
teardown(function()
|
||||||
|
os.remove(".Xtest.swp")
|
||||||
|
os.remove(".Xtest.swo")
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('is working', function()
|
||||||
|
source([=[
|
||||||
|
set swapfile fileformat=unix undolevels=-1
|
||||||
|
e! Xtest
|
||||||
|
let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
|
||||||
|
let i = 1
|
||||||
|
let linecount = 10000
|
||||||
|
while i <= linecount | call append(i - 1, i . text) | let i += 1 | endwhile
|
||||||
|
preserve
|
||||||
|
|
||||||
|
" Get the name of the swap file, and clean up the :redir capture.
|
||||||
|
redir => g:swapname | swapname | redir END
|
||||||
|
let g:swapname = substitute(g:swapname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', 'g')
|
||||||
|
let g:swapname = fnameescape(g:swapname)
|
||||||
|
|
||||||
|
" Make a copy of the swap file in Xswap
|
||||||
|
set bin
|
||||||
|
exe 'sp ' . g:swapname
|
||||||
|
w! Xswap
|
||||||
|
|
||||||
|
set nobin
|
||||||
|
new
|
||||||
|
only!
|
||||||
|
bwipe! Xtest
|
||||||
|
call rename('Xswap', g:swapname)
|
||||||
|
|
||||||
|
"TODO(jkeyes): without 'silent', this hangs the test " at message:
|
||||||
|
" 'Recovery completed. You should check if everything is OK.'
|
||||||
|
silent recover Xtest
|
||||||
|
|
||||||
|
call delete(g:swapname)
|
||||||
|
new
|
||||||
|
call append(0, 'recovery start')
|
||||||
|
wincmd w
|
||||||
|
|
||||||
|
let g:linedollar = line('$')
|
||||||
|
if g:linedollar < linecount
|
||||||
|
wincmd w
|
||||||
|
call append(line('$'), "expected " . linecount
|
||||||
|
\ . " lines but found only " . g:linedollar)
|
||||||
|
wincmd w
|
||||||
|
let linecount = g:linedollar
|
||||||
|
endif
|
||||||
|
|
||||||
|
let i = 1
|
||||||
|
while i <= linecount
|
||||||
|
if getline(i) != i . text
|
||||||
|
exe 'wincmd w'
|
||||||
|
call append(line('$'), i . ' differs')
|
||||||
|
exe 'wincmd w'
|
||||||
|
endif
|
||||||
|
let i += 1
|
||||||
|
endwhile
|
||||||
|
q!
|
||||||
|
call append(line('$'), 'recovery end')
|
||||||
|
]=])
|
||||||
|
|
||||||
|
expect([[
|
||||||
|
recovery start
|
||||||
|
|
||||||
|
recovery end]])
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
Reference in New Issue
Block a user