Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Advice section #265

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
117 changes: 96 additions & 21 deletions helpful.el
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,40 @@ unescaping too."
'follow-link t
'help-echo "Follow this link")

(defun helpful--remove-advice (button)
"Remove advice for BUTTON."
(advice-remove (button-get button 'symbol)
(button-get button 'advice))
(helpful-update))

(define-button-type 'helpful-remove-advice-button
'action #'helpful--remove-advice
'help-echo "Remove advice")

(defun helpful--remove-all-advice-1 (sym)
"Remove all advice from SYM."
(advice-mapc (lambda (advice x) (advice-remove sym advice)) sym)
(helpful-update))

(defun helpful--remove-all-advice (button)
"Remove all advice for BUTTON."
(helpful--remove-all-advice-1 (button-get button 'symbol)))

(define-button-type 'helpful-remove-all-advice-button
'action #'helpful--remove-all-advice
'help-echo "Remove all advice")

(defun helpful-remove-all-advice ()
"Remove all advice for the current helpful symbol."
(interactive)
(unless (derived-mode-p #'helpful-mode)
(user-error "Must be in a *helpful* buffer"))
(unless helpful--callable-p
(user-error "Cannot unadvise a variable"))
(unless (helpful--advised-p helpful--sym)
(user-error "Function not advised"))
(helpful--remove-all-advice-1 helpful--sym))

(defun helpful--propertize-links (docstring)
"Convert URL links in docstrings to buttons."
(replace-regexp-in-string
Expand Down Expand Up @@ -2159,7 +2193,8 @@ state of the current symbol."
(references (helpful--calculate-references
helpful--sym helpful--callable-p
source-path))
(aliases (helpful--aliases helpful--sym helpful--callable-p)))
(aliases (helpful--aliases helpful--sym helpful--callable-p))
(advised? (helpful--advised-p helpful--sym)))

(erase-buffer)

Expand Down Expand Up @@ -2257,6 +2292,26 @@ state of the current symbol."
(insert "\n\n")
(insert (helpful--make-manual-button helpful--sym)))))

(when advised?
(helpful--insert-section-break)
(insert (helpful--heading "Advice"))
(dolist (x (helpful--get-advice helpful--sym))
(cl-destructuring-bind (combinator . advice) x
(insert (helpful--button "X" 'helpful-remove-advice-button
'symbol helpful--sym
'advice advice)
" "
(propertize (symbol-name combinator) 'face 'font-lock-builtin-face)
" "
(helpful--button
(helpful--format-symbol advice) 'helpful-describe-button
'symbol advice
'callable-p t)
"\n")))
;; We've inserted one newline too many, since the next section will insert
;; a section break.
(delete-char -1))

;; Show keybindings.
;; TODO: allow users to conveniently add and remove keybindings.
(when (commandp helpful--sym)
Expand Down Expand Up @@ -2301,13 +2356,6 @@ state of the current symbol."
" "
(helpful--make-callees-button helpful--sym source)))

(when (helpful--advised-p helpful--sym)
(helpful--insert-section-break)
(insert
(helpful--heading "Advice")
(format "This %s is advised."
(if (macrop helpful--sym) "macro" "function"))))

(let ((can-edebug
(helpful--can-edebug-p helpful--sym helpful--callable-p buf pos))
(can-trace
Expand Down Expand Up @@ -2336,7 +2384,7 @@ state of the current symbol."

(when (and
(or can-edebug can-trace)
(or can-disassemble can-forget))
(or can-disassemble can-forget advised?))
(insert "\n"))

(when can-disassemble
Expand All @@ -2345,7 +2393,12 @@ state of the current symbol."
(when can-forget
(when can-disassemble
(insert " "))
(insert (helpful--make-forget-button helpful--sym helpful--callable-p))))
(insert (helpful--make-forget-button helpful--sym helpful--callable-p)))
(when advised?
(when (or can-forget can-disassemble)
(insert " "))
(insert (helpful--button "Remove all advice" 'helpful-remove-all-advice-button
'symbol helpful--sym))))

(when aliases
(helpful--insert-section-break)
Expand Down Expand Up @@ -2421,16 +2474,41 @@ state of the current symbol."
(when opened
(kill-buffer buf))))

(defconst helpful--advice-regexp
"^\\(?:This function has \\)?\\(:[-a-z]+\\) advice: `\\(.*\\)'\\.?\n\n?"
"Regexp matching advice lines.
Match group 1 is the combinator, with colon, and match group 2 is
the advice.")

;; TODO: this isn't sufficient for `edebug-eval-defun'.
(defun helpful--skip-advice (docstring)
"Remove mentions of advice from DOCSTRING."
(let* ((lines (s-lines docstring))
(relevant-lines
(--drop-while
(or (s-starts-with-p ":around advice:" it)
(s-starts-with-p "This function has :around advice:" it))
lines)))
(s-trim (s-join "\n" relevant-lines))))
(with-temp-buffer
(insert docstring)
(goto-char (point-min))
(save-match-data
(while (looking-at helpful--advice-regexp)
(delete-region (match-beginning 0) (match-end 0))))
(buffer-substring-no-properties (point-min) (point-max))))

(defun helpful--extract-advice (docstring)
"Extract `advice' from DOCSTRING."
(with-temp-buffer
(insert docstring)
(goto-char (point-min))
(save-match-data
(let (result)
(while (looking-at helpful--advice-regexp)
(push (cons (intern (match-string-no-properties 1))
(read (match-string-no-properties 2)))
result)
(goto-char (match-end 0)))
result))))

(defun helpful--get-advice (sym)
"Extract `advice' from SYM."
(helpful--extract-advice (let ((text-quoting-style 'grave))
(documentation sym t))))

(defun helpful--format-argument (arg)
"Format ARG (a symbol) according to Emacs help conventions."
Expand Down Expand Up @@ -2529,10 +2607,7 @@ escapes that are used by `substitute-command-keys'."
(setq docstring (documentation sym t))
(-when-let (docstring-with-usage (help-split-fundoc docstring sym))
(setq docstring (cdr docstring-with-usage))
(when docstring
;; Advice mutates the docstring, see
;; `advice--make-docstring'. Undo that.
;; TODO: Only do this if the function is advised.
(when (helpful--advised-p sym)
(setq docstring (helpful--skip-advice docstring)))))
(setq docstring
(documentation-property sym 'variable-documentation t)))
Expand Down