abo-abo / hydra

make Emacs bindings that stick around
1.85k stars 112 forks source link

dynamically created hydras? #164

Open benedekfazekas opened 9 years ago

benedekfazekas commented 9 years ago

hi,

this is more like a question than an issue. we decided to use hydras to improve discoverability for clojure refactor see: https://github.com/clojure-emacs/clj-refactor.el/issues/214#issuecomment-136383190. however, would be nice to be able to generate hydras as we have a nice datastructure (and helper functions) which could power that, see: https://github.com/clojure-emacs/clj-refactor.el/blob/new-all-helpers-structure/clj-refactor.el#L293-L373

I have seen the conditional hydra on the wiki but that is not exactly what we need. Any advice how to generate hydra docstring and heads dynamically?

abo-abo commented 9 years ago

If you want to stick to your data structure, maybe like this:

(eval `(defhydra hydra-foo (:columns 3)
           "cljr"
           ,@(mapcar (lambda (x)
                       (list (car x) (cadr x) (caddr x)))
                     cljr--all-helpers)))
abo-abo commented 9 years ago

Also look at pandoc-mode. It generates some hydras dynamically.

benedekfazekas commented 9 years ago

thx for the help. will give these a try

joostkremers commented 9 years ago

@benedekfazekas Sorry to barge in here, but as the maintainer of pandoc-mode, I'd be very interested in anything you come up with. There may be better ways to do what I did in pandoc-mode. Would you mind sharing your code when you've come up with something that works? TIA

benedekfazekas commented 9 years ago

I have to disappoint you I am afraid. I played a bit with @abo-abo's sample code and then gave up and did not have time to go back. so current hydra code in clj-refactor is pretty hardwired, although i have my helper fns around. Will let you know if I have more 'meaningful' stuff added to clj-refactor.

squiter commented 8 years ago

I don't know if this is a right place to write my doubt but I want to create hydras dynamically by projects.
My first idea is to create launcher with helper links by projects like: ci url, repository, online documentation, etc. There is any way to create hydras like that?

abo-abo commented 8 years ago

@squiter Just write out the hydra that you need by hand. If you have a few more that fit the same template, use the eval trick above. If you give an example, perhaps I can help you.

squiter commented 8 years ago

@abo-abo thanks for your response!
The eval trick above works fine to me :D

(eval `(defhydra hydra-project-launcher (:column 3)
         "Fast links by projects"
         ,@(mapcar (lambda (x)
                     (list (car x) `(browse-url ,(cadr x)) (caddr x)))
                   (mapcar (lambda (line)
                             (split-string line " - "))
                           (read-lines (concat (projectile-project-root) ".hydra-links"))))))

Thank you again!

stig commented 7 years ago

I'm trying to use the eval trick above, and it works but is not 100% ideal.

This works (auxiliary functions omitted):

(eval `(defhydra sb/hydra-select-themes (:hint nil :color pink)
         "Select Theme"
         ,@(sb/hydra-load-theme-heads (sb/sort-themes (custom-available-themes)))
         ("DEL" (sb/disable-all-themes))
         ("RET" nil "done" :color blue)))

(bind-keys ("C-c w t" . sb/hydra-select-themes/body))

However, that means that if I install a new theme it won't show up in this hydra until I manually re-eval the config snippet, or restart Emacs. That's not ideal. So I wanted to rewrite it to something like this, hoping that the Hydra would be re-created at the point when I invoke it:

(bind-keys ("C-c w t" .
          (eval `(defhydra sb/hydra-select-themes (:hint nil :color pink)
                   "Select Theme"
                   ,@(sb/hydra-load-theme-heads (sb/sort-themes (custom-available-themes)))
                   ("DEL" (sb/disable-all-themes))
                   ("RET" nil "done" :color blue)))))

However, if I try to launch the Hydra now I get the following error:

command-execute: Wrong type argument: commandp, (eval (\` (defhydra sb/hydra-select-themes (:hint nil :color pink) "Select Theme" (\,@ (sb/hydra-load-theme-heads (sb/sort-themes (custom-available-themes)))) ("DEL" (sb/disable-all-themes)) ("RET" nil "done" :color blue))))

Is there a work-around for this? I've tried wrapping the eval in a defun and lambda but neither helped. (Or, I didn't do it correctly: I'm an Emacs-lisp novice.)

Can anyone help with a work-around for this case?

Update: FWIW the complete code is here: https://github.com/stig/dot-files/blob/master/emacs.d/Themes.org#hydra-theme-switching

Update 2: Using https://github.com/abo-abo/hydra/issues/137#issuecomment-117132873 as a reference I finally managed to get it working with the aid of call-interactively:

    (bind-keys ("C-c w t" .
                (lambda ()
                  (interactive)
                  (call-interactively
                   (eval `(defhydra sb/hydra-select-themes (:hint nil :color pink)
                            "Select Theme"
                            ,@(sb/hydra-load-theme-heads (sb/sort-themes (custom-available-themes)))
                            ("DEL" (sb/disable-all-themes))
                            ("RET" nil "done" :color blue)))))))
abo-abo commented 7 years ago

@stig So now it works for you? Because I don't see why it should not work if custom-available-themes is aware of new themes.

Still, I recommend to simply use counsel-load-theme: it's 2-3 more keys to type but a lot less theme names to read.

stig commented 7 years ago

@abo-abo yeah, it works now.

I don't know what counsel-load-theme is; it doesn't appear to be a function available in my Emacs version (25.1.1)

abo-abo commented 7 years ago

I don't know what counsel-load-theme is; it doesn't appear to be a function available in my Emacs version (25.1.1)

Available from the counsel package on MELPA.