Klimi's new dotfiles with stow.
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.

972 lines
35 KiB

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