mclear-tools / tabspaces

GNU General Public License v3.0
226 stars 14 forks source link

[Sharing code] Switching tabs via frog-menu #19

Closed EFLS closed 1 year ago

EFLS commented 1 year ago

Thanks for this package Colin! I've recently made the switch to using tabs (rather than perspectives), and I really like the simplicity of the package.

I'm sharing the code below as it might be useful to others. Hopefully this is the right place to do so.

When I have many tabs open, I like to switch between them quickly. One way to do this is via frog-menu which pops up a posframe and uses avy keys to select a candidate. More on frog-menu here: https://elpa.gnu.org/packages/frog-menu.html

In short: the code below allows to (1) pop-up a list of tabs in a posframe, and (2) switch to a tab by typing a single key (based on the first letter of the key). It takes inspiration from https://github.com/waymondo/frog-jump-buffer

(require 'frog-menu)

(defun efls/frog-tab ()
  "Pick a tab to switch to via `frog-menu'."
  (interactive)
  (let* ((frog-menu-avy-padding t)
         (frog-menu-min-col-padding 1)
         (frog-menu-display-option-alist
          '((avy-posframe . posframe-poshandler-frame-center)
            (avy-side-window display-buffer-in-side-window (side . bottom))))
         (prompt "Switch tab")
         (tabs (mapcar (lambda (tab) (alist-get 'name tab))
                       (tab-bar-tabs)))
         (frog-menu-avy-keys (efls/frog-tabs-generate-keys tabs))
         (actions '(("C-l" "List tabs"
                      (call-interactively tabspaces-switch-or-create-workspace))))
         (res (frog-menu-read prompt tabs actions)))
    (if (stringp res)
        (progn (message res)
               (tabspaces-switch-or-create-workspace res))
      (apply res))))

Generating the keys for switching perspectives is done via a separate function.

(defun efls/frog-tabs-generate-keys (tabs)
  "Generate keys for TABS (a list of tab names).
Returns a list of first chars from each tab. If two chars are
identical, make second capitalized. If more chars than two are
identical, then... nothing else."
  (let ((new-chars))
    (dolist (char (-map (lambda (s) (string (string-to-char s)))
                        tabs))
      (if (member char new-chars)
          (setq new-chars (append new-chars (list (capitalize char))))
        (setq new-chars (append new-chars (list char)))))
    (-map 'string-to-char new-chars)))

It works as follows:

  1. Create a list of tab names.
  2. Construct a list of strings with first character of each tab name.
  3. Make a new list where each repetition of a char is capitalized.
  4. Turn that list of strings into a list of characters.

There are potential issues:

mclearc commented 1 year ago

Very nice! Perhaps I'll add a wiki so that we can post such Workflows in a more discoverable way.

mclearc commented 1 year ago

Thanks again -- moved this to the wiki