sekka 1.5.3 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
data/emacs/deferred.el ADDED
@@ -0,0 +1,956 @@
1
+ ;;; deferred.el --- Simple asynchronous functions for emacs lisp
2
+
3
+ ;; Copyright (C) 2010, 2011, 2012 SAKURAI Masashi
4
+
5
+ ;; Author: SAKURAI Masashi <m.sakurai at kiwanami.net>
6
+ ;; Version: 0.3.2
7
+ ;; Keywords: deferred, async
8
+ ;; URL: https://github.com/kiwanami/emacs-deferred
9
+
10
+ ;; This program is free software; you can redistribute it and/or modify
11
+ ;; it under the terms of the GNU General Public License as published by
12
+ ;; the Free Software Foundation, either version 3 of the License, or
13
+ ;; (at your option) any later version.
14
+
15
+ ;; This program is distributed in the hope that it will be useful,
16
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ ;; GNU General Public License for more details.
19
+
20
+ ;; You should have received a copy of the GNU General Public License
21
+ ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
22
+
23
+ ;;; Commentary:
24
+
25
+ ;; 'deferred.el' is a simple library for asynchronous tasks.
26
+ ;; [https://github.com/kiwanami/emacs-deferred]
27
+
28
+ ;; The API is almost the same as JSDeferred written by cho45. See the
29
+ ;; JSDeferred and Mochikit.Async web sites for further documentations.
30
+ ;; [https://github.com/cho45/jsdeferred]
31
+ ;; [http://mochikit.com/doc/html/MochiKit/Async.html]
32
+
33
+ ;; A good introduction document (JavaScript)
34
+ ;; [http://cho45.stfuawsc.com/jsdeferred/doc/intro.en.html]
35
+
36
+ ;;; Samples:
37
+
38
+ ;; ** HTTP Access
39
+
40
+ ;; (require 'url)
41
+ ;; (deferred:$
42
+ ;; (deferred:url-retrieve "http://www.gnu.org")
43
+ ;; (deferred:nextc it
44
+ ;; (lambda (buf)
45
+ ;; (insert (with-current-buffer buf (buffer-string)))
46
+ ;; (kill-buffer buf))))
47
+
48
+ ;; ** Invoking command tasks
49
+
50
+ ;; (deferred:$
51
+ ;; (deferred:process "wget" "-O" "a.jpg" "http://www.gnu.org/software/emacs/tour/images/splash.png")
52
+ ;; (deferred:nextc it
53
+ ;; (lambda (x) (deferred:process "convert" "a.jpg" "-resize" "100x100" "jpg:b.jpg")))
54
+ ;; (deferred:nextc it
55
+ ;; (lambda (x)
56
+ ;; (insert-image (create-image (expand-file-name "b.jpg") 'jpeg nil)))))
57
+
58
+ ;; See the readme for further API documentation.
59
+
60
+ ;; ** Applications
61
+
62
+ ;; *Inertial scrolling for Emacs
63
+ ;; [https://github.com/kiwanami/emacs-inertial-scroll]
64
+
65
+ ;; This program makes simple multi-thread function, using
66
+ ;; deferred.el.
67
+
68
+ (require 'cl)
69
+
70
+ (defvar deferred:version nil "deferred.el version")
71
+ (setq deferred:version "0.3.2")
72
+
73
+ ;;; Code:
74
+
75
+ (defmacro deferred:aand (test &rest rest)
76
+ "[internal] Anaphoric AND."
77
+ (declare (debug ("test" form &rest form)))
78
+ `(let ((it ,test))
79
+ (if it ,(if rest `(deferred:aand ,@rest) 'it))))
80
+
81
+ (defmacro deferred:$ (&rest elements)
82
+ "Anaphoric function chain macro for deferred chains."
83
+ (declare (debug (&rest form)))
84
+ `(let (it)
85
+ ,@(loop for i in elements
86
+ with it = nil
87
+ collect
88
+ `(setq it ,i))
89
+ it))
90
+
91
+ (defmacro deferred:lambda (args &rest body)
92
+ "Anaphoric lambda macro for self recursion."
93
+ (declare (debug ("args" form &rest form)))
94
+ (let ((argsyms (loop for i in args collect (gensym))))
95
+ `(lambda (,@argsyms)
96
+ (lexical-let (self)
97
+ (setq self (lambda( ,@args ) ,@body))
98
+ (funcall self ,@argsyms)))))
99
+
100
+ (defun deferred:setTimeout (f msec)
101
+ "[internal] Timer function that emulates the `setTimeout' function in JS."
102
+ (run-at-time (/ msec 1000.0) nil f))
103
+
104
+ (defun deferred:cancelTimeout (id)
105
+ "[internal] Timer cancellation function that emulates the `cancelTimeout' function in JS."
106
+ (cancel-timer id))
107
+
108
+ (defun deferred:run-with-idle-timer (sec f)
109
+ "[internal] Wrapper function for run-with-idle-timer."
110
+ (run-with-idle-timer sec nil f))
111
+
112
+ (defun deferred:call-lambda (f &optional arg)
113
+ "[internal] Call a function with one or zero argument safely.
114
+ The lambda function can define with zero and one argument."
115
+ (condition-case err
116
+ (funcall f arg)
117
+ ('wrong-number-of-arguments
118
+ (display-warning 'deferred "\
119
+ Callback that takes no argument may be specified.
120
+ Passing callback with no argument is deprecated.
121
+ Callback must take one argument.
122
+ Or, this error is coming from somewhere inside of the callback: %S" err)
123
+ (condition-case err2
124
+ (funcall f)
125
+ ('wrong-number-of-arguments
126
+ (signal 'wrong-number-of-arguments (cdr err))))))) ; return the first error
127
+
128
+ ;; debug
129
+
130
+ (eval-and-compile
131
+ (defvar deferred:debug nil "Debug output switch."))
132
+ (defvar deferred:debug-count 0 "[internal] Debug output counter.")
133
+
134
+ (defmacro deferred:message (&rest args)
135
+ "[internal] Debug log function."
136
+ (when deferred:debug
137
+ `(progn
138
+ (with-current-buffer (get-buffer-create "*deferred:debug*")
139
+ (save-excursion
140
+ (goto-char (point-max))
141
+ (insert (format "%5i %s\n" deferred:debug-count (format ,@args)))))
142
+ (incf deferred:debug-count))))
143
+
144
+ (defun deferred:message-mark ()
145
+ "[internal] Debug log function."
146
+ (interactive)
147
+ (deferred:message "==================== mark ==== %s"
148
+ (format-time-string "%H:%M:%S" (current-time))))
149
+
150
+ (defun deferred:pp (d)
151
+ (require 'pp)
152
+ (deferred:$
153
+ (deferred:nextc d
154
+ (lambda (x)
155
+ (pp-display-expression x "*deferred:pp*")))
156
+ (deferred:error it
157
+ (lambda (e)
158
+ (pp-display-expression e "*deferred:pp*")))
159
+ (deferred:nextc it
160
+ (lambda (x) (pop-to-buffer "*deferred:pp*")))))
161
+
162
+ (defvar deferred:debug-on-signal nil
163
+ "If non nil, the value `debug-on-signal' is substituted this
164
+ value in the `condition-case' form in deferred
165
+ implementations. Then, Emacs debugger can catch an error occurred
166
+ in the asynchronous tasks.")
167
+
168
+ (defmacro deferred:condition-case (var protected-form &rest handlers)
169
+ "[internal] Custom condition-case. See the comment for
170
+ `deferred:debug-on-signal'."
171
+ (declare (debug condition-case)
172
+ (indent 2))
173
+ `(let ((debug-on-signal
174
+ (or debug-on-signal deferred:debug-on-signal)))
175
+ (condition-case ,var
176
+ ,protected-form
177
+ ,@handlers)))
178
+
179
+
180
+
181
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182
+ ;; Back end functions of deferred tasks
183
+
184
+ (defvar deferred:tick-time 0.001
185
+ "Waiting time between asynchronous tasks (second).
186
+ The shorter waiting time increases the load of Emacs. The end
187
+ user can tune this paramter. However, applications should not
188
+ modify it because the applications run on various environments.")
189
+
190
+ (defvar deferred:queue nil
191
+ "[internal] The execution queue of deferred objects.
192
+ See the functions `deferred:post-task' and `deferred:worker'.")
193
+
194
+ (defmacro deferred:pack (a b c)
195
+ `(cons ,a (cons ,b ,c)))
196
+
197
+ (defun deferred:schedule-worker ()
198
+ "[internal] Schedule consuming a deferred task in the execution queue."
199
+ (run-at-time deferred:tick-time nil 'deferred:worker))
200
+
201
+ (defun deferred:post-task (d which &optional arg)
202
+ "[internal] Add a deferred object to the execution queue
203
+ `deferred:queue' and schedule to execute.
204
+ D is a deferred object. WHICH is a symbol, `ok' or `ng'. ARG is
205
+ an argument value for execution of the deferred task."
206
+ (push (deferred:pack d which arg) deferred:queue)
207
+ (deferred:message "QUEUE-POST [%s]: %s"
208
+ (length deferred:queue) (deferred:pack d which arg))
209
+ (deferred:schedule-worker)
210
+ d)
211
+
212
+ (defun deferred:clear-queue ()
213
+ "Clear the execution queue. For test and debugging."
214
+ (interactive)
215
+ (deferred:message "QUEUE-CLEAR [%s -> 0]" (length deferred:queue))
216
+ (setq deferred:queue nil))
217
+
218
+ (defun deferred:worker ()
219
+ "[internal] Consume a deferred task.
220
+ Mainly this function is called by timer asynchronously."
221
+ (when deferred:queue
222
+ (let* ((pack (car (last deferred:queue)))
223
+ (d (car pack))
224
+ (which (cadr pack))
225
+ (arg (cddr pack)) value)
226
+ (setq deferred:queue (nbutlast deferred:queue))
227
+ (condition-case err
228
+ (setq value (deferred:exec-task d which arg))
229
+ (error
230
+ (deferred:message "ERROR : %s" err)
231
+ (message "deferred error : %s" err)))
232
+ value)))
233
+
234
+ (defun deferred:flush-queue! ()
235
+ "Call all deferred tasks synchronously. For test and debugging."
236
+ (let (value)
237
+ (while deferred:queue
238
+ (setq value (deferred:worker)))
239
+ value))
240
+
241
+ (defun deferred:sync! (d)
242
+ "Wait for the given deferred task. For test and debugging."
243
+ (progn
244
+ (lexical-let ((last-value 'deferred:undefined*))
245
+ (deferred:nextc d
246
+ (lambda (x) (setq last-value x)))
247
+ (while (eq 'deferred:undefined* last-value)
248
+ (sit-for 0.05)
249
+ (sleep-for 0.05))
250
+ last-value)))
251
+
252
+
253
+
254
+ ;; Struct: deferred
255
+ ;;
256
+ ;; callback : a callback function (default `deferred:default-callback')
257
+ ;; errorback : an errorback function (default `deferred:default-errorback')
258
+ ;; cancel : a canceling function (default `deferred:default-cancel')
259
+ ;; next : a next chained deferred object (default nil)
260
+ ;; status : if 'ok or 'ng, this deferred has a result (error) value. (default nil)
261
+ ;; value : saved value (default nil)
262
+ ;;
263
+ (defstruct deferred
264
+ (callback 'deferred:default-callback)
265
+ (errorback 'deferred:default-errorback)
266
+ (cancel 'deferred:default-cancel)
267
+ next status value)
268
+
269
+ (defun deferred:default-callback (i)
270
+ "[internal] Default callback function."
271
+ (identity i))
272
+
273
+ (defun deferred:default-errorback (err)
274
+ "[internal] Default errorback function."
275
+ (deferred:resignal err))
276
+
277
+ (defun deferred:resignal (err)
278
+ "[internal] Safely resignal ERR as an Emacs condition.
279
+
280
+ If ERR is a cons (ERROR-SYMBOL . DATA) where ERROR-SYMBOL has an
281
+ `error-conditions' property, it is re-signaled unchanged. If ERR
282
+ is a string, it is signaled as a generic error using `error'.
283
+ Otherwise, ERR is formatted into a string as if by `print' before
284
+ raising with `error'."
285
+ (cond ((and (listp err)
286
+ (symbolp (car err))
287
+ (get (car err) 'error-conditions))
288
+ (signal (car err) (cdr err)))
289
+ ((stringp err)
290
+ (error "%s" err))
291
+ (t
292
+ (error "%S" err))))
293
+
294
+ (defun deferred:default-cancel (d)
295
+ "[internal] Default canceling function."
296
+ (deferred:message "CANCEL : %s" d)
297
+ (setf (deferred-callback d) 'deferred:default-callback)
298
+ (setf (deferred-errorback d) 'deferred:default-errorback)
299
+ (setf (deferred-next d) nil)
300
+ d)
301
+
302
+ (defun deferred:exec-task (d which &optional arg)
303
+ "[internal] Executing deferred task. If the deferred object has
304
+ next deferred task or the return value is a deferred object, this
305
+ function adds the task to the execution queue.
306
+ D is a deferred object. WHICH is a symbol, `ok' or `ng'. ARG is
307
+ an argument value for execution of the deferred task."
308
+ (deferred:message "EXEC : %s / %s / %s" d which arg)
309
+ (when (null d) (error "deferred:exec-task was given a nil."))
310
+ (let ((callback (if (eq which 'ok)
311
+ (deferred-callback d)
312
+ (deferred-errorback d)))
313
+ (next-deferred (deferred-next d)))
314
+ (cond
315
+ (callback
316
+ (deferred:condition-case err
317
+ (let ((value (deferred:call-lambda callback arg)))
318
+ (cond
319
+ ((deferred-p value)
320
+ (deferred:message "WAIT NEST : %s" value)
321
+ (if next-deferred
322
+ (deferred:set-next value next-deferred)
323
+ value))
324
+ (t
325
+ (if next-deferred
326
+ (deferred:post-task next-deferred 'ok value)
327
+ (setf (deferred-status d) 'ok)
328
+ (setf (deferred-value d) value)
329
+ value))))
330
+ (error
331
+ (cond
332
+ (next-deferred
333
+ (deferred:post-task next-deferred 'ng err))
334
+ (deferred:onerror
335
+ (deferred:call-lambda deferred:onerror err))
336
+ (t
337
+ (deferred:message "ERROR : %S" err)
338
+ (message "deferred error : %S" err)
339
+ (setf (deferred-status d) 'ng)
340
+ (setf (deferred-value d) err)
341
+ err)))))
342
+ (t ; <= (null callback)
343
+ (cond
344
+ (next-deferred
345
+ (deferred:exec-task next-deferred which arg))
346
+ ((eq which 'ok) arg)
347
+ (t ; (eq which 'ng)
348
+ (deferred:resignal arg)))))))
349
+
350
+ (defun deferred:set-next (prev next)
351
+ "[internal] Connect deferred objects."
352
+ (setf (deferred-next prev) next)
353
+ (cond
354
+ ((eq 'ok (deferred-status prev))
355
+ (setf (deferred-status prev) nil)
356
+ (let ((ret (deferred:exec-task
357
+ next 'ok (deferred-value prev))))
358
+ (if (deferred-p ret) ret
359
+ next)))
360
+ ((eq 'ng (deferred-status prev))
361
+ (setf (deferred-status prev) nil)
362
+ (let ((ret (deferred:exec-task next 'ng (deferred-value prev))))
363
+ (if (deferred-p ret) ret
364
+ next)))
365
+ (t
366
+ next)))
367
+
368
+
369
+
370
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
371
+ ;; Basic functions for deferred objects
372
+
373
+ (defun deferred:new (&optional callback)
374
+ "Create a deferred object."
375
+ (if callback
376
+ (make-deferred :callback callback)
377
+ (make-deferred)))
378
+
379
+ (defun deferred:callback (d &optional arg)
380
+ "Start deferred chain with a callback message."
381
+ (deferred:exec-task d 'ok arg))
382
+
383
+ (defun deferred:errorback (d &optional arg)
384
+ "Start deferred chain with an errorback message."
385
+ (deferred:exec-task d 'ng arg))
386
+
387
+ (defun deferred:callback-post (d &optional arg)
388
+ "Add the deferred object to the execution queue."
389
+ (deferred:post-task d 'ok arg))
390
+
391
+ (defun deferred:errorback-post (d &optional arg)
392
+ "Add the deferred object to the execution queue."
393
+ (deferred:post-task d 'ng arg))
394
+
395
+ (defun deferred:cancel (d)
396
+ "Cancel all callbacks and deferred chain in the deferred object."
397
+ (deferred:message "CANCEL : %s" d)
398
+ (funcall (deferred-cancel d) d)
399
+ d)
400
+
401
+ (defun deferred:status (d)
402
+ "Return a current status of the deferred object. The returned value means following:
403
+ `ok': the callback was called and waiting for next deferred.
404
+ `ng': the errorback was called and waiting for next deferred.
405
+ nil: The neither callback nor errorback was not called."
406
+ (deferred-status d))
407
+
408
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
409
+ ;; Basic utility functions
410
+
411
+ (defvar deferred:onerror nil
412
+ "Default error handler. This value is nil or a function that
413
+ have one argument for the error message.")
414
+
415
+ (defun deferred:succeed (&optional arg)
416
+ "Create a synchronous deferred object."
417
+ (let ((d (deferred:new)))
418
+ (deferred:exec-task d 'ok arg)
419
+ d))
420
+
421
+ (defun deferred:fail (&optional arg)
422
+ "Create a synchronous deferred object."
423
+ (let ((d (deferred:new)))
424
+ (deferred:exec-task d 'ng arg)
425
+ d))
426
+
427
+ (defun deferred:next (&optional callback arg)
428
+ "Create a deferred object and schedule executing. This function
429
+ is a short cut of following code:
430
+ (deferred:callback-post (deferred:new callback))."
431
+ (let ((d (if callback
432
+ (make-deferred :callback callback)
433
+ (make-deferred))))
434
+ (deferred:callback-post d arg)
435
+ d))
436
+
437
+ (defun deferred:nextc (d callback)
438
+ "Create a deferred object with OK callback and connect it to the given deferred object."
439
+ (let ((nd (make-deferred :callback callback)))
440
+ (deferred:set-next d nd)))
441
+
442
+ (defun deferred:error (d callback)
443
+ "Create a deferred object with errorback and connect it to the given deferred object."
444
+ (let ((nd (make-deferred :errorback callback)))
445
+ (deferred:set-next d nd)))
446
+
447
+ (defun deferred:watch (d callback)
448
+ "Create a deferred object with watch task and connect it to the given deferred object.
449
+ The watch task CALLBACK can not affect deferred chains with
450
+ return values. This function is used in following purposes,
451
+ simulation of try-finally block in asynchronous tasks, progress
452
+ monitoring of tasks."
453
+ (lexical-let*
454
+ ((callback callback)
455
+ (normal (lambda (x) (ignore-errors (deferred:call-lambda callback x)) x))
456
+ (err (lambda (e)
457
+ (ignore-errors (deferred:call-lambda callback e))
458
+ (deferred:resignal e))))
459
+ (let ((nd (make-deferred :callback normal :errorback err)))
460
+ (deferred:set-next d nd))))
461
+
462
+ (defun deferred:wait (msec)
463
+ "Return a deferred object scheduled at MSEC millisecond later."
464
+ (lexical-let
465
+ ((d (deferred:new)) (start-time (float-time)) timer)
466
+ (deferred:message "WAIT : %s" msec)
467
+ (setq timer (deferred:setTimeout
468
+ (lambda ()
469
+ (deferred:exec-task d 'ok
470
+ (* 1000.0 (- (float-time) start-time)))
471
+ nil) msec))
472
+ (setf (deferred-cancel d)
473
+ (lambda (x)
474
+ (deferred:cancelTimeout timer)
475
+ (deferred:default-cancel x)))
476
+ d))
477
+
478
+ (defun deferred:wait-idle (msec)
479
+ "Return a deferred object which will run when Emacs has been
480
+ idle for MSEC millisecond."
481
+ (lexical-let
482
+ ((d (deferred:new)) (start-time (float-time)) timer)
483
+ (deferred:message "WAIT-IDLE : %s" msec)
484
+ (setq timer
485
+ (deferred:run-with-idle-timer
486
+ (/ msec 1000.0)
487
+ (lambda ()
488
+ (deferred:exec-task d 'ok
489
+ (* 1000.0 (- (float-time) start-time)))
490
+ nil)))
491
+ (setf (deferred-cancel d)
492
+ (lambda (x)
493
+ (deferred:cancelTimeout timer)
494
+ (deferred:default-cancel x)))
495
+ d))
496
+
497
+ (defun deferred:call (f &rest args)
498
+ "Call the given function asynchronously."
499
+ (lexical-let ((f f) (args args))
500
+ (deferred:next
501
+ (lambda (x)
502
+ (apply f args)))))
503
+
504
+ (defun deferred:apply (f &optional args)
505
+ "Call the given function asynchronously."
506
+ (lexical-let ((f f) (args args))
507
+ (deferred:next
508
+ (lambda (x)
509
+ (apply f args)))))
510
+
511
+
512
+
513
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
514
+ ;; Utility functions
515
+
516
+ (defun deferred:empty-p (times-or-list)
517
+ "[internal] Return non-nil if TIMES-OR-LIST is the number zero or nil."
518
+ (or (and (numberp times-or-list) (<= times-or-list 0))
519
+ (and (listp times-or-list) (null times-or-list))))
520
+
521
+ (defun deferred:loop (times-or-list func)
522
+ "Return a iteration deferred object."
523
+ (deferred:message "LOOP : %s" times-or-list)
524
+ (if (deferred:empty-p times-or-list) (deferred:next)
525
+ (lexical-let*
526
+ (items (rd
527
+ (cond
528
+ ((numberp times-or-list)
529
+ (loop for i from 0 below times-or-list
530
+ with ld = (deferred:next)
531
+ do
532
+ (push ld items)
533
+ (setq ld
534
+ (lexical-let ((i i) (func func))
535
+ (deferred:nextc ld (lambda (x) (deferred:call-lambda func i)))))
536
+ finally return ld))
537
+ ((listp times-or-list)
538
+ (loop for i in times-or-list
539
+ with ld = (deferred:next)
540
+ do
541
+ (push ld items)
542
+ (setq ld
543
+ (lexical-let ((i i) (func func))
544
+ (deferred:nextc ld (lambda (x) (deferred:call-lambda func i)))))
545
+ finally return ld)))))
546
+ (setf (deferred-cancel rd)
547
+ (lambda (x) (deferred:default-cancel x)
548
+ (loop for i in items
549
+ do (deferred:cancel i))))
550
+ rd)))
551
+
552
+ (defun deferred:trans-multi-args (args self-func list-func main-func)
553
+ "[internal] Check the argument values and dispatch to methods."
554
+ (cond
555
+ ((and (= 1 (length args)) (consp (car args)) (not (functionp (car args))))
556
+ (let ((lst (car args)))
557
+ (cond
558
+ ((or (null lst) (null (car lst)))
559
+ (deferred:next))
560
+ ((deferred:aand lst (car it) (or (functionp it) (deferred-p it)))
561
+ ;; a list of deferred objects
562
+ (funcall list-func lst))
563
+ ((deferred:aand lst (consp it))
564
+ ;; an alist of deferred objects
565
+ (funcall main-func lst))
566
+ (t (error "Wrong argument type. %s" args)))))
567
+ (t (funcall self-func args))))
568
+
569
+ (defun deferred:parallel-array-to-alist (lst)
570
+ "[internal] Translation array to alist."
571
+ (loop for d in lst
572
+ for i from 0 below (length lst)
573
+ collect (cons i d)))
574
+
575
+ (defun deferred:parallel-alist-to-array (alst)
576
+ "[internal] Translation alist to array."
577
+ (loop for pair in
578
+ (sort alst (lambda (x y)
579
+ (< (car x) (car y))))
580
+ collect (cdr pair)))
581
+
582
+ (defun deferred:parallel-func-to-deferred (alst)
583
+ "[internal] Normalization for parallel and earlier arguments."
584
+ (loop for pair in alst
585
+ for d = (cdr pair)
586
+ collect
587
+ (progn
588
+ (unless (deferred-p d)
589
+ (setf (cdr pair) (deferred:next d)))
590
+ pair)))
591
+
592
+ (defun deferred:parallel-main (alst)
593
+ "[internal] Deferred alist implementation for `deferred:parallel'. "
594
+ (deferred:message "PARALLEL<KEY . VALUE>" )
595
+ (lexical-let ((nd (deferred:new))
596
+ (len (length alst))
597
+ values)
598
+ (loop for pair in
599
+ (deferred:parallel-func-to-deferred alst)
600
+ with cd ; current child deferred
601
+ do
602
+ (lexical-let ((name (car pair)))
603
+ (setq cd
604
+ (deferred:nextc (cdr pair)
605
+ (lambda (x)
606
+ (push (cons name x) values)
607
+ (deferred:message "PARALLEL VALUE [%s/%s] %s"
608
+ (length values) len (cons name x))
609
+ (when (= len (length values))
610
+ (deferred:message "PARALLEL COLLECTED")
611
+ (deferred:post-task nd 'ok (nreverse values)))
612
+ nil)))
613
+ (deferred:error cd
614
+ (lambda (e)
615
+ (push (cons name e) values)
616
+ (deferred:message "PARALLEL ERROR [%s/%s] %s"
617
+ (length values) len (cons name e))
618
+ (when (= (length values) len)
619
+ (deferred:message "PARALLEL COLLECTED")
620
+ (deferred:post-task nd 'ok (nreverse values)))
621
+ nil))))
622
+ nd))
623
+
624
+ (defun deferred:parallel-list (lst)
625
+ "[internal] Deferred list implementation for `deferred:parallel'. "
626
+ (deferred:message "PARALLEL<LIST>" )
627
+ (lexical-let*
628
+ ((pd (deferred:parallel-main (deferred:parallel-array-to-alist lst)))
629
+ (rd (deferred:nextc pd 'deferred:parallel-alist-to-array)))
630
+ (setf (deferred-cancel rd)
631
+ (lambda (x) (deferred:default-cancel x)
632
+ (deferred:cancel pd)))
633
+ rd))
634
+
635
+ (defun deferred:parallel (&rest args)
636
+ "Return a deferred object that calls given deferred objects or
637
+ functions in parallel and wait for all callbacks. The following
638
+ deferred task will be called with an array of the return
639
+ values. ARGS can be a list or an alist of deferred objects or
640
+ functions."
641
+ (deferred:message "PARALLEL : %s" args)
642
+ (deferred:trans-multi-args args
643
+ 'deferred:parallel 'deferred:parallel-list 'deferred:parallel-main))
644
+
645
+ (defun deferred:earlier-main (alst)
646
+ "[internal] Deferred alist implementation for `deferred:earlier'. "
647
+ (deferred:message "EARLIER<KEY . VALUE>" )
648
+ (lexical-let ((nd (deferred:new))
649
+ (len (length alst))
650
+ value results)
651
+ (loop for pair in
652
+ (deferred:parallel-func-to-deferred alst)
653
+ with cd ; current child deferred
654
+ do
655
+ (lexical-let ((name (car pair)))
656
+ (setq cd
657
+ (deferred:nextc (cdr pair)
658
+ (lambda (x)
659
+ (push (cons name x) results)
660
+ (cond
661
+ ((null value)
662
+ (setq value (cons name x))
663
+ (deferred:message "EARLIER VALUE %s" (cons name value))
664
+ (deferred:post-task nd 'ok value))
665
+ (t
666
+ (deferred:message "EARLIER MISS [%s/%s] %s" (length results) len (cons name value))
667
+ (when (eql (length results) len)
668
+ (deferred:message "EARLIER COLLECTED"))))
669
+ nil)))
670
+ (deferred:error cd
671
+ (lambda (e)
672
+ (push (cons name e) results)
673
+ (deferred:message "EARLIER ERROR [%s/%s] %s" (length results) len (cons name e))
674
+ (when (and (eql (length results) len) (null value))
675
+ (deferred:message "EARLIER FAILED")
676
+ (deferred:post-task nd 'ok nil))
677
+ nil))))
678
+ nd))
679
+
680
+ (defun deferred:earlier-list (lst)
681
+ "[internal] Deferred list implementation for `deferred:earlier'. "
682
+ (deferred:message "EARLIER<LIST>" )
683
+ (lexical-let*
684
+ ((pd (deferred:earlier-main (deferred:parallel-array-to-alist lst)))
685
+ (rd (deferred:nextc pd (lambda (x) (cdr x)))))
686
+ (setf (deferred-cancel rd)
687
+ (lambda (x) (deferred:default-cancel x)
688
+ (deferred:cancel pd)))
689
+ rd))
690
+
691
+
692
+ (defun deferred:earlier (&rest args)
693
+ "Return a deferred object that calls given deferred objects or
694
+ functions in parallel and wait for the first callback. The
695
+ following deferred task will be called with the first return
696
+ value. ARGS can be a list or an alist of deferred objects or
697
+ functions."
698
+ (deferred:message "EARLIER : %s" args)
699
+ (deferred:trans-multi-args args
700
+ 'deferred:earlier 'deferred:earlier-list 'deferred:earlier-main))
701
+
702
+ (defmacro deferred:timeout (timeout-msec timeout-form d)
703
+ "Time out macro on a deferred task D. If the deferred task D
704
+ does not complete within TIMEOUT-MSEC, this macro cancels the
705
+ deferred task and return the TIMEOUT-FORM."
706
+ `(deferred:earlier
707
+ (deferred:nextc (deferred:wait ,timeout-msec)
708
+ (lambda (x) ,timeout-form))
709
+ ,d))
710
+
711
+ (defmacro* deferred:try (d &key catch finally)
712
+ "Try-catch-finally macro. This macro simulates the
713
+ try-catch-finally block asynchronously. CATCH and FINALLY can be
714
+ nil. Because of asynchrony, this macro does not ensure that the
715
+ task FINALLY should be called."
716
+ (let ((chain
717
+ (if catch `((deferred:error it ,catch)))))
718
+ (when finally
719
+ (setq chain (append chain `((deferred:watch it ,finally)))))
720
+ `(deferred:$ ,d ,@chain)))
721
+
722
+
723
+
724
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
725
+ ;; Application functions
726
+
727
+ (defvar deferred:uid 0 "[internal] Sequence number for some utilities. See the function `deferred:uid'.")
728
+
729
+ (defun deferred:uid ()
730
+ "[internal] Generate a sequence number."
731
+ (incf deferred:uid))
732
+
733
+ (defun deferred:buffer-string (strformat buf)
734
+ "[internal] Return a string in the buffer with the given format."
735
+ (format strformat
736
+ (with-current-buffer buf (buffer-string))))
737
+
738
+ (defun deferred:process (command &rest args)
739
+ "A deferred wrapper of `start-process'. Return a deferred
740
+ object. The process name and buffer name of the argument of the
741
+ `start-process' are generated by this function automatically.
742
+ The next deferred object receives stdout string from the command
743
+ process."
744
+ (deferred:process-gen 'start-process command args))
745
+
746
+ (defun deferred:process-shell (command &rest args)
747
+ "A deferred wrapper of `start-process-shell-command'. Return a deferred
748
+ object. The process name and buffer name of the argument of the
749
+ `start-process-shell-command' are generated by this function automatically.
750
+ The next deferred object receives stdout string from the command
751
+ process."
752
+ (deferred:process-gen 'start-process-shell-command command args))
753
+
754
+ (defun deferred:process-buffer (command &rest args)
755
+ "A deferred wrapper of `start-process'. Return a deferred
756
+ object. The process name and buffer name of the argument of the
757
+ `start-process' are generated by this function automatically.
758
+ The next deferred object receives stdout buffer from the command
759
+ process."
760
+ (deferred:process-buffer-gen 'start-process command args))
761
+
762
+ (defun deferred:process-shell-buffer (command &rest args)
763
+ "A deferred wrapper of `start-process-shell-command'. Return a deferred
764
+ object. The process name and buffer name of the argument of the
765
+ `start-process-shell-command' are generated by this function automatically.
766
+ The next deferred object receives stdout buffer from the command
767
+ process."
768
+ (deferred:process-buffer-gen 'start-process-shell-command command args))
769
+
770
+ (defun deferred:process-gen (f command args)
771
+ "[internal]"
772
+ (lexical-let
773
+ ((pd (deferred:process-buffer-gen f command args)) d)
774
+ (setq d (deferred:nextc pd
775
+ (lambda (buf)
776
+ (prog1
777
+ (with-current-buffer buf (buffer-string))
778
+ (kill-buffer buf)))))
779
+ (setf (deferred-cancel d)
780
+ (lambda (x)
781
+ (deferred:default-cancel d)
782
+ (deferred:default-cancel pd)))
783
+ d))
784
+
785
+ (defun deferred:process-buffer-gen (f command args)
786
+ "[internal]"
787
+ (let ((d (deferred:next)) (uid (deferred:uid)))
788
+ (lexical-let
789
+ ((f f) (command command) (args args)
790
+ (proc-name (format "*deferred:*%s*:%s" command uid))
791
+ (buf-name (format " *deferred:*%s*:%s" command uid))
792
+ (pwd default-directory)
793
+ (nd (deferred:new)) proc-buf proc)
794
+ (deferred:nextc d
795
+ (lambda (x)
796
+ (setq proc-buf (get-buffer-create buf-name))
797
+ (condition-case err
798
+ (let ((default-directory pwd))
799
+ (setq proc
800
+ (if (null (car args))
801
+ (apply f proc-name buf-name command nil)
802
+ (apply f proc-name buf-name command args)))
803
+ (set-process-sentinel
804
+ proc
805
+ (lambda (proc event)
806
+ (cond
807
+ ((string-match "exited abnormally" event)
808
+ (let ((msg (if (buffer-live-p proc-buf)
809
+ (format "Process [%s] exited abnormally : %s"
810
+ command
811
+ (with-current-buffer proc-buf (buffer-string)))
812
+ (concat "Process exited abnormally: " proc-name))))
813
+ (kill-buffer proc-buf)
814
+ (deferred:post-task nd 'ng msg)))
815
+ ((equal event "finished\n")
816
+ (deferred:post-task nd 'ok proc-buf)))))
817
+ (setf (deferred-cancel nd)
818
+ (lambda (x) (deferred:default-cancel x)
819
+ (when proc
820
+ (kill-process proc)
821
+ (kill-buffer proc-buf)))))
822
+ (error (deferred:post-task nd 'ng err)))
823
+ nil))
824
+ nd)))
825
+
826
+ (defmacro deferred:processc (d command &rest args)
827
+ "Process chain of `deferred:process'."
828
+ `(deferred:nextc ,d
829
+ (lambda (,(gensym)) (deferred:process ,command ,@args))))
830
+
831
+ (defmacro deferred:process-bufferc (d command &rest args)
832
+ "Process chain of `deferred:process-buffer'."
833
+ `(deferred:nextc ,d
834
+ (lambda (,(gensym)) (deferred:process-buffer ,command ,@args))))
835
+
836
+ (defmacro deferred:process-shellc (d command &rest args)
837
+ "Process chain of `deferred:process'."
838
+ `(deferred:nextc ,d
839
+ (lambda (,(gensym)) (deferred:process-shell ,command ,@args))))
840
+
841
+ (defmacro deferred:process-shell-bufferc (d command &rest args)
842
+ "Process chain of `deferred:process-buffer'."
843
+ `(deferred:nextc ,d
844
+ (lambda (,(gensym)) (deferred:process-shell-buffer ,command ,@args))))
845
+
846
+ (eval-after-load "url"
847
+ ;; for url package
848
+ ;; TODO: proxy, charaset
849
+ '(progn
850
+
851
+ (defun deferred:url-retrieve (url &optional cbargs)
852
+ "A wrapper function for url-retrieve. The next deferred
853
+ object receives the buffer object that URL will load
854
+ into. Currently dynamic binding variables are not supported."
855
+ (lexical-let ((nd (deferred:new)) (url url) (cbargs cbargs) buf)
856
+ (deferred:next
857
+ (lambda (x)
858
+ (condition-case err
859
+ (setq buf
860
+ (url-retrieve
861
+ url (lambda (xx) (deferred:post-task nd 'ok buf))
862
+ cbargs))
863
+ (error (deferred:post-task nd 'ng err)))
864
+ nil))
865
+ (setf (deferred-cancel nd)
866
+ (lambda (x)
867
+ (when (buffer-live-p buf)
868
+ (kill-buffer buf))))
869
+ nd))
870
+
871
+ (defun deferred:url-delete-header (buf)
872
+ (with-current-buffer buf
873
+ (let ((pos (url-http-symbol-value-in-buffer
874
+ 'url-http-end-of-headers buf)))
875
+ (when pos
876
+ (delete-region (point-min) (1+ pos)))))
877
+ buf)
878
+
879
+ (defun deferred:url-delete-buffer (buf)
880
+ (when (and buf (buffer-live-p buf))
881
+ (kill-buffer buf))
882
+ nil)
883
+
884
+ (defun deferred:url-get (url &optional params)
885
+ "Perform a HTTP GET method with `url-retrieve'. PARAMS is
886
+ a parameter list of (key . value) or key. The next deferred
887
+ object receives the buffer object that URL will load into."
888
+ (when params
889
+ (setq url
890
+ (concat url "?" (deferred:url-param-serialize params))))
891
+ (let ((d (deferred:$
892
+ (deferred:url-retrieve url)
893
+ (deferred:nextc it 'deferred:url-delete-header))))
894
+ (deferred:set-next
895
+ d (deferred:new 'deferred:url-delete-buffer))
896
+ d))
897
+
898
+ (defun deferred:url-post (url &optional params)
899
+ "Perform a HTTP POST method with `url-retrieve'. PARAMS is
900
+ a parameter list of (key . value) or key. The next deferred
901
+ object receives the buffer object that URL will load into."
902
+ (lexical-let ((nd (deferred:new))
903
+ (url url) (params params)
904
+ buf)
905
+ (deferred:next
906
+ (lambda (x)
907
+ (let ((url-request-method "POST")
908
+ (url-request-extra-headers
909
+ '(("Content-Type" . "application/x-www-form-urlencoded")))
910
+ (url-request-data
911
+ (deferred:url-param-serialize params)))
912
+ (condition-case err
913
+ (setq buf
914
+ (url-retrieve
915
+ url
916
+ (lambda (&rest args)
917
+ (deferred:post-task nd 'ok buf))))
918
+ (error (deferred:post-task nd 'ng err))))
919
+ nil))
920
+ (setf (deferred-cancel nd)
921
+ (lambda (x)
922
+ (when (buffer-live-p buf)
923
+ (kill-buffer buf))))
924
+ (let ((d (deferred:nextc nd 'deferred:url-delete-header)))
925
+ (deferred:set-next
926
+ d (deferred:new 'deferred:url-delete-buffer))
927
+ d)))
928
+
929
+ (defun deferred:url-escape (val)
930
+ "[internal] Return a new string that is VAL URI-encoded."
931
+ (unless (stringp val)
932
+ (setq val (format "%s" val)))
933
+ (url-hexify-string
934
+ (encode-coding-string val 'utf-8)))
935
+
936
+ (defun deferred:url-param-serialize (params)
937
+ "[internal] Serialize a list of (key . value) cons cells
938
+ into a query string."
939
+ (when params
940
+ (mapconcat
941
+ 'identity
942
+ (loop for p in params
943
+ collect
944
+ (cond
945
+ ((consp p)
946
+ (concat
947
+ (deferred:url-escape (car p)) "="
948
+ (deferred:url-escape (cdr p))))
949
+ (t
950
+ (deferred:url-escape p))))
951
+ "&")))
952
+ ))
953
+
954
+
955
+ (provide 'deferred)
956
+ ;;; deferred.el ends here