Klimi's new dotfiles with stow.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

193 satır
6.6 KiB

5 yıl önce
  1. ;;; nrepl-dict.el --- Dictionary functions for Clojure nREPL -*- lexical-binding: t -*-
  2. ;; Copyright © 2012-2013 Tim King, Phil Hagelberg, Bozhidar Batsov
  3. ;; Copyright © 2013-2019 Bozhidar Batsov, Artur Malabarba and CIDER contributors
  4. ;;
  5. ;; Author: Tim King <kingtim@gmail.com>
  6. ;; Phil Hagelberg <technomancy@gmail.com>
  7. ;; Bozhidar Batsov <bozhidar@batsov.com>
  8. ;; Artur Malabarba <bruce.connor.am@gmail.com>
  9. ;; Hugo Duncan <hugo@hugoduncan.org>
  10. ;; Steve Purcell <steve@sanityinc.com>
  11. ;;
  12. ;; This program is free software: you can redistribute it and/or modify
  13. ;; it under the terms of the GNU General Public License as published by
  14. ;; the Free Software Foundation, either version 3 of the License, or
  15. ;; (at your option) any later version.
  16. ;;
  17. ;; This program is distributed in the hope that it will be useful,
  18. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. ;; GNU General Public License for more details.
  21. ;;
  22. ;; You should have received a copy of the GNU General Public License
  23. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. ;;
  25. ;; This file is not part of GNU Emacs.
  26. ;;
  27. ;;; Commentary:
  28. ;;
  29. ;; Provides functions to interact with and create `nrepl-dict's. These are
  30. ;; simply plists with an extra element at the head.
  31. ;;; Code:
  32. (require 'cl-lib)
  33. (defun nrepl-dict (&rest key-vals)
  34. "Create nREPL dict from KEY-VALS."
  35. (cons 'dict key-vals))
  36. (defun nrepl-dict-from-hash (hash)
  37. "Create nREPL dict from HASH."
  38. (let ((dict (nrepl-dict)))
  39. (maphash (lambda (k v) (nrepl-dict-put dict k v)) hash)
  40. dict))
  41. (defun nrepl-dict-p (object)
  42. "Return t if OBJECT is an nREPL dict."
  43. (and (listp object)
  44. (eq (car object) 'dict)))
  45. (defun nrepl-dict-empty-p (dict)
  46. "Return t if nREPL dict DICT is empty."
  47. (null (cdr dict)))
  48. (defun nrepl-dict-contains (dict key)
  49. "Return nil if nREPL dict DICT doesn't contain KEY.
  50. If DICT does contain KEY, then a non-nil value is returned. Due to the
  51. current implementation, this return value is the tail of DICT's key-list
  52. whose car is KEY. Comparison is done with `equal'."
  53. (member key (nrepl-dict-keys dict)))
  54. (defun nrepl-dict-get (dict key &optional default)
  55. "Get from DICT value associated with KEY, optional DEFAULT if KEY not in DICT.
  56. If dict is nil, return nil. If DEFAULT not provided, and KEY not in DICT,
  57. return nil. If DICT is not an nREPL dict object, an error is thrown."
  58. (when dict
  59. (if (nrepl-dict-p dict)
  60. (if (nrepl-dict-contains dict key)
  61. (lax-plist-get (cdr dict) key)
  62. default)
  63. (error "Not an nREPL dict object: %s" dict))))
  64. (defun nrepl-dict-put (dict key value)
  65. "Associate in DICT, KEY to VALUE.
  66. Return new dict. Dict is modified by side effects."
  67. (if (null dict)
  68. `(dict ,key ,value)
  69. (if (not (nrepl-dict-p dict))
  70. (error "Not an nREPL dict object: %s" dict)
  71. (setcdr dict (lax-plist-put (cdr dict) key value))
  72. dict)))
  73. (defun nrepl-dict-keys (dict)
  74. "Return all the keys in the nREPL DICT."
  75. (if (nrepl-dict-p dict)
  76. (cl-loop for l on (cdr dict) by #'cddr
  77. collect (car l))
  78. (error "Not an nREPL dict")))
  79. (defun nrepl-dict-vals (dict)
  80. "Return all the values in the nREPL DICT."
  81. (if (nrepl-dict-p dict)
  82. (cl-loop for l on (cdr dict) by #'cddr
  83. collect (cadr l))
  84. (error "Not an nREPL dict")))
  85. (defun nrepl-dict-map (fn dict)
  86. "Map FN on nREPL DICT.
  87. FN must accept two arguments key and value."
  88. (if (nrepl-dict-p dict)
  89. (cl-loop for l on (cdr dict) by #'cddr
  90. collect (funcall fn (car l) (cadr l)))
  91. (error "Not an nREPL dict")))
  92. (defun nrepl-dict-merge (dict1 dict2)
  93. "Destructively merge DICT2 into DICT1.
  94. Keys in DICT2 override those in DICT1."
  95. (let ((base (or dict1 '(dict))))
  96. (nrepl-dict-map (lambda (k v)
  97. (nrepl-dict-put base k v))
  98. (or dict2 '(dict)))
  99. base))
  100. (defun nrepl-dict-get-in (dict keys)
  101. "Return the value in a nested DICT.
  102. KEYS is a list of keys. Return nil if any of the keys is not present or if
  103. any of the values is nil."
  104. (let ((out dict))
  105. (while (and keys out)
  106. (setq out (nrepl-dict-get out (pop keys))))
  107. out))
  108. (defun nrepl-dict-flat-map (function dict)
  109. "Map FUNCTION over DICT and flatten the result.
  110. FUNCTION follows the same restrictions as in `nrepl-dict-map', and it must
  111. also alway return a sequence (since the result will be flattened)."
  112. (when dict
  113. (apply #'append (nrepl-dict-map function dict))))
  114. ;;; More specific functions
  115. (defun nrepl--cons (car list-or-dict)
  116. "Generic cons of CAR to LIST-OR-DICT."
  117. (if (eq (car list-or-dict) 'dict)
  118. (cons 'dict (cons car (cdr list-or-dict)))
  119. (cons car list-or-dict)))
  120. (defun nrepl--nreverse (list-or-dict)
  121. "Generic `nreverse' which works on LIST-OR-DICT."
  122. (if (eq (car list-or-dict) 'dict)
  123. (cons 'dict (nreverse (cdr list-or-dict)))
  124. (nreverse list-or-dict)))
  125. (defun nrepl--push (obj stack)
  126. "Cons OBJ to the top element of the STACK."
  127. ;; stack is assumed to be a list
  128. (if (eq (caar stack) 'dict)
  129. (cons (cons 'dict (cons obj (cdar stack)))
  130. (cdr stack))
  131. (cons (if (null stack)
  132. obj
  133. (cons obj (car stack)))
  134. (cdr stack))))
  135. (defun nrepl--merge (dict1 dict2 &optional no-join)
  136. "Join nREPL dicts DICT1 and DICT2 in a meaningful way.
  137. String values for non \"id\" and \"session\" keys are concatenated. Lists
  138. are appended. nREPL dicts merged recursively. All other objects are
  139. accumulated into a list. DICT1 is modified destructively and
  140. then returned.
  141. If NO-JOIN is given, return the first non nil dict."
  142. (if no-join
  143. (or dict1 dict2)
  144. (cond ((null dict1) dict2)
  145. ((null dict2) dict1)
  146. ((stringp dict1) (concat dict1 dict2))
  147. ((nrepl-dict-p dict1)
  148. (nrepl-dict-map
  149. (lambda (k2 v2)
  150. (nrepl-dict-put dict1 k2
  151. (nrepl--merge (nrepl-dict-get dict1 k2) v2
  152. (member k2 '("id" "session")))))
  153. dict2)
  154. dict1)
  155. ((and (listp dict2) (listp dict1)) (append dict1 dict2))
  156. ((listp dict1) (append dict1 (list dict2)))
  157. (t `(,dict1 ,dict2)))))
  158. ;;; Dbind
  159. (defmacro nrepl-dbind-response (response keys &rest body)
  160. "Destructure an nREPL RESPONSE dict.
  161. Bind the value of the provided KEYS and execute BODY."
  162. (declare (debug (form (&rest symbolp) body)))
  163. `(let ,(cl-loop for key in keys
  164. collect `(,key (nrepl-dict-get ,response ,(format "%s" key))))
  165. ,@body))
  166. (put 'nrepl-dbind-response 'lisp-indent-function 2)
  167. (provide 'nrepl-dict)
  168. ;;; nrepl-dict.el ends here