Add more comfortable way to execute hammy commands without prompting for the hammy every time (e.g. transient menu)
This is more a discussion item than an issue. hammy.el is designed to be able to handle multiple timers simultaneously. However, personally, I just use it for work interval timers and usually just one at a time. Either pomodoro, 1/3-time or the flywheel, and usually I keep using the commands for one hammy-type during a session. Then, I was annoyed by being prompted for the hammy each time I call an interative hammy commmand.
Of course I could bind the non-interactive forms for different hammy-types to different keys, but this would result in too many key-bindings to remember. Another idea was to have a global state variable which selects a hammy that I want to focus on right now. I then figured out that an elegant solution would be to define a transient menu for selecting hammy commands (I wanted that anyway) with an infix argument to optionally select the hammy-type that the commands should act upon.
So this is my first draft of what I came up with:
(EDIT: The transient menu looks correct, but when using it I just found out that I seem to have a bug somwhere, hammy-menu--next seems to not to advance to the next interval for me. But I'll keep it here to showcase the idea.)
(require 'seq)
(transient-define-infix hammy-menu-select-hammy-infix ()
:description "Restrict commands to"
:class 'transient-option
:argument "--hammy="
:key "h"
:always-read nil
:choices (mapcar #'hammy-name hammy-hammys))
(defun hammy--by-name (hammy-name)
(seq-find (lambda (hammy) (string= (hammy-name hammy) hammy-name))
hammy-hammys))
(defun hammy-menu--call-with-infix-args (hammy-command &optional args)
"Version of HAMMY-COMMAND for transient sufffixes which takes into account infix arguments.
If infix args contain specific hammy, run HAMMY-COMMAND with that, otherwise call interactively."
(let ((selected-hammy-name (transient-arg-value "--hammy=" args)))
(if (and selected-hammy-name (not (string-empty-p selected-hammy-name)))
;; if user selected a hammy via the infix argument, use that
(funcall hammy-command (hammy--by-name selected-hammy-name))
;; otherwise, normal command with completing-read
(call-interactively hammy-command))))
(defmacro hammy-menu--define-hammmy-command-suffix (hammy-command suffix-name)
"Create transient suffix names SUFFIX-NAME for HAMMY-COMMAND, modified to take into account infix arguments."
`(transient-define-suffix ,suffix-name (&optional args)
(interactive (list (transient-args transient-current-command)))
(hammy-menu--call-with-infix-args ,hammy-command args)))
(hammy-menu--define-hammmy-command-suffix #'hammy-start hammy-menu--start)
(hammy-menu--define-hammmy-command-suffix #'hammy-next hammy-menu--next)
(hammy-menu--define-hammmy-command-suffix #'hammy-stop hammy-menu--stop)
(hammy-menu--define-hammmy-command-suffix #'hammy-reset hammy-menu--reset)
(hammy-menu--define-hammmy-command-suffix #'hammy-toggle hammy-menu--toggle)
(hammy-menu--define-hammmy-command-suffix #'hammy-adjust hammy-menu--adjust)
(transient-define-prefix my-hammy-menu ()
"Hammy menu 🐹"
[:description "Hammy 🐹"
[("s" "start 🛞" hammy-menu--start)
("n" "next ⏩" hammy-menu--next)
("q" "stop 🛑" hammy-menu--stop)
("r" "reset 🔄" hammy-menu--reset)
("t" "toggle hammy" hammy-menu--toggle)]
[("a" "adjust" hammy-menu--adjust)
("l" "log" hammy-view-log)
("m" "toggle mode" hammy-mode)]]
[(hammy-menu-select-hammy-infix)])
Here's a screenshot of how that looks (because I couldn't figure out quickly how to copy the transient buffer into the kill ring).

A usefull feature that comes with transient is that I can call transient-save (C-x C-s) and it will remember my selected hammy for the quick commands until next time.
I don't think this is in any way ready to merge, it's for my opinionated workflow and I'm quite new to transient menus, so coding wise it is not polished. But for me this menu will be useful for now, as it solves my problems. But it would be nice to have something similar within hammy or as a tip in the documentation.
Maybe there are also other ways to address my user story, e.g. an interactive commands to focus on a specific hammy some major mode. One simple improvement would be to not prompt for the hammy via completing-read if only one hammy is defined/active. E.g. in hammy-stop and hammy-nextI'm sometimes annoyed to have to confirm the completing-read suggestion even if there is just one candidate. Using the non-interactive commands via my transient solves that for me, but maybe just fixing that in hammy might be enough and simpler from a developer perspective.
Hi Michael,
Yes, I'd considered making hammy-complete not prompt if there is only one hammy, so now I've gone ahead and done it. Please let me know if it solves that irritation in your use.
That Transient menu looks very nice! I suppose we could add something like that, maybe call it hammy-menu.
Thaniks, I commented on your disabled prompt for one hammy, I had the same changed patched into my fork of this package, as I also commented on the commit
The problem I tried to solve with the menu is to allow for two possible workflows with hammies:
- action->hammy: First call the hammy command (e.g.
hammy-start) and then decide which hammy to act upon. Useful for when running multiple hammies in parallel. - hammy->action: First select a hammy and then choose commands. An optional persistent hammy-selection is useful if you want to focus on a specific hammy for a while.
But in hindsight, workflow 2 is of implicit as after selecting a hammy with hammy-start, most commands only show the active hammy in the completions and now since 81e0316a98c4788375bc0e50e5d6ba9dd440e586 there's no prompt for it anymore.
But also in general I like menus like hydras or transients. Though to be honest one can achieve something similar by binding keys to a keymap and enable which-key, which then has the advantage of adapting automatically to the users keybindings, but having one optional built-in menu, or at least an example in the documentation, might be useful for some. One could also add toggles for the quiet version of commands etc.
Copying my comment on the commit:
Yeah, that's why I didn't implement this initially. I use Vertico, which automatically remembers the history of selected items, so for most cases I just have to press RET an extra time to select the most recently selected hammy, rather than actually having to choose the right one.
I also agree that it served as a small extra confirmation, which can be useful. So I wouldn't mind making this customizeable...
Closing this because with 81e0316 I'm not prompted for the hammy every time I do hammy-next with only one active hammy, and this was the main reason why I opened this in the first place.