emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master 51d7fa7 3/4: Add 'packages/timerfunctions/' from commit 'f


From: Stefan Monnier
Subject: [elpa] master 51d7fa7 3/4: Add 'packages/timerfunctions/' from commit 'f0a06654092bcd4ccbcceb9566673e6dd8b01e9e'
Date: Wed, 18 Feb 2015 14:22:35 +0000

branch: master
commit 51d7fa7df773f61ff1db908c7acf5a495e1cc4d5
Merge: be78cfd f0a0665
Author: Stefan Monnier <address@hidden>
Commit: Stefan Monnier <address@hidden>

    Add 'packages/timerfunctions/' from commit 
'f0a06654092bcd4ccbcceb9566673e6dd8b01e9e'
    
    git-subtree-dir: packages/timerfunctions
    git-subtree-mainline: be78cfda9a7a48cfac0f65f3103fc37d2a95d62c
    git-subtree-split: f0a06654092bcd4ccbcceb9566673e6dd8b01e9e
---
 packages/timerfunctions/timerfunctions.el |  447 +++++++++++++++++++++++++++++
 1 files changed, 447 insertions(+), 0 deletions(-)

diff --git a/packages/timerfunctions/timerfunctions.el 
b/packages/timerfunctions/timerfunctions.el
new file mode 100644
index 0000000..42e7bfd
--- /dev/null
+++ b/packages/timerfunctions/timerfunctions.el
@@ -0,0 +1,447 @@
+;;; timerfunctions.el---enhanced versions of some timer.el functions.
+;; Time-stamp: <2011-10-04 21:58:10 deego>
+;; Copyright (C) Deepak Goel 2000, 2001, 2002
+;; Emacs Lisp Archive entry
+;; Filename: timerfunctions.el
+;; Author: Deepak Goel <address@hidden>
+;; Version: 1.4.2
+;; Created: 2000/11/20
+
+;; Author's homepage: http://gnufans.net/~deego
+;; For latest version: 
+
+(defconst timerfunctions-home-page
+  "http://gnufans.net/~deego/emacspub/timerfunctions";)
+
+
+
+(defvar timerfunctions-version "1.4.2")
+
+
+;;;========================================================
+;;;========================================================
+;;; Commentary:   The latest version can always be downloaded from
+;;; http://www.glue.umd.edu/~deego/emacs.html
+
+
+ 
+;; This file is NOT (yet) part of GNU Emacs.
+ 
+;; This is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+ 
+;; This is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+
+;;; See also: midnight.el (part of emacs), timer.el
+
+
+
+
+;;; New features:
+(defconst timerfunctions-new-features
+  "New since last posting: Changed the syntax of `tf-with-timeout' and
+provided a `tf-with-timeout-check'.")
+
+(defun timerfunctions-new-features ()
+  "Provides electric help from variable `timerfunctions-new-features'."
+  (interactive)
+  (with-electric-help
+   '(lambda () (insert timerfunctions-new-features) nil) "*doc*"))
+
+
+(defconst timerfunctions-introduction
+  "timerfunctions.el contains some 'enhanced' versions of a few timer.el
+functions.  It is also used by vel.el, idledo.el etc.
+
+ Suppose you want emacs to run an action every REDOSECS for
+ _as_long_as emacs remains idle.  `tf-run-with-idle-timer' allows that.
+  
+ `tf-with-timeout' is a generalized with-timeout where you can inhibit
+ breaks within parts of the body that you want.
+
+ QUICKSTART: 
+ Place this file somewhere in yr emacs-load-path, and add the
+ foll. to your .emacs: (load \"timerfunctions.el\")
+"
+)
+
+;;;###autoload
+(defun timerfunctions-introduction ()
+  "Provides electric help from variable `timerfunctions-introduction'."
+  (interactive)
+  (with-electric-help
+   '(lambda () (insert timerfunctions-introduction) nil) "*doc*"))
+
+;;; Real Code: 
+
+
+;;;###autoload
+(defun tf-time-difference (timeplus timesub)
+  "Gives the time in seconds elaspsed from TIMESUB to TIMEPLUS.
+Almost like \(- TIMEPLUS TIMESUB \)."
+  (+ (* (expt 2 16) (- (car timeplus) (car timesub)))
+     (- (cadr timeplus) (cadr timesub)))
+)
+
+
+;;;###autoload
+(defun tf-run-with-idle-timer  (secs repeat redosecs redorepeat includeruntime 
function &rest args) 
+  "Args are SECS, REPEAT, REDOSECS, REDOREPEAT, INCLUDERUNTIME,
+FUNCTION and &rest ARGS.
+Similar to run-with-idle-timer, except that provides more options.
+Suppose you want emacs to run an action every REDOSECS for as long as
+emacs remains idle.  Think you can do it with the emacs' 
+run-with-idle-timer? Think again.. :)   That function will perform the
+action exactly once every time emacs goes idle.  This funciton, 
+tf-run-with-idle-timer *will* allow you to keep performing an action
+as long as emacs remains idle.
+
+SECS is the number of seconds to wait once emacs has first gone
+idle. It can really be any expression whose at runtime yields a
+number..  Note that the way run-with-idle-timer is defined, SECS will
+unfortunately be evalled immediately after you call this function, but
+redosecs will be *every* time emacs *remains* idle..yay..
+
+
+If REDOREPEAT is non-nil, the action is repeated as long emacs remains
+idle.  REDOSECS is the number of additional seconds (after the action
+has been done) to wait if emacs remains idle before performing the
+action again.  Again, redosecs does not have to be a number, it can be
+any expression whose eval yields to a number...
+
+If INCLUDERUNTIME is non-nil, REDOSECS is the number of
+additional seconds to wait after the action has been invoked (not
+finished).
+
+If REPEAT is nonnil, the entire cycle is repeated every time emacs
+next goes idle.. (as in the default run-with-idle-timer."
+  (apply 'run-with-idle-timer 
+        (eval secs) repeat 'tf-run-while-idle 
+        redosecs redorepeat includeruntime
+        function args)
+  )
+
+
+(defun tf-run-while-idle (redosecs redorepeat includeruntime
+function &rest args)
+  "Runs FUNCTION with ARGS and optionally repeats if emacs idle.
+Probably is of no use unless used in programs.
+ If REDOREPEAT is non-nil, the function is repeated periodically every
+REDOSECS as long as emacs remains idle. By default, emacs waits
+REDOSECS *after* the function is done executing to repeat. If you want
+the execution-time to count towards REDOSECS, make INCLUDERUNTIME
+non-nil.
+SECS and REDOSECS can be any expressions that eval at runtime to
+numbers.. In particular, they can simply be numbers..
+
+"
+  (if (not includeruntime)
+      (progn
+       (apply function args)
+       (if redorepeat
+           (while (sit-for (eval redosecs))
+             (apply function args))))
+    (progn
+      (let ((before-time (current-time)))
+       (apply function args)
+       (if redorepeat
+           (while (sit-for (- 
+                            (eval redosecs)
+                            (tf-time-difference (current-time)
+                                                before-time)))
+             (setq before-time (current-time))
+             (apply function args))))))
+  )
+
+
+;;;====================================================
+;;;TESTS FOLLOW
+(defun tf-test-display-time-internal
+  ()
+  (interactive)
+  (let ((thisbuffer (buffer-name)))
+    (switch-to-buffer-other-window "*scratch*")
+    (goto-char (point-max))
+    (insert (concat "\n" (format "%S" (cadr (current-time)))))
+    (recenter)
+    (switch-to-buffer-other-window thisbuffer))
+)
+
+
+(defun tf-test-idle-timer ()
+  "Run this and watch..Play around with the options.. If you run it,
+you may have to exit your emacs session to restore normal emacs!
+unless you are an expert, that is.."
+
+  (interactive)
+  (tf-run-with-idle-timer
+  1 t 3 t nil 'tf-test-display-time-internal)
+)
+
+
+  
+
+
+(defun tf-test-timeout ()
+  "Bad count should be zero. "
+  (interactive)
+  (let ((inhi nil) (goodcount 0) (badcount 0) (ctr 0) (a 1) (b 2)
+       (mytag nil)
+       (myvar nil)
+       )
+    (loop 
+     for ctr from 0 to 10 do
+     (message "ctr=%S" ctr)
+     (tf-with-timeout 'inhi 'mytah 'myvar
+      (0.3 nil)
+      (loop for i from 0 to 100000 do
+           (message "ctr=%S, i=%S" ctr i)
+           (setq inhi t)
+           (setq a (random 100))
+           (sleep-for 0.1)
+           (setq b a)
+           (setq inhi nil)
+           (sleep-for 0.02)
+           ))
+     (if (equal b a) (incf goodcount) (incf badcount)))
+    (message "Goodcount: %S; badcount: %S" goodcount badcount)))
+
+
+
+(defun tf-test-timeout-complex ()
+  "Should return a value of 20000 for a. "
+
+  (interactive)
+  (let ((inhi t) (goodcount 0) (badcount 0) (ctr 0) (a 1) (b 2)
+       (mytag nil)
+       (myvar nil)
+       )
+    (setq a 0)
+    (message "ctr=%S" ctr)
+    (tf-with-timeout 
+     'inhi 'mytag 'myvar
+     (0.1 nil)
+     (loop for i from 0 to 10000 do
+          (message "first loop. i=%S" ctr i)
+          (incf a))
+     (message "initial loop ends here.")
+     ;; no throw here because loop prohibited. 
+     (tf-with-timeout-check 'inhi 'mytag 'myvar)
+     ;; this shouldn't help either
+     (sit-for 0.3)
+
+     (loop for i from 0 to 10000 do
+          (message "second loop.  i=%S" i)
+          (incf a))
+     (message "second loop ends here.")
+     (setq inhi nil)
+     ;; this should throw. 
+     (tf-with-timeout-check 'inhi 'mytag 'myvar)
+     ;; this should NOT be needed. 
+     ;;(sit-for 0.2)
+     ;; this loop should never take place.
+     (loop for i from 0 to 1000 do
+          (message "third loop, i=%S" i)
+          (incf a))
+     (message "third loop ends here."))
+    (message "%S" a)
+    a))
+
+
+
+(defvar tf-internal-var-recenter 1)
+(defun tf-internal-recenter-toggle-my ()
+  (interactive)
+  (recenter tmpp)
+  (setq tf-internal-var-recenter (- 0 tf-internal-var-recenter)))
+
+(defun tf-example-timer-recenter ()
+  "Changes the screen display every 3 seconds, thus ensuring that you
+  don't time out of ssh sessions."
+  tf-run-with-idle-timer 3 t 3 t nil 'tf-internal-recenter-toggle-my)
+
+
+
+
+(defun tf-wait-until-idle (&optional secs)
+  "DOES NOT WORK YET. Waits until idle. 
+Will help run processes in background.  This function will NOT create
+a timer.  Will simply use sit-for.  "
+  (if (null secs)
+      (setq secs 1))
+  (while (not (sit-for secs))
+    (sit-for 1))
+  (message "tf-wait-until-idle DONE WAITING!")
+)
+
+
+;;;Tue Jan 23 17:38:44 2001
+(defmacro tf-ignore-errors (&rest body)
+ "Like ignore-errors, but tells the error.."
+ (let ((err (gensym)))
+   (list 'condition-case err (cons 'progn body)
+        (list 'error
+              (list 'message
+                    (list 'concat
+                          "IGNORED ERROR: "
+                          (list 'error-message-string err)))))
+   ))
+
+
+
+
+(defvar tf-with-timeout-repeat-sec 0.01
+  "If the initial timeout fails because of inhibitedness, we shall
+check every this many seconds to see if we are uninhibited.  This
+variable is customizable. ")
+
+
+(defun tf-with-timeout-handler-internal (tag timedoutvar inhibitp)
+  (set timedoutvar t)
+  ;;(tf-with-timeout-check tag timedoutvar inhibitp)
+  ;; which is equivalent to:
+  (unless (eval inhibitp) 
+    (tf-ignore-errors (throw tag 'timeout)))
+  )
+
+(defun tf-with-timeout-check (inhibitp tag timedoutvar)
+  ;; check whether timeout has actually reached. 
+  ;; we need this step because this function might be called by the
+  ;; user as well. 
+  (when (eval timedoutvar)
+    (unless (eval inhibitp) 
+      (tf-ignore-errors (throw tag 'timeout)))))
+
+
+
+(defvar tf-tag-tmpvar nil)
+
+(defmacro tf-catch (tag &rest body)
+  `(let 
+       ;; unquote the tag here..
+       ((,(cadr tag) 'tf-catch))
+     (catch ,tag
+       ,@body)))
+
+(defmacro tf-throw (tag value)
+  `(when (eql (eval ,tag) 'tf-catch)
+     (throw ,tag value)))
+
+  
+;;;###autoload
+(defmacro tf-with-timeout (inhibitp timertag timedoutvar tlist &rest body)
+  "Like `with-timeout' but provide ability to inhibit timeout during
+parts of the body.  Note that most of the time, you may not need this
+functionality at all unless you want to be very 'clean' about
+things---you could get by with the regular with-timeout and not using
+sit-for's in the body.  Or with the regular with-timeout and using
+unwind-protect.
+
+
+TO DECIDE: IN VIEW OF THE UNWIND-PROTECT, DO WE NEED THIS FUNCTION AT ALL??
+
+Run BODY, but if it doesn't finish in SECONDS seconds, give up.
+If we give up, we run the TIMEOUT-FORMS which are contained in TLIST 
+and return the value of the last one.
+The call should look like:
+ (tf-with-timeout quoted-expr (SECONDS TIMEOUT-FORMS...) BODY...)
+
+The timeout is checked whenever Emacs waits for some kind of external
+event \(such as keyboard input, input from subprocesses, or a certain time);
+if the program loops without waiting in any way, the timeout will not
+be detected.  Furthermore:
+
+During the execution of the body, we SHALL NOT time out when INHIBITP
+evals to non-nil.  Thus, for example, you might initially setq a
+variable my-var as nil, supply inhibitp as 'my-var, and then you may
+setq my-var to t or nil within the body of tf-with-timeout to enable
+or disable timeout.  The best use of this functionality is to setq
+inhibitp to t when during parts of loops where you do not want the
+body broken within certain parts of the loop.  (Of course, if that
+part of the loop does not contain any sit-for's or read's then you
+don't have to worry about this in the first place..)
+
+
+again, Do not forget my-var to some value before attempting to use this
+tf-with-timeout :)
+
+Here's an example: 
+
+ 
+ (let ((myinhibit t))
+  (tf-with-timeout 'myinhibit 'mytag 'mytimedoutvar
+                  (2 2)
+                  (setq a nil)
+                  (setq b nil)
+                  (sit-for 4)
+                  (setq a 4)
+                  (setq myinhibit nil)
+                  (sit-for 2)
+                  (setq b 5)
+                  ))
+
+
+The above example requests a timeout within 2 seconds.  However, the
+timeout can takes place only when myinhibit is set to nil,
+which becomes true after about 4 seconds.  Thus, after the execution of the
+body, a has the value 4, but b has the value nil.
+
+See `tf-test-timeout' for another example. 
+
+Important Note: If the body of a loop tends to stay in a timeout
+inhibited region for most of the time, then make sure that the timeout
+enabled region atleast spans about 0.02 seconds.. thus, use (sleep-for
+0.02) if needed.. this is because we check every 0.01 seconds if an
+uninhibited timeout condition has been satisfied.  
+
+But perhaps you do not want to include (sleep-for 0.02) because that
+wastes precious cpu time.  Simple, don't include it, just after a long
+inhibited body, you can include a timeout check within the body
+instead of (sleep-for 0.02):
+ (tf-with-timeout-check 'mytag 'mytimedoutvar 'myinhibitp)
+
+Moreover, if that is the main check you rely on, you it perhaps makes
+sense to increase the value of tf-with-timeout-repeat-sec, so that
+your cpu cycles are not wasted every 0.01 sec.  See the doc of that
+variable for more. 
+
+Timertag should be a quoted symbol, also we WILL set that symbol to t
+during the execution of these forms.
+
+"
+  (let ((seconds (car tlist))
+       (timeout-forms (cdr tlist)))
+    `(let (
+          ;;(with-timeout-tag (cons nil nil))
+          with-timeout-value with-timeout-timer)
+       (set ,timedoutvar nil)
+       (if (catch ,timertag
+            (progn
+              (setq with-timeout-timer
+                    (run-with-timer ,seconds tf-with-timeout-repeat-sec
+                                    'tf-with-timeout-handler-internal
+                                    ,timertag ,timedoutvar 
+                                    ,inhibitp))
+              (setq with-timeout-value (progn ,@body))
+              nil))
+          (progn ,@timeout-forms)
+        (cancel-timer with-timeout-timer)
+        with-timeout-value))))
+
+
+(provide 'timerfunctions)
+
+;;;timerfunctions.el ends here.
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]