3131; ;
3232; ; To throttle a function FUNC to run no more than once every 2 seconds, run
3333; ; (timeout-throttle 'func 2.0)
34- ; ;
34+ ; ;
3535; ; To debounce a function FUNC to run after a delay of 0.3 seconds, run
3636; ; (timeout-debounce 'func 0.3)
3737; ;
4545; ; (defalias 'throttled-func (timeout-throttled-func 'func 2.0))
4646; ; (fset 'throttled-func (timeout-throttled-func 'func 2.0))
4747; ;
48+ ; ; Dynamic duration is supported by passing a symbol or function instead of
49+ ; ; a number:
50+ ; ;
51+ ; ; (defvar my-timeout 1.5)
52+ ; ; (timeout-throttle 'func 'my-timeout) ; uses value of my-timeout
53+ ; ; (timeout-throttle 'func (lambda () (if busy-p 0.1 2.0))) ; conditional
54+ ; ;
4855; ; The interactive spec and documentation of FUNC is carried over to the new
4956; ; function.
5057
5461(define-obsolete-function-alias 'timeout-throttle! 'timeout-throttle " v2.0" )
5562(define-obsolete-function-alias 'timeout-debounce! 'timeout-debounce " v2.0" )
5663
64+ (defsubst timeout--eval-value (value )
65+ " Eval a VALUE.
66+ If value is a function (either lambda or a callable symbol), eval the
67+ function (with no argument) and return the result. Else if value is a
68+ symbol, return its value. Else return itself."
69+ (cond ((numberp value) value)
70+ ((functionp value) (funcall value))
71+ ((and (symbolp value) (boundp value)) (symbol-value value))
72+ (t (error " Invalid value %s " value))))
73+
5774(defun timeout--throttle-advice (&optional timeout )
5875 " Return a function that throttles its argument function.
5976
60- TIMEOUT defaults to 1 second .
77+ For the meaning of TIMEOUT see `timeout-throttle' .
6178
6279When FUNC does not run because of the throttle, the result from the
6380previous successful call is returned.
6481
6582This is intended for use as function advice."
6683 (let ((throttle-timer)
67- (timeout (or timeout 1.0 ))
84+ (timeout-value (or timeout 1.0 ))
6885 (result))
6986 (lambda (orig-fn &rest args )
7087 " Throttle calls to this function."
@@ -73,29 +90,31 @@ This is intended for use as function advice."
7390 (setq result (apply orig-fn args))
7491 (setq throttle-timer
7592 (run-with-timer
76- timeout nil
93+ ( timeout--eval-value timeout-value) nil
7794 (lambda ()
7895 (cancel-timer throttle-timer)
7996 (setq throttle-timer nil )))))))))
8097
8198(defun timeout--debounce-advice (&optional delay default )
8299 " Return a function that debounces its argument function.
83100
84- DELAY defaults to 0.50 seconds. The function returns immediately with
85- value DEFAULT when called the first time. On future invocations, the
86- result from the previous call is returned.
101+ For the meaning of DELAY see `timeout-debounce' .
102+
103+ The function returns immediately with value DEFAULT when called the
104+ first time. On future invocations, the result from the previous call is
105+ returned.
87106
88107This is intended for use as function advice."
89108 (let ((debounce-timer nil )
90- (delay (or delay 0.50 )))
109+ (delay-value (or delay 0.50 )))
91110 (lambda (orig-fn &rest args )
92111 " Debounce calls to this function."
93112 (prog1 default
94113 (if (timerp debounce-timer)
95- (timer-set-idle-time debounce-timer delay)
114+ (timer-set-idle-time debounce-timer (timeout--eval-value delay-value) )
96115 (setq debounce-timer
97116 (run-with-idle-timer
98- delay nil
117+ (timeout--eval-value delay-value) nil
99118 (lambda (buf )
100119 (cancel-timer debounce-timer)
101120 (setq debounce-timer nil )
@@ -114,13 +133,15 @@ This advises FUNC, when called (interactively or from code), to
114133run after DELAY seconds. If FUNC is called again within this time,
115134the timer is reset.
116135
117- DELAY defaults to 0.5 seconds. Using a delay of 0 removes any
118- debounce advice.
136+ DELAY defaults to 0.5 seconds. DELAY can be a number, a symbol (whose
137+ value is a number), or a function (that evaluates to a number). When
138+ passed a symbol or function, it is evaluated at runtime for dynamic
139+ duration. Using a delay of 0 removes any debounce advice.
119140
120141The function returns immediately with value DEFAULT when called the
121142first time. On future invocations, the result from the previous call is
122143returned."
123- (if (and delay (= delay 0 ))
144+ (if (and delay (eq delay 0 ))
124145 (advice-remove func 'debounce )
125146 (advice-add func :around (timeout--debounce-advice delay default )
126147 '((name . debounce)
@@ -130,12 +151,14 @@ returned."
130151(defun timeout-throttle (func &optional throttle )
131152 " Make FUNC run no more frequently than once every THROTTLE seconds.
132153
133- THROTTLE defaults to 1 second. Using a throttle of 0 removes any
134- throttle advice.
154+ THROTTLE defaults to 1 second. THROTTLE can be a number, a symbol (whose
155+ value is a number), or a function (that evaluates to a number). When
156+ passed a symbol or function, it is evaluated at runtime for dynamic
157+ duration. Using a throttle of 0 removes any throttle advice.
135158
136159When FUNC does not run because of the throttle, the result from the
137160previous successful call is returned."
138- (if (and throttle (= throttle 0 ))
161+ (if (and throttle (eq throttle 0 ))
139162 (advice-remove func 'throttle )
140163 (advice-add func :around (timeout--throttle-advice throttle)
141164 '((name . throttle)
@@ -145,28 +168,31 @@ previous successful call is returned."
145168 " Return a throttled version of function FUNC.
146169
147170The throttled function runs no more frequently than once every THROTTLE
148- seconds. THROTTLE defaults to 1 second.
171+ seconds. THROTTLE defaults to 1 second. THROTTLE can be a number, a
172+ symbol (whose value is a number), or a function (that evaluates to a
173+ number). When passed a symbol or function, it is evaluated at runtime
174+ for dynamic duration.
149175
150176When FUNC does not run because of the throttle, the result from the
151177previous successful call is returned."
152178 (let ((throttle-timer nil )
153- (throttle (or throttle 1 ))
179+ (throttle-value (or throttle 1 ))
154180 (result))
155181 (if (commandp func)
156182 ; ; INTERACTIVE version
157183 (lambda (&rest args )
158184 (:documentation
159185 (concat
160186 (documentation func)
161- ( format " \n\n Throttle calls to this function by %f seconds " throttle) ))
187+ " \n\n Throttle calls to this function" ))
162188 (interactive (advice-eval-interactive-spec
163189 (cadr (interactive-form func))))
164190 (prog1 result
165191 (unless (and throttle-timer (timerp throttle-timer))
166192 (setq result (apply func args))
167193 (setq throttle-timer
168194 (run-with-timer
169- throttle nil
195+ (timeout--eval-value throttle-value) nil
170196 (lambda ()
171197 (cancel-timer throttle-timer)
172198 (setq throttle-timer nil )))))))
@@ -175,13 +201,13 @@ previous successful call is returned."
175201 (:documentation
176202 (concat
177203 (documentation func)
178- ( format " \n\n Throttle calls to this function by %f seconds " throttle) ))
204+ " \n\n Throttle calls to this function" ))
179205 (prog1 result
180206 (unless (and throttle-timer (timerp throttle-timer))
181207 (setq result (apply func args))
182208 (setq throttle-timer
183209 (run-with-timer
184- throttle nil
210+ (timeout--eval-value throttle-value) nil
185211 (lambda ()
186212 (cancel-timer throttle-timer)
187213 (setq throttle-timer nil ))))))))))
@@ -190,28 +216,30 @@ previous successful call is returned."
190216 " Return a debounced version of function FUNC.
191217
192218The debounced function runs DELAY seconds after it is called. DELAY
193- defaults to 0.5 seconds.
219+ defaults to 0.5 seconds. DELAY can be a number, a symbol (whose value
220+ is a number), or a function (that evaluates to a number). When passed
221+ a symbol or function, it is evaluated at runtime for dynamic duration.
194222
195223The function returns immediately with value DEFAULT when called the
196224first time. On future invocations, the result from the previous call is
197225returned."
198226 (let ((debounce-timer nil )
199- (delay (or delay 0.50 )))
227+ (delay-value (or delay 0.50 )))
200228 (if (commandp func)
201229 ; ; INTERACTIVE version
202230 (lambda (&rest args )
203231 (:documentation
204232 (concat
205233 (documentation func)
206- ( format " \n\n Debounce calls to this function by %f seconds " delay) ))
234+ " \n\n Debounce calls to this function" ))
207235 (interactive (advice-eval-interactive-spec
208236 (cadr (interactive-form func))))
209237 (prog1 default
210238 (if (timerp debounce-timer)
211- (timer-set-idle-time debounce-timer delay)
239+ (timer-set-idle-time debounce-timer (timeout--eval-value delay-value) )
212240 (setq debounce-timer
213241 (run-with-idle-timer
214- delay nil
242+ (timeout--eval-value delay-value) nil
215243 (lambda (buf )
216244 (cancel-timer debounce-timer)
217245 (setq debounce-timer nil )
@@ -226,13 +254,13 @@ returned."
226254 (:documentation
227255 (concat
228256 (documentation func)
229- ( format " \n\n Debounce calls to this function by %f seconds " delay) ))
257+ " \n\n Debounce calls to this function" ))
230258 (prog1 default
231259 (if (timerp debounce-timer)
232- (timer-set-idle-time debounce-timer delay)
260+ (timer-set-idle-time debounce-timer (timeout--eval-value delay-value) )
233261 (setq debounce-timer
234262 (run-with-idle-timer
235- delay nil
263+ (timeout--eval-value delay-value) nil
236264 (lambda (buf )
237265 (cancel-timer debounce-timer)
238266 (setq debounce-timer nil )
0 commit comments