|
|
- (require 'slime)
- (require 'eldoc)
- (require 'cl-lib)
- (require 'slime-parse)
-
- (define-slime-contrib slime-autodoc
- "Show fancy arglist in echo area."
- (:license "GPL")
- (:authors "Luke Gorrie <luke@bluetail.com>"
- "Lawrence Mitchell <wence@gmx.li>"
- "Matthias Koeppe <mkoeppe@mail.math.uni-magdeburg.de>"
- "Tobias C. Rittweiler <tcr@freebits.de>")
- (:slime-dependencies slime-parse)
- (:swank-dependencies swank-arglists)
- (:on-load (slime-autodoc--enable))
- (:on-unload (slime-autodoc--disable)))
-
- (defcustom slime-autodoc-accuracy-depth 10
- "Number of paren levels that autodoc takes into account for
- context-sensitive arglist display (local functions. etc)"
- :type 'integer
- :group 'slime-ui)
-
- ;;;###autoload
- (defcustom slime-autodoc-mode-string (purecopy " adoc")
- "String to display in mode line when Autodoc Mode is enabled; nil for none."
- :type '(choice string (const :tag "None" nil))
- :group 'slime-ui)
-
-
- (defun slime-arglist (name)
- "Show the argument list for NAME."
- (interactive (list (slime-read-symbol-name "Arglist of: " t)))
- (let ((arglist (slime-retrieve-arglist name)))
- (if (eq arglist :not-available)
- (error "Arglist not available")
- (message "%s" (slime-autodoc--fontify arglist)))))
-
- ;; used also in slime-c-p-c.el.
- (defun slime-retrieve-arglist (name)
- (let ((name (cl-etypecase name
- (string name)
- (symbol (symbol-name name)))))
- (car (slime-eval `(swank:autodoc '(,name ,slime-cursor-marker))))))
-
- (defun slime-autodoc-manually ()
- "Like autodoc informtion forcing multiline display."
- (interactive)
- (let ((doc (slime-autodoc t)))
- (cond (doc (eldoc-message doc))
- (t (eldoc-message nil)))))
-
- ;; Must call eldoc-add-command otherwise (eldoc-display-message-p)
- ;; returns nil and eldoc clears the echo area instead.
- (eldoc-add-command 'slime-autodoc-manually)
-
- (defun slime-autodoc-space (n)
- "Like `slime-space' but nicer."
- (interactive "p")
- (self-insert-command n)
- (let ((doc (slime-autodoc)))
- (when doc
- (eldoc-message doc))))
-
- (eldoc-add-command 'slime-autodoc-space)
-
- ;;;; Autodoc cache
-
- (defvar slime-autodoc--cache-last-context nil)
- (defvar slime-autodoc--cache-last-autodoc nil)
-
- (defun slime-autodoc--cache-get (context)
- "Return the cached autodoc documentation for `context', or nil."
- (and (equal context slime-autodoc--cache-last-context)
- slime-autodoc--cache-last-autodoc))
-
- (defun slime-autodoc--cache-put (context autodoc)
- "Update the autodoc cache for CONTEXT with AUTODOC."
- (setq slime-autodoc--cache-last-context context)
- (setq slime-autodoc--cache-last-autodoc autodoc))
-
- ;;;; Formatting autodoc
-
- (defsubst slime-autodoc--canonicalize-whitespace (string)
- (replace-regexp-in-string "[ \n\t]+" " " string))
-
- (defun slime-autodoc--format (doc multilinep)
- (let ((doc (slime-autodoc--fontify doc)))
- (cond (multilinep doc)
- (t (slime-oneliner (slime-autodoc--canonicalize-whitespace doc))))))
-
- (defun slime-autodoc--fontify (string)
- "Fontify STRING as `font-lock-mode' does in Lisp mode."
- (with-current-buffer (get-buffer-create (slime-buffer-name :fontify 'hidden))
- (erase-buffer)
- (unless (eq major-mode 'lisp-mode)
- ;; Just calling (lisp-mode) will turn slime-mode on in that buffer,
- ;; which may interfere with this function
- (setq major-mode 'lisp-mode)
- (lisp-mode-variables t))
- (insert string)
- (let ((font-lock-verbose nil))
- (font-lock-fontify-buffer))
- (goto-char (point-min))
- (when (re-search-forward "===> \\(\\(.\\|\n\\)*\\) <===" nil t)
- (let ((highlight (match-string 1)))
- ;; Can't use (replace-match highlight) here -- broken in Emacs 21
- (delete-region (match-beginning 0) (match-end 0))
- (slime-insert-propertized '(face eldoc-highlight-function-argument) highlight)))
- (buffer-substring (point-min) (point-max))))
-
- (define-obsolete-function-alias 'slime-fontify-string
- 'slime-autodoc--fontify
- "SLIME 2.10")
-
- ;;;; Autodocs (automatic context-sensitive help)
-
- (defun slime-autodoc (&optional force-multiline)
- "Returns the cached arglist information as string, or nil.
- If it's not in the cache, the cache will be updated asynchronously."
- (save-excursion
- (save-match-data
- (let ((context (slime-autodoc--parse-context)))
- (when context
- (let* ((cached (slime-autodoc--cache-get context))
- (multilinep (or force-multiline
- eldoc-echo-area-use-multiline-p)))
- (cond (cached (slime-autodoc--format cached multilinep))
- (t
- (when (slime-background-activities-enabled-p)
- (slime-autodoc--async context multilinep))
- nil))))))))
-
- ;; Return the context around point that can be passed to
- ;; swank:autodoc. nil is returned if nothing reasonable could be
- ;; found.
- (defun slime-autodoc--parse-context ()
- (and (slime-autodoc--parsing-safe-p)
- (let ((levels slime-autodoc-accuracy-depth))
- (slime-parse-form-upto-point levels))))
-
- (defun slime-autodoc--parsing-safe-p ()
- (cond ((fboundp 'slime-repl-inside-string-or-comment-p)
- (not (slime-repl-inside-string-or-comment-p)))
- (t
- (not (slime-inside-string-or-comment-p)))))
-
- (defun slime-autodoc--async (context multilinep)
- (slime-eval-async
- `(swank:autodoc ',context ;; FIXME: misuse of quote
- :print-right-margin ,(window-width (minibuffer-window)))
- (slime-curry #'slime-autodoc--async% context multilinep)))
-
- (defun slime-autodoc--async% (context multilinep doc)
- (cl-destructuring-bind (doc &optional cache-p) doc
- (unless (eq doc :not-available)
- (when cache-p
- (slime-autodoc--cache-put context doc))
- ;; Now that we've got our information,
- ;; get it to the user ASAP.
- (when (eldoc-display-message-p)
- (eldoc-message (slime-autodoc--format doc multilinep))))))
-
- ;;; Minor mode definition
-
- ;; Compute the prefix for slime-doc-map, usually this is C-c C-d.
- (defun slime-autodoc--doc-map-prefix ()
- (concat
- (car (rassoc '(slime-prefix-map) slime-parent-bindings))
- (car (rassoc '(slime-doc-map) slime-prefix-bindings))))
-
- (define-minor-mode slime-autodoc-mode
- "Toggle echo area display of Lisp objects at point."
- :lighter slime-autodoc-mode-string
- :keymap (let ((prefix (slime-autodoc--doc-map-prefix)))
- `((,(concat prefix "A") . slime-autodoc-manually)
- (,(concat prefix (kbd "C-A")) . slime-autodoc-manually)
- (,(kbd "SPC") . slime-autodoc-space)))
- (set (make-local-variable 'eldoc-documentation-function) 'slime-autodoc)
- (set (make-local-variable 'eldoc-minor-mode-string) nil)
- (setq slime-autodoc-mode (eldoc-mode arg))
- (when (called-interactively-p 'interactive)
- (message "Slime autodoc mode %s."
- (if slime-autodoc-mode "enabled" "disabled"))))
-
- ;;; Noise to enable/disable slime-autodoc-mode
-
- (defun slime-autodoc--on () (slime-autodoc-mode 1))
- (defun slime-autodoc--off () (slime-autodoc-mode 0))
-
- (defvar slime-autodoc--relevant-hooks
- '(slime-mode-hook slime-repl-mode-hook sldb-mode-hook))
-
- (defun slime-autodoc--enable ()
- (dolist (h slime-autodoc--relevant-hooks)
- (add-hook h 'slime-autodoc--on))
- (dolist (b (buffer-list))
- (with-current-buffer b
- (when slime-mode
- (slime-autodoc--on)))))
-
- (defun slime-autodoc--disable ()
- (dolist (h slime-autodoc--relevant-hooks)
- (remove-hook h 'slime-autodoc--on))
- (dolist (b (buffer-list))
- (with-current-buffer b
- (when slime-autodoc-mode
- (slime-autodoc--off)))))
-
- (provide 'slime-autodoc)
|