branch: master commit 622c798a7efd52ed873c60d80b97c1b5e0366885 Author: Oleh Krehel <ohwoeo...@gmail.com> Commit: Oleh Krehel <ohwoeo...@gmail.com>
README.md: move some stuff to wiki, add more stuff --- README.md | 349 +++++++++++++++++++++++++++---------------------------------- 1 files changed, 155 insertions(+), 194 deletions(-) diff --git a/README.md b/README.md index e0441a0..47ed9cc 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,12 @@ With this simple code, you can: - Zoom in five times at once with <kbd>5g</kbd>. - Stop zooming with *any* key that isn't <kbd>g</kbd> or <kbd>l</kbd>. +For any Hydra: + +- `digit-argment` can be called with <kbd>0</kbd>-<kbd>9</kbd>. +- `negative-argument` can be called with <kbd>-</kbd>. +- `universal-argument` can be called with <kbd>C-u</kbd>. + ### The impressive-looking one Here's the result of pressing <kbd>.</kbd> in the good-old Buffer menu: @@ -45,12 +51,12 @@ The code is large but very simple: :hint nil) " ^Mark^ ^Unmark^ ^Actions^ ^Search -^^^^^^^^----------------------------------------------------------------- (__) -_m_: mark _u_: unmark _x_: execute _R_: re-isearch (oo) -_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_: 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) @@ -74,8 +80,8 @@ _~_: modified ^ ^ ^ ^ ^^ (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 +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. @@ -91,211 +97,187 @@ A good amount of useful hydras are aggregated in projects [community wiki](https://github.com/abo-abo/hydra/wiki/Hydras%20by%20Topic). Feel free to add your own or edit the existing ones. -## Using the functions generated by `defhydra` +## The Rules Hydra-tics -With the example above, you can e.g.: +Each hydra (take `awesome` as a prefix to make it more specific) looks like this: -```cl -(key-chord-define-global "tt" 'hydra-zoom/body) ``` - -In fact, since `defhydra` returns the body symbol, you can even write -it like this: - -```cl -(key-chord-define-global - "tt" - (defhydra hydra-zoom (global-map "<f2>") - "zoom" - ("g" text-scale-increase "in") - ("l" text-scale-decrease "out"))) +(defhydra hydra-awesome (awesome-map awesome-binding awesome-plist) + awesome-docstring + awesome-head-1 + awesome-head-2 + awesome-head-3 + ...) ``` -If you like key chords so much that you don't want to touch the global -map at all, you can e.g.: - -``` -(key-chord-define-global - "hh" - (defhydra hydra-error () - "goto-error" - ("h" first-error "first") - ("j" next-error "next") - ("k" previous-error "prev"))) -``` +### `hydra-awesome` -You can also substitute `global-map` with any other keymap, like -`c++-mode-map` or `yas-minor-mode-map`. +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. -See the [introductory blog post](http://oremacs.com/2015/01/20/introducing-hydra/) for more information. +If you name your hydra `hydra-awesome`, the return result of `defhydra` will be `hydra-awesome/body`. -## Using Hydra for major-mode or minor-mode bindings - -Here's an example: +Here's what `hydra-zoom/body` looks like, if you're interested: ```cl -(defhydra lispy-vi (lispy-mode-map "C-z") - "vi" - ("l" forward-char) - ("h" backward-char) - ("j" next-line) - ("k" previous-line)) +(defun hydra-zoom/body nil + "Create a hydra with a \"<f2>\" body and the heads: + +\"g\": `text-scale-increase', +\"l\": `text-scale-decrease' + +The body can be accessed via `hydra-zoom/body'." + (interactive) + (hydra-disable) + (catch (quote hydra-disable) + (when hydra-is-helpful (hydra-zoom/hint)) + (setq hydra-last + (hydra-set-transient-map + (setq hydra-curr-map + (quote + (keymap (7 . hydra-keyboard-quit) + (108 . hydra-zoom/text-scale-decrease) + (103 . hydra-zoom/text-scale-increase) + (kp-subtract . hydra--negative-argument) + (kp-9 . hydra--digit-argument) + (kp-8 . hydra--digit-argument) + (kp-7 . hydra--digit-argument) + (kp-6 . hydra--digit-argument) + (kp-5 . hydra--digit-argument) + (kp-4 . hydra--digit-argument) + (kp-3 . hydra--digit-argument) + (kp-2 . hydra--digit-argument) + (kp-1 . hydra--digit-argument) + (kp-0 . hydra--digit-argument) + (57 . hydra--digit-argument) + (56 . hydra--digit-argument) + (55 . hydra--digit-argument) + (54 . hydra--digit-argument) + (53 . hydra--digit-argument) + (52 . hydra--digit-argument) + (51 . hydra--digit-argument) + (50 . hydra--digit-argument) + (49 . hydra--digit-argument) + (48 . hydra--digit-argument) + (45 . hydra--negative-argument) + (21 . hydra--universal-argument)))) + t (lambda nil (hydra-cleanup)))) + (setq prefix-arg current-prefix-arg))) ``` -## Can Hydras can be helpful? +### `awesome-map` and `awesome-binding` -They can, if +This can be any keymap, for instance, `global-map` or `isearch-mode-map`. -```cl -(setq hydra-is-helpful t) -``` +For this example: -This is the default setting. In this case, you'll get a hint in the -echo area consisting of current Hydra's base comment and heads. You -can even add comments to the heads like this: - -``` +```cl (defhydra hydra-zoom (global-map "<f2>") "zoom" ("g" text-scale-increase "in") ("l" text-scale-decrease "out")) ``` -With this, you'll see `zoom: [g]: in, [l]: out.` in your echo area, -once the zoom Hydra becomes active. +- `awesome-map` is `global-map` +- `awesome-binding` is `"<f2>"` -## Colorful Hydras - -Since version `0.5.0`, Hydra's heads all have a color associated with them: - -- *red* (default) means the calling this head will not vanquish the Hydra -- *blue* means that the Hydra will be vanquished after calling this head - -In all the older examples, all heads are red by default. You can specify blue heads like this: +And here's the relevant generated code: ```cl -(global-set-key - (kbd "C-c C-v") - (defhydra toggle () - "toggle" - ("a" abbrev-mode "abbrev" :color blue) - ("d" toggle-debug-on-error "debug" :color blue) - ("f" auto-fill-mode "fill" :color blue) - ("t" toggle-truncate-lines "truncate" :color blue) - ("w" whitespace-mode "whitespace" :color blue) - ("q" nil "cancel"))) +(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)) ``` -Or, since the heads can inherit the color from the body, the following is equivalent: +As you see, `"<f2>"` is used as a prefix for <kbd>g</kbd> (char value 103) and <kbd>l</kbd> +(char value 108). + +If you don't want to use a map right now, you can skip it like this: ```cl -(global-set-key - (kbd "C-c C-v") - (defhydra toggle (:color blue) - "toggle" - ("a" abbrev-mode "abbrev") - ("d" toggle-debug-on-error "debug") - ("f" auto-fill-mode "fill") - ("t" toggle-truncate-lines "truncate") - ("w" whitespace-mode "whitespace") - ("q" nil "cancel"))) +(defhydra hydra-zoom (nil nil) + "zoom" + ("g" text-scale-increase "in") + ("l" text-scale-decrease "out")) ``` -The above Hydra is very similar to this code: +Or even simpler: ```cl -(global-set-key (kbd "C-c C-v t") 'toggle-truncate-lines) -(global-set-key (kbd "C-c C-v f") 'auto-fill-mode) -(global-set-key (kbd "C-c C-v a") 'abbrev-mode) +(defhydra hydra-zoom () + "zoom" + ("g" text-scale-increase "in") + ("l" text-scale-decrease "out")) ``` -However, there are two important differences: - -- you get a hint like this right after <kbd>C-c C-v</kbd>: +But then you would have to bind `hydra-zoom/text-scale-increase` and +`hydra-zoom/text-scale-decrease` yourself. - toggle: [t]: truncate, [f]: fill, [a]: abbrev, [q]: cancel. +### `awesome-plist` -- you can cancel <kbd>C-c C-v</kbd> with a command while executing that command, instead of e.g. -getting an error `C-c C-v C-n is undefined` for <kbd>C-c C-v C-n</kbd>. +You can read up on what a plist is in +[the Elisp manual](https://www.gnu.org/software/emacs/manual/html_node/elisp/Property-Lists.html). -## Hydras and numeric arguments - -Since version `0.6.0`, for any Hydra: - -- `digit-argment` can be called with <kbd>0</kbd>-<kbd>9</kbd>. -- `negative-argument` can be called with <kbd>-</kbd> -- `universal-argument` can be called with <kbd>C-u</kbd> +You can use `awesome-plist` to modify the behavior of each head in some way. +Below is a list of each key. -## Hydras can have `:pre` and `:post` statements +#### `:pre` and `:post` -Since version `0.7.0`, you can specify code that will be called before each head, and -after the body. For example: +You can specify code that will be called before each head, and after the body. For example: ```cl -(global-set-key - (kbd "C-z") - (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"))) +(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")) ``` -## New Hydra color: amaranth +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`. -Since version `0.8.0`, a new color - amaranth, in addition to the previous red and blue, is -available for the Hydra body. +### `awesome-head-1` -According to [Wikipedia](http://en.wikipedia.org/wiki/Amaranth): +Each head looks like this: -> The word amaranth comes from the Greek word amaranton, meaning "unwilting" (from the -> verb marainesthai, meaning "wilt"). The word was applied to amaranth because it did not -> soon fade and so symbolized immortality. +```cl +(head-binding head-command head-hint head-plist) +``` -Hydras with amaranth body are impossible to quit with any binding *except* a blue head. -A check for at least one blue head exists in `defhydra`, so that you don't get stuck by accident. +For a head `("g" text-scale-increase "in")`: -Here's an example of an amaranth Hydra: +- `head-binding` is `"g"`. +- `head-command` is `text-scale-increase`. +- `head-hint` is `"in"`. +- `head-plist` is `nil`. -```cl -(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"))) -``` +#### `head-command` + +The `head-command` can be: -The only way to exit it, is to press <kbd>q</kbd>. No other methods will work. You can -use an amaranth Hydra instead of a red one, if for you the cost of being able to exit only -though certain bindings is less than the cost of accidentally exiting a red Hydra by -pressing the wrong prefix. +- command name, like `text-scale-increase`. +- a lambda, like -Note that it does not make sense to define a single amaranth head, so this color can only -be assigned to the body. An amaranth body will always have some amaranth heads and some -blue heads (otherwise, it's impossible to exit), no reds. + ("g" (lambda () + (interactive) + (let ((current-prefix-arg 4)) + (call-interactively #'magit-status))) + "git") -## Generate simple lambdas in-place: +- nil, which exits the hydra. +- a single sexp, which will be wrapped in an interactive lambda. -Since version `0.9.0` it's possible to pass a single sexp instead of a function name or a lambda -to a head. This sexp will be wrapped in an interactive lambda. Here's an example: +Here's an example of the last option: ```cl (defhydra hydra-launcher (:color blue) @@ -308,40 +290,19 @@ to a head. This sexp will be wrapped in an interactive lambda. Here's an example (global-set-key (kbd "C-c r") 'hydra-launcher/body) ``` -## Define Hydra heads that don't show up in the hint at all - -This can be done by setting the head's hint explicitly to `nil`, instead of the usual string. - -## Use a dedicated window for Hydra hints - -Since version `0.10.0`, setting `hydra-lv` to `t` (the default setting) will make it use a dedicated -window right above the Echo Area for hints. This has the advantage that you can immediately see -any `message` output from the functions that you call, since Hydra no longer uses `message` to display -the hint. You can still have the old behavior by setting `hydra-lv` to `nil`. - -## Color table - +#### `head-hint` - | Body Color | Head Inherited | Executing NON-HEADS | Executing HEADS | - |------------+----------------+-----------------------+-----------------| - | amaranth | red | Disallow and Continue | Continue | - | teal | blue | Disallow and Continue | Quit | - | pink | red | Allow and Continue | Continue | - | red | red | Allow and Quit | Continue | - | blue | blue | Allow and Quit | Quit | +In case of a large body docstring, you usually don't want the head hint to show up, since +you've already documented it the the body docstring. +You can set the head hint to `nil` to do this. -## Color to toggle correspondence +Example: -By popular demand, an alternative syntax has been implemented that translates to colors without -using them in the syntax. `:exit` can be used both in body (heads will inherit) and in heads -(possible to override body). `:exit` is nil by default, corresponding to `red` head; you don't need -to set it explicitly to nil. `:foreign-keys` can be used only in body and can be either nil (default), -`warn` or `run`. - - | color | toggle | - |----------+----------------------------| - | red | | - | blue | :exit t | - | amaranth | :foreign-keys warn | - | teal | :foreign-keys warn :exit t | - | pink | :foreign-keys run | +```cl +(defhydra hydra-zoom (global-map "<f2>") + " +Press _g_ to zoom in. +" + ("g" text-scale-increase nil) + ("l" text-scale-decrease "out")) +```