(require 'slime)
|
|
(require 'advice)
|
|
(require 'slime-compiler-notes-tree) ; FIXME: actually only uses the tree bits, so that should be a library.
|
|
|
|
(define-slime-contrib slime-references
|
|
"Clickable references to documentation (SBCL only)."
|
|
(:authors "Christophe Rhodes <csr21@cantab.net>"
|
|
"Luke Gorrie <luke@bluetail.com>"
|
|
"Tobias C. Rittweiler <tcr@freebits.de>")
|
|
(:license "GPL")
|
|
(:on-load
|
|
(ad-enable-advice 'slime-note.message 'after 'slime-note.message+references)
|
|
(ad-activate 'slime-note.message)
|
|
(setq slime-tree-printer 'slime-tree-print-with-references)
|
|
(add-hook 'sldb-extras-hooks 'sldb-maybe-insert-references))
|
|
(:on-unload
|
|
(ad-disable-advice 'slime-note.message 'after 'slime-note.message+references)
|
|
(ad-deactivate 'slime-note.message)
|
|
(setq slime-tree-printer 'slime-tree-default-printer)
|
|
(remove-hook 'sldb-extras-hooks 'sldb-maybe-insert-references)))
|
|
|
|
(defcustom slime-sbcl-manual-root "http://www.sbcl.org/manual/"
|
|
"*The base URL of the SBCL manual, for documentation lookup."
|
|
:type '(choice (string :tag "HTML Documentation")
|
|
(const :tag "Info Documentation" :info))
|
|
:group 'slime-mode)
|
|
|
|
(defface sldb-reference-face
|
|
(list (list t '(:underline t)))
|
|
"Face for references."
|
|
:group 'slime-debugger)
|
|
|
|
|
|
;;;;; SBCL-style references
|
|
|
|
(defvar slime-references-local-keymap
|
|
(let ((map (make-sparse-keymap "local keymap for slime references")))
|
|
(define-key map [mouse-2] 'slime-lookup-reference-at-mouse)
|
|
(define-key map [return] 'slime-lookup-reference-at-point)
|
|
map))
|
|
|
|
(defun slime-reference-properties (reference)
|
|
"Return the properties for a reference.
|
|
Only add clickability to properties we actually know how to lookup."
|
|
(cl-destructuring-bind (where type what) reference
|
|
(if (or (and (eq where :sbcl) (eq type :node))
|
|
(and (eq where :ansi-cl)
|
|
(memq type '(:function :special-operator :macro
|
|
:type :system-class
|
|
:section :glossary :issue))))
|
|
`(slime-reference ,reference
|
|
font-lock-face sldb-reference-face
|
|
follow-link t
|
|
mouse-face highlight
|
|
help-echo "mouse-2: visit documentation."
|
|
keymap ,slime-references-local-keymap))))
|
|
|
|
(defun slime-insert-reference (reference)
|
|
"Insert documentation reference from a condition.
|
|
See SWANK-BACKEND:CONDITION-REFERENCES for the datatype."
|
|
(cl-destructuring-bind (where type what) reference
|
|
(insert "\n" (slime-format-reference-source where) ", ")
|
|
(slime-insert-propertized (slime-reference-properties reference)
|
|
(slime-format-reference-node what))
|
|
(insert (format " [%s]" type))))
|
|
|
|
(defun slime-insert-references (references)
|
|
(when references
|
|
(insert "\nSee also:")
|
|
(slime-with-rigid-indentation 2
|
|
(mapc #'slime-insert-reference references))))
|
|
|
|
(defun slime-format-reference-source (where)
|
|
(cl-case where
|
|
(:amop "The Art of the Metaobject Protocol")
|
|
(:ansi-cl "Common Lisp Hyperspec")
|
|
(:sbcl "SBCL Manual")
|
|
(t (format "%S" where))))
|
|
|
|
(defun slime-format-reference-node (what)
|
|
(if (listp what)
|
|
(mapconcat #'prin1-to-string what ".")
|
|
what))
|
|
|
|
(defun slime-lookup-reference-at-point ()
|
|
"Browse the documentation reference at point."
|
|
(interactive)
|
|
(let ((refs (get-text-property (point) 'slime-reference)))
|
|
(if (null refs)
|
|
(error "No references at point")
|
|
(cl-destructuring-bind (where type what) refs
|
|
(cl-case where
|
|
(:ansi-cl
|
|
(cl-case type
|
|
(:section
|
|
(browse-url (funcall common-lisp-hyperspec-section-fun what)))
|
|
(:glossary
|
|
(browse-url (funcall common-lisp-hyperspec-glossary-function what)))
|
|
(:issue
|
|
(browse-url (common-lisp-issuex what)))
|
|
(:special-operator
|
|
(browse-url (common-lisp-special-operator (downcase name))))
|
|
(t
|
|
(hyperspec-lookup what))))
|
|
(t
|
|
(case slime-sbcl-manual-root
|
|
(:info
|
|
(info (format "(sbcl)%s" what)))
|
|
(t
|
|
(browse-url
|
|
(format "%s#%s" slime-sbcl-manual-root
|
|
(subst-char-in-string ?\ ?\- what)))))))))))
|
|
|
|
(defun slime-lookup-reference-at-mouse (event)
|
|
"Invoke the action pointed at by the mouse."
|
|
(interactive "e")
|
|
(cl-destructuring-bind (mouse-1 (w pos . _) . _) event
|
|
(save-excursion
|
|
(goto-char pos)
|
|
(slime-lookup-reference-at-point))))
|
|
|
|
;;;;; Hook into *SLIME COMPILATION*
|
|
|
|
(defun slime-note.references (note)
|
|
(plist-get note :references))
|
|
|
|
;;; FIXME: `compilation-mode' will swallow the `mouse-face'
|
|
;;; etc. properties.
|
|
(defadvice slime-note.message (after slime-note.message+references)
|
|
(setq ad-return-value
|
|
(concat ad-return-value
|
|
(with-temp-buffer
|
|
(slime-insert-references
|
|
(slime-note.references (ad-get-arg 0)))
|
|
(buffer-string)))))
|
|
|
|
;;;;; Hook into slime-compiler-notes-tree
|
|
|
|
(defun slime-tree-print-with-references (tree)
|
|
;; for SBCL-style references
|
|
(slime-tree-default-printer tree)
|
|
(let ((note (plist-get (slime-tree.plist tree) 'note)))
|
|
(when note
|
|
(let ((references (slime-note.references note)))
|
|
(when references
|
|
(terpri (current-buffer))
|
|
(slime-insert-references references))))))
|
|
|
|
;;;;; Hook into SLDB
|
|
|
|
(defun sldb-maybe-insert-references (extra)
|
|
(slime-dcase extra
|
|
((:references references) (slime-insert-references references) t)
|
|
(t nil)))
|
|
|
|
(provide 'slime-references)
|