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

[Feature request] helpful-go-back, helpful-go-forward functions #250

Open
sebmiq opened this issue Oct 3, 2020 · 3 comments · May be fixed by #292
Open

[Feature request] helpful-go-back, helpful-go-forward functions #250

sebmiq opened this issue Oct 3, 2020 · 3 comments · May be fixed by #292

Comments

@sebmiq
Copy link

sebmiq commented Oct 3, 2020

Hi, I've recently been trying this package out.

help-mode provides help-go-back and help-go-forward functions that I find helpful to navigate the help.

I couldn't find any similar feature for helpful.

Regards,

@srnnkls
Copy link

srnnkls commented Oct 16, 2020

I would love to see those, too.

@Janfel
Copy link

Janfel commented Oct 28, 2021

I am currently experimenting with something like that in my own config. This is what I have so far, feel free to use it until the devs get around to implementing this feature.

;; Only needed when using Doom Emacs with (featurep! :ui popup).
(set-popup-rule! "^\\*helpful " :size 0.35 :ttl nil :select t)

(defvar *helpful-buffer-ring-size 5
  "How many buffers are stored for use with `*helpful-next'.")

(defvar *helpful--buffer-ring (make-ring *helpful-buffer-ring-size)
  "Ring that stores the current Helpful buffer history.")

(defun *helpful--buffer-index (&optional buffer)
  "If BUFFER is a Helpful buffer, return it’s index in the buffer ring."
  (let ((buf (or buffer (current-buffer))))
    (and (eq (buffer-local-value 'major-mode buf) 'helpful-mode)
         (seq-position (ring-elements *helpful--buffer-ring) buf #'eq))))

;; This macro is basically just `defun' + `advice-add'.
(defadvice! *helpful--new-buffer-a (help-buf)
  "Update the buffer ring according to the current buffer and HELP-BUF."
  :filter-return #'helpful--buffer
  (let ((buf-ring *helpful--buffer-ring))
    (let ((newer-buffers (or (*helpful--buffer-index) 0)))
      (dotimes (_ newer-buffers) (ring-remove buf-ring 0)))
    (when (/= (ring-size buf-ring) *helpful-buffer-ring-size)
      (ring-resize buf-ring *helpful-buffer-ring-size))
    (ring-insert buf-ring help-buf)))

(defun *helpful--next (&optional buffer)
  "Return the next live Helpful buffer relative to BUFFER."
  (let ((buf-ring *helpful--buffer-ring)
        (index (or (*helpful--buffer-index buffer) -1)))
    (cl-block nil
      (while (> index 0)
        (cl-decf index)
        (let ((buf (ring-ref buf-ring index)))
          (if (buffer-live-p buf) (cl-return buf)))
        (ring-remove buf-ring index)))))

(defun *helpful--previous (&optional buffer)
  "Return the previous live Helpful buffer relative to BUFFER."
  (let ((buf-ring *helpful--buffer-ring)
        (index (1+ (or (*helpful--buffer-index buffer) -1))))
    (cl-block nil
      (while (< index (ring-length buf-ring))
        (let ((buf (ring-ref buf-ring index)))
          (if (buffer-live-p buf) (cl-return buf)))
        (ring-remove buf-ring index)))))

(defun *helpful-next ()
  "Go to the next Helpful buffer."
  (interactive)
  (when-let (buf (*helpful--next))
    (funcall helpful-switch-buffer-function buf)))

(defun *helpful-previous ()
  "Go to the previous Helpful buffer."
  (interactive)
  (when-let (buf (*helpful--previous))
    (funcall helpful-switch-buffer-function buf)))

@axelknock
Copy link

Reproducing defadvice! from Doom Emacs for reference:

(defmacro defadvice! (symbol arglist &optional docstring &rest body)
  "Define an advice called SYMBOL and add it to PLACES.

ARGLIST is as in `defun'. WHERE is a keyword as passed to `advice-add', and
PLACE is the function to which to add the advice, like in `advice-add'.
DOCSTRING and BODY are as in `defun'.

\(fn SYMBOL ARGLIST &optional DOCSTRING &rest [WHERE PLACES...] BODY\)"
  (declare (doc-string 3) (indent defun))
  (unless (stringp docstring)
    (push docstring body)
    (setq docstring nil))
  (let (where-alist)
    (while (keywordp (car body))
      (push `(cons ,(pop body) (ensure-list ,(pop body)))
            where-alist))
    `(progn
       (defun ,symbol ,arglist ,docstring ,@body)
       (dolist (targets (list ,@(nreverse where-alist)))
         (dolist (target (cdr targets))
           (advice-add target (car targets) #',symbol))))))

(defmacro undefadvice! (symbol _arglist &optional docstring &rest body)
  "Undefine an advice called SYMBOL.

This has the same signature as `defadvice!' an exists as an easy undefiner when
testing advice (when combined with `rotate-text').

\(fn SYMBOL ARGLIST &optional DOCSTRING &rest [WHERE PLACES...] BODY\)"
  (declare (doc-string 3) (indent defun))
  (let (where-alist)
    (unless (stringp docstring)
      (push docstring body))
    (while (keywordp (car body))
      (push `(cons ,(pop body) (ensure-list ,(pop body)))
            where-alist))
    `(dolist (targets (list ,@(nreverse where-alist)))
       (dolist (target (cdr targets))
         (advice-remove target #',symbol)))))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants