]> granicus.if.org Git - vim/commitdiff
patch 8.0.0408: updating folds does not always work properly v8.0.0408
authorBram Moolenaar <Bram@vim.org>
Sat, 4 Mar 2017 17:42:39 +0000 (18:42 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 4 Mar 2017 17:42:39 +0000 (18:42 +0100)
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)

src/fold.c
src/testdir/test_fold.vim
src/version.c

index cba1375159132121d6b6f21f4686ee5045f08ee0..d75e937003467d88081097369869ca4fa009ad03 100644 (file)
@@ -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)
index cdf9fd314214e3d667b477dc5350c2b78ff5e8d0..3c27f4f70099bb3f239a08a8f4fe86b7cad9a4a1 100644 (file)
@@ -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
index 39c6b4e41ae720846c3ac54b10626c101acc4a95..9b350e7243a289264121a831237b2ebbf908b80a 100644 (file)
@@ -764,6 +764,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    408,
 /**/
     407,
 /**/