changeset 11038:c8b49300c6b7 v8.0.0408

patch 8.0.0408: updating folds does not always work properly commit https://github.com/vim/vim/commit/eadbc2b46176e2aff2cde5f3874b734ae2ae082a Author: Bram Moolenaar <Bram@vim.org> Date: Sat Mar 4 18:42:39 2017 +0100 patch 8.0.0408: updating folds does not always work properly Problem: Updating folds does not work properly when inserting a file and a few other situations. Solution: Adjust the way folds are updated. (Matthew Malcomson)
author Christian Brabandt <cb@256bit.org>
date Sat, 04 Mar 2017 18:45:04 +0100
parents 81b54ec5af71
children 2d12e32c6d3f
files src/fold.c src/testdir/test_fold.vim src/version.c
diffstat 3 files changed, 142 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/fold.c
+++ b/src/fold.c
@@ -2505,7 +2505,11 @@ foldUpdateIEMSRecurse(
 			 * before where we started looking, extend it.  If it
 			 * starts at another line, update nested folds to keep
 			 * their position, compensating for the new fd_top. */
-			if (fp->fd_top >= startlnum && fp->fd_top != firstlnum)
+			if (fp->fd_top == firstlnum)
+			{
+			    /* have found a fold beginning where we want */
+			}
+			else if (fp->fd_top >= startlnum)
 			{
 			    if (fp->fd_top > firstlnum)
 				/* like lines are inserted */
@@ -2523,18 +2527,44 @@ foldUpdateIEMSRecurse(
 			    fp->fd_top = firstlnum;
 			    fold_changed = TRUE;
 			}
-			else if (flp->start != 0 && lvl == level
-						   && fp->fd_top != firstlnum)
+			else if ((flp->start != 0 && lvl == level)
+						     || firstlnum != startlnum)
 			{
-			    /* Existing fold that includes startlnum must stop
-			     * if we find the start of a new fold at the same
-			     * level.  Split it.  Delete contained folds at
-			     * this point to split them too. */
-			    foldRemove(&fp->fd_nested, flp->lnum - fp->fd_top,
-						      flp->lnum - fp->fd_top);
+			    linenr_T breakstart;
+			    linenr_T breakend;
+
+			    /*
+			     * Before there was a fold spanning from above
+			     * startlnum to below firstlnum. This fold is valid
+			     * above startlnum (because we are not updating
+			     * that range), but there should now be a break in
+			     * it.
+			     * If the break is because we are now forced to
+			     * start a new fold at the level "level" at line
+			     * fline->lnum, then we need to split the fold at
+			     * fline->lnum.
+			     * If the break is because the range
+			     * [startlnum, firstlnum) is now at a lower indent
+			     * than "level", we need to split the fold in this
+			     * range.
+			     * Any splits have to be done recursively.
+			     */
+			    if (firstlnum != startlnum)
+			    {
+				breakstart = startlnum;
+				breakend = firstlnum;
+			    }
+			    else
+			    {
+				breakstart = flp->lnum;
+				breakend = flp->lnum;
+			    }
+			    foldRemove(&fp->fd_nested, breakstart - fp->fd_top,
+						      breakend - fp->fd_top);
 			    i = (int)(fp - (fold_T *)gap->ga_data);
-			    foldSplit(gap, i, flp->lnum, flp->lnum - 1);
+			    foldSplit(gap, i, breakstart, breakend - 1);
 			    fp = (fold_T *)gap->ga_data + i + 1;
+
 			    /* If using the "marker" or "syntax" method, we
 			     * need to continue until the end of the fold is
 			     * found. */
@@ -2543,6 +2573,20 @@ foldUpdateIEMSRecurse(
 				    || getlevel == foldlevelSyntax)
 				finish = TRUE;
 			}
+
+			if (fp->fd_top == startlnum && concat)
+			{
+			    i = (int)(fp - (fold_T *)gap->ga_data);
+			    if (i != 0)
+			    {
+				fp2 = fp - 1;
+				if (fp2->fd_top + fp2->fd_len == fp->fd_top)
+				{
+				    foldMerge(fp2, gap, fp);
+				    fp = fp2;
+				}
+			    }
+			}
 			break;
 		    }
 		    if (fp->fd_top >= startlnum)
--- a/src/testdir/test_fold.vim
+++ b/src/testdir/test_fold.vim
@@ -117,3 +117,89 @@ func Test_manual_fold_with_filter()
     set foldmethod&
   endfor
 endfunc
+
+func! Test_indent_fold_with_read()
+  new
+  set foldmethod=indent
+  call setline(1, repeat(["\<Tab>a"], 4))
+  for n in range(1, 4)
+    call assert_equal(1, foldlevel(n))
+  endfor
+
+  call writefile(["a", "", "\<Tab>a"], 'Xfile')
+  foldopen
+  2read Xfile
+  %foldclose
+  call assert_equal(1, foldlevel(1))
+  call assert_equal(2, foldclosedend(1))
+  call assert_equal(0, foldlevel(3))
+  call assert_equal(0, foldlevel(4))
+  call assert_equal(1, foldlevel(5))
+  call assert_equal(7, foldclosedend(5))
+
+  bwipe!
+  set foldmethod&
+  call delete('Xfile')
+endfunc
+
+func Test_combining_folds_indent()
+  new
+  let one = "\<Tab>a"
+  let zero = 'a'
+  call setline(1, [one, one, zero, zero, zero, one, one, one])
+  set foldmethod=indent
+  3,5d
+  %foldclose
+  call assert_equal(5, foldclosedend(1))
+
+  set foldmethod&
+  bwipe!
+endfunc
+
+func Test_combining_folds_marker()
+  new
+  call setline(1, ['{{{', '}}}', '', '', '', '{{{', '', '}}}'])
+  set foldmethod=marker
+  3,5d
+  %foldclose
+  call assert_equal(2, foldclosedend(1))
+
+  set foldmethod&
+  bwipe!
+endfunc
+
+func s:TestFoldExpr(lnum)
+  let thisline = getline(a:lnum)
+  if thisline == 'a'
+    return 1
+  elseif thisline == 'b'
+    return 0
+  elseif thisline == 'c'
+    return '<1'
+  elseif thisline == 'd'
+    return '>1'
+  endif
+  return 0
+endfunction
+
+func Test_update_folds_expr_read()
+  new
+  call setline(1, ['a', 'a', 'a', 'a', 'a', 'a'])
+  set foldmethod=expr
+  set foldexpr=s:TestFoldExpr(v:lnum)
+  2
+  foldopen
+  call writefile(['b', 'b', 'a', 'a', 'd', 'a', 'a', 'c'], 'Xfile')
+  read Xfile
+  %foldclose
+  call assert_equal(2, foldclosedend(1))
+  call assert_equal(0, foldlevel(3))
+  call assert_equal(0, foldlevel(4))
+  call assert_equal(6, foldclosedend(5))
+  call assert_equal(10, foldclosedend(7))
+  call assert_equal(14, foldclosedend(11))
+
+  call delete('Xfile')
+  bwipe!
+  set foldmethod& foldexpr&
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -765,6 +765,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    408,
+/**/
     407,
 /**/
     406,