machakann / vim-highlightedundo

Make the undo region apparent!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Slow in large undos

infokiller opened this issue · comments

Thanks for this plugin, I think it's a great idea, but I have one gripe: I ran into major slowness when the undo region is large undos (a few hundred lines).
For example, delete 500 lines and then try to undo them. For me, vim became unresponsive for a few seconds.
Is this because the plugin tries to draw the entire screen? or is it because of the diff tool?

Thanks

I think it should restrict max highlight item count.

For example, changing as below makes it greatly faster
(I don't know it is valid fix, though).

--- a/autoload/highlightedundo.vim
+++ b/autoload/highlightedundo.vim
@@ -121,7 +121,7 @@ function! s:Diff(kind, from, to, lines) abort
   elseif a:kind ==# 'c'
     let fromlinenrlist = range(a:from[0], a:from[1])
     let tolinenrlist = range(a:to[0], a:to[1])
-    for i in range(max([len(fromlinenrlist), len(tolinenrlist)]))
+    for i in range(min([max([len(fromlinenrlist), len(tolinenrlist)]), 100]))
       if i < len(fromlinenrlist) && i < len(tolinenrlist)
         let before = a:lines.delete[i]
         let after = a:lines.add[i]

My check operation is as below:

:r !seq 1 1000                  " Create 1000 lines
:1d_                            " Remove extra empty line
:0i                             " Insert 10 lines to buffer head










.
:11,$ s/^/./                    " Insert `.` each lines of numbers
:noh                            " Turn the search highlight off to make this plugin's highlight visible

15gg                            " Move cursor pos (for cursor position check)
u                               " Undo (`.` disappears)

15gg                            " Move cursor pos (for cursor position check)
<C-r>                           " Redo (`.` appears; **THIS IS TOO SLOW**)

Futhremore, in some cases, highlight match is applied line-by-line.

I think it can be hacked there, but will be a bit difficult change.


In my check operation above,

  • redoing :r !seq 1 1000 is whole-change (was a Region of wise = V, for whole part of the change)
  • redoing :11,$ s/^/./ is line-by-line (was Regions of wise = v, for each changed line).

In the function s:glow() that sets highlights,
as subdiff,
the former whole-change case gives only one Region object; and
the latter line-by-line case gives line number of Region objects.

Each Region object turns into a highlightedundo#highlight object, and sets one matchaddpos().

A matchaddpos() allows having up to eight highlight position,
so, in the latter line-by-line case, several Regions can be reduced into one matchaddpos().

To do so, it must be rewrote the way of Region object handling, or such
(currently, every one Region object does one matchaddpos()).
Not a piece of cake as the patch I showed above.

Also this may help with too-long-line undos.

It stores diff lines into variables.
So, huge diff takes too much memory spaces to extremely slow it down.

To avoid this, check up to 250 chars per line.
As a side effect, diffs for more than 250 chars are not correctly highlighted.

--- a/autoload/highlightedundo.vim
+++ b/autoload/highlightedundo.vim
@@ -414,14 +414,15 @@ function! s:parsechunk(diffoutput, from, to, i, n) abort "{{{
       break
     endif
 
-    let [addedline, pos, _] = matchstrpos(line, '\m^>\s\zs.*')
+    " XXX: For performance, check only up to 250 chars.
+    let [addedline, pos, _] = matchstrpos(line, '\m^>\s\zs.\{,250}')
     if pos != -1
       call add(lines.add, addedline)
       let i += 1
       continue
     endif
 
-    let [deletedline, pos, _] = matchstrpos(line, '\m^<\s\zs.*')
+    let [deletedline, pos, _] = matchstrpos(line, '\m^<\s\zs.\{,250}')
     if pos != -1
       call add(lines.delete, deletedline)
       let i += 1

Check Operations

" Repeat `.` for 80 chars in one line
80a
.

" Copy the line to 10,000 lines
yy
9999p

" Join the 10,000 lines into one line
" CAUTION: Without the change above, it takes too much time.
"          Try with up to 30 or 40 lines.
gg
<Shift-V>
G
gJ

" Undo / Redo
u
<Ctrl-r>