Emacs config utilizing prelude as a base
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.

928 lines
29 KiB

  1. ;;; dash.el --- A modern list library for Emacs
  2. ;; Copyright (C) 2012 Magnar Sveen
  3. ;; Author: Magnar Sveen <magnars@gmail.com>
  4. ;; Version: 20130424.943
  5. ;; X-Original-Version: 1.2.0
  6. ;; Keywords: lists
  7. ;; This program is free software; you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; This program is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; A modern list api for Emacs.
  19. ;;
  20. ;; See documentation on https://github.com/magnars/dash.el#functions
  21. ;;; Code:
  22. (defmacro !cons (car cdr)
  23. "Destructive: Sets CDR to the cons of CAR and CDR."
  24. `(setq ,cdr (cons ,car ,cdr)))
  25. (defmacro !cdr (list)
  26. "Destructive: Sets LIST to the cdr of LIST."
  27. `(setq ,list (cdr ,list)))
  28. (defmacro --each (list &rest body)
  29. "Anaphoric form of `-each'."
  30. (let ((l (make-symbol "list")))
  31. `(let ((,l ,list)
  32. (it-index 0))
  33. (while ,l
  34. (let ((it (car ,l)))
  35. ,@body)
  36. (setq it-index (1+ it-index))
  37. (!cdr ,l)))))
  38. (put '--each 'lisp-indent-function 1)
  39. (defun -each (list fn)
  40. "Calls FN with every item in LIST. Returns nil, used for side-effects only."
  41. (--each list (funcall fn it)))
  42. (defmacro --each-while (list pred &rest body)
  43. "Anaphoric form of `-each-while'."
  44. (let ((l (make-symbol "list"))
  45. (c (make-symbol "continue")))
  46. `(let ((,l ,list)
  47. (,c t))
  48. (while (and ,l ,c)
  49. (let ((it (car ,l)))
  50. (if (not ,pred) (setq ,c nil) ,@body))
  51. (!cdr ,l)))))
  52. (put '--each-while 'lisp-indent-function 2)
  53. (defun -each-while (list pred fn)
  54. "Calls FN with every item in LIST while (PRED item) is non-nil.
  55. Returns nil, used for side-effects only."
  56. (--each-while list (funcall pred it) (funcall fn it)))
  57. (defmacro --dotimes (num &rest body)
  58. "Repeatedly executes BODY (presumably for side-effects) with `it` bound to integers from 0 through n-1."
  59. `(let ((it 0))
  60. (while (< it ,num)
  61. ,@body
  62. (setq it (1+ it)))))
  63. (put '--dotimes 'lisp-indent-function 1)
  64. (defun -dotimes (num fn)
  65. "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through n-1."
  66. (--dotimes num (funcall fn it)))
  67. (defun -map (fn list)
  68. "Returns a new list consisting of the result of applying FN to the items in LIST."
  69. (mapcar fn list))
  70. (defmacro --map (form list)
  71. "Anaphoric form of `-map'."
  72. `(mapcar (lambda (it) ,form) ,list))
  73. (defmacro --reduce-from (form initial-value list)
  74. "Anaphoric form of `-reduce-from'."
  75. `(let ((acc ,initial-value))
  76. (--each ,list (setq acc ,form))
  77. acc))
  78. (defun -reduce-from (fn initial-value list)
  79. "Returns the result of applying FN to INITIAL-VALUE and the
  80. first item in LIST, then applying FN to that result and the 2nd
  81. item, etc. If LIST contains no items, returns INITIAL-VALUE and
  82. FN is not called.
  83. In the anaphoric form `--reduce-from', the accumulated value is
  84. exposed as `acc`."
  85. (--reduce-from (funcall fn acc it) initial-value list))
  86. (defmacro --reduce (form list)
  87. "Anaphoric form of `-reduce'."
  88. (let ((lv (make-symbol "list-value")))
  89. `(let ((,lv ,list))
  90. (if ,lv
  91. (--reduce-from ,form (car ,lv) (cdr ,lv))
  92. (let (acc it) ,form)))))
  93. (defun -reduce (fn list)
  94. "Returns the result of applying FN to the first 2 items in LIST,
  95. then applying FN to that result and the 3rd item, etc. If LIST
  96. contains no items, FN must accept no arguments as well, and
  97. reduce returns the result of calling FN with no arguments. If
  98. LIST has only 1 item, it is returned and FN is not called.
  99. In the anaphoric form `--reduce', the accumulated value is
  100. exposed as `acc`."
  101. (if list
  102. (-reduce-from fn (car list) (cdr list))
  103. (funcall fn)))
  104. (defmacro --filter (form list)
  105. "Anaphoric form of `-filter'."
  106. (let ((r (make-symbol "result")))
  107. `(let (,r)
  108. (--each ,list (when ,form (!cons it ,r)))
  109. (nreverse ,r))))
  110. (defun -filter (pred list)
  111. "Returns a new list of the items in LIST for which PRED returns a non-nil value.
  112. Alias: `-select'"
  113. (--filter (funcall pred it) list))
  114. (defalias '-select '-filter)
  115. (defalias '--select '--filter)
  116. (defmacro --remove (form list)
  117. "Anaphoric form of `-remove'."
  118. `(--filter (not ,form) ,list))
  119. (defun -remove (pred list)
  120. "Returns a new list of the items in LIST for which PRED returns nil.
  121. Alias: `-reject'"
  122. (--remove (funcall pred it) list))
  123. (defalias '-reject '-remove)
  124. (defalias '--reject '--remove)
  125. (defmacro --keep (form list)
  126. "Anaphoric form of `-keep'."
  127. (let ((r (make-symbol "result"))
  128. (m (make-symbol "mapped")))
  129. `(let (,r)
  130. (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r))))
  131. (nreverse ,r))))
  132. (defun -keep (fn list)
  133. "Returns a new list of the non-nil results of applying FN to the items in LIST."
  134. (--keep (funcall fn it) list))
  135. (defmacro --map-when (pred rep list)
  136. "Anaphoric form of `-map-when'."
  137. (let ((r (make-symbol "result")))
  138. `(let (,r)
  139. (--each ,list (!cons (if ,pred ,rep it) ,r))
  140. (nreverse ,r))))
  141. (defmacro --map-indexed (form list)
  142. "Anaphoric form of `-map-indexed'."
  143. (let ((r (make-symbol "result")))
  144. `(let (,r)
  145. (--each ,list
  146. (!cons ,form ,r))
  147. (nreverse ,r))))
  148. (defun -map-indexed (fn list)
  149. "Returns a new list consisting of the result of (FN index item) for each item in LIST.
  150. In the anaphoric form `--map-indexed', the index is exposed as `it-index`."
  151. (--map-indexed (funcall fn it-index it) list))
  152. (defun -map-when (pred rep list)
  153. "Returns a new list where the elements in LIST that does not match the PRED function
  154. are unchanged, and where the elements in LIST that do match the PRED function are mapped
  155. through the REP function."
  156. (--map-when (funcall pred it) (funcall rep it) list))
  157. (defalias '--replace-where '--map-when)
  158. (defalias '-replace-where '-map-when)
  159. (defun -flatten (l)
  160. "Takes a nested list L and returns its contents as a single, flat list."
  161. (if (and (listp l) (listp (cdr l)))
  162. (-mapcat '-flatten l)
  163. (list l)))
  164. (defun -concat (&rest lists)
  165. "Returns a new list with the concatenation of the elements in the supplied LISTS."
  166. (apply 'append lists))
  167. (defmacro --mapcat (form list)
  168. "Anaphoric form of `-mapcat'."
  169. `(apply 'append (--map ,form ,list)))
  170. (defun -mapcat (fn list)
  171. "Returns the concatenation of the result of mapping FN over LIST.
  172. Thus function FN should return a list."
  173. (--mapcat (funcall fn it) list))
  174. (defun -cons* (&rest args)
  175. "Makes a new list from the elements of ARGS.
  176. The last 2 members of ARGS are used as the final cons of the
  177. result so if the final member of ARGS is not a list the result is
  178. a dotted list."
  179. (let (res)
  180. (--each
  181. args
  182. (cond
  183. ((not res)
  184. (setq res it))
  185. ((consp res)
  186. (setcdr res (cons (cdr res) it)))
  187. (t
  188. (setq res (cons res it)))))
  189. res))
  190. (defmacro --first (form list)
  191. "Anaphoric form of `-first'."
  192. (let ((n (make-symbol "needle")))
  193. `(let (,n)
  194. (--each-while ,list (not ,n)
  195. (when ,form (setq ,n it)))
  196. ,n)))
  197. (defun -first (pred list)
  198. "Returns the first x in LIST where (PRED x) is non-nil, else nil.
  199. To get the first item in the list no questions asked, use `car'."
  200. (--first (funcall pred it) list))
  201. (defmacro --last (form list)
  202. "Anaphoric form of `-last'."
  203. (let ((n (make-symbol "needle")))
  204. `(let (,n)
  205. (--each ,list
  206. (when ,form (setq ,n it)))
  207. ,n)))
  208. (defun -last (pred list)
  209. "Return the last x in LIST where (PRED x) is non-nil, else nil."
  210. (--last (funcall pred it) list))
  211. (defmacro --count (pred list)
  212. "Anaphoric form of `-count'."
  213. (let ((r (make-symbol "result")))
  214. `(let ((,r 0))
  215. (--each ,list (when ,pred (setq ,r (1+ ,r))))
  216. ,r)))
  217. (defun -count (pred list)
  218. "Counts the number of items in LIST where (PRED item) is non-nil."
  219. (--count (funcall pred it) list))
  220. (defun ---truthy? (val)
  221. (not (null val)))
  222. (defmacro --any? (form list)
  223. "Anaphoric form of `-any?'."
  224. `(---truthy? (--first ,form ,list)))
  225. (defun -any? (pred list)
  226. "Returns t if (PRED x) is non-nil for any x in LIST, else nil.
  227. Alias: `-some?'"
  228. (--any? (funcall pred it) list))
  229. (defalias '-some? '-any?)
  230. (defalias '--some? '--any?)
  231. (defalias '-any-p '-any?)
  232. (defalias '--any-p '--any?)
  233. (defalias '-some-p '-any?)
  234. (defalias '--some-p '--any?)
  235. (defmacro --all? (form list)
  236. "Anaphoric form of `-all?'."
  237. (let ((a (make-symbol "all")))
  238. `(let ((,a t))
  239. (--each-while ,list ,a (setq ,a ,form))
  240. (---truthy? ,a))))
  241. (defun -all? (pred list)
  242. "Returns t if (PRED x) is non-nil for all x in LIST, else nil.
  243. Alias: `-every?'"
  244. (--all? (funcall pred it) list))
  245. (defalias '-every? '-all?)
  246. (defalias '--every? '--all?)
  247. (defalias '-all-p '-all?)
  248. (defalias '--all-p '--all?)
  249. (defalias '-every-p '-all?)
  250. (defalias '--every-p '--all?)
  251. (defmacro --none? (form list)
  252. "Anaphoric form of `-none?'."
  253. `(--all? (not ,form) ,list))
  254. (defun -none? (pred list)
  255. "Returns t if (PRED x) is nil for all x in LIST, else nil."
  256. (--none? (funcall pred it) list))
  257. (defalias '-none-p '-none?)
  258. (defalias '--none-p '--none?)
  259. (defmacro --only-some? (form list)
  260. "Anaphoric form of `-only-some?'."
  261. (let ((y (make-symbol "yes"))
  262. (n (make-symbol "no")))
  263. `(let (,y ,n)
  264. (--each-while ,list (not (and ,y ,n))
  265. (if ,form (setq ,y t) (setq ,n t)))
  266. (---truthy? (and ,y ,n)))))
  267. (defun -only-some? (pred list)
  268. "Returns `t` if there is a mix of items in LIST that matches and does not match PRED.
  269. Returns `nil` both if all items match the predicate, and if none of the items match the predicate."
  270. (--only-some? (funcall pred it) list))
  271. (defalias '-only-some-p '-only-some?)
  272. (defalias '--only-some-p '--only-some?)
  273. (defun -slice (list from &optional to)
  274. "Return copy of LIST, starting from index FROM to index TO.
  275. FROM or TO may be negative."
  276. (let ((length (length list))
  277. (new-list nil)
  278. (index 0))
  279. ;; to defaults to the end of the list
  280. (setq to (or to length))
  281. ;; handle negative indices
  282. (when (< from 0)
  283. (setq from (mod from length)))
  284. (when (< to 0)
  285. (setq to (mod to length)))
  286. ;; iterate through the list, keeping the elements we want
  287. (while (< index to)
  288. (when (>= index from)
  289. (!cons (car list) new-list))
  290. (!cdr list)
  291. (setq index (1+ index)))
  292. (nreverse new-list)))
  293. (defun -take (n list)
  294. "Returns a new list of the first N items in LIST, or all items if there are fewer than N."
  295. (let (result)
  296. (--dotimes n
  297. (when list
  298. (!cons (car list) result)
  299. (!cdr list)))
  300. (nreverse result)))
  301. (defun -drop (n list)
  302. "Returns the tail of LIST without the first N items."
  303. (--dotimes n (!cdr list))
  304. list)
  305. (defmacro --take-while (form list)
  306. "Anaphoric form of `-take-while'."
  307. (let ((r (make-symbol "result")))
  308. `(let (,r)
  309. (--each-while ,list ,form (!cons it ,r))
  310. (nreverse ,r))))
  311. (defun -take-while (pred list)
  312. "Returns a new list of successive items from LIST while (PRED item) returns a non-nil value."
  313. (--take-while (funcall pred it) list))
  314. (defmacro --drop-while (form list)
  315. "Anaphoric form of `-drop-while'."
  316. (let ((l (make-symbol "list")))
  317. `(let ((,l ,list))
  318. (while (and ,l (let ((it (car ,l))) ,form))
  319. (!cdr ,l))
  320. ,l)))
  321. (defun -drop-while (pred list)
  322. "Returns the tail of LIST starting from the first item for which (PRED item) returns nil."
  323. (--drop-while (funcall pred it) list))
  324. (defun -split-at (n list)
  325. "Returns a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list."
  326. (let (result)
  327. (--dotimes n
  328. (when list
  329. (!cons (car list) result)
  330. (!cdr list)))
  331. (list (nreverse result) list)))
  332. (defun -insert-at (n x list)
  333. "Returns a list with X inserted into LIST at position N."
  334. (let ((split-list (-split-at n list)))
  335. (nconc (car split-list) (cons x (cadr split-list)))))
  336. (defmacro --split-with (pred list)
  337. "Anaphoric form of `-split-with'."
  338. (let ((l (make-symbol "list"))
  339. (r (make-symbol "result"))
  340. (c (make-symbol "continue")))
  341. `(let ((,l ,list)
  342. (,r nil)
  343. (,c t))
  344. (while (and ,l ,c)
  345. (let ((it (car ,l)))
  346. (if (not ,pred)
  347. (setq ,c nil)
  348. (!cons it ,r)
  349. (!cdr ,l))))
  350. (list (nreverse ,r) ,l))))
  351. (defun -split-with (pred list)
  352. "Returns a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list."
  353. (--split-with (funcall pred it) list))
  354. (defmacro --separate (form list)
  355. "Anaphoric form of `-separate'."
  356. (let ((y (make-symbol "yes"))
  357. (n (make-symbol "no")))
  358. `(let (,y ,n)
  359. (--each ,list (if ,form (!cons it ,y) (!cons it ,n)))
  360. (list (nreverse ,y) (nreverse ,n)))))
  361. (defun -separate (pred list)
  362. "Returns a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list."
  363. (--separate (funcall pred it) list))
  364. (defun -partition (n list)
  365. "Returns a new list with the items in LIST grouped into N-sized sublists.
  366. If there are not enough items to make the last group N-sized,
  367. those items are discarded."
  368. (let ((result nil)
  369. (sublist nil)
  370. (len 0))
  371. (while list
  372. (!cons (car list) sublist)
  373. (setq len (1+ len))
  374. (when (= len n)
  375. (!cons (nreverse sublist) result)
  376. (setq sublist nil)
  377. (setq len 0))
  378. (!cdr list))
  379. (nreverse result)))
  380. (defun -partition-all (n list)
  381. "Returns a new list with the items in LIST grouped into N-sized sublists.
  382. The last group may contain less than N items."
  383. (let (result)
  384. (while list
  385. (!cons (-take n list) result)
  386. (setq list (-drop n list)))
  387. (nreverse result)))
  388. (defmacro --partition-by (form list)
  389. "Anaphoric form of `-partition-by'."
  390. (let ((r (make-symbol "result"))
  391. (s (make-symbol "sublist"))
  392. (v (make-symbol "value"))
  393. (n (make-symbol "new-value"))
  394. (l (make-symbol "list")))
  395. `(let ((,l ,list))
  396. (when ,l
  397. (let* ((,r nil)
  398. (it (car ,l))
  399. (,s (list it))
  400. (,v ,form)
  401. (,l (cdr ,l)))
  402. (while ,l
  403. (let* ((it (car ,l))
  404. (,n ,form))
  405. (unless (equal ,v ,n)
  406. (!cons (nreverse ,s) ,r)
  407. (setq ,s nil)
  408. (setq ,v ,n))
  409. (!cons it ,s)
  410. (!cdr ,l)))
  411. (!cons (nreverse ,s) ,r)
  412. (nreverse ,r))))))
  413. (defun -partition-by (fn list)
  414. "Applies FN to each item in LIST, splitting it each time FN returns a new value."
  415. (--partition-by (funcall fn it) list))
  416. (defmacro --partition-by-header (form list)
  417. "Anaphoric form of `-partition-by-header'."
  418. (let ((r (make-symbol "result"))
  419. (s (make-symbol "sublist"))
  420. (h (make-symbol "header-value"))
  421. (b (make-symbol "seen-body?"))
  422. (n (make-symbol "new-value"))
  423. (l (make-symbol "list")))
  424. `(let ((,l ,list))
  425. (when ,l
  426. (let* ((,r nil)
  427. (it (car ,l))
  428. (,s (list it))
  429. (,h ,form)
  430. (,b nil)
  431. (,l (cdr ,l)))
  432. (while ,l
  433. (let* ((it (car ,l))
  434. (,n ,form))
  435. (if (equal ,h, n)
  436. (when ,b
  437. (!cons (nreverse ,s) ,r)
  438. (setq ,s nil)
  439. (setq ,b nil))
  440. (setq ,b t))
  441. (!cons it ,s)
  442. (!cdr ,l)))
  443. (!cons (nreverse ,s) ,r)
  444. (nreverse ,r))))))
  445. (defun -partition-by-header (fn list)
  446. "Applies FN to the first item in LIST. That is the header
  447. value. Applies FN to each item in LIST, splitting it each time
  448. FN returns the header value, but only after seeing at least one
  449. other value (the body)."
  450. (--partition-by-header (funcall fn it) list))
  451. (defmacro --group-by (form list)
  452. "Anaphoric form of `-group-by'."
  453. (let ((l (make-symbol "list"))
  454. (v (make-symbol "value"))
  455. (k (make-symbol "key"))
  456. (r (make-symbol "result")))
  457. `(let ((,l ,list)
  458. ,r)
  459. ;; Convert `list' to an alist and store it in `r'.
  460. (while ,l
  461. (let* ((,v (car ,l))
  462. (it ,v)
  463. (,k ,form)
  464. (kv (assoc ,k ,r)))
  465. (if kv
  466. (setcdr kv (cons ,v (cdr kv)))
  467. (push (list ,k ,v) ,r))
  468. (setq ,l (cdr ,l))))
  469. ;; Reverse lists in each group.
  470. (let ((rest ,r))
  471. (while rest
  472. (let ((kv (car rest)))
  473. (setcdr kv (nreverse (cdr kv))))
  474. (setq rest (cdr rest))))
  475. ;; Reverse order of keys.
  476. (nreverse ,r))))
  477. (defun -group-by (fn list)
  478. "Separate LIST into an alist whose keys are FN applied to the
  479. elements of LIST. Keys are compared by `equal'."
  480. (--group-by (funcall fn it) list))
  481. (defun -interpose (sep list)
  482. "Returns a new list of all elements in LIST separated by SEP."
  483. (let (result)
  484. (when list
  485. (!cons (car list) result)
  486. (!cdr list))
  487. (while list
  488. (setq result (cons (car list) (cons sep result)))
  489. (!cdr list))
  490. (nreverse result)))
  491. (defun -interleave (&rest lists)
  492. "Returns a new list of the first item in each list, then the second etc."
  493. (let (result)
  494. (while (-none? 'null lists)
  495. (--each lists (!cons (car it) result))
  496. (setq lists (-map 'cdr lists)))
  497. (nreverse result)))
  498. (defmacro --zip-with (form list1 list2)
  499. "Anaphoric form of `-zip-with'.
  500. The elements in list1 is bound as `it`, the elements in list2 as `other`."
  501. (let ((r (make-symbol "result"))
  502. (l1 (make-symbol "list1"))
  503. (l2 (make-symbol "list2")))
  504. `(let ((,r nil)
  505. (,l1 ,list1)
  506. (,l2 ,list2))
  507. (while (and ,l1 ,l2)
  508. (let ((it (car ,l1))
  509. (other (car ,l2)))
  510. (!cons ,form ,r)
  511. (!cdr ,l1)
  512. (!cdr ,l2)))
  513. (nreverse ,r))))
  514. (defun -zip-with (fn list1 list2)
  515. "Zip the two lists LIST1 and LIST2 using a function FN. This
  516. function is applied pairwise taking as first argument element of
  517. LIST1 and as second argument element of LIST2 at corresponding
  518. position.
  519. The anaphoric form `--zip-with' binds the elements from LIST1 as `it`,
  520. and the elements from LIST2 as `other`."
  521. (--zip-with (funcall fn it other) list1 list2))
  522. (defun -zip (list1 list2)
  523. "Zip the two lists together. Return the list where elements
  524. are cons pairs with car being element from LIST1 and cdr being
  525. element from LIST2. The length of the returned list is the
  526. length of the shorter one."
  527. (-zip-with 'cons list1 list2))
  528. (defun -partial (fn &rest args)
  529. "Takes a function FN and fewer than the normal arguments to FN,
  530. and returns a fn that takes a variable number of additional ARGS.
  531. When called, the returned function calls FN with ARGS first and
  532. then additional args."
  533. (apply 'apply-partially fn args))
  534. (defun -rpartial (fn &rest args)
  535. "Takes a function FN and fewer than the normal arguments to FN,
  536. and returns a fn that takes a variable number of additional ARGS.
  537. When called, the returned function calls FN with the additional
  538. args first and then ARGS.
  539. Requires Emacs 24 or higher."
  540. `(closure (t) (&rest args)
  541. (apply ',fn (append args ',args))))
  542. (defun -applify (fn)
  543. "Changes an n-arity function FN to a 1-arity function that
  544. expects a list with n items as arguments"
  545. (apply-partially 'apply fn))
  546. (defmacro -> (x &optional form &rest more)
  547. "Threads the expr through the forms. Inserts X as the second
  548. item in the first form, making a list of it if it is not a list
  549. already. If there are more forms, inserts the first form as the
  550. second item in second form, etc."
  551. (cond
  552. ((null form) x)
  553. ((null more) (if (listp form)
  554. `(,(car form) ,x ,@(cdr form))
  555. (list form x)))
  556. (:else `(-> (-> ,x ,form) ,@more))))
  557. (defmacro ->> (x form &rest more)
  558. "Threads the expr through the forms. Inserts X as the last item
  559. in the first form, making a list of it if it is not a list
  560. already. If there are more forms, inserts the first form as the
  561. last item in second form, etc."
  562. (if (null more)
  563. (if (listp form)
  564. `(,(car form) ,@(cdr form) ,x)
  565. (list form x))
  566. `(->> (->> ,x ,form) ,@more)))
  567. (defmacro --> (x form &rest more)
  568. "Threads the expr through the forms. Inserts X at the position
  569. signified by the token `it' in the first form. If there are more
  570. forms, inserts the first form at the position signified by `it'
  571. in in second form, etc."
  572. (if (null more)
  573. (if (listp form)
  574. (--map-when (eq it 'it) x form)
  575. (list form x))
  576. `(--> (--> ,x ,form) ,@more)))
  577. (put '-> 'lisp-indent-function 1)
  578. (put '->> 'lisp-indent-function 1)
  579. (put '--> 'lisp-indent-function 1)
  580. (defmacro -when-let (var-val &rest body)
  581. "If VAL evaluates to non-nil, bind it to VAR and execute body.
  582. VAR-VAL should be a (VAR VAL) pair."
  583. (let ((var (car var-val))
  584. (val (cadr var-val)))
  585. `(let ((,var ,val))
  586. (when ,var
  587. ,@body))))
  588. (defmacro -when-let* (vars-vals &rest body)
  589. "If all VALS evaluate to true, bind them to their corresponding
  590. VARS and execute body. VARS-VALS should be a list of (VAR VAL)
  591. pairs (corresponding to bindings of `let*')."
  592. (if (= (length vars-vals) 1)
  593. `(-when-let ,(car vars-vals)
  594. ,@body)
  595. `(-when-let ,(car vars-vals)
  596. (-when-let* ,(cdr vars-vals)
  597. ,@body))))
  598. (defmacro --when-let (val &rest body)
  599. "If VAL evaluates to non-nil, bind it to `it' and execute
  600. body."
  601. `(let ((it ,val))
  602. (when it
  603. ,@body)))
  604. (defmacro -if-let (var-val then &optional else)
  605. "If VAL evaluates to non-nil, bind it to VAR and do THEN,
  606. otherwise do ELSE. VAR-VAL should be a (VAR VAL) pair."
  607. (let ((var (car var-val))
  608. (val (cadr var-val)))
  609. `(let ((,var ,val))
  610. (if ,var ,then ,else))))
  611. (defmacro -if-let* (vars-vals then &optional else)
  612. "If all VALS evaluate to true, bind them to their corresponding
  613. VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list
  614. of (VAR VAL) pairs (corresponding to the bindings of `let*')."
  615. (let ((first-pair (car vars-vals))
  616. (rest (cdr vars-vals)))
  617. (if (= (length vars-vals) 1)
  618. `(-if-let ,first-pair ,then ,else)
  619. `(-if-let ,first-pair
  620. (-if-let* ,rest ,then ,else)
  621. ,else))))
  622. (defmacro --if-let (val then &optional else)
  623. "If VAL evaluates to non-nil, bind it to `it' and do THEN,
  624. otherwise do ELSE."
  625. `(let ((it ,val))
  626. (if it ,then ,else)))
  627. (put '-when-let 'lisp-indent-function 1)
  628. (put '-when-let* 'lisp-indent-function 1)
  629. (put '--when-let 'lisp-indent-function 1)
  630. (put '-if-let 'lisp-indent-function 1)
  631. (put '-if-let* 'lisp-indent-function 1)
  632. (put '--if-let 'lisp-indent-function 1)
  633. (defun -distinct (list)
  634. "Return a new list with all duplicates removed.
  635. The test for equality is done with `equal',
  636. or with `-compare-fn' if that's non-nil.
  637. Alias: `-uniq'"
  638. (let (result)
  639. (--each list (unless (-contains? result it) (!cons it result)))
  640. (nreverse result)))
  641. (defun -union (list list2)
  642. "Return a new list containing the elements of LIST1 and elements of LIST2 that are not in LIST1.
  643. The test for equality is done with `equal',
  644. or with `-compare-fn' if that's non-nil."
  645. (let (result)
  646. (--each list (!cons it result))
  647. (--each list2 (unless (-contains? result it) (!cons it result)))
  648. (nreverse result)))
  649. (defalias '-uniq '-distinct)
  650. (defun -intersection (list list2)
  651. "Return a new list containing only the elements that are members of both LIST and LIST2.
  652. The test for equality is done with `equal',
  653. or with `-compare-fn' if that's non-nil."
  654. (--filter (-contains? list2 it) list))
  655. (defun -difference (list list2)
  656. "Return a new list with only the members of LIST that are not in LIST2.
  657. The test for equality is done with `equal',
  658. or with `-compare-fn' if that's non-nil."
  659. (--filter (not (-contains? list2 it)) list))
  660. (defvar -compare-fn nil
  661. "Tests for equality use this function or `equal' if this is nil.
  662. It should only be set using dynamic scope with a let, like:
  663. (let ((-compare-fn =)) (-union numbers1 numbers2 numbers3)")
  664. (defun -contains? (list element)
  665. "Return whether LIST contains ELEMENT.
  666. The test for equality is done with `equal',
  667. or with `-compare-fn' if that's non-nil."
  668. (not
  669. (null
  670. (cond
  671. ((null -compare-fn) (member element list))
  672. ((eq -compare-fn 'eq) (memq element list))
  673. ((eq -compare-fn 'eql) (memql element list))
  674. (t
  675. (let ((lst list))
  676. (while (and lst
  677. (not (funcall -compare-fn element (car lst))))
  678. (setq lst (cdr lst)))
  679. lst))))))
  680. (defalias '-contains-p '-contains?)
  681. (defun -repeat (n x)
  682. "Return a list with X repeated N times.
  683. Returns nil if N is less than 1."
  684. (let (ret)
  685. (--dotimes n (!cons x ret))
  686. ret))
  687. (eval-after-load "lisp-mode"
  688. '(progn
  689. (let ((new-keywords '(
  690. "--each"
  691. "-each"
  692. "--each-while"
  693. "-each-while"
  694. "--dotimes"
  695. "-dotimes"
  696. "-map"
  697. "--map"
  698. "--reduce-from"
  699. "-reduce-from"
  700. "--reduce"
  701. "-reduce"
  702. "--filter"
  703. "-filter"
  704. "-select"
  705. "--select"
  706. "--remove"
  707. "-remove"
  708. "-reject"
  709. "--reject"
  710. "--keep"
  711. "-keep"
  712. "-flatten"
  713. "-concat"
  714. "--mapcat"
  715. "-mapcat"
  716. "--first"
  717. "-first"
  718. "--any?"
  719. "-any?"
  720. "-some?"
  721. "--some?"
  722. "-any-p"
  723. "--any-p"
  724. "-some-p"
  725. "--some-p"
  726. "--all?"
  727. "-all?"
  728. "-every?"
  729. "--every?"
  730. "-all-p"
  731. "--all-p"
  732. "-every-p"
  733. "--every-p"
  734. "--none?"
  735. "-none?"
  736. "-none-p"
  737. "--none-p"
  738. "-only-some?"
  739. "--only-some?"
  740. "-only-some-p"
  741. "--only-some-p"
  742. "-take"
  743. "-drop"
  744. "--take-while"
  745. "-take-while"
  746. "--drop-while"
  747. "-drop-while"
  748. "-split-at"
  749. "-insert-at"
  750. "--split-with"
  751. "-split-with"
  752. "-partition"
  753. "-partition-all"
  754. "-interpose"
  755. "-interleave"
  756. "--zip-with"
  757. "-zip-with"
  758. "-zip"
  759. "--map-when"
  760. "-map-when"
  761. "--replace-where"
  762. "-replace-where"
  763. "-partial"
  764. "-rpartial"
  765. "->"
  766. "->>"
  767. "-->"
  768. "-when-let"
  769. "-when-let*"
  770. "--when-let"
  771. "-if-let"
  772. "-if-let*"
  773. "--if-let"
  774. "-distinct"
  775. "-intersection"
  776. "-difference"
  777. "-contains?"
  778. "-contains-p"
  779. "-repeat"
  780. "-cons*"
  781. ))
  782. (special-variables '(
  783. "it"
  784. "it-index"
  785. "acc"
  786. "other"
  787. )))
  788. (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\<" (regexp-opt special-variables 'paren) "\\>")
  789. 1 font-lock-variable-name-face)) 'append)
  790. (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\>")
  791. 1 font-lock-keyword-face)) 'append))
  792. (--each (buffer-list)
  793. (with-current-buffer it
  794. (when (and (eq major-mode 'emacs-lisp-mode)
  795. (boundp 'font-lock-mode)
  796. font-lock-mode)
  797. (font-lock-refresh-defaults))))))
  798. (provide 'dash)
  799. ;;; dash.el ends here