Skip to content

Commit

Permalink
Implement generalized rate limiting of CursorHold events
Browse files Browse the repository at this point in the history
  • Loading branch information
xolox committed Jun 21, 2014
1 parent 7616b72 commit ec5942f
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 29 deletions.
50 changes: 48 additions & 2 deletions README.md
Expand Up @@ -37,8 +37,8 @@ from the source code of the miscellaneous scripts using the Python module

<!-- Start of generated documentation -->

The documentation of the 81 functions below was extracted from
15 Vim scripts on June 22, 2014 at 00:52.
The documentation of the 83 functions below was extracted from
16 Vim scripts on June 22, 2014 at 01:04.

### Handling of special buffers

Expand Down Expand Up @@ -96,6 +96,52 @@ example of how you would use it:

:command -nargs=* -complete=customlist,xolox#misc#complete#keywords MyCmd call s:MyCmd(<f-args>)

### Rate limiting for Vim's CursorHold event

Several of my Vim plug-ins (e.g. [vim-easytags][], [vim-notes][] and
[vim-session][]) use Vim's [CursorHold][] and [CursorHoldI][] events to
perform periodic tasks when the user doesn't press any keys for a couple of
seconds. These events by default fire after four seconds, this is
configurable using Vim's ['updatetime'][] option. The problem that this
script solves is that there are Vim plug-ins which set the ['updatetime'][]
option to unreasonably low values, thereby breaking my Vim plug-ins and
probably a lot of other Vim plug-ins out there. When users complain about
this I can tell them that another Vim plug-in is to blame, but users don't
care for the difference, their Vim is broken! So I implemented a workaround.
This script enables registration of [CursorHold][] event handlers with a
configurable interval (expressed in seconds). The event handlers will be
called no more than once every interval.

['updatetime']: http://vimdoc.sourceforge.net/htmldoc/options.html#'updatetime'
[CursorHold]: http://vimdoc.sourceforge.net/htmldoc/autocmd.html#CursorHold
[CursorHoldI]: http://vimdoc.sourceforge.net/htmldoc/autocmd.html#CursorHoldI
[vim-easytags]: http://peterodding.com/code/vim/easytags/
[vim-notes]: http://peterodding.com/code/vim/notes/
[vim-session]: http://peterodding.com/code/vim/session/

#### The `xolox#misc#cursorhold#register()` function

Register a [CursorHold][] event handler with a custom interval. This
function takes a single argument which is a dictionary with the following
fields:

- **function** (required): The name of the event handler function (a
string).

- **arguments** (optional): A list of arguments to pass to the event
handler function (defaults to an empty list).

- **interval** (optional): The number of seconds between calls to the
event handler (defaults to 4).

#### The `xolox#misc#cursorhold#autocmd()` function

The 'top level event handler' that's called by Vim whenever the
[CursorHold][] or [CursorHoldI][] event fires. It iterates through the
event handlers registered using `xolox#misc#cursorhold#register()` and
calls each event handler at the appropriate interval, keeping track of
the time when each event handler was last run.

### String escaping functions

#### The `xolox#misc#escape#pattern()` function
Expand Down
4 changes: 2 additions & 2 deletions autoload/xolox/misc.vim
@@ -1,7 +1,7 @@
" The version of my miscellaneous scripts.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: July 20, 2013
" Last Change: June 22, 2014
" URL: http://peterodding.com/code/vim/misc/

let g:xolox#misc#version = '1.8.5'
let g:xolox#misc#version = '1.9'
71 changes: 71 additions & 0 deletions autoload/xolox/misc/cursorhold.vim
@@ -0,0 +1,71 @@
" Rate limiting for Vim's CursorHold event.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 22, 2014
" URL: http://peterodding.com/code/vim/misc/
"
" Several of my Vim plug-ins (e.g. [vim-easytags][], [vim-notes][] and
" [vim-session][]) use Vim's [CursorHold][] and [CursorHoldI][] events to
" perform periodic tasks when the user doesn't press any keys for a couple of
" seconds. These events by default fire after four seconds, this is
" configurable using Vim's ['updatetime'][] option. The problem that this
" script solves is that there are Vim plug-ins which set the ['updatetime'][]
" option to unreasonably low values, thereby breaking my Vim plug-ins and
" probably a lot of other Vim plug-ins out there. When users complain about
" this I can tell them that another Vim plug-in is to blame, but users don't
" care for the difference, their Vim is broken! So I implemented a workaround.
" This script enables registration of [CursorHold][] event handlers with a
" configurable interval (expressed in seconds). The event handlers will be
" called no more than once every interval.
"
" ['updatetime']: http://vimdoc.sourceforge.net/htmldoc/options.html#'updatetime'
" [CursorHold]: http://vimdoc.sourceforge.net/htmldoc/autocmd.html#CursorHold
" [CursorHoldI]: http://vimdoc.sourceforge.net/htmldoc/autocmd.html#CursorHoldI
" [vim-easytags]: http://peterodding.com/code/vim/easytags/
" [vim-notes]: http://peterodding.com/code/vim/notes/
" [vim-session]: http://peterodding.com/code/vim/session/

if !exists('g:xolox#misc#cursorhold#handlers')
let g:xolox#misc#cursorhold#handlers = []
endif

function! xolox#misc#cursorhold#register(options)
" Register a [CursorHold][] event handler with a custom interval. This
" function takes a single argument which is a dictionary with the following
" fields:
"
" - **function** (required): The name of the event handler function (a
" string).
"
" - **arguments** (optional): A list of arguments to pass to the event
" handler function (defaults to an empty list).
"
" - **interval** (optional): The number of seconds between calls to the
" event handler (defaults to 4).
call add(g:xolox#misc#cursorhold#handlers, copy(a:options))
endfunction

function! xolox#misc#cursorhold#autocmd()
" The 'top level event handler' that's called by Vim whenever the
" [CursorHold][] or [CursorHoldI][] event fires. It iterates through the
" event handlers registered using `xolox#misc#cursorhold#register()` and
" calls each event handler at the appropriate interval, keeping track of
" the time when each event handler was last run.
for handler in g:xolox#misc#cursorhold#handlers
let function = handler['function']
let last_run = get(handler, 'last_run', 0)
let interval = get(handler, 'interval', 4)
call xolox#misc#msg#debug("vim-misc %s: Checking handler %s with interval %i and last run %i ..", g:xolox#misc#version, function, interval, last_run)
" Rate limit in case &updatetime is set (very) low.
let time_until_next_run = (last_run + interval) - localtime()
if time_until_next_run > 0
call xolox#misc#msg#debug("vim-misc %s: Rate limiting handler %s (time until next run: %i seconds).", g:xolox#misc#version, function, time_until_next_run)
else
call xolox#misc#msg#debug("vim-misc %s: Running handler %s ..", g:xolox#misc#version, function)
call call(function, get(handler, 'arguments', []))
let handler['last_run'] = localtime()
endif
endfor
endfunction

" vim: ts=2 sw=2 et
95 changes: 70 additions & 25 deletions doc/misc.txt
Expand Up @@ -13,37 +13,40 @@ Contents ~
4. The |xolox#misc#buffer#unlock()| function
2. Tab completion for user defined commands |misc-tab-completion-for-user-defined-commands|
1. The |xolox#misc#complete#keywords()| function
3. String escaping functions |misc-string-escaping-functions|
3. Rate limiting for Vim's CursorHold event |misc-rate-limiting-for-vims-cursorhold-event|
1. The |xolox#misc#cursorhold#register()| function
2. The |xolox#misc#cursorhold#autocmd()| function
4. String escaping functions |misc-string-escaping-functions|
1. The |xolox#misc#escape#pattern()| function
2. The |xolox#misc#escape#substitute()| function
3. The |xolox#misc#escape#shell()| function
4. Human friendly string formatting for Vim |misc-human-friendly-string-formatting-for-vim|
5. Human friendly string formatting for Vim |misc-human-friendly-string-formatting-for-vim|
1. The |xolox#misc#format#pluralize()| function
2. The |xolox#misc#format#timestamp()| function
5. List handling functions |misc-list-handling-functions|
6. List handling functions |misc-list-handling-functions|
1. The |xolox#misc#list#unique()| function
2. The |xolox#misc#list#binsert()| function
6. Functions to interact with the user |misc-functions-to-interact-with-user|
7. Functions to interact with the user |misc-functions-to-interact-with-user|
1. The |xolox#misc#msg#info()| function
2. The |xolox#misc#msg#warn()| function
3. The |xolox#misc#msg#debug()| function
7. Integration between Vim and its environment |misc-integration-between-vim-its-environment|
8. Integration between Vim and its environment |misc-integration-between-vim-its-environment|
1. The |xolox#misc#open#file()| function
2. The |xolox#misc#open#url()| function
8. Vim and plug-in option handling |misc-vim-plug-in-option-handling|
9. Vim and plug-in option handling |misc-vim-plug-in-option-handling|
1. The |xolox#misc#option#get()| function
2. The |xolox#misc#option#split()| function
3. The |xolox#misc#option#join()| function
4. The |xolox#misc#option#split_tags()| function
5. The |xolox#misc#option#join_tags()| function
6. The |xolox#misc#option#eval_tags()| function
9. Operating system interfaces |misc-operating-system-interfaces|
10. Operating system interfaces |misc-operating-system-interfaces|
1. The |xolox#misc#os#is_mac()| function
2. The |xolox#misc#os#is_win()| function
3. The |xolox#misc#os#find_vim()| function
4. The |xolox#misc#os#exec()| function
5. The |xolox#misc#os#can_use_dll()| function
10. Pathname manipulation functions |misc-pathname-manipulation-functions|
11. Pathname manipulation functions |misc-pathname-manipulation-functions|
1. The |xolox#misc#path#which()| function
2. The |xolox#misc#path#split()| function
3. The |xolox#misc#path#join()| function
Expand All @@ -56,14 +59,14 @@ Contents ~
10. The |xolox#misc#path#decode()| function
11. The |xolox#misc#path#is_relative()| function
12. The |xolox#misc#path#tempdir()| function
11. String handling |misc-string-handling|
12. String handling |misc-string-handling|
1. The |xolox#misc#str#slug()| function
2. The |xolox#misc#str#ucfirst()| function
3. The |xolox#misc#str#compact()| function
4. The |xolox#misc#str#trim()| function
5. The |xolox#misc#str#indent()| function
6. The |xolox#misc#str#dedent()| function
12. Test runner & infrastructure for Vim plug-ins |misc-test-runner-infrastructure-for-vim-plug-ins|
13. Test runner & infrastructure for Vim plug-ins |misc-test-runner-infrastructure-for-vim-plug-ins|
1. The |xolox#misc#test#reset()| function
2. The |xolox#misc#test#summarize()| function
3. The |xolox#misc#test#wrap()| function
Expand All @@ -72,7 +75,7 @@ Contents ~
6. The |xolox#misc#test#assert_true()| function
7. The |xolox#misc#test#assert_equals()| function
8. The |xolox#misc#test#assert_same_type()| function
13. Tests for the miscellaneous Vim scripts |tests-for-miscellaneous-vim-scripts|
14. Tests for the miscellaneous Vim scripts |tests-for-miscellaneous-vim-scripts|
1. The |xolox#misc#tests#run()| function
2. The |xolox#misc#tests#pattern_escaping()| function
3. The |xolox#misc#tests#substitute_escaping()| function
Expand All @@ -96,12 +99,12 @@ function
19. The |xolox#misc#tests#multiline_string_dedent()| function
20. The |xolox#misc#tests#version_string_parsing()| function
21. The |xolox#misc#tests#version_string_comparison()| function
14. Timing of long during operations |misc-timing-of-long-during-operations|
15. Timing of long during operations |misc-timing-of-long-during-operations|
1. The |xolox#misc#timer#start()| function
2. The |xolox#misc#timer#stop()| function
3. The |xolox#misc#timer#force()| function
4. The |xolox#misc#timer#convert()| function
15. Version string handling |misc-version-string-handling|
16. Version string handling |misc-version-string-handling|
1. The |xolox#misc#version#parse()| function
2. The |xolox#misc#version#at_least()| function
4. Contact |misc-contact|
Expand Down Expand Up @@ -151,8 +154,8 @@ For those who are curious: The function descriptions given below were extracted
from the source code of the miscellaneous scripts using the Python module
'vimdoctool.py' included in vim-tools [5].

The documentation of the 81 functions below was extracted from 15 Vim scripts
on June 22, 2014 at 00:52.
The documentation of the 83 functions below was extracted from 16 Vim scripts
on June 22, 2014 at 01:04.

-------------------------------------------------------------------------------
*misc-handling-of-special-buffers*
Expand Down Expand Up @@ -213,6 +216,46 @@ you would use it:
>
:command -nargs=* -complete=customlist,xolox#misc#complete#keywords MyCmd call s:MyCmd(<f-args>)
<
-------------------------------------------------------------------------------
*misc-rate-limiting-for-vims-cursorhold-event*
Rate limiting for Vim's CursorHold event ~

Several of my Vim plug-ins (e.g. vim-easytags [9], vim-notes [6] and vim-
session [10]) use Vim's |CursorHold| and |CursorHoldI| events to perform
periodic tasks when the user doesn't press any keys for a couple of seconds.
These events by default fire after four seconds, this is configurable using
Vim's |'updatetime'| option. The problem that this script solves is that there
are Vim plug-ins which set the |'updatetime'| option to unreasonably low
values, thereby breaking my Vim plug-ins and probably a lot of other Vim plug-
ins out there. When users complain about this I can tell them that another Vim
plug-in is to blame, but users don't care for the difference, their Vim is
broken! So I implemented a workaround. This script enables registration of
|CursorHold| event handlers with a configurable interval (expressed in
seconds). The event handlers will be called no more than once every interval.

-------------------------------------------------------------------------------
The *xolox#misc#cursorhold#register()* function

Register a |CursorHold| event handler with a custom interval. This function
takes a single argument which is a dictionary with the following fields:

- **function** (required): The name of the event handler function (a string).

- **arguments** (optional): A list of arguments to pass to the event handler
function (defaults to an empty list).

- **interval** (optional): The number of seconds between calls to the event
handler (defaults to 4).

-------------------------------------------------------------------------------
The *xolox#misc#cursorhold#autocmd()* function

The 'top level event handler' that's called by Vim whenever the |CursorHold| or
|CursorHoldI| event fires. It iterates through the event handlers registered
using |xolox#misc#cursorhold#register()| and calls each event handler at the
appropriate interval, keeping track of the time when each event handler was
last run.

-------------------------------------------------------------------------------
*misc-string-escaping-functions*
String escaping functions ~
Expand Down Expand Up @@ -439,7 +482,7 @@ value of |v:progname|, but if you have a preference you can pass the string
The *xolox#misc#os#exec()* function

Execute an external command (hiding the console on Microsoft Windows when my
vim-shell plug-in [9] is installed).
vim-shell plug-in [11] is installed).

Expects a dictionary with the following key/value pairs as the first argument:

Expand Down Expand Up @@ -845,15 +888,15 @@ version string. Returns 1 (true) when it is, 0 (false) otherwise.
Contact ~

If you have questions, bug reports, suggestions, etc. please open an issue or
pull request on GitHub [10]. Download links and documentation can be found on
the plug-in's homepage [11]. If you like the script please vote for it on Vim
Online [12].
pull request on GitHub [12]. Download links and documentation can be found on
the plug-in's homepage [13]. If you like the script please vote for it on Vim
Online [14].

===============================================================================
*misc-license*
License ~

This software is licensed under the MIT license [13]. Š 2014 Peter Odding
This software is licensed under the MIT license [15]. Š 2014 Peter Odding
<peter@peterodding.com>.

===============================================================================
Expand All @@ -868,10 +911,12 @@ References ~
[6] http://peterodding.com/code/vim/notes/
[7] http://peterodding.com/code/vim/notes/#recentnotes_command
[8] http://peterodding.com/code/vim/notes/#showtaggednotes_command
[9] http://peterodding.com/code/vim/shell/
[10] http://github.com/xolox/vim-misc
[11] http://peterodding.com/code/vim/misc
[12] http://www.vim.org/scripts/script.php?script_id=4597
[13] http://en.wikipedia.org/wiki/MIT_License
[9] http://peterodding.com/code/vim/easytags/
[10] http://peterodding.com/code/vim/session/
[11] http://peterodding.com/code/vim/shell/
[12] http://github.com/xolox/vim-misc
[13] http://peterodding.com/code/vim/misc
[14] http://www.vim.org/scripts/script.php?script_id=4597
[15] http://en.wikipedia.org/wiki/MIT_License

vim: ft=help
19 changes: 19 additions & 0 deletions plugin/xolox/misc.vim
@@ -0,0 +1,19 @@
" Vim plug-in
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 21, 2014
" URL: http://peterodding.com/code/vim/misc/

" Don't source the plug-in when it's already been loaded or &compatible is set.
if &cp || exists('g:loaded_xolox_misc')
finish
endif

" Automatic commands used by the vim-misc plug-in.
augroup PluginXoloxMisc
autocmd! CursorHold,CursorHoldI * call xolox#misc#cursorhold#autocmd()
augroup END

" Make sure the plug-in is only loaded once.
let g:loaded_xolox_misc = 1

" vim: ts=2 sw=2 et

0 comments on commit ec5942f

Please sign in to comment.