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.

313 lines
12 KiB

5 years ago
  1. (require 'slime)
  2. (require 'cl-lib)
  3. (require 'grep)
  4. (define-slime-contrib slime-asdf
  5. "ASDF support."
  6. (:authors "Daniel Barlow <dan@telent.net>"
  7. "Marco Baringer <mb@bese.it>"
  8. "Edi Weitz <edi@agharta.de>"
  9. "Stas Boukarev <stassats@gmail.com>"
  10. "Tobias C Rittweiler <tcr@freebits.de>")
  11. (:license "GPL")
  12. (:slime-dependencies slime-repl)
  13. (:swank-dependencies swank-asdf)
  14. (:on-load
  15. (add-to-list 'slime-edit-uses-xrefs :depends-on t)
  16. (define-key slime-who-map [?d] 'slime-who-depends-on)))
  17. ;;; NOTE: `system-name' is a predefined variable in Emacs. Try to
  18. ;;; avoid it as local variable name.
  19. ;;; Utilities
  20. (defgroup slime-asdf nil
  21. "ASDF support for Slime."
  22. :prefix "slime-asdf-"
  23. :group 'slime)
  24. (defvar slime-system-history nil
  25. "History list for ASDF system names.")
  26. (defun slime-read-system-name (&optional prompt
  27. default-value
  28. determine-default-accurately)
  29. "Read a system name from the minibuffer, prompting with PROMPT.
  30. If no `default-value' is given, one is tried to be determined: if
  31. `determine-default-accurately' is true, by an RPC request which
  32. grovels through all defined systems; if it's not true, by looking
  33. in the directory of the current buffer."
  34. (let* ((completion-ignore-case nil)
  35. (prompt (or prompt "System"))
  36. (system-names (slime-eval `(swank:list-asdf-systems)))
  37. (default-value
  38. (or default-value
  39. (if determine-default-accurately
  40. (slime-determine-asdf-system (buffer-file-name)
  41. (slime-current-package))
  42. (slime-find-asd-file (or default-directory
  43. (buffer-file-name))
  44. system-names))))
  45. (prompt (concat prompt (if default-value
  46. (format " (default `%s'): " default-value)
  47. ": "))))
  48. (completing-read prompt (slime-bogus-completion-alist system-names)
  49. nil nil nil
  50. 'slime-system-history default-value)))
  51. (defun slime-find-asd-file (directory system-names)
  52. "Tries to find an ASDF system definition file in the
  53. `directory' and returns it if it's in `system-names'."
  54. (let ((asd-files
  55. (directory-files (file-name-directory directory) nil "\.asd$")))
  56. (cl-loop for system in asd-files
  57. for candidate = (file-name-sans-extension system)
  58. when (cl-find candidate system-names :test #'string-equal)
  59. do (cl-return candidate))))
  60. (defun slime-determine-asdf-system (filename buffer-package)
  61. "Try to determine the asdf system that `filename' belongs to."
  62. (slime-eval
  63. `(swank:asdf-determine-system ,(and filename
  64. (slime-to-lisp-filename filename))
  65. ,buffer-package)))
  66. (defun slime-who-depends-on-rpc (system)
  67. (slime-eval `(swank:who-depends-on ,system)))
  68. (defcustom slime-asdf-collect-notes t
  69. "Collect and display notes produced by the compiler.
  70. See also `slime-highlight-compiler-notes' and
  71. `slime-compilation-finished-hook'."
  72. :group 'slime-asdf)
  73. (defun slime-asdf-operation-finished-function (system)
  74. (if slime-asdf-collect-notes
  75. #'slime-compilation-finished
  76. (slime-curry (lambda (system result)
  77. (let (slime-highlight-compiler-notes
  78. slime-compilation-finished-hook)
  79. (slime-compilation-finished result)))
  80. system)))
  81. (defun slime-oos (system operation &rest keyword-args)
  82. "Operate On System."
  83. (slime-save-some-lisp-buffers)
  84. (slime-display-output-buffer)
  85. (message "Performing ASDF %S%s on system %S"
  86. operation (if keyword-args (format " %S" keyword-args) "")
  87. system)
  88. (slime-repl-shortcut-eval-async
  89. `(swank:operate-on-system-for-emacs ,system ',operation ,@keyword-args)
  90. (slime-asdf-operation-finished-function system)))
  91. ;;; Interactive functions
  92. (defun slime-load-system (&optional system)
  93. "Compile and load an ASDF system.
  94. Default system name is taken from first file matching *.asd in current
  95. buffer's working directory"
  96. (interactive (list (slime-read-system-name)))
  97. (slime-oos system 'load-op))
  98. (defun slime-open-system (name &optional load interactive)
  99. "Open all files in an ASDF system."
  100. (interactive (list (slime-read-system-name) nil t))
  101. (when (or load
  102. (and interactive
  103. (not (slime-eval `(swank:asdf-system-loaded-p ,name)))
  104. (y-or-n-p "Load it? ")))
  105. (slime-load-system name))
  106. (slime-eval-async
  107. `(swank:asdf-system-files ,name)
  108. (lambda (files)
  109. (when files
  110. (let ((files (mapcar 'slime-from-lisp-filename
  111. (nreverse files))))
  112. (find-file-other-window (car files))
  113. (mapc 'find-file (cdr files)))))))
  114. (defun slime-browse-system (name)
  115. "Browse files in an ASDF system using Dired."
  116. (interactive (list (slime-read-system-name)))
  117. (slime-eval-async `(swank:asdf-system-directory ,name)
  118. (lambda (directory)
  119. (when directory
  120. (dired (slime-from-lisp-filename directory))))))
  121. (if (fboundp 'rgrep)
  122. (defun slime-rgrep-system (sys-name regexp)
  123. "Run `rgrep' on the base directory of an ASDF system."
  124. (interactive (progn (grep-compute-defaults)
  125. (list (slime-read-system-name nil nil t)
  126. (grep-read-regexp))))
  127. (rgrep regexp "*.lisp"
  128. (slime-from-lisp-filename
  129. (slime-eval `(swank:asdf-system-directory ,sys-name)))))
  130. (defun slime-rgrep-system ()
  131. (interactive)
  132. (error "This command is only supported on GNU Emacs >21.x.")))
  133. (if (boundp 'multi-isearch-next-buffer-function)
  134. (defun slime-isearch-system (sys-name)
  135. "Run `isearch-forward' on the files of an ASDF system."
  136. (interactive (list (slime-read-system-name nil nil t)))
  137. (let* ((files (mapcar 'slime-from-lisp-filename
  138. (slime-eval `(swank:asdf-system-files ,sys-name))))
  139. (multi-isearch-next-buffer-function
  140. (lexical-let*
  141. ((buffers-forward (mapcar #'find-file-noselect files))
  142. (buffers-backward (reverse buffers-forward)))
  143. #'(lambda (current-buffer wrap)
  144. ;; Contrarily to the docstring of
  145. ;; `multi-isearch-next-buffer-function', the first
  146. ;; arg is not necessarily a buffer. Report sent
  147. ;; upstream. (2009-11-17)
  148. (setq current-buffer (or current-buffer (current-buffer)))
  149. (let* ((buffers (if isearch-forward
  150. buffers-forward
  151. buffers-backward)))
  152. (if wrap
  153. (car buffers)
  154. (second (memq current-buffer buffers))))))))
  155. (isearch-forward)))
  156. (defun slime-isearch-system ()
  157. (interactive)
  158. (error "This command is only supported on GNU Emacs >23.1.x.")))
  159. (defun slime-read-query-replace-args (format-string &rest format-args)
  160. (let* ((minibuffer-setup-hook (slime-minibuffer-setup-hook))
  161. (minibuffer-local-map slime-minibuffer-map)
  162. (common (query-replace-read-args (apply #'format format-string
  163. format-args)
  164. t t)))
  165. (list (nth 0 common) (nth 1 common) (nth 2 common))))
  166. (defun slime-query-replace-system (name from to &optional delimited)
  167. "Run `query-replace' on an ASDF system."
  168. (interactive (let ((system (slime-read-system-name nil nil t)))
  169. (cons system (slime-read-query-replace-args
  170. "Query replace throughout `%s'" system))))
  171. (condition-case c
  172. ;; `tags-query-replace' actually uses `query-replace-regexp'
  173. ;; internally.
  174. (tags-query-replace (regexp-quote from) to delimited
  175. '(mapcar 'slime-from-lisp-filename
  176. (slime-eval `(swank:asdf-system-files ,name))))
  177. (error
  178. ;; Kludge: `tags-query-replace' does not actually return but
  179. ;; signals an unnamed error with the below error
  180. ;; message. (<=23.1.2, at least.)
  181. (unless (string-equal (error-message-string c) "All files processed")
  182. (signal (car c) (cdr c))) ; resignal
  183. t)))
  184. (defun slime-query-replace-system-and-dependents
  185. (name from to &optional delimited)
  186. "Run `query-replace' on an ASDF system and all the systems
  187. depending on it."
  188. (interactive (let ((system (slime-read-system-name nil nil t)))
  189. (cons system (slime-read-query-replace-args
  190. "Query replace throughout `%s'+dependencies"
  191. system))))
  192. (slime-query-replace-system name from to delimited)
  193. (dolist (dep (slime-who-depends-on-rpc name))
  194. (when (y-or-n-p (format "Descend into system `%s'? " dep))
  195. (slime-query-replace-system dep from to delimited))))
  196. (defun slime-delete-system-fasls (name)
  197. "Delete FASLs produced by compiling a system."
  198. (interactive (list (slime-read-system-name)))
  199. (slime-repl-shortcut-eval-async
  200. `(swank:delete-system-fasls ,name)
  201. 'message))
  202. (defun slime-reload-system (system)
  203. "Reload an ASDF system without reloading its dependencies."
  204. (interactive (list (slime-read-system-name)))
  205. (slime-save-some-lisp-buffers)
  206. (slime-display-output-buffer)
  207. (message "Performing ASDF LOAD-OP on system %S" system)
  208. (slime-repl-shortcut-eval-async
  209. `(swank:reload-system ,system)
  210. (slime-asdf-operation-finished-function system)))
  211. (defun slime-who-depends-on (system-name)
  212. (interactive (list (slime-read-system-name)))
  213. (slime-xref :depends-on system-name))
  214. (defun slime-save-system (system)
  215. "Save files belonging to an ASDF system."
  216. (interactive (list (slime-read-system-name)))
  217. (slime-eval-async
  218. `(swank:asdf-system-files ,system)
  219. (lambda (files)
  220. (dolist (file files)
  221. (let ((buffer (get-file-buffer (slime-from-lisp-filename file))))
  222. (when buffer
  223. (with-current-buffer buffer
  224. (save-buffer buffer)))))
  225. (message "Done."))))
  226. ;;; REPL shortcuts
  227. (defslime-repl-shortcut slime-repl-load/force-system ("force-load-system")
  228. (:handler (lambda ()
  229. (interactive)
  230. (slime-oos (slime-read-system-name) 'load-op :force t)))
  231. (:one-liner "Recompile and load an ASDF system."))
  232. (defslime-repl-shortcut slime-repl-load-system ("load-system")
  233. (:handler (lambda ()
  234. (interactive)
  235. (slime-oos (slime-read-system-name) 'load-op)))
  236. (:one-liner "Compile (as needed) and load an ASDF system."))
  237. (defslime-repl-shortcut slime-repl-test/force-system ("force-test-system")
  238. (:handler (lambda ()
  239. (interactive)
  240. (slime-oos (slime-read-system-name) 'test-op :force t)))
  241. (:one-liner "Recompile and test an ASDF system."))
  242. (defslime-repl-shortcut slime-repl-test-system ("test-system")
  243. (:handler (lambda ()
  244. (interactive)
  245. (slime-oos (slime-read-system-name) 'test-op)))
  246. (:one-liner "Compile (as needed) and test an ASDF system."))
  247. (defslime-repl-shortcut slime-repl-compile-system ("compile-system")
  248. (:handler (lambda ()
  249. (interactive)
  250. (slime-oos (slime-read-system-name) 'compile-op)))
  251. (:one-liner "Compile (but not load) an ASDF system."))
  252. (defslime-repl-shortcut slime-repl-compile/force-system
  253. ("force-compile-system")
  254. (:handler (lambda ()
  255. (interactive)
  256. (slime-oos (slime-read-system-name) 'compile-op :force t)))
  257. (:one-liner "Recompile (but not completely load) an ASDF system."))
  258. (defslime-repl-shortcut slime-repl-open-system ("open-system")
  259. (:handler 'slime-open-system)
  260. (:one-liner "Open all files in an ASDF system."))
  261. (defslime-repl-shortcut slime-repl-browse-system ("browse-system")
  262. (:handler 'slime-browse-system)
  263. (:one-liner "Browse files in an ASDF system using Dired."))
  264. (defslime-repl-shortcut slime-repl-delete-system-fasls ("delete-system-fasls")
  265. (:handler 'slime-delete-system-fasls)
  266. (:one-liner "Delete FASLs of an ASDF system."))
  267. (defslime-repl-shortcut slime-repl-reload-system ("reload-system")
  268. (:handler 'slime-reload-system)
  269. (:one-liner "Recompile and load an ASDF system."))
  270. (provide 'slime-asdf)