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