Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

973 lines
35 KiB

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