branch: externals/timeout
commit 441734b52029707032bb0fac184ab687b687bcc8
Author: Karthik Chikmagalur <karthikchikmaga...@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>

    timeout: Add functions for throttling and debouncing
    
    * timeout.el (timeout-throttle, timeout-debounce): Add functions
    to generate new throttled and debounced versions of their argument
    functions, as opposed to advising them.  Try to maintain the
    documentation and interactive specs of the argument functions.
---
 timeout.el | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 106 insertions(+)

diff --git a/timeout.el b/timeout.el
index 2bf41b833d..161955e5e6 100644
--- a/timeout.el
+++ b/timeout.el
@@ -34,6 +34,19 @@
 ;; 
 ;; To debounce a function FUNC to run after a delay of 0.3 seconds, run
 ;; (timeout-debounce! func 0.3)
+;;
+;; To create a new throttled or debounced version of FUNC instead, run
+;;
+;; (timeout-throttle func 2.0)
+;; (timeout-debounce func 0.3)
+;;
+;; You can bind this via fset or defalias:
+;;
+;; (defalias 'throttled-func (timeout-throttle func 2.0))
+;; (fset     'throttled-func (timeout-throttle func 2.0))
+;;
+;; The interactive spec and documentation of FUNC is carried over to the new
+;; function.
 
 ;;; Code:
 (require 'nadvice)
@@ -118,5 +131,98 @@ function."
                 '((name . throttle)
                   (depth . -98)))))
 
+(defun timeout-throttle (func &optional throttle default)
+  "Return a throttled version of function FUNC.
+
+THROTTLE defaults to 1 second.  DEFAULT is the immediate return
+value of the function when called."
+  (let ((throttle-timer nil)
+        (throttle (or throttle 1))
+        (result default))
+    (if (commandp func)
+        ;; INTERACTIVE version
+        (lambda (&rest args)
+          (:documentation
+           (concat
+            (documentation func)
+            (format "\n\nThrottle calls to this function by %f seconds" 
throttle)))
+          (interactive (advice-eval-interactive-spec
+                        (cadr (interactive-form func))))
+          (if (and throttle-timer (timerp throttle-timer))
+              result
+            (setq result (apply func args))
+            (setq throttle-timer
+                  (run-with-timer
+                   throttle nil
+                   (lambda ()
+                     (cancel-timer throttle-timer)
+                     (setq throttle-timer nil))))))
+      ;; NON-INTERACTIVE version
+      (lambda (&rest args)
+        (:documentation
+           (concat
+            (documentation func)
+            (format "\n\nThrottle calls to this function by %f seconds" 
throttle)))
+        (if (and throttle-timer (timerp throttle-timer))
+            result
+          (setq result (apply func args))
+          (setq throttle-timer
+                (run-with-timer
+                 throttle nil
+                 (lambda ()
+                   (cancel-timer throttle-timer)
+                   (setq throttle-timer nil)))))))))
+
+(defun timeout-debounce (func &optional delay default)
+  "Return a debounced version of function FUNC.
+
+DELAY defaults to 0.5 seconds.  DEFAULT is the immediate return
+value of the function when called."
+  (let ((debounce-timer nil)
+        (delay (or delay 0.50)))
+    (if (commandp func)
+        ;; INTERACTIVE version
+        (lambda (&rest args)
+          (:documentation
+           (concat
+            (documentation func)
+            (format "\n\nDebounce calls to this function by %f seconds" 
delay)))
+          (interactive (advice-eval-interactive-spec
+                        (cadr (interactive-form func))))
+          (if (timerp debounce-timer)
+              (timer-set-idle-time debounce-timer delay)
+            (prog1 default
+              (setq debounce-timer
+                    (run-with-idle-timer
+                     delay nil
+                     (lambda (buf)
+                       (cancel-timer debounce-timer)
+                       (setq debounce-timer nil)
+                       (if (buffer-live-p buf)
+                           (with-current-buffer buf
+                             (apply func args))
+                         (apply func args)))
+                     (current-buffer))))))
+      ;; NON-INTERACTIVE version
+      (lambda (&rest args)
+        (:documentation
+         (concat
+          (documentation func)
+          (format "\n\nDebounce calls to this function by %f seconds" delay)))
+        (if (timerp debounce-timer)
+            (timer-set-idle-time debounce-timer delay)
+          (prog1 default
+            (setq debounce-timer
+                  (run-with-idle-timer
+                   delay nil
+                   (lambda (buf)
+                     (cancel-timer debounce-timer)
+                     (setq debounce-timer nil)
+                     (if (buffer-live-p buf)
+                         (with-current-buffer buf
+                           (apply func args))
+                       (apply func args)))
+                   (current-buffer)))))))))
+
 (provide 'timeout)
 ;;; timeout.el ends here

Reply via email to