|
|
- (require 'slime)
- (require 'cl-lib)
- (require 'grep)
-
- (define-slime-contrib slime-asdf
- "ASDF support."
- (:authors "Daniel Barlow <dan@telent.net>"
- "Marco Baringer <mb@bese.it>"
- "Edi Weitz <edi@agharta.de>"
- "Stas Boukarev <stassats@gmail.com>"
- "Tobias C Rittweiler <tcr@freebits.de>")
- (:license "GPL")
- (:slime-dependencies slime-repl)
- (:swank-dependencies swank-asdf)
- (:on-load
- (add-to-list 'slime-edit-uses-xrefs :depends-on t)
- (define-key slime-who-map [?d] 'slime-who-depends-on)))
-
- ;;; NOTE: `system-name' is a predefined variable in Emacs. Try to
- ;;; avoid it as local variable name.
-
- ;;; Utilities
-
- (defgroup slime-asdf nil
- "ASDF support for Slime."
- :prefix "slime-asdf-"
- :group 'slime)
-
- (defvar slime-system-history nil
- "History list for ASDF system names.")
-
- (defun slime-read-system-name (&optional prompt
- default-value
- determine-default-accurately)
- "Read a system name from the minibuffer, prompting with PROMPT.
- If no `default-value' is given, one is tried to be determined: if
- `determine-default-accurately' is true, by an RPC request which
- grovels through all defined systems; if it's not true, by looking
- in the directory of the current buffer."
- (let* ((completion-ignore-case nil)
- (prompt (or prompt "System"))
- (system-names (slime-eval `(swank:list-asdf-systems)))
- (default-value
- (or default-value
- (if determine-default-accurately
- (slime-determine-asdf-system (buffer-file-name)
- (slime-current-package))
- (slime-find-asd-file (or default-directory
- (buffer-file-name))
- system-names))))
- (prompt (concat prompt (if default-value
- (format " (default `%s'): " default-value)
- ": "))))
- (completing-read prompt (slime-bogus-completion-alist system-names)
- nil nil nil
- 'slime-system-history default-value)))
-
-
-
- (defun slime-find-asd-file (directory system-names)
- "Tries to find an ASDF system definition file in the
- `directory' and returns it if it's in `system-names'."
- (let ((asd-files
- (directory-files (file-name-directory directory) nil "\.asd$")))
- (cl-loop for system in asd-files
- for candidate = (file-name-sans-extension system)
- when (cl-find candidate system-names :test #'string-equal)
- do (cl-return candidate))))
-
- (defun slime-determine-asdf-system (filename buffer-package)
- "Try to determine the asdf system that `filename' belongs to."
- (slime-eval
- `(swank:asdf-determine-system ,(and filename
- (slime-to-lisp-filename filename))
- ,buffer-package)))
-
- (defun slime-who-depends-on-rpc (system)
- (slime-eval `(swank:who-depends-on ,system)))
-
- (defcustom slime-asdf-collect-notes t
- "Collect and display notes produced by the compiler.
-
- See also `slime-highlight-compiler-notes' and
- `slime-compilation-finished-hook'."
- :group 'slime-asdf)
-
- (defun slime-asdf-operation-finished-function (system)
- (if slime-asdf-collect-notes
- #'slime-compilation-finished
- (slime-curry (lambda (system result)
- (let (slime-highlight-compiler-notes
- slime-compilation-finished-hook)
- (slime-compilation-finished result)))
- system)))
-
- (defun slime-oos (system operation &rest keyword-args)
- "Operate On System."
- (slime-save-some-lisp-buffers)
- (slime-display-output-buffer)
- (message "Performing ASDF %S%s on system %S"
- operation (if keyword-args (format " %S" keyword-args) "")
- system)
- (slime-repl-shortcut-eval-async
- `(swank:operate-on-system-for-emacs ,system ',operation ,@keyword-args)
- (slime-asdf-operation-finished-function system)))
-
- ;;; Interactive functions
-
- (defun slime-load-system (&optional system)
- "Compile and load an ASDF system.
-
- Default system name is taken from first file matching *.asd in current
- buffer's working directory"
- (interactive (list (slime-read-system-name)))
- (slime-oos system 'load-op))
-
- (defun slime-open-system (name &optional load interactive)
- "Open all files in an ASDF system."
- (interactive (list (slime-read-system-name) nil t))
- (when (or load
- (and interactive
- (not (slime-eval `(swank:asdf-system-loaded-p ,name)))
- (y-or-n-p "Load it? ")))
- (slime-load-system name))
- (slime-eval-async
- `(swank:asdf-system-files ,name)
- (lambda (files)
- (when files
- (let ((files (mapcar 'slime-from-lisp-filename
- (nreverse files))))
- (find-file-other-window (car files))
- (mapc 'find-file (cdr files)))))))
-
- (defun slime-browse-system (name)
- "Browse files in an ASDF system using Dired."
- (interactive (list (slime-read-system-name)))
- (slime-eval-async `(swank:asdf-system-directory ,name)
- (lambda (directory)
- (when directory
- (dired (slime-from-lisp-filename directory))))))
-
- (if (fboundp 'rgrep)
- (defun slime-rgrep-system (sys-name regexp)
- "Run `rgrep' on the base directory of an ASDF system."
- (interactive (progn (grep-compute-defaults)
- (list (slime-read-system-name nil nil t)
- (grep-read-regexp))))
- (rgrep regexp "*.lisp"
- (slime-from-lisp-filename
- (slime-eval `(swank:asdf-system-directory ,sys-name)))))
- (defun slime-rgrep-system ()
- (interactive)
- (error "This command is only supported on GNU Emacs >21.x.")))
-
- (if (boundp 'multi-isearch-next-buffer-function)
- (defun slime-isearch-system (sys-name)
- "Run `isearch-forward' on the files of an ASDF system."
- (interactive (list (slime-read-system-name nil nil t)))
- (let* ((files (mapcar 'slime-from-lisp-filename
- (slime-eval `(swank:asdf-system-files ,sys-name))))
- (multi-isearch-next-buffer-function
- (lexical-let*
- ((buffers-forward (mapcar #'find-file-noselect files))
- (buffers-backward (reverse buffers-forward)))
- #'(lambda (current-buffer wrap)
- ;; Contrarily to the docstring of
- ;; `multi-isearch-next-buffer-function', the first
- ;; arg is not necessarily a buffer. Report sent
- ;; upstream. (2009-11-17)
- (setq current-buffer (or current-buffer (current-buffer)))
- (let* ((buffers (if isearch-forward
- buffers-forward
- buffers-backward)))
- (if wrap
- (car buffers)
- (second (memq current-buffer buffers))))))))
- (isearch-forward)))
- (defun slime-isearch-system ()
- (interactive)
- (error "This command is only supported on GNU Emacs >23.1.x.")))
-
- (defun slime-read-query-replace-args (format-string &rest format-args)
- (let* ((minibuffer-setup-hook (slime-minibuffer-setup-hook))
- (minibuffer-local-map slime-minibuffer-map)
- (common (query-replace-read-args (apply #'format format-string
- format-args)
- t t)))
- (list (nth 0 common) (nth 1 common) (nth 2 common))))
-
- (defun slime-query-replace-system (name from to &optional delimited)
- "Run `query-replace' on an ASDF system."
- (interactive (let ((system (slime-read-system-name nil nil t)))
- (cons system (slime-read-query-replace-args
- "Query replace throughout `%s'" system))))
- (condition-case c
- ;; `tags-query-replace' actually uses `query-replace-regexp'
- ;; internally.
- (tags-query-replace (regexp-quote from) to delimited
- '(mapcar 'slime-from-lisp-filename
- (slime-eval `(swank:asdf-system-files ,name))))
- (error
- ;; Kludge: `tags-query-replace' does not actually return but
- ;; signals an unnamed error with the below error
- ;; message. (<=23.1.2, at least.)
- (unless (string-equal (error-message-string c) "All files processed")
- (signal (car c) (cdr c))) ; resignal
- t)))
-
- (defun slime-query-replace-system-and-dependents
- (name from to &optional delimited)
- "Run `query-replace' on an ASDF system and all the systems
- depending on it."
- (interactive (let ((system (slime-read-system-name nil nil t)))
- (cons system (slime-read-query-replace-args
- "Query replace throughout `%s'+dependencies"
- system))))
- (slime-query-replace-system name from to delimited)
- (dolist (dep (slime-who-depends-on-rpc name))
- (when (y-or-n-p (format "Descend into system `%s'? " dep))
- (slime-query-replace-system dep from to delimited))))
-
- (defun slime-delete-system-fasls (name)
- "Delete FASLs produced by compiling a system."
- (interactive (list (slime-read-system-name)))
- (slime-repl-shortcut-eval-async
- `(swank:delete-system-fasls ,name)
- 'message))
-
- (defun slime-reload-system (system)
- "Reload an ASDF system without reloading its dependencies."
- (interactive (list (slime-read-system-name)))
- (slime-save-some-lisp-buffers)
- (slime-display-output-buffer)
- (message "Performing ASDF LOAD-OP on system %S" system)
- (slime-repl-shortcut-eval-async
- `(swank:reload-system ,system)
- (slime-asdf-operation-finished-function system)))
-
- (defun slime-who-depends-on (system-name)
- (interactive (list (slime-read-system-name)))
- (slime-xref :depends-on system-name))
-
- (defun slime-save-system (system)
- "Save files belonging to an ASDF system."
- (interactive (list (slime-read-system-name)))
- (slime-eval-async
- `(swank:asdf-system-files ,system)
- (lambda (files)
- (dolist (file files)
- (let ((buffer (get-file-buffer (slime-from-lisp-filename file))))
- (when buffer
- (with-current-buffer buffer
- (save-buffer buffer)))))
- (message "Done."))))
-
- ;;; REPL shortcuts
-
- (defslime-repl-shortcut slime-repl-load/force-system ("force-load-system")
- (:handler (lambda ()
- (interactive)
- (slime-oos (slime-read-system-name) 'load-op :force t)))
- (:one-liner "Recompile and load an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-load-system ("load-system")
- (:handler (lambda ()
- (interactive)
- (slime-oos (slime-read-system-name) 'load-op)))
- (:one-liner "Compile (as needed) and load an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-test/force-system ("force-test-system")
- (:handler (lambda ()
- (interactive)
- (slime-oos (slime-read-system-name) 'test-op :force t)))
- (:one-liner "Recompile and test an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-test-system ("test-system")
- (:handler (lambda ()
- (interactive)
- (slime-oos (slime-read-system-name) 'test-op)))
- (:one-liner "Compile (as needed) and test an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-compile-system ("compile-system")
- (:handler (lambda ()
- (interactive)
- (slime-oos (slime-read-system-name) 'compile-op)))
- (:one-liner "Compile (but not load) an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-compile/force-system
- ("force-compile-system")
- (:handler (lambda ()
- (interactive)
- (slime-oos (slime-read-system-name) 'compile-op :force t)))
- (:one-liner "Recompile (but not completely load) an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-open-system ("open-system")
- (:handler 'slime-open-system)
- (:one-liner "Open all files in an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-browse-system ("browse-system")
- (:handler 'slime-browse-system)
- (:one-liner "Browse files in an ASDF system using Dired."))
-
- (defslime-repl-shortcut slime-repl-delete-system-fasls ("delete-system-fasls")
- (:handler 'slime-delete-system-fasls)
- (:one-liner "Delete FASLs of an ASDF system."))
-
- (defslime-repl-shortcut slime-repl-reload-system ("reload-system")
- (:handler 'slime-reload-system)
- (:one-liner "Recompile and load an ASDF system."))
-
- (provide 'slime-asdf)
|