From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.help Subject: Re: Returning variable "references" under lexical binding Date: Wed, 22 May 2013 21:01:59 -0400 Message-ID: References: <87fvxgc2mz.fsf@gmail.com> <87bo84b85k.fsf@gmail.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1369270958 9602 80.91.229.3 (23 May 2013 01:02:38 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 23 May 2013 01:02:38 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Thu May 23 03:02:38 2013 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1UfJvR-0000yT-OZ for geh-help-gnu-emacs@m.gmane.org; Thu, 23 May 2013 03:02:37 +0200 Original-Received: from localhost ([::1]:55698 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UfJvR-0006jv-Cd for geh-help-gnu-emacs@m.gmane.org; Wed, 22 May 2013 21:02:37 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:53999) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UfJvC-0006jn-1u for help-gnu-emacs@gnu.org; Wed, 22 May 2013 21:02:27 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UfJv6-0006xe-31 for help-gnu-emacs@gnu.org; Wed, 22 May 2013 21:02:21 -0400 Original-Received: from plane.gmane.org ([80.91.229.3]:55321) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UfJv5-0006xU-PF for help-gnu-emacs@gnu.org; Wed, 22 May 2013 21:02:16 -0400 Original-Received: from list by plane.gmane.org with local (Exim 4.69) (envelope-from ) id 1UfJv3-0000qZ-TX for help-gnu-emacs@gnu.org; Thu, 23 May 2013 03:02:13 +0200 Original-Received: from 69-165-154-5.dsl.teksavvy.com ([69.165.154.5]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Thu, 23 May 2013 03:02:13 +0200 Original-Received: from monnier by 69-165-154-5.dsl.teksavvy.com with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Thu, 23 May 2013 03:02:13 +0200 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 82 Original-X-Complaints-To: usenet@ger.gmane.org X-Gmane-NNTP-Posting-Host: 69-165-154-5.dsl.teksavvy.com User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) Cancel-Lock: sha1:iTiID4UnCvxGHz+3ugr/VK/FfaM= X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 80.91.229.3 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:90990 Archived-At: > (defun run-periodically-when-idle (seconds func) > (let (timer count) > (labels ((on-first-idle () > (when timer > (cancel-timer timer)) > (setq count 1) > (run-and-schedule-next)) > (run-and-schedule-next () > (setq timer > (and (funcall func count) > (run-with-idle-timer > (* seconds (incf count)) > nil > #'run-and-schedule-next))))) > (list (run-with-idle-timer seconds t #'on-first-idle) > (lambda () timer))))) BTW, for the curious, the byte-compiler will turn the above code into something similar to: (defun run-periodically-when-idle (seconds func) (let ((timer (list nil)) (count (list nil))) (letrec ((on-first-idle `(lambda () (when (car ',timer) (cancel-timer (car ',timer))) (setcar ',count 1) (funcall ',run-and-schedule-next))) (run-and-schedule-next `(lambda () (setcar ',timer (and (funcall ',func (car ',count)) (run-with-idle-timer (* ',seconds (incf (car ',count))) nil ',run-and-schedule-next)))))) (list (run-with-idle-timer seconds t on-first-idle) `(lambda () (car ',timer)))))) So if I were you I'd be tempted to use something like (defun run-periodically-when-idle (seconds func) (let ((timers (list nil)) count) (labels ((on-first-idle () (when (cdr timers) (cancel-timer (cdr timers))) (setq count 1) (run-and-schedule-next)) (run-and-schedule-next () (setcdr timers (and (funcall func count) (run-with-idle-timer (* seconds (incf count)) nil #'run-and-schedule-next))))) (setcar timers (run-with-idle-timer seconds t #'on-first-idle)) timers))) (defun cancel-periodic-idle-timer (timers) (cancel-timer (car timers)) (aif (cdr timers) (cancel-timer it))) BTW, as you have discovered there is often the need to do what your code does, and in the packages that need it, they often use a run-with-timer (i.e. a non-idle timer) for the repetition (which they usually cancel in something like a pre-command-hook). In jit-lock, the repetition is done with an idle timer (like here), but instead of creating a new timer each time, the old timer is re-armed for a different idle time. I'm not very satisfied with either of the solutions. It would be good to add the functionality directly in timer.el (even if using one of the existing techniques: at least clients could be later upgraded to a better technique by improving timer.el). IOW, I'd welcome a patch to timer.el providing this feature. Stefan