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 aRegion
ofwise = V
, for whole part of the change) - redoing
:11,$ s/^/./
is line-by-line (wasRegion
s ofwise = 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 Region
s 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>