mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge #6221
This commit is contained in:
commit
0cd829161a
@ -756,14 +756,6 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
|
|||||||
linenr_T num_lines; // Num lines moved
|
linenr_T num_lines; // Num lines moved
|
||||||
linenr_T last_line; // Last line in file after adding new text
|
linenr_T last_line; // Last line in file after adding new text
|
||||||
|
|
||||||
// Moving lines seems to corrupt the folds, delete folding info now
|
|
||||||
// and recreate it when finished. Don't do this for manual folding, it
|
|
||||||
// would delete all folds.
|
|
||||||
bool isFolded = hasAnyFolding(curwin) && !foldmethodIsManual(curwin);
|
|
||||||
if (isFolded) {
|
|
||||||
deleteFoldRecurse(&curwin->w_folds);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dest >= line1 && dest < line2) {
|
if (dest >= line1 && dest < line2) {
|
||||||
EMSG(_("E134: Move lines into themselves"));
|
EMSG(_("E134: Move lines into themselves"));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -801,21 +793,29 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
|
|||||||
* their final destination at the new text position -- webb
|
* their final destination at the new text position -- webb
|
||||||
*/
|
*/
|
||||||
last_line = curbuf->b_ml.ml_line_count;
|
last_line = curbuf->b_ml.ml_line_count;
|
||||||
mark_adjust(line1, line2, last_line - line2, 0L);
|
mark_adjust_nofold(line1, line2, last_line - line2, 0L);
|
||||||
changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines);
|
|
||||||
if (dest >= line2) {
|
if (dest >= line2) {
|
||||||
mark_adjust(line2 + 1, dest, -num_lines, 0L);
|
mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L);
|
||||||
|
FOR_ALL_TAB_WINDOWS(tab, win) {
|
||||||
|
if (win->w_buffer == curbuf) {
|
||||||
|
foldMoveRange(&win->w_folds, line1, line2, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
curbuf->b_op_start.lnum = dest - num_lines + 1;
|
curbuf->b_op_start.lnum = dest - num_lines + 1;
|
||||||
curbuf->b_op_end.lnum = dest;
|
curbuf->b_op_end.lnum = dest;
|
||||||
} else {
|
} else {
|
||||||
mark_adjust(dest + 1, line1 - 1, num_lines, 0L);
|
mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L);
|
||||||
|
FOR_ALL_TAB_WINDOWS(tab, win) {
|
||||||
|
if (win->w_buffer == curbuf) {
|
||||||
|
foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2);
|
||||||
|
}
|
||||||
|
}
|
||||||
curbuf->b_op_start.lnum = dest + 1;
|
curbuf->b_op_start.lnum = dest + 1;
|
||||||
curbuf->b_op_end.lnum = dest + num_lines;
|
curbuf->b_op_end.lnum = dest + num_lines;
|
||||||
}
|
}
|
||||||
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
|
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
|
||||||
mark_adjust(last_line - num_lines + 1, last_line,
|
mark_adjust_nofold(last_line - num_lines + 1, last_line,
|
||||||
-(last_line - dest - extra), 0L);
|
-(last_line - dest - extra), 0L);
|
||||||
changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we delete the original text -- webb
|
* Now we delete the original text -- webb
|
||||||
@ -851,11 +851,6 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
|
|||||||
changed_lines(dest + 1, 0, line1 + num_lines, 0L);
|
changed_lines(dest + 1, 0, line1 + num_lines, 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
// recreate folds
|
|
||||||
if (isFolded) {
|
|
||||||
foldUpdateAll(curwin);
|
|
||||||
}
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
179
src/nvim/fold.c
179
src/nvim/fold.c
@ -2507,6 +2507,8 @@ static void foldSplit(garray_T *gap, int i, linenr_T top, linenr_T bot)
|
|||||||
|
|
||||||
fp = (fold_T *)gap->ga_data + i;
|
fp = (fold_T *)gap->ga_data + i;
|
||||||
fp[1].fd_top = bot + 1;
|
fp[1].fd_top = bot + 1;
|
||||||
|
// check for wrap around (MAXLNUM, and 32bit)
|
||||||
|
assert(fp[1].fd_top > bot);
|
||||||
fp[1].fd_len = fp->fd_len - (fp[1].fd_top - fp->fd_top);
|
fp[1].fd_len = fp->fd_len - (fp[1].fd_top - fp->fd_top);
|
||||||
fp[1].fd_flags = fp->fd_flags;
|
fp[1].fd_flags = fp->fd_flags;
|
||||||
fp[1].fd_small = MAYBE;
|
fp[1].fd_small = MAYBE;
|
||||||
@ -2555,34 +2557,35 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
|
|||||||
{
|
{
|
||||||
fold_T *fp = NULL;
|
fold_T *fp = NULL;
|
||||||
|
|
||||||
if (bot < top)
|
if (bot < top) {
|
||||||
return; /* nothing to do */
|
return; // nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
for (;; ) {
|
for (;; ) {
|
||||||
/* Find fold that includes top or a following one. */
|
// Find fold that includes top or a following one.
|
||||||
if (foldFind(gap, top, &fp) && fp->fd_top < top) {
|
if (foldFind(gap, top, &fp) && fp->fd_top < top) {
|
||||||
/* 2: or 3: need to delete nested folds */
|
// 2: or 3: need to delete nested folds
|
||||||
foldRemove(&fp->fd_nested, top - fp->fd_top, bot - fp->fd_top);
|
foldRemove(&fp->fd_nested, top - fp->fd_top, bot - fp->fd_top);
|
||||||
if (fp->fd_top + fp->fd_len > bot + 1) {
|
if (fp->fd_top + fp->fd_len - 1 > bot) {
|
||||||
/* 3: need to split it. */
|
// 3: need to split it.
|
||||||
foldSplit(gap, (int)(fp - (fold_T *)gap->ga_data), top, bot);
|
foldSplit(gap, (int)(fp - (fold_T *)gap->ga_data), top, bot);
|
||||||
} else {
|
} else {
|
||||||
/* 2: truncate fold at "top". */
|
// 2: truncate fold at "top".
|
||||||
fp->fd_len = top - fp->fd_top;
|
fp->fd_len = top - fp->fd_top;
|
||||||
}
|
}
|
||||||
fold_changed = TRUE;
|
fold_changed = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (fp >= (fold_T *)(gap->ga_data) + gap->ga_len
|
if (fp >= (fold_T *)(gap->ga_data) + gap->ga_len
|
||||||
|| fp->fd_top > bot) {
|
|| fp->fd_top > bot) {
|
||||||
/* 6: Found a fold below bot, can stop looking. */
|
// 6: Found a fold below bot, can stop looking.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fp->fd_top >= top) {
|
if (fp->fd_top >= top) {
|
||||||
/* Found an entry below top. */
|
// Found an entry below top.
|
||||||
fold_changed = TRUE;
|
fold_changed = true;
|
||||||
if (fp->fd_top + fp->fd_len - 1 > bot) {
|
if (fp->fd_top + fp->fd_len - 1 > bot) {
|
||||||
/* 5: Make fold that includes bot start below bot. */
|
// 5: Make fold that includes bot start below bot.
|
||||||
foldMarkAdjustRecurse(&fp->fd_nested,
|
foldMarkAdjustRecurse(&fp->fd_nested,
|
||||||
(linenr_T)0, (long)(bot - fp->fd_top),
|
(linenr_T)0, (long)(bot - fp->fd_top),
|
||||||
(linenr_T)MAXLNUM, (long)(fp->fd_top - bot - 1));
|
(linenr_T)MAXLNUM, (long)(fp->fd_top - bot - 1));
|
||||||
@ -2591,12 +2594,160 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4: Delete completely contained fold. */
|
// 4: Delete completely contained fold.
|
||||||
deleteFoldEntry(gap, (int)(fp - (fold_T *)gap->ga_data), TRUE);
|
deleteFoldEntry(gap, (int)(fp - (fold_T *)gap->ga_data), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// foldMoveRange() {{{2
|
||||||
|
static void reverse_fold_order(garray_T *gap, size_t start, size_t end)
|
||||||
|
{
|
||||||
|
for (; start < end; start++, end--) {
|
||||||
|
fold_T *left = (fold_T *)gap->ga_data + start;
|
||||||
|
fold_T *right = (fold_T *)gap->ga_data + end;
|
||||||
|
fold_T tmp = *left;
|
||||||
|
*left = *right;
|
||||||
|
*right = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move folds within the inclusive range "line1" to "line2" to after "dest"
|
||||||
|
// require "line1" <= "line2" <= "dest"
|
||||||
|
//
|
||||||
|
// There are the following situations for the first fold at or below line1 - 1.
|
||||||
|
// 1 2 3 4
|
||||||
|
// 1 2 3 4
|
||||||
|
// line1 2 3 4
|
||||||
|
// 2 3 4 5 6 7
|
||||||
|
// line2 3 4 5 6 7
|
||||||
|
// 3 4 6 7 8 9
|
||||||
|
// dest 4 7 8 9
|
||||||
|
// 4 7 8 10
|
||||||
|
// 4 7 8 10
|
||||||
|
//
|
||||||
|
// In the following descriptions, "moved" means moving in the buffer, *and* in
|
||||||
|
// the fold array.
|
||||||
|
// Meanwhile, "shifted" just means moving in the buffer.
|
||||||
|
// 1. not changed
|
||||||
|
// 2. truncated above line1
|
||||||
|
// 3. length reduced by line2 - line1, folds starting between the end of 3 and
|
||||||
|
// dest are truncated and shifted up
|
||||||
|
// 4. internal folds moved (from [line1, line2] to dest)
|
||||||
|
// 5. moved to dest.
|
||||||
|
// 6. truncated below line2 and moved.
|
||||||
|
// 7. length reduced by line2 - dest, folds starting between line2 and dest are
|
||||||
|
// removed, top is moved down by move_len.
|
||||||
|
// 8. truncated below dest and shifted up.
|
||||||
|
// 9. shifted up
|
||||||
|
// 10. not changed
|
||||||
|
static void truncate_fold(fold_T *fp, linenr_T end)
|
||||||
|
{
|
||||||
|
// I want to stop *at here*, foldRemove() stops *above* top
|
||||||
|
end += 1;
|
||||||
|
foldRemove(&fp->fd_nested, end - fp->fd_top, MAXLNUM);
|
||||||
|
fp->fd_len = end - fp->fd_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FOLD_END(fp) ((fp)->fd_top + (fp)->fd_len - 1)
|
||||||
|
#define VALID_FOLD(fp, gap) ((fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len))
|
||||||
|
#define FOLD_INDEX(fp, gap) ((size_t)(fp - ((fold_T *)(gap)->ga_data)))
|
||||||
|
void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2,
|
||||||
|
const linenr_T dest)
|
||||||
|
{
|
||||||
|
fold_T *fp;
|
||||||
|
const linenr_T range_len = line2 - line1 + 1;
|
||||||
|
const linenr_T move_len = dest - line2;
|
||||||
|
const bool at_start = foldFind(gap, line1 - 1, &fp);
|
||||||
|
|
||||||
|
if (at_start) {
|
||||||
|
if (FOLD_END(fp) > dest) {
|
||||||
|
// Case 4 -- don't have to change this fold, but have to move nested
|
||||||
|
// folds.
|
||||||
|
foldMoveRange(&fp->fd_nested, line1 - fp->fd_top, line2 -
|
||||||
|
fp->fd_top, dest - fp->fd_top);
|
||||||
|
return;
|
||||||
|
} else if (FOLD_END(fp) > line2) {
|
||||||
|
// Case 3 -- Remove nested folds between line1 and line2 & reduce the
|
||||||
|
// length of fold by "range_len".
|
||||||
|
// Folds after this one must be dealt with.
|
||||||
|
foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top,
|
||||||
|
line2 - fp->fd_top, MAXLNUM, -range_len);
|
||||||
|
fp->fd_len -= range_len;
|
||||||
|
} else {
|
||||||
|
// Case 2 -- truncate fold *above* line1.
|
||||||
|
// Folds after this one must be dealt with.
|
||||||
|
truncate_fold(fp, line1 - 1);
|
||||||
|
}
|
||||||
|
// Look at the next fold, and treat that one as if it were the first after
|
||||||
|
// "line1" (because now it is).
|
||||||
|
fp = fp + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!VALID_FOLD(fp, gap) || fp->fd_top > dest) {
|
||||||
|
// No folds after "line1" and before "dest"
|
||||||
|
// Case 10.
|
||||||
|
return;
|
||||||
|
} else if (fp->fd_top > line2) {
|
||||||
|
for (; VALID_FOLD(fp, gap) && FOLD_END(fp) <= dest; fp++) {
|
||||||
|
// Case 9. (for all case 9's) -- shift up.
|
||||||
|
fp->fd_top -= range_len;
|
||||||
|
}
|
||||||
|
if (VALID_FOLD(fp, gap) && fp->fd_top <= dest) {
|
||||||
|
// Case 8. -- ensure truncated at dest, shift up
|
||||||
|
truncate_fold(fp, dest);
|
||||||
|
fp->fd_top -= range_len;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (FOLD_END(fp) > dest) {
|
||||||
|
// Case 7 -- remove nested folds and shrink
|
||||||
|
foldMarkAdjustRecurse(&fp->fd_nested, line2 + 1 - fp->fd_top,
|
||||||
|
dest - fp->fd_top, MAXLNUM, -move_len);
|
||||||
|
fp->fd_len -= move_len;
|
||||||
|
fp->fd_top += move_len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 5 or 6: changes rely on whether there are folds between the end of
|
||||||
|
// this fold and "dest".
|
||||||
|
size_t move_start = FOLD_INDEX(fp, gap);
|
||||||
|
size_t move_end = 0, dest_index = 0;
|
||||||
|
for (; VALID_FOLD(fp, gap) && fp->fd_top <= dest; fp++) {
|
||||||
|
if (fp->fd_top <= line2) {
|
||||||
|
// 5, or 6
|
||||||
|
if (FOLD_END(fp) > line2) {
|
||||||
|
// 6, truncate before moving
|
||||||
|
truncate_fold(fp, line2);
|
||||||
|
}
|
||||||
|
fp->fd_top += move_len;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record index of the first fold after the moved range.
|
||||||
|
if (move_end == 0) {
|
||||||
|
move_end = FOLD_INDEX(fp, gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FOLD_END(fp) > dest) {
|
||||||
|
truncate_fold(fp, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
fp->fd_top -= range_len;
|
||||||
|
}
|
||||||
|
dest_index = FOLD_INDEX(fp, gap);
|
||||||
|
|
||||||
|
// All folds are now correct, but they are not necessarily in the correct
|
||||||
|
// order.
|
||||||
|
// We have to swap folds in the range [move_end, dest_index) with those in
|
||||||
|
// the range [move_start, move_end).
|
||||||
|
reverse_fold_order(gap, move_start, dest_index - 1);
|
||||||
|
reverse_fold_order(gap, move_start, move_start + dest_index - move_end - 1);
|
||||||
|
reverse_fold_order(gap, move_start + dest_index - move_end, dest_index - 1);
|
||||||
|
}
|
||||||
|
#undef FOLD_END
|
||||||
|
#undef VALID_FOLD
|
||||||
|
#undef FOLD_INDEX
|
||||||
|
|
||||||
/* foldMerge() {{{2 */
|
/* foldMerge() {{{2 */
|
||||||
/*
|
/*
|
||||||
* Merge two adjacent folds (and the nested ones in them).
|
* Merge two adjacent folds (and the nested ones in them).
|
||||||
|
@ -886,6 +886,23 @@ void ex_changes(exarg_T *eap)
|
|||||||
* or: mark_adjust(56, 55, MAXLNUM, 2);
|
* or: mark_adjust(56, 55, MAXLNUM, 2);
|
||||||
*/
|
*/
|
||||||
void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
|
void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
|
||||||
|
{
|
||||||
|
mark_adjust_internal(line1, line2, amount, amount_after, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark_adjust_nofold() does the same as mark_adjust() but without adjusting
|
||||||
|
// folds in any way. Folds must be adjusted manually by the caller.
|
||||||
|
// This is only useful when folds need to be moved in a way different to
|
||||||
|
// calling foldMarkAdjust() with arguments line1, line2, amount, amount_after,
|
||||||
|
// for an example of why this may be necessary, see do_move().
|
||||||
|
void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount,
|
||||||
|
long amount_after)
|
||||||
|
{
|
||||||
|
mark_adjust_internal(line1, line2, amount, amount_after, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount,
|
||||||
|
long amount_after, bool adjust_folds)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int fnum = curbuf->b_fnum;
|
int fnum = curbuf->b_fnum;
|
||||||
@ -1011,8 +1028,9 @@ void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adjust folds */
|
if (adjust_folds) {
|
||||||
foldMarkAdjust(win, line1, line2, amount, amount_after);
|
foldMarkAdjust(win, line1, line2, amount, amount_after);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
" Test for folding
|
" Test for folding
|
||||||
|
|
||||||
|
func! PrepIndent(arg)
|
||||||
|
return [a:arg] + repeat(["\t".a:arg], 5)
|
||||||
|
endfu
|
||||||
|
|
||||||
func! Test_address_fold()
|
func! Test_address_fold()
|
||||||
new
|
new
|
||||||
call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
|
call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
|
||||||
@ -116,15 +120,157 @@ func Test_manual_fold_with_filter()
|
|||||||
if !executable('cat')
|
if !executable('cat')
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
new
|
for type in ['manual', 'marker']
|
||||||
call setline(1, range(1, 20))
|
exe 'set foldmethod=' . type
|
||||||
4,$fold
|
new
|
||||||
%foldopen
|
call setline(1, range(1, 20))
|
||||||
10,$fold
|
4,$fold
|
||||||
%foldopen
|
%foldopen
|
||||||
" This filter command should not have an effect
|
10,$fold
|
||||||
1,8! cat
|
%foldopen
|
||||||
call feedkeys('5ggzdzMGdd', 'xt')
|
" This filter command should not have an effect
|
||||||
call assert_equal(['1', '2', '3', '4', '5', '6', '7', '8', '9'], getline(1, '$'))
|
1,8! cat
|
||||||
bwipe!
|
call feedkeys('5ggzdzMGdd', 'xt')
|
||||||
|
call assert_equal(['1', '2', '3', '4', '5', '6', '7', '8', '9'], getline(1, '$'))
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
set foldmethod&
|
||||||
|
endfor
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_move_folds_around_manual()
|
||||||
|
new
|
||||||
|
let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
|
||||||
|
call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
|
||||||
|
let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
|
||||||
|
" all folds closed
|
||||||
|
set foldenable foldlevel=0 fdm=indent
|
||||||
|
" needs a forced redraw
|
||||||
|
redraw!
|
||||||
|
set fdm=manual
|
||||||
|
call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
call assert_equal(input, getline(1, '$'))
|
||||||
|
7,12m0
|
||||||
|
call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
|
||||||
|
call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
10,12m0
|
||||||
|
call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] + PrepIndent("c"), getline(1, '$'))
|
||||||
|
call assert_equal([1, 1, 1, 1, 1, -1, 7, 7, 7, 7, 7, -1, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
" moving should not close the folds
|
||||||
|
%d
|
||||||
|
call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
|
||||||
|
set fdm=indent
|
||||||
|
redraw!
|
||||||
|
set fdm=manual
|
||||||
|
call cursor(2, 1)
|
||||||
|
%foldopen
|
||||||
|
7,12m0
|
||||||
|
let folds=repeat([-1], 18)
|
||||||
|
call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
|
||||||
|
call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
norm! zM
|
||||||
|
" folds are not corrupted and all have been closed
|
||||||
|
call assert_equal([-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
%d
|
||||||
|
call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
|
||||||
|
set fdm=indent
|
||||||
|
redraw!
|
||||||
|
set fdm=manual
|
||||||
|
%foldopen
|
||||||
|
3m4
|
||||||
|
%foldclose
|
||||||
|
call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
|
||||||
|
call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
|
||||||
|
%d
|
||||||
|
call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
|
||||||
|
set fdm=indent foldlevel=0
|
||||||
|
set fdm=manual
|
||||||
|
%foldopen
|
||||||
|
3m1
|
||||||
|
%foldclose
|
||||||
|
call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
|
||||||
|
call assert_equal(0, foldlevel(2))
|
||||||
|
call assert_equal(5, foldclosedend(3))
|
||||||
|
call assert_equal([-1, -1, 3, 3, 3, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
2,6m$
|
||||||
|
%foldclose
|
||||||
|
call assert_equal(5, foldclosedend(2))
|
||||||
|
call assert_equal(0, foldlevel(6))
|
||||||
|
call assert_equal(9, foldclosedend(7))
|
||||||
|
call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
%d
|
||||||
|
" Ensure moving around the edges still works.
|
||||||
|
call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
|
||||||
|
set fdm=indent foldlevel=0
|
||||||
|
set fdm=manual
|
||||||
|
%foldopen
|
||||||
|
6m$
|
||||||
|
" The first fold has been truncated to the 5'th line.
|
||||||
|
" Second fold has been moved up because the moved line is now below it.
|
||||||
|
call assert_equal([0, 1, 1, 1, 1, 0, 0, 0, 1, 0], map(range(1, line('$')), 'foldlevel(v:val)'))
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_move_folds_around_indent()
|
||||||
|
new
|
||||||
|
let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
|
||||||
|
call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
|
||||||
|
let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
|
||||||
|
" all folds closed
|
||||||
|
set fdm=indent
|
||||||
|
call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
call assert_equal(input, getline(1, '$'))
|
||||||
|
7,12m0
|
||||||
|
call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
|
||||||
|
call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
10,12m0
|
||||||
|
call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] + PrepIndent("c"), getline(1, '$'))
|
||||||
|
call assert_equal([1, 1, 1, 1, 1, -1, 7, 7, 7, 7, 7, -1, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
" moving should not close the folds
|
||||||
|
%d
|
||||||
|
call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
|
||||||
|
set fdm=indent
|
||||||
|
call cursor(2, 1)
|
||||||
|
%foldopen
|
||||||
|
7,12m0
|
||||||
|
let folds=repeat([-1], 18)
|
||||||
|
call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
|
||||||
|
call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
norm! zM
|
||||||
|
" folds are not corrupted and all have been closed
|
||||||
|
call assert_equal([-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
%d
|
||||||
|
call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
|
||||||
|
set fdm=indent
|
||||||
|
%foldopen
|
||||||
|
3m4
|
||||||
|
%foldclose
|
||||||
|
call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
|
||||||
|
call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
|
||||||
|
%d
|
||||||
|
call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
|
||||||
|
set fdm=indent foldlevel=0
|
||||||
|
%foldopen
|
||||||
|
3m1
|
||||||
|
%foldclose
|
||||||
|
call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
|
||||||
|
call assert_equal(1, foldlevel(2))
|
||||||
|
call assert_equal(5, foldclosedend(3))
|
||||||
|
call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
2,6m$
|
||||||
|
%foldclose
|
||||||
|
call assert_equal(9, foldclosedend(2))
|
||||||
|
call assert_equal(1, foldlevel(6))
|
||||||
|
call assert_equal(9, foldclosedend(7))
|
||||||
|
call assert_equal([-1, 2, 2, 2, 2, 2, 2, 2, 2, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
|
||||||
|
" Ensure moving around the edges still works.
|
||||||
|
%d
|
||||||
|
call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
|
||||||
|
set fdm=indent foldlevel=0
|
||||||
|
%foldopen
|
||||||
|
6m$
|
||||||
|
" The first fold has been truncated to the 5'th line.
|
||||||
|
" Second fold has been moved up because the moved line is now below it.
|
||||||
|
call assert_equal([0, 1, 1, 1, 1, 0, 0, 0, 1, 1], map(range(1, line('$')), 'foldlevel(v:val)'))
|
||||||
|
bw!
|
||||||
endfunc
|
endfunc
|
||||||
|
@ -5,9 +5,13 @@ local insert = helpers.insert
|
|||||||
local feed = helpers.feed
|
local feed = helpers.feed
|
||||||
local expect = helpers.expect
|
local expect = helpers.expect
|
||||||
local execute = helpers.execute
|
local execute = helpers.execute
|
||||||
|
local funcs = helpers.funcs
|
||||||
|
local foldlevel, foldclosedend = funcs.foldlevel, funcs.foldclosedend
|
||||||
|
local eq = helpers.eq
|
||||||
|
|
||||||
describe('Folds', function()
|
describe('Folds', function()
|
||||||
clear()
|
clear()
|
||||||
|
before_each(function() execute('enew!') end)
|
||||||
it('manual folding adjusts with filter', function()
|
it('manual folding adjusts with filter', function()
|
||||||
insert([[
|
insert([[
|
||||||
1
|
1
|
||||||
@ -44,4 +48,186 @@ describe('Folds', function()
|
|||||||
8
|
8
|
||||||
9]])
|
9]])
|
||||||
end)
|
end)
|
||||||
|
describe('adjusting folds after :move', function()
|
||||||
|
local function manually_fold_indent()
|
||||||
|
-- setting foldmethod twice is a trick to get vim to set the folds for me
|
||||||
|
execute('set foldmethod=indent', 'set foldmethod=manual')
|
||||||
|
-- Ensure that all folds will get closed (makes it easier to test the
|
||||||
|
-- length of folds).
|
||||||
|
execute('set foldminlines=0')
|
||||||
|
-- Start with all folds open (so :move ranges aren't affected by closed
|
||||||
|
-- folds).
|
||||||
|
execute('%foldopen!')
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_folds()
|
||||||
|
local rettab = {}
|
||||||
|
for i = 1, funcs.line('$') do
|
||||||
|
table.insert(rettab, foldlevel(i))
|
||||||
|
end
|
||||||
|
return rettab
|
||||||
|
end
|
||||||
|
|
||||||
|
local function test_move_indent(insert_string, move_command)
|
||||||
|
-- This test is easy because we just need to ensure that the resulting
|
||||||
|
-- fold is the same as calculated when creating folds from scratch.
|
||||||
|
insert(insert_string)
|
||||||
|
execute(move_command)
|
||||||
|
local after_move_folds = get_folds()
|
||||||
|
-- Doesn't change anything, but does call foldUpdateAll()
|
||||||
|
execute('set foldminlines=0')
|
||||||
|
eq(after_move_folds, get_folds())
|
||||||
|
-- Set up the buffer with insert_string for the manual fold testing.
|
||||||
|
execute('enew!')
|
||||||
|
insert(insert_string)
|
||||||
|
manually_fold_indent()
|
||||||
|
execute(move_command)
|
||||||
|
end
|
||||||
|
|
||||||
|
it('neither closes nor corrupts folds', function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '7,12m0')
|
||||||
|
expect([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]])
|
||||||
|
-- lines are not closed, folds are correct
|
||||||
|
for i = 1,funcs.line('$') do
|
||||||
|
eq(-1, funcs.foldclosed(i))
|
||||||
|
if i == 1 or i == 7 or i == 13 then
|
||||||
|
eq(0, foldlevel(i))
|
||||||
|
elseif i == 4 then
|
||||||
|
eq(2, foldlevel(i))
|
||||||
|
else
|
||||||
|
eq(1, foldlevel(i))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- folds are not corrupted
|
||||||
|
feed('zM')
|
||||||
|
eq(6, foldclosedend(2))
|
||||||
|
eq(12, foldclosedend(8))
|
||||||
|
eq(18, foldclosedend(14))
|
||||||
|
end)
|
||||||
|
it("doesn't split a fold when the move is within it", function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '5m6')
|
||||||
|
eq({0, 1, 1, 2, 2, 2, 2, 1, 1, 0}, get_folds())
|
||||||
|
end)
|
||||||
|
it('truncates folds that end in the moved range', function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '4,5m6')
|
||||||
|
eq({0, 1, 2, 0, 0, 0, 0}, get_folds())
|
||||||
|
end)
|
||||||
|
it('moves folds that start between moved range and destination', function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '3,4m$')
|
||||||
|
eq({0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0}, get_folds())
|
||||||
|
end)
|
||||||
|
it('does not affect folds outside changed lines', function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '4m5')
|
||||||
|
eq({1, 1, 1, 0, 0, 0, 1, 1, 1}, get_folds())
|
||||||
|
end)
|
||||||
|
it('moves and truncates folds that start in moved range', function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '1,3m7')
|
||||||
|
eq({0, 0, 0, 0, 0, 1, 2, 0, 0, 0}, get_folds())
|
||||||
|
end)
|
||||||
|
it('breaks a fold when moving text into it', function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '$m4')
|
||||||
|
eq({0, 1, 2, 2, 0, 0, 0}, get_folds())
|
||||||
|
end)
|
||||||
|
it('adjusts correctly when moving a range backwards', function()
|
||||||
|
test_move_indent([[
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a
|
||||||
|
a]], '2,3m0')
|
||||||
|
eq({1, 2, 0, 0, 0}, get_folds())
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user