Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/slime/contrib/swank-asdf.lisp
990 views
1
;;; swank-asdf.el -- ASDF support
2
;;
3
;; Authors: Daniel Barlow <[email protected]>
4
;; Marco Baringer <[email protected]>
5
;; Edi Weitz <[email protected]>
6
;; and others
7
;; License: Public Domain
8
;;
9
10
(in-package :swank)
11
12
#-asdf
13
(eval-when (:compile-toplevel :load-toplevel :execute)
14
(require :asdf))
15
16
(defun find-operation (operation)
17
(or (find-symbol (symbol-name operation) :asdf)
18
(error "Couldn't find ASDF operation ~S" operation)))
19
20
(defun map-defined-systems (fn)
21
(loop for (nil . system) being the hash-values in asdf::*defined-systems*
22
do (funcall fn system)))
23
24
;;; This is probably a crude hack, see ASDF's LP #481187.
25
(defslimefun who-depends-on (system)
26
(flet ((system-dependencies (op system)
27
(mapcar #'(lambda (dep)
28
(asdf::coerce-name (if (consp dep) (second dep) dep)))
29
(cdr (assoc op (asdf:component-depends-on op system))))))
30
(let ((system-name (asdf::coerce-name system))
31
(result))
32
(map-defined-systems
33
#'(lambda (system)
34
(when (member system-name
35
(system-dependencies 'asdf:load-op system)
36
:test #'string=)
37
(push (asdf:component-name system) result))))
38
result)))
39
40
(defmethod xref-doit ((type (eql :depends-on)) thing)
41
(loop for dependency in (who-depends-on thing)
42
for asd-file = (asdf:system-definition-pathname dependency)
43
when asd-file
44
collect (list dependency
45
(swank-backend::make-location
46
`(:file ,(namestring asd-file))
47
`(:position 1)
48
`(:snippet ,(format nil "(defsystem :~A" dependency)
49
:align t)))))
50
51
52
(defslimefun operate-on-system-for-emacs (system-name operation &rest keywords)
53
"Compile and load SYSTEM using ASDF.
54
Record compiler notes signalled as `compiler-condition's."
55
(collect-notes
56
(lambda ()
57
(apply #'operate-on-system system-name operation keywords))))
58
59
(defun operate-on-system (system-name operation-name &rest keyword-args)
60
"Perform OPERATION-NAME on SYSTEM-NAME using ASDF.
61
The KEYWORD-ARGS are passed on to the operation.
62
Example:
63
\(operate-on-system \"swank\" 'compile-op :force t)"
64
(handler-case
65
(with-compilation-hooks ()
66
(apply #'asdf:operate (find-operation operation-name)
67
system-name keyword-args)
68
t)
69
(asdf:compile-error () nil)))
70
71
(defun asdf-central-registry ()
72
asdf:*central-registry*)
73
74
(defslimefun list-all-systems-in-central-registry ()
75
"Returns a list of all systems in ASDF's central registry."
76
(mapcar #'pathname-name
77
(delete-duplicates
78
(loop for dir in (asdf-central-registry)
79
for defaults = (eval dir)
80
when defaults
81
nconc (mapcar #'file-namestring
82
(directory
83
(make-pathname :defaults defaults
84
:version :newest
85
:type "asd"
86
:name :wild
87
:case :local))))
88
:test #'string=)))
89
90
(defslimefun list-all-systems-known-to-asdf ()
91
"Returns a list of all systems ASDF knows already."
92
(let ((result))
93
(map-defined-systems
94
#'(lambda (system) (push (asdf:component-name system) result)))
95
result))
96
97
(defslimefun list-asdf-systems ()
98
"Returns the systems in ASDF's central registry and those which ASDF
99
already knows."
100
(nunion (list-all-systems-known-to-asdf)
101
(list-all-systems-in-central-registry)
102
:test #'string=))
103
104
(defun asdf-module-files (module)
105
(mapcan (lambda (component)
106
(typecase component
107
(asdf:source-file
108
(list (asdf:component-pathname component)))
109
(asdf:module
110
(asdf-module-files component))))
111
(asdf:module-components module)))
112
113
(defun asdf-module-output-files (module)
114
(mapcan (lambda (component)
115
(typecase component
116
(asdf:source-file
117
(asdf:output-files (make-instance 'asdf:compile-op)
118
component))
119
(asdf:module
120
(asdf-module-output-files component))))
121
(asdf:module-components module)))
122
123
(defslimefun asdf-system-files (name)
124
(let* ((system (asdf:find-system name))
125
(files (mapcar #'namestring
126
(cons
127
(asdf:system-definition-pathname system)
128
(asdf-module-files system))))
129
(main-file (find name files
130
:test #'equalp :key #'pathname-name :start 1)))
131
(if main-file
132
(cons main-file (remove main-file files
133
:test #'equal :count 1))
134
files)))
135
136
(defslimefun asdf-system-loaded-p (name)
137
(and (gethash 'asdf:load-op
138
(asdf::component-operation-times (asdf:find-system name)))
139
t))
140
141
(defslimefun asdf-system-directory (name)
142
(cl:directory-namestring
143
(cl:truename
144
(asdf:system-definition-pathname (asdf:find-system name)))))
145
146
(defun system-contains-file-p (module pathname pathname-name)
147
(some #'(lambda (component)
148
(typecase component
149
(asdf:cl-source-file
150
;; We first compare the relative names because
151
;; retrieving the full pathname is somewhat costy; this
152
;; function is called a lot, and its performance
153
;; translates directly into response time to the user.
154
(and (equal pathname-name
155
(pathname-name
156
(asdf:component-relative-pathname component)))
157
(equal pathname (asdf:component-pathname component))))
158
(asdf:module
159
(system-contains-file-p component pathname pathname-name))))
160
(asdf:module-components module)))
161
162
(defslimefun asdf-determine-system (file buffer-package-name)
163
;; First try to grovel through all defined systems to find a system
164
;; which contains FILE.
165
(when file
166
(let* ((pathname (pathname file))
167
(pathname-name (pathname-name pathname)))
168
(map-defined-systems
169
#'(lambda (system)
170
(when (system-contains-file-p system pathname pathname-name)
171
(return-from asdf-determine-system
172
(asdf:component-name system)))))))
173
;; If we couldn't find a system by that, we now try if there's a
174
;; system that's named like BUFFER-PACKAGE-NAME.
175
(let ((package (guess-buffer-package buffer-package-name)))
176
(dolist (name (package-names package))
177
(let ((system (asdf:find-system (asdf::coerce-name name) nil)))
178
(when system
179
(return-from asdf-determine-system
180
(asdf:component-name system)))))))
181
182
(defslimefun delete-system-fasls (name)
183
(let ((removed-count
184
(loop for file in (asdf-module-output-files (asdf:find-system name))
185
when (probe-file file) count it
186
and do (delete-file file))))
187
(format nil "~d file~:p ~:*~[were~;was~:;were~] removed" removed-count)))
188
189
(defvar *recompile-system* nil)
190
191
#+#.(swank-backend:with-symbol 'around 'asdf)
192
(defmethod asdf:operation-done-p asdf:around ((operation asdf:compile-op)
193
component)
194
(unless (eql *recompile-system*
195
(asdf:component-system component))
196
(call-next-method)))
197
198
(defslimefun reload-system (name)
199
(let ((*recompile-system* (asdf:find-system name)))
200
(operate-on-system-for-emacs name 'asdf:load-op)))
201
202
;; Doing list-all-systems-in-central-registry might be quite slow
203
;; since it accesses a file-system, so run it once at the background
204
;; to initialize caches.
205
(eval-when (:load-toplevel :execute)
206
(when (eql *communication-style* :spawn)
207
(spawn (lambda ()
208
(ignore-errors (list-all-systems-in-central-registry)))
209
:name "init-asdf-fs-caches")))
210
211
(provide :swank-asdf)
212
213