@@ -1312,6 +1312,9 @@ endfunction
13121312" there will Mutex poison error.
13131313let s: last_cursor_line = -1
13141314function ! LanguageClient#handleCursorMoved () abort
1315+ call s: timer_stop (' LanguageClient#handleCursorMoved' )
1316+
1317+ function ! DebounceHandleCursorMoved () abort
13151318 let l: cursor_line = getcurpos ()[1 ] - 1
13161319 if l: cursor_line == s: last_cursor_line
13171320 return
@@ -1328,6 +1331,9 @@ function! LanguageClient#handleCursorMoved() abort
13281331 catch
13291332 call s: Debug (' LanguageClient caught exception: ' . string (v: exception ))
13301333 endtry
1334+ endfunction
1335+
1336+ call s: timer_start_store (100 , { - > DebounceHandleCursorMoved () }, ' LanguageClient#handleCursorMoved' )
13311337endfunction
13321338
13331339function ! LanguageClient#handleCompleteDone () abort
@@ -1711,14 +1717,18 @@ endfunction
17111717
17121718" receives the v:event from the CompleteChanged autocmd
17131719function ! LanguageClient#handleCompleteChanged (event ) abort
1714- " this timer is just to stop textlock from locking our changes
1715- call timer_start ( 0 , funcref ( ' s: ClosePopups' ))
1716-
1717- if has_key ( s: timers , ' LanguageClient#handleCompleteChanged ' )
1718- call timer_stop ( s: timers [ ' LanguageClient#handleCompleteChanged ' ])
1720+ " this function needs timer_start because by the time it is called the
1721+ " `textlock` lock is set, so calling something ( ClosePopups in this case) in
1722+ " a timer basically unsets that lock.
1723+ if ! exists ( ' *timer_start ' )
1724+ return
17191725 endif
17201726
1721- function ! Debounced (event ) abort
1727+ " this timer is just to stop textlock from locking our changes
1728+ call s: timer_start (0 , funcref (' s:ClosePopups' ))
1729+ call s: timer_stop (' LanguageClient#handleCompleteChanged' )
1730+
1731+ function ! DebounceHandleCompleteChanged (event ) abort
17221732 let l: user_data = get (v: completed_item , ' user_data' , ' ' )
17231733 if len (l: user_data ) == # 0
17241734 return
@@ -1751,7 +1761,7 @@ function! LanguageClient#handleCompleteChanged(event) abort
17511761 endif
17521762 endfunction
17531763
1754- let s: timers [ ' LanguageClient#handleCompleteChanged ' ] = timer_start (100 , { - > Debounced (a: event ) })
1764+ call s: timer_start_store (100 , { - > DebounceHandleCompleteChanged (a: event ) }, ' LanguageClient#handleCompleteChanged ' )
17551765endfunction
17561766
17571767function ! s: ShowCompletionItemDocumentation (doc, completion_event) abort
@@ -1785,4 +1795,34 @@ function! s:ShowCompletionItemDocumentation(doc, completion_event) abort
17851795 call s: OpenHoverPreview (' CompletionItemDocumentation' , l: lines , l: kind , l: x_pos , l: pos [' row' ])
17861796endfunction
17871797
1798+ " s:timer_stop tries to stop the timer with the given name by calling vim's
1799+ " timer_stop. If vim's timer_stop function does not exist it just returns.
1800+ function ! s: timer_stop (name) abort
1801+ if ! exists (' *timer_stop' )
1802+ return
1803+ endif
1804+
1805+ if has_key (s: timers , a: name )
1806+ call timer_stop (s: timers [a: name ])
1807+ endif
1808+ endfunction
1809+
1810+ " s:timer_start tries to start a timer by calling vim's timer_start function,
1811+ " if it does not exist it just calls the function given in the second
1812+ " argument.
1813+ function ! s: timer_start (delay, func ) abort
1814+ if ! exists (' *timer_start' )
1815+ return a: func ()
1816+ endif
1817+
1818+ return timer_start (a: delay , a: func )
1819+ endfunction
1820+
1821+ " s:timer_start_store calls s:timer_start and stores the returned timer_id in
1822+ " a script scoped s:timers variable that we can use to debounce function
1823+ " calls.
1824+ function ! s: timer_start_store (delay, func , name) abort
1825+ let s: timers [a: name ] = s: timer_start (a: delay , a: func )
1826+ endfunction
1827+
17881828let g: LanguageClient_loaded = s: Launch ()
0 commit comments