waymondo / frog-jump-buffer

The fastest buffer-jumping Emacs lisp package around
158 stars 5 forks source link

Option to scroll through the buffers, if the number of buffers is bigger than the `frog-jump-buffer-max-buffers` #17

Open tmythicator opened 4 years ago

tmythicator commented 4 years ago

Quite often I have more than 20 buffers. I don't seem to find a way to find all of them. But showing them all at one would be too much. It would be really nice to have an option scroll through the buffer lists, e.g. with buttons n or p (for next and previous). Just an idea: frogJump2

waymondo commented 4 years ago

I like this idea. I'm not sure when I can get to implementing it, but I sanction the thought of it. PR's are always welcome too.

xwl commented 4 years ago

I use a different strategy.

First, I use 1-9 for the avy key to jump, then if the buffer is not in displayed in the list, i start typing part of the buffer name (like 'cpp'), in that case, i make frog-jump-buffer switches to ivy-switch-buffer with 'cpp' as initial input, which gives me a pretty seamless solution.

But for that, i have to also make some minor changes to frog-menu--posframe-ace-handler to store last user input before avy aborts (maybe there is better ways to do it?)

waymondo commented 3 years ago

@xwl do you mind providing the code for your solution for reference?

xwl commented 3 years ago

Below is my full config for frog-jump-buffer, I have to change a ivy function too.

(require 'frog-jump-buffer)
(setq frog-jump-buffer-default-filter 'frog-jump-buffer-filter-all)
(setq frog-jump-buffer-include-current-buffer nil)
(setq frog-jump-buffer-max-buffers 9)
(setq frog-jump-buffer-posframe-handler 'posframe-poshandler-frame-center)

(setq frog-jump-buffer-use-default-filter-actions nil)
(setq frog-jump-buffer-filter-actions
      (list
       ;; (list "I" "[ivy]" 'ivy-switch-buffer)
       (list "R" "[Recent]" 'xwl-recentf-open-files)
       (list "P" "[Project]" 'xwl-find-project-file)))

(setq frog-menu-avy-keys (append (number-sequence ?1 ?9) frog-menu-avy-keys))

(defun xwl-call-func-or-ivy-switch (orig-fun res)
  (cond ((and res (symbolp res) (not (string-match "frog-" (symbol-name res))))
         (funcall res))
        ((equal xwl-frog-jump-buffer-last-input "")
         (funcall orig-fun res))
        (t
         (ivy-switch-buffer xwl-frog-jump-buffer-last-input))))

(advice-add 'frog-jump-buffer-handle-result :around 'xwl-call-func-or-ivy-switch)

(defun xwl-frog-jump-buffer-no-error (orig-fun &rest args)
  (setq xwl-frog-jump-buffer-last-input "")
  (unless (ignore-errors (apply orig-fun args))
    (frog-jump-buffer-handle-result nil)))

(advice-add 'frog-jump-buffer :around 'xwl-frog-jump-buffer-no-error)

(require 'ivy)
(defun ivy-switch-buffer (&optional initial-input)
  "Switch to another buffer."
  (interactive)
  (ivy-read "Switch to buffer: " #'internal-complete-buffer
            :keymap ivy-switch-buffer-map
            :preselect (buffer-name (other-buffer (current-buffer)))
            :action #'ivy--switch-buffer-action
            :matcher #'ivy--switch-buffer-matcher
            :caller 'ivy-switch-buffer
            :initial-input (or initial-input "") ; xwl
            ))

(defun frog-menu--posframe-ace-handler (char)
  "Execute menu action for CHAR."
  (cond ((memq char '(?\e ?\C-g))
          ;; exit silently
          (setq xwl-frog-jump-buffer-last-input ""))
        ((mouse-event-p char)
         (signal 'user-error (list "Mouse event not handled" char)))
        (t
         (let* ((key (kbd (key-description (vector char))))
                (f (lookup-key frog-menu--avy-action-map key)))
           (if (functionp f)
               (progn
                 (setq xwl-frog-jump-buffer-last-input "")
                 (throw 'done (list f)))
             ;; (message "No such candidate, hit `C-g' to quit.")
             ;; (throw 'done 'restart))))))
             (message "No such candidate, switch to ivy.")
             ;; (throw 'done (list (lambda () (ivy-switch-buffer (char-to-string char)))))
             (when (or (and (>= char ?a) (<= char ?z))
                       (and (>= char ?A) (<= char ?Z))
                       (memq char '(?. ?_ ?~)))
               (setq xwl-frog-jump-buffer-last-input (char-to-string char)))
             (throw 'done 'exit)
             )))))

(defun frog-menu-read (prompt collection &optional actions)
  "..."
  (let* ((frog-menu-type (funcall frog-menu-type-function))
         (convf (and collection (consp (car collection))
                     #'car))
         (strings (if convf
                      (mapcar convf collection)
                    collection))
         (strings (if frog-menu-sort-function
                      (sort strings frog-menu-sort-function)
                    strings))
         (buf (frog-menu--init-buffer (get-buffer-create frog-menu--buffer)
                                      prompt
                                      strings
                                      actions))
         (dhandler (cdr (assq frog-menu-type
                              frog-menu-display-handler-alist)))
         (doption (cdr (assq frog-menu-type
                             frog-menu-display-option-alist)))
         (window (funcall dhandler buf doption))
         (qhandler (cdr (assq frog-menu-type
                              frog-menu-query-handler-alist)))
         (cuhandler (cdr (assq frog-menu-type
                               frog-menu-cleanup-handler-alist)))
         (res nil))
    (unwind-protect
        (setq res (funcall qhandler buf window actions))
      (when cuhandler
        (funcall cuhandler buf window)))
    (when (eq res 'frog-menu--complete)
      (setq res (frog-menu--complete prompt strings)))
    ;; (cond ((and (eq convf #'car) (stringp res))
    (cond ((and (eq convf #'car)
                (stringp res); xwl
                (eq (get-text-property 0 'face res)
                    'frog-menu-candidates-face))
           (cdr (assoc res collection)))
          (t res))))