Giter VIP home page Giter VIP logo

hydra's Introduction

Hydra

Build Status GNU ELPA MELPA MELPA Stable

This is a package for GNU Emacs that can be used to tie related commands into a family of short bindings with a common prefix - a Hydra.

hydra

Description for Poets

Once you summon the Hydra through the prefixed binding (the body + any one head), all heads can be called in succession with only a short extension.

The Hydra is vanquished once Hercules, any binding that isn't the Hydra's head, arrives. Note that Hercules, besides vanquishing the Hydra, will still serve his original purpose, calling his proper command. This makes the Hydra very seamless, it's like a minor mode that disables itself auto-magically.

Description for Pragmatics

Imagine that you have bound C-c j and C-c k in your config. You want to call C-c j and C-c k in some (arbitrary) sequence. Hydra allows you to:

  • Bind your functions in a way that pressing C-c jjkk3j5k is equivalent to pressing C-c j C-c j C-c k C-c k M-3 C-c j M-5 C-c k. Any key other than j or k exits this state.

  • Assign a custom hint to this group of functions, so that you know immediately after pressing C-c that you can follow up with j or k.

If you want to quickly understand the concept, see the video demo.

Table of Contents

Sample Hydras

The one with the least amount of code

(defhydra hydra-zoom (global-map "<f2>")
  "zoom"
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))

With this simple code, you can:

  • Start zooming in with <f2> g.
  • Continue to zoom in with g.
  • Or zoom out with l.
  • Zoom in five times at once with 5g.
  • Stop zooming with any key that isn't g or l.

For any Hydra:

  • digit-argument can be called with 0-9.
  • negative-argument can be called with -.
  • universal-argument can be called with C-u.

The impressive-looking one

Here's the result of pressing . in the good-old Buffer menu:

hydra-buffer-menu

The code is large but very simple:

(defhydra hydra-buffer-menu (:color pink
                             :hint nil)
  "
^Mark^             ^Unmark^           ^Actions^          ^Search
^^^^^^^^-----------------------------------------------------------------
_m_: mark          _u_: unmark        _x_: execute       _R_: re-isearch
_s_: save          _U_: unmark up     _b_: bury          _I_: isearch
_d_: delete        ^ ^                _g_: refresh       _O_: multi-occur
_D_: delete up     ^ ^                _T_: files only: % -28`Buffer-menu-files-only
_~_: modified
"
  ("m" Buffer-menu-mark)
  ("u" Buffer-menu-unmark)
  ("U" Buffer-menu-backup-unmark)
  ("d" Buffer-menu-delete)
  ("D" Buffer-menu-delete-backwards)
  ("s" Buffer-menu-save)
  ("~" Buffer-menu-not-modified)
  ("x" Buffer-menu-execute)
  ("b" Buffer-menu-bury)
  ("g" revert-buffer)
  ("T" Buffer-menu-toggle-files-only)
  ("O" Buffer-menu-multi-occur :color blue)
  ("I" Buffer-menu-isearch-buffers :color blue)
  ("R" Buffer-menu-isearch-buffers-regexp :color blue)
  ("c" nil "cancel")
  ("v" Buffer-menu-select "select" :color blue)
  ("o" Buffer-menu-other-window "other-window" :color blue)
  ("q" quit-window "quit" :color blue))

(define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)

Looking at the code, you can see hydra-buffer-menu as sort of a namespace construct that wraps each function that it's given in code that shows that hint and makes it easy to call the related functions. One additional function is created and returned as the result of defhydra - hydra-buffer-menu/body. This function does nothing except setting up the hint and the keymap, and is usually the entry point to complex hydras.

To write your own hydras, you can:

  • Either modify an existing hydra to do what you want to do.
  • Or read the rules, the examples, the docstrings and comments in the source.

Community wiki

You can find some user created hydras and more documentation in the project's community wiki. Feel free to add your own or edit the existing ones.

The Rules of Hydra-tics

Each hydra (take awesome as a prefix to make it more specific) looks like this:

(defhydra hydra-awesome (awesome-map awesome-binding awesome-plist)
  awesome-docstring
  awesome-head-1
  awesome-head-2
  awesome-head-3
  ...)

hydra-awesome

Each hydra needs a name, and this one is named hydra-awesome. You can name your hydras as you wish, but I prefer to start each one with hydra-, because it acts as an additional namespace layer, for example: hydra-zoom, hydra-helm, hydra-apropos etc.

If you name your hydra hydra-awesome, the return result of defhydra will be hydra-awesome/body.

Here's what hydra-zoom/body looks like, if you're interested:

(defun hydra-zoom/body ()
  "Call the body in the \"hydra-zoom\" hydra.

The heads for the associated hydra are:

\"g\":    `text-scale-increase',
\"l\":    `text-scale-decrease'

The body can be accessed via `hydra-zoom/body', which is bound to \"<f2>\"."
  (interactive)
  (require 'hydra)
  (hydra-default-pre)
  (let ((hydra--ignore nil))
    (hydra-keyboard-quit)
    (setq hydra-curr-body-fn
          'hydra-zoom/body))
  (hydra-show-hint
   hydra-zoom/hint
   'hydra-zoom)
  (hydra-set-transient-map
   hydra-zoom/keymap
   (lambda nil
     (hydra-keyboard-quit)
     nil)
   nil)
  (setq prefix-arg
        current-prefix-arg))

awesome-map and awesome-binding

This can be any keymap, for instance, global-map or isearch-mode-map.

For this example:

(defhydra hydra-zoom (global-map "<f2>")
  "zoom"
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))
  • awesome-map is global-map
  • awesome-binding is "<f2>"

And here's the relevant generated code:

(unless (keymapp (lookup-key global-map (kbd "<f2>")))
  (define-key global-map (kbd "<f2>") nil))
(define-key global-map [f2 103]
  (function hydra-zoom/text-scale-increase))
(define-key global-map [f2 108]
  (function hydra-zoom/text-scale-decrease))

As you see, "<f2>" is used as a prefix for g (char value 103) and l (char value 108).

If you don't want to use a map right now, you can skip it like this:

(defhydra hydra-zoom (nil nil)
  "zoom"
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))

Or even simpler:

(defhydra hydra-zoom ()
  "zoom"
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))

But then you would have to bind hydra-zoom/text-scale-increase and hydra-zoom/text-scale-decrease yourself.

awesome-plist

You can read up on what a plist is in the Elisp manual.

You can use awesome-plist to modify the behavior of each head in some way. Below is a list of each key.

:pre and :post

You can specify code that will be called before each head, and after the body. For example:

(defhydra hydra-vi (:pre (set-cursor-color "#40e0d0")
                    :post (progn
                            (set-cursor-color "#ffffff")
                            (message
                             "Thank you, come again.")))
  "vi"
  ("l" forward-char)
  ("h" backward-char)
  ("j" next-line)
  ("k" previous-line)
  ("q" nil "quit"))

Thanks to :pre, each time any head is called, the cursor color is changed. And when the hydra quits, the cursor color will be made black again with :post.

:exit

The :exit key is inherited by every head (they can override it) and influences what will happen after executing head's command:

  • :exit nil (the default) means that the hydra state will continue - you'll still see the hint and be able to use short bindings.
  • :exit t means that the hydra state will stop.

:foreign-keys

The :foreign-keys key belongs to the body and decides what to do when a key is pressed that doesn't belong to any head:

  • :foreign-keys nil (the default) means that the hydra state will stop and the foreign key will do whatever it was supposed to do if there was no hydra state.
  • :foreign-keys warn will not stop the hydra state, but instead will issue a warning without running the foreign key.
  • :foreign-keys run will not stop the hydra state, and try to run the foreign key.

:color

The :color key is a shortcut. It aggregates :exit and :foreign-keys key in the following way:

| color    | toggle                     |
|----------+----------------------------|
| red      |                            |
| blue     | :exit t                    |
| amaranth | :foreign-keys warn         |
| teal     | :foreign-keys warn :exit t |
| pink     | :foreign-keys run          |

It's also a trick to make you instantly aware of the current hydra keys that you're about to press: the keys will be highlighted with the appropriate color.

:timeout

The :timeout key starts a timer for the corresponding amount of seconds that disables the hydra. Calling any head will refresh the timer.

:hint

The :hint key will be inherited by each head. Each head is allowed to override it, of course. One value that makes sense is :hint nil. See below for an explanation of head hint.

:bind

The :bind key provides a lambda to be used to bind each head. This is quite advanced and rarely used, you're not likely to need it. But if you would like to bind your heads with e.g. bind-key instead of define-key you can use this option.

The :bind key can be overridden by each head. This is useful if you want to have a few heads that are not bound outside the hydra.

:base-map

Use this option if you want to override hydra-base-map for the current hydra.

awesome-docstring

This can be a simple string used to build the final hydra hint. However, if you start it with a newline, the key-highlighting and Ruby-style string interpolation becomes enabled, as you can see in hydra-buffer-menu above.

To highlight a key, just wrap it in underscores. Note that the key must belong to one of the heads. The key will be highlighted with the color that is appropriate to the behavior of the key, i.e. if the key will make the hydra exit, the color will be blue.

To insert an empty character, use ^. The only use of this is to have your code aligned as nicely as the result.

To insert a dynamic Elisp variable, use %` followed by the variable. Each time the variable changes due to a head, the docstring will be updated. format-style width specifiers can be used.

To insert a dynamic Elisp expression, use e.g. %(length (dired-get-marked-files)). If a head will change the amount of marked files, for example, it will be appropriately updated.

If the result of the Elisp expression is a string and you don't want to quote it, use this form: %s(shell-command-to-string "du -hs").

awesome-head-1

Each head looks like this:

(head-binding head-command head-hint head-plist)

For the head ("g" text-scale-increase "in"):

  • head-binding is "g".
  • head-command is text-scale-increase.
  • head-hint is "in".
  • head-plist is nil.

head-binding

The head-binding is a string that can be passed to kbd.

head-command

The head-command can be:

  • command name, like text-scale-increase.

  • a lambda, like

      ("g" (lambda ()
             (interactive)
             (let ((current-prefix-arg 4))
               (call-interactively #'magit-status)))
           "git")
    
  • nil, which exits the hydra.

  • a single sexp, which will be wrapped in an interactive lambda.

Here's an example of the last option:

(defhydra hydra-launcher (:color blue)
   "Launch"
   ("h" man "man")
   ("r" (browse-url "http://www.reddit.com/r/emacs/") "reddit")
   ("w" (browse-url "http://www.emacswiki.org/") "emacswiki")
   ("s" shell "shell")
   ("q" nil "cancel"))
(global-set-key (kbd "C-c r") 'hydra-launcher/body)

head-hint

In case of a large body docstring, you usually don't want the head hint to show up, since you've already documented it in the body docstring. You can set the head hint to nil to do this.

Example:

(defhydra hydra-zoom (global-map "<f2>")
  "
Press _g_ to zoom in.
"
  ("g" text-scale-increase nil)
  ("l" text-scale-decrease "out"))

head-plist

Here's a list of body keys that can be overridden in each head:

  • :exit
  • :color
  • :bind
  • :column

Use :column feature to have an aligned rectangular docstring without defining it manually. See hydra-examples.el for an example code.

hydra's People

Contributors

abo-abo avatar bmag avatar culot avatar drot avatar duianto avatar ema2159 avatar ffevotte avatar glucas avatar hura avatar jasonblewis avatar jasonm23 avatar jhonnyseven avatar joewreschnig avatar jtatarik avatar justbur avatar monnier avatar mugu-mugu avatar phst avatar sdwolfz avatar sjbach avatar skangas avatar syohex avatar tarsius avatar ubolonton avatar walseb avatar wbolster avatar yanghaoxie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hydra's Issues

Request: Amaranth Hydra but Unbound Keys Work

I'm not sure how easy or possible it would be, but I think it would be cool if there was another color that was like a mixture of amaranth and red. Keys that aren't bound in the hydra perform their default actions like with red except that the hydra isn't exited like with amaranth.

Problem if you set the head to `C-x` in global map

The below code can become a problem if the head is set to C-x instead of C-M-=.

(hydra-create "C-M-="
  '(("=" modi/font-size-incr  "Increase font size")
    ("-" modi/font-size-decr  "Decrease font size")
    ("0" modi/font-size-reset "Reset font to default size")))

Is some other way possible than setting the binding of head to nil for any map (global or not)?

Issue binding multiple keys to the same function

It seems like a hydra with multiple keys for the same target function does not behave properly. For example:

(hydra-create "M-g" '(("n" next-error "next error")
                      ("p" previous-error "previous error")
                      ("M-n" next-error "next error")
                      ("M-p" previous-error "previous error")))

The M-n / M-p bindings only work once, while the n and p bindings are repeatable.

Hydra heads for control keys (<tab>, <up>, <down>, etc)

Love your idea, but noticed a limitation: hydra heads get cut the second time I press . The setup is the following:

(hydra-create "<f2>"
  '(
    ;; navigation
    ("u" outline-up-heading)
    ("f" org-forward-heading-same-level)
    ("b" org-backward-heading-same-level)
    ("n" outline-next-visible-heading)
    ("p" outline-previous-visible-heading)

    ;; manipulation
    ("<tab>" org-cycle)
    )
  org-mode-map)

Same goes to other control keys. I didn't yet dive into hydra.el code, can't give any more details. Is it a fundamental limitation or a bug?

Extra properties for head with nil body

Hi,

The commits on Feb 23 started giving me this error for almost all of my hydra definitions:

Debugger entered--Lisp error: (error "Extra properties for head with nil body: (\"q\" nil \"cancel\" :color blue)")
  signal(error ("Extra properties for head with nil body: (\"q\" nil \"cancel\" :color blue)"))
  error("Extra properties for head with nil body: %S" ("q" nil "cancel" :color blue))
  hydra--head-color(("q" nil "cancel" :color blue) (nil nil :color red))
  #[(head name) "\306๏ฟฝ\307  \211A@\262๏ฟฝ!\310    \n\"\311\312๏ฟฝ   \211A@\262๏ฟฝ#\f
๏ฟฝ๏ฟฝ๏ฟฝ\f๏ฟฝ
&   \207" [name head body doc hint-name keymap hydra--make-defun hydra--make-callable hydra--head-color format "%s\n\nCall the head: `%S'." body-color body-pre body-post] 10](("q" nil "cancel" :color blue) hydra-change-case/nil)
  cl-mapcar(#[(head name) "\306๏ฟฝ\307    \211A@\262๏ฟฝ!\310    \n\"\311\312๏ฟฝ   \211A@\262๏ฟฝ#\f
๏ฟฝ๏ฟฝ๏ฟฝ\f๏ฟฝ
&   \207" [name head body doc hint-name keymap hydra--make-defun hydra--make-callable hydra--head-color format "%s\n\nCall the head: `%S'." body-color body-pre body-post] 10] (("c" modi/capitalize "Capitalize") ("u" modi/upcase "UPCASE") ("l" modi/downcase "downcase") ("M-c" xah-cycle-letter-case "โ†’Capโ†’UPโ†’downโ†’") ("q" nil "cancel" :color blue)) (hydra-change-case/modi/capitalize hydra-change-case/modi/upcase hydra-change-case/modi/downcase hydra-change-case/xah-cycle-letter-case hydra-change-case/nil))
  #[(name body &optional docstring &rest heads) "๏ฟฝ;\204๏ฟฝ

Here is one of just defhydras:

(defhydra hydra-change-case(:color red)
  "change-case"
  ("c"   modi/capitalize       "Capitalize")
  ("u"   modi/upcase           "UPCASE")
  ("l"   modi/downcase         "downcase")
  ("M-c" xah-cycle-letter-case "โ†’Capโ†’UPโ†’downโ†’")
  ("q"   nil                   "cancel" :color blue))

More formats allowed in "docstrings"

Hi

using "The extra-awesome Ruby-style Hydra docstrings" for a hydra, it would be nice if they could be a bit more flexible with the formats so one can list multiple options in one line,
without it starting to look ugly (say, by giving it hard size limits)

Using your example

(defhydra hydra-toggle (:color pink)
  "
_a_ abbrev-mode:       %`abbrev-mode
_d_ debug-on-error:    %`debug-on-error
_f_ auto-fill-mode:    %`auto-fill-function
_g_ golden-ratio-mode: %`golden-ratio-mode
_t_ truncate-lines:    %`truncate-lines
_w_ whitespace-mode:   %`whitespace-mode

"

look at how it turns out when you use it as

  "
_a_ abbrev-mode:       %`abbrev-mode                _d_ debug-on-error:    %`debug-on-error
_f_ auto-fill-mode:    %`auto-fill-function         _g_ golden-ratio-mode: %`golden-ratio-mode
_t_ truncate-lines:    %`truncate-lines             _w_ whitespace-mode:   %`whitespace-mode

"

and then toggle some.
It displays it all nice, but depending on how the toggles go, the right site options move around.

And on screens with not so many rows (but loads of width, like this 16:x crap), and big hydras, it would be good to be able to use screen space better, without hurting our eyes. :)

Thanks for the hydra, quite nice!

Joerg

hydra-disable: Lisp nesting exceeds `max-lisp-eval-depth'

After updating to the version with lv.el, I am getting this error

hydra-disable: Lisp nesting exceeds `max-lisp-eval-depth'

Here is a sample of my defhydras. In general, I get this error when trying to execute any hydra.

Update: The problem persists even when I set hydra-lv to nil.

Update 2: I have verified that that issue does not occur if I revert to a version older commit

git checkout 06b35f77fdd77ce2c86d9cb5ad30d1c13134d176

I was able to repeat this problem on both emacs 25.0 and stable emacs 24.4.

Jumping to register bookmarks

I'm currently have bookmarks for frequently accessed files:

  (mapcar
   (lambda (r)
     (set-register (car r) (cons 'file (cdr r))))
   '((?i . "~/.emacs.d/Srid.org")
     (?p . "~/Dropbox/Notes/Productive.org")
     (?w . "~/Dropbox/Notes/Work.org")))

Is this something I can use a hydra for (to save keystrokes)? Specifically I want to invoke C-M-j and hit p or w to directly go to the file. Please let me know if there is a better place to ask this kind of questions instead of opening a GitHub issue.

can we customise the color

I was very happy to see colourful hydra, but I myself had difficultly reading red letter in a dark theme. Could you provide a customised variable or something so I can choose whatever colour I like for persistent commands?

`hydra-disable` broken

So, I think there's something wrong with the hydra-disable logic (or, at least, it's broken in my case).

hydra-disable never actually works for me because it does a consp on the car of emulation-mode-map-alists, which fails every time, because my emulation-mode-map-alists looks like this, so the check under the while fails:

(yas--direct-keymaps
 ((override-global-mode keymap
            #^[nil nil keymap
                   #^^[3 0 nil nil nil nil nil ..........

^^ Truncated for your sanity.

Anyway, all in all, the single-key escape doesn't work (for me).

Hydra in question:

(defhydra hydra-window ()
      "window"
      ("h" windmove-left "left")
      ("j" windmove-down "down")
      ("k" windmove-up "up")
      ("l" windmove-right "right")
      ("a" ace-window "ace-window")
      ("v" (lambda ()
             (interactive)
             (split-window-right)
             (windmove-right))
       "open vertically")
      ("x" (lambda ()
             (interactive)
             (split-window-below)
             (windmove-down))
       "open vertically")
      ("s" (lambda () (interactive) (ace-window 4)) "swap")
      ("d" (lambda () (interactive) (ace-window 16)) "delete")
      ("Q" bc/narrow-or-cycle-window "cycle")
      ("q" nil "cancel"))

Emacs version: 24.4.1

Increased sluggishness when calling a function via hydra

I have noticed that over time, after launching emacs, the execution of hydra heads, especially the ones you would normally use in a repeated fashion would become too sluggish.

Here's an example:

(defhydra hydra-vi (:color amaranth)
  "vi"
  ;; basic navigation
  ("l"        forward-char                  nil)
  ("h"        backward-char                 nil)
  ("j"        next-line                     nil)
  ("k"        previous-line                 nil)
  ("q"        nil :color blue))

After calling hydra-vi/body if I randomly move the point around using j and k, I find the movement to gradually become more sluggish.

I don't find that behavior when doing normal C-p/C-n.

I used M-x elp-instrument-function to figure out how much wall time the next-line and hydra-vi/next-line commands took and this was the result:

clipboard01

Here is how the command execution speed was perceived in practice:

  • Slamming down the C-n/C-p key smoothly moves the cursor up and down and I can see it switching to each consecutive line.
  • After executing hydra-vi/body, slamming down j/k made the cursor jump few lines at a time. If I held down either key for too long, I would literally need to wait for few seconds to see where the cursor ends up being.

The sluggishness is considerably less if I relaunch emacs. But the same issue comes back very soon. Before I start bisecting my init, I'd like to know if you or anyone else can repeat this issue.

I have disabled the key-chord-mode and guide-key packages to test this. They are the ones which are think could mess this up.

Here are the performance numbers after some more time:

clipboard01

A few questions / suggestions

This is cool! I can now finally scroll through a buffer with space and backspace:

(defhydra hydra-scroll (global-map "C-S-SPC")
  "scroll"
  ("SPC" scroll-up-command "down")
  ("<backspace>" scroll-down-command "up"))

A few questions:

  • Would it be possible to have the comment appear when I press C-S-SPC? Right now, it seems to be displayed only after I hit space or backspace at least once.
  • Is it possible to add comments for the prefix arguments (digit-argument, negative-argument and universal-argument)?
  • It'd be great if it were possible to have the comment appear in a popup window rather than in the echo area. (Not necessarily by default, but by using some keyword argument).
  • Is it possible to create chained hydras, where one head calls forth another hydra?

The last two questions are inspired by the menu that org-export-dispatch pops up. I'd be nice to have something similar to that but more general. But perhaps that's not the direction you want to take hydra...

Avoid exiting the hydra on hitting a wrong key.

While testing the Hydra I noticed that sometimes I accidentally quit the hydra 'mode' by clicking the wrong button. As much as I know from reading your blog this is a design decision.

For some hydras it's ok, for others - might be a problem. If you have, say, a simple hydra using only two bindings - it might be alright, as you don't move your hands a lot.

If you use hydra to build a special mode of sorts - a better code browsing mode, for example - chances are that you will click a wrong button at some point, killing the hydra.

So, the question is... Do you plan to implement a way to disable all non-hydra keybindings while using the hydra?

Programmatically creating hydras?

Following up on http://oremacs.com/2015/02/19/hydra-colors-reloaded/#comment-1866197495

I post the example code below, but to get to the point quickly: It probably wouldnโ€™t be difficult to write a macro that generates a call to defhydra based on some the contents of pandoc--binary-options. The problem is that I would like to have a nice menu like the ones generated by the new doc string but that the number of rows and columns in which the hydraโ€™s heads are presented canโ€™t be determined in advance. If the frame is wide, there can be more columns and fewer rows, if it is narrower, there will need to be more rows and fewer columns.

Anyway, to see what I do with the menus: the code creating the menu in pandoc-mode is here:

https://github.com/joostkremers/pandoc-mode/blob/master/pandoc-mode.el#L1522

As an example, I have an alist pandoc--binary-options which contains conses of the form (<descr> . <option>). <descr> is a string that will appear in the menu, <option> is a symbol that is used internally to keep track of the optionโ€™s value. Using this alist, I create a submenu with the following code ineasy-menu-define (starting at line 1613):

("Switches"
     ;; put the binary options into the menu
     ,@(mapcar (lambda (option)
                 (vector (car option) `(pandoc--toggle (quote ,(cdr option)))
                         :active t
                         :style 'toggle
                         :selected `(pandoc--get (quote ,(cdr option)))))
               pandoc--binary-options))

The alist pandoc--binary-options is populated by a macro pandoc-define-binary-option, which takes <descr> and <option> as arguments (and does a few other things as well). This way, when Pandoc adds a new option, I only need to add a single line to pandoc-mode.el, everything else is generated automatically.

Specify an unhelpful hydra

I love how hydras can be helpful, but one of my hydras shows information in the echo area, which is hidden by the hydra help. Is there any way I can disable help just for that hydra?

Ideally, I'd like to just wrap the whole (anonymous) hydra in a (let ...), but that doesn't seem to work.

Enable to define key-chord when hydra on

As a evil user, I bind key-chord "fd" to a function, which enable me to escape from insert state and everything else. So, How can I do that when hydra is active?

I have tryed (key-chord-define hydra-base-map "df" 'pl/escape-dwim) but it not work.

where is hydra-create function?

Hi,

I would like to try hydra package and install it from melpa. When I run this example

(require 'hydra)
(hydra-create "<f2>"
  '(("g" text-scale-increase)
    ("l" text-scale-decrease)))

I got this error message:

Symbol's function definition is void: hydra-create

Did I miss something from the manual?

Support for key-chords and mode-maps

This is an awesome package! Do you have plans to support key-chords and mode-maps? Currently I see that it always does global-set-key.

You already saw the application of key-chords in hydra context.

I find the support of mode-maps even more useful because I always define my bindings in my minor mode that rules them all. I rarely ever bind anything to the global map because I like to have the option to revert back to pristine emacs default bindings by simply disabling that minor mode that ruled them all :)

hydra--face: Unknown color

I tried out the amaranth example in README, and this is what I see: hydra--face: Unknown color for ("l" forward-char)

For quick reference, here's the code:

  (global-set-key
   (kbd "C-z")
   (defhydra hydra-vi
       (:pre
        (set-cursor-color "#40e0d0")
        :post
        (set-cursor-color "#ffffff")
        :color amaranth)
     "vi"
     ("l" forward-char)
     ("h" backward-char)
     ("j" next-line)
     ("k" previous-line)
     ("q" nil "quit")))

nil heads no longer executes :post action?

I have the following hydra (pseudo code):

(defvar vi-motion-init-pos nil)
(defhydra vi-motion
  (:body-pre (progn (set-cursor-color "yellow") (setq vi-motion-init-pos (point)))
   :post (set-cursor-color "red"))
""
  ("h" ...) ;; non-exiting heads
  ("q" (goto-char vi-motion-init-pos) :exit t)
  ("<escape>" nil))

Before MELPA version 20150224.655, pressing the escape key used to be able to restore the cursor color after exiting from the hydra. Now it exits but the cursor color stays in yellow. Pressing "q", on the other hand, still sets the cursor color back to red, in addition to returning to initial position.

I have the two exiting heads for different side effects: "q" returns to the initial position, ESC stays where the point is at after navigation.

I am guessing the fix for #48 might have caused this regression. If that is the desired behavior onwards, is there a workaround?

Hydras don't like commands that prompt you to enter some numbers (like `goto-line`)

Take a Hydra like this:

(defhydra hydra-goto-line (global-map "M-g")
  "goto"
  ("g" goto-line "line"))
(global-set-key (kbd "M-g") 'hydra-goto-line/body)

Invoking it by pressing M-g g will give you the prompt Goto line:. Numbers won't appear, instead, they are interpreted as numerical arguments. Typing 1 0 x will give you ten x's. But after you type letters, you can kill the line and type numbers and they are inputted just fine.

Assigning colors to the head doesn't change the behavior.

Support for :start

Hi there,

I'd love to have a key :start that would be used to execute code initially when starting a hydra but not before each head like :pre.

Here's an example use-case: Entering a ``browse'' mode that pushes your current point to the mark ring so you can return after you've browsed around a bit.

(global-set-key
 (kbd "C-c b")
 (defhydra hydra-browse
     (:start (progn
               (push-mark)
               (set-cursor-color "#e52b50"))
      :post (set-cursor-color "#ffffff")
      :color amaranth)
   "browse"
   ("f" forward-char)
   ("b" backward-char)
   ("n" next-line)
   ("p" previous-line)
   ("a" move-beginning-of-line "beg")
   ("e" move-end-of-line "end")
   ("u" scroll-down-command)
   ("d" scroll-up-command)
   ("q" nil "quit")))

Ruby style heading indentation

Currently, to show the help text for my projectile hydra with good alignment, I need to format it in the defhydra as below:

    (defhydra hydra-projectile (:color teal)
      "
     PROJECTILE

     Find File            Search/Tags          Buffers                Cache
------------------------------------------------------------------------------------------
_s-f_: file            _a_: ag              _i_: Ibuffer           _c_: cache clear
_ff_: file dwim       _g_: update gtags    _b_: switch to buffer  _x_: remove known project
_fd_: file curr dir   _o_: multi-occur     _s-k_: Kill all buffers  _X_: cleanup non-existing
_r_: recent file                                                 _z_: cache current
_d_: dir
"

Here is the full code

That gives me:

clipboard01

If I prettify the alignment in the defhydra code, it messes up the actual alignment.

clipboard01

What's the best workaround to get proper alignment both in the defhydra definition and the visual representation?

Thanks.

binding different keys to same expression broken

First of all, thanks for the wonderful package. I like it very much.

Just upgraded to version 0.11.0 (melpa version 20150223.1403). Binding different keys to same expression is broken. The following hydra used to work:

(bind-key
 "C-c 1"
 (defhydra hydra-foo ()
   "foo"
  ("a" (message "foo"))
  ("b" (message "foo"))
  ("q" nil "quit")))

Now pressing "b" gives this error: "Symbol's function definition is void: hydra-foo/lambda-b"

Head a still works just fine.

UPDATE: Replacing the implicit lambda expressions with a defun makes it work again:

(defun say-foo ()
  (interactive)
  (message "foo"))

(bind-key
 "C-c 1"
 (defhydra hydra-foo ()
   "foo"
  ("a" say-foo)
  ("b" say-foo)
  ("q" nil "quit")))

Adding descriptions to hydra & its heads

It would be nice to be able to have some feedback on currently active hydra. I'm yet to try out the code, but it should be rather easy to change your prime example to:

(require 'hydra)
(hydra-create "<f2>"
  '(("g" text-scale-increase "increase")
    ("l" text-scale-decrease "decrease"))
 "Text scale")

And make it display something like Text scale: <g> increase <l> decrease in minibuffer or popwin window.

I have smth like this in my dot-emacs and since I don't use symbol highlighting very often the hint that appears in the minibuffer (see (message ...)) is very helpful.

Merge hints for mutiple heads bound to the same function [Feature request]

Hi,

I have a defined the following hydra that calls my custom functions and binds them to my custom mode map using bind-key:

(defhydra hydra-font-resize
    (nil "C-x" :bind (lambda (key cmd) (bind-key key cmd modi-mode-map)))
  "font-resize"
  ("_"   modi/font-size-incr  "Increase")
  ("-"   modi/font-size-decr  "Decrease")
  ("C-0" modi/font-size-reset "Reset to default size")
  ("="   modi/font-size-reset "Reset to default size" :bind nil)
  ("0"   modi/font-size-reset "Reset to default size" :bind nil))

Currently the hint is repeating the description for the C-0, = and 0 bindings. If the bound function is identical, modi/font-size-reset in this case, can you merge the hints so that it says something like below?

    font-resize: [_]: Increase, [-]: Decrease, [C-0 / = / 0] Reset to default size

FR: font-locking for `defhydra` macro

I find it useful to have these definition macros fontified, it makes the orientation in your .emacs easier.

Here's a snippet you can use to fontify defhydras like defclass

(font-lock-add-keywords 'emacs-lisp-mode '(("(\\(defhydra\\)\\>[[:blank:]]+\\(.*?\\)\\([[:blank:]]\\|$\\)"
                                                (1 font-lock-keyword-face)
                                                (2 font-lock-type-face))))

Some people might not like it so it would be a good idea to put it under a customize option so it can be disabled.

Sorry I'm too lazy to create a PR, I'm sure you can handle this in 3 minutes time.

Cheers.

When using hydra-create to bind with a minor mode map, it is wiping off my earlier bindings

Hi,

I have created this gist to explain this problem better.

bind-key package is required for the gist code to work.

What the gist does:

  • Create a minor mode called xyz-mode
  • Set xyz-mode-map to have the highest priority.. overrides all global and major/minor mode bindings
  • Binds previous-line command to C-M-o p and next-line command to C-M-o n (just for the sake of demonstrating this issue).
  • Enables the minor mode

After that you will see that C-M-o p calls previous-line as you would expect.

But when below is evaluated, the C-M-o p and all the bindings made earlier to C-M-o prefix are gone!

(hydra-create "C-M-o"
  '(("h" . hydra-move-splitter-left)
    ("j" . hydra-move-splitter-down)
    ("k" . hydra-move-splitter-up)
    ("l" . hydra-move-splitter-right))
  xyz-mode-map)

Hydra with timeout

I'm currently using smartrep to implement key-chords in areas where key-chords are unavailable. I'm trying to migrate to hydra instead.

Take, for example, the following code, which mimics a jj โ‡’ escape from isearch chord.

(defun isearch-exit-chord-worker ()
  "Exit out of isearch after a chord"
  (interactive)
  (execute-kbd-macro (kbd "<backspace> <return>")))

(defhydra isearch-exit-hydra
  (:pre (setq hydra-is-helpful nil)
    :post (setq hydra-is-helpful t))
  ("j" isearch-exit-chord-worker)
  ("k" isearch-exit-chord-worker))

(defun isearch-exit-chord (arg)
  (interactive "p")
  (isearch-printing-char)
  (isearch-exit-hydra/body))

(define-key isearch-mode-map "j" #'isearch-exit-chord)
(define-key isearch-mode-map "k" #'isearch-exit-chord)

The only problem is that it is impossible to actually type jj. I'm my previous solution, I could break out after a certain amount of time has passed (so you can type j wait... j to literally insert), but I haven't figured out how to do that in hydras.

Docstring special characters & spaces

Two things:

  1. I can't seem to get / and 9 (or any number) work in docstrings. Can this be supported?
  2. f in docstring will result in 2 spaces before the word. I think it'd be nice to also allow f in the middle of a word: "in_f_use". I know this would break alignment in the source code where the docstring is defined.

Let Ruby-style Hydra docstrings support sexp.

There's no single variable to check current buffer is narrow or not, you have to use the function `buffer-narrowed-p' to get that. How about let Ruby-style Hydra docstrings support sexp?

(defhydra hydra-toggle (:color pink)
  "
_n_ narrow-or-widen-dwim %`(buffer-narrowed-p)

"
  ("n" narrow-to-region nil)
  ("q" nil "cancel"))

Should `amaranth` be a "color"?

When playing with amaranth hydras, I got struck by what looks to my like an inconsistency in hydra's API:

  • amaranth (or rather, the concept of a hydra that is only killed by predefined keys) is a property related to the hydra's body. It doesn't make sense to inherit this from body to heads.
  • blue/red (or, rather, the concepts of hydra heads that get the hydra killed or not) are properties related to hydra heads.
  • both are orthogonal, i.e. the fact that the body is amaranth or not doesn't necessarily imply that heads should be blue or red.

Therefore, I would suggest:

  1. that different property names be used for these different concepts (instead of the common :color property), so that heads can always inherit from a default value from the body,
  2. optionally, that more meaningful/mnemonic names be chosen for the properties. I know this specific question has already been raised in the blog post introducing colorful hydrae, but I'm raising it again here in case the change related to amaranth hydras would be reason enough to justify a move.

As always, I love hydrae as they are and all these are just suggestions. Please feel free to ignore them.


Just a bit of context here to justify my position:

Like many endless parentheses fans, I have defined a toggle map and a launcher map. Since I don't use them all the time, I use guide-key to help me remember the bindings in them.

I then realized that I could convert these keymaps to hydras with all blue heads. Taking advantage of the inheritance between hydra body and heads greatly reduces the burden of defining this:

(global-set-key
 (kbd "C-x t")
 (defhydra hydra/toggle (:color blue)
   ("c" column-number-mode)
   ("d" toggle-debug-on-error)
   ("f" auto-fill-mode)
   ...))

A bit later I realized that I could improve this by making the hydra amaranth: the toggle/launcher maps would then be error-free. But by doing this, I can't use color inheritance any more, which is a pity:

(global-set-key
 (kbd "C-x t")
 (defhydra hydra/toggle (:color amaranth)
   ("c" column-number-mode :color blue)
   ("d" toggle-debug-on-error :color blue)
   ("f" auto-fill-mode :color blue)
   ...))

Anonymous hydras?

I'd like to programmatically generate hydras at runtime. Is there any way I can avoid polluting the global function space by making anonymous hydras?

I'm sure you can come up with something clever to call them. :)

EDIT: reading more into this, it looks pretty hard to do.

Change cursor color

Hello! Thank you for the hydra!

I want to change cursor color if any head is active. What is the most simple and effective way to call the function which will change the color?

Prefix hydra arguments (one more minor improvement)

One of the issues fixed a few days ago included prefix argument use within a hydra. This is great and certainly helps a lot. I switched to hydra dozens of my custom commands.

But there is a problem with my finger memory: usual non-hydra Emacs commands accept prefix args before the prefix. Think C-u C-z s, where C-z s is bound to a command, which accepts a universal argument.

Now, when the command is within the hydra, I have to the following: `C-z C-u s. This conflicts with my muscle memory, and I believe this is typical for most Emacs users.

Maybe it is possible to pass the hydra args to the first command? So I can do something like C-u C-z s C-u s?

`:exit` not getting overridden

The following hydra has two heads, one red and one blue:

(defhydra test-hydra (:color blue)
  "Test"
  ("e" (message "Exiting now") "blue")
  ("c" (message "Continuing") "red" :color red))

As far as I understand, the following hydra should be identical:

(defhydra test-hydra (:exit t)
  "Test"
  ("e" (message "Exiting now") "blue")
  ("c" (message "Continuing") "red" :exit nil))

However, the second head c is blue rather than red. Is this a bug or am I overlooking something?

Emacs 24.4.1, hydra version 20150221.844 (installed from Melpa).

Single-key escape feature isn't working

So, in your recent blog post about Hydra, you described a way to break out of the Hydra by pressing o in your case (a list with a single element in the Hydra).

That feature doesn't seem to be working for me.

It throws funcall: Symbol's function definition is void: nil when I try.

Any ideas?

Error when trying example

When I try the text zoom example:

(require 'hydra)
(setq hydra-is-helpful t)
(hydra-create "<f2>"
  '(("g" text-scale-increase)
    ("l" text-scale-decrease)))

I get the following error (image, because it won't let me copy or save it all...)

Imgur

I'm not sure how to proceed, but the keybinding doesn't get set at all.

Hydra command to open other hydra

Hi

i was thinking that it would be useful (..for me at least) to have a hydra head to open a "secondary/other" hydra

i tried something like this

("x" hydra-org2 "ins date" :color blue)

and i have this extra hydra to test:

(global-set-key
(kbd "C-M-O")
(defhydra hydra-org2 ()
"extra command "
("t" org-insert-todo-heading-respect-content "insert TODO" :color blue)
("d" org-cut-subtree "org cut" :color blue)
("y" org-copy-subtree "org copy" :color blue)
("p" org-paste-subtree "org paste" :color blue)
("q" nil "cancel")))

is this possible at all? and if so how is the proper way to do so?

thanks alot again for hydra, i love it :)

Z

[feature] Hooks !

Great package. Really.

I am an avid user of guide-key, but the two packages conflict in trying to show helper keys at the same time. To fix the issue, I guess the easier would be to disable guide-key temporaly throught a hydra-pre-hook or similar. The idea might extend to other possible conflicts (and custom advanced features)

What do you think about pre and post hooks ?

Hydra with golden-window-mode

Hi, @abo-abo

First, thanks for this awesome package.

I am using golden-ratio package [1] which can split windows according to golden ratio.
When i call hydra keybinds, the hydra window occupys most of screen like below because it needs to obey golden ratio. Of course, this is not what I want.
image

Golden-ratio offers golden-ratio-exclude-modes function to exclude some modes, but since hydra is not a mode, so it can not help.

But since you are the author, I think maybe you can give a solution. So can you do me a favor?

[1] https://github.com/roman/golden-ratio.el

The lispy example is not great

It actually prevents you from inserting z everywhere, because z will activate Hydra. :)

Of course, it can be amended to:

(hydra-create "z"
  '(("l" forward-char)
    ("h" backward-char)
    ("j" next-line)
    ("k" previous-line)
    ("z" (lambda () (interactive) (insert-char ?z))))
  lispy-mode-map)

But that doesn't feel great either.

Upgrade from version 0.9.0 to 0.10.0: Deactivation of Mark within a hydra

Hi,

It's great to see hydra evolving rapidly.

For hydras (or heads thereof) intended to repeatedly operate on a
pre-defined region, upgrading from hydra 0.9.0 to hydra 0.10.0 seems
to cause a regression: the mark is deactivated after the first
invocation and subsequent head invocations within the hydra state either
fail to perform the intended function or behave different from the first
head invocation in that session e.g. operating on the current line
instead when using a whole-line-or-region function.

The minimal example below is for a subset of the shift-text package from
elpa:

(defhydra hydra-rigid-indent (global-map "C-x")
  "rigid-indent"
  ("<tab>" shift-text-right))

Can you let me know if you need more details please?

Getting stuck in amaranth-mode when mixing red and blue

Starting with emacs -Q:

(let ((default-directory "~/.emacs.d/elpa/"))
    (normal-top-level-add-subdirs-to-load-path))

(require 'hydra)

(defhydra hydra-window (global-map "C-w" :color amaranth)
  "window"
  ("k"   windmove-up "move-up" :color blue)
  ("j"   windmove-down "move-down" :color red)
  ("s"   split-window "split" :color blue))

I load the following and create a few split-windows with C-w s, which works fine. I can move windows up with C-w k just fine as well, but as soon as I use C-w j to try move down a window, the command executes but I get stuck in the amaranth mode with no way to get out. Neither q or C-g help either, so the only way I was able quit was by restarting Emacs.

Never bind a nil cmd

It seems fairly common to use nil heads to define quit keys, and hydra will automatically treat a nil command as an exit point.

It would be convenient to also automatically set :bind to nil for nil commands. Since such a head's only purpose is to exit the hydra, there is no need to create an externally visible binding to my-cool-hydra/nil.

Prefix command arguments

Some of the functions I want to use as hydra heads can make use of a prefix argument. For example, a few projectile commands accept a C-u prefix, thus invalidating project file cache.

Is it possible to do with hydra?

"#<window 22> is not a valid window"

Hi,

after installing the latest version (through Melpa), whenever I quit a hydra, I get an error message the main part of which is #<window 22> is not a valid window. (The window number varies). Setting hydra-lv to nil gets rid of the error.

Note that the exact error message I get varies. I've defined a launcher (blue hydra) much like the one in the README, which gives the following error:

window-normalize-window: #<window 32> is not a valid window

while a red hydra gives:

set-transient-map PCH: (error "#<window 42> is not a valid window")

Any idea what's wrong here?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.