2

I have

(global-set-key (kbd "<C-x-right>") 'other-window)

in my .emacs file.

When I use this keymap, I am able to switch the window one time. When I hit the right arrow key again nothing happens.

How do I have to denote the keymap to that I can use it like this:

  1. C-x *pressed and held*
  2. *press right* to change window
  3. *press right again* change window
  4. *press right again* change window and so on
1
  • 1
    Use (kbd "C-x <right>"), not (kbd "<C-x-right>"). You can use C-h k to see how Emacs denotes a key sequence.
    – Drew
    Commented May 12, 2016 at 20:29

4 Answers 4

2

Solution

Using the hydra package (also available from Melpa/GNU Elpa) could be one of the solutions.

Below hydra-binding style does not take over the whole C-x map.1 The hydra hints will show up only after you hit C-x <right> or C-x <left> for the first time.

After evaluating the below code (or adding it to your config and restarting emacs),

  • You can now do C-x <right> <right> <right> <left> <right> <left> <left> ..
  • Whenever you want to get out of that hydra, hit C-g.

Original

(defhydra hydra-other-window
  (global-map "C-x"
              :color red)
  "other window"
  ("<right>" other-window "→")
  ("<left>" (lambda () (interactive) (other-window -1)) "←"))

Alternative without hints

If you do not want to see any hints, even the "hydra title window" (known as lv in the hydra package), add the below hydra-set-property form2 in addition to the above hydra definition [Reference].

(hydra-set-property 'hydra-other-window :verbosity 0) 

1 That is the "Don't mess with the prefix" style described here.

2 If you get an error saying that hydra-set-property is undefined, ensure that you have the latest version of hydra installed from Melpa.

This is possibly one of the simplest hydras possible. Check out its wiki for more hydra application examples. :)

6
  • Is i possible to not show the "hint" at the bottom when switching between window, since the hint is redundant so such a simple task Commented May 12, 2016 at 21:17
  • @DanielHitzel Please see the updated answer. Commented May 12, 2016 at 21:32
  • 1
    @DanielHitzel I have added a slightly expanded version of his hydra to my config. Commented May 12, 2016 at 21:36
  • nice, I opened a issue here: github.com/abo-abo/hydra/issues/196 Commented May 12, 2016 at 21:44
  • 1
    @DanielHitzel I would not suggest publishing (setq hydra-is-helpful nil) in the answer above (as you suggested in an edit). Because that can cause a lot of confusion, especially to people who use multiple hydras and borrow that customization. In my experience, this is probably the only hydra for which setting hydra-is-helpful to nil is fine. Commented May 13, 2016 at 15:11
2

(Function repeat-command, shown here, is also defined in library misc-cmds.el, but you do not need any library or package outside vanilla Emacs for this simple question. This answer makes use of standard Emacs library repeat.el, but nothing else.)

You can use function repeat-command to "repeatify" any nonrepeatable command. Here it is used to repeatify `other-window'.

(defun repeat-command (command)
  "Repeat COMMAND."
  (let ((repeat-message-function  'ignore))
    (setq last-repeatable-command  command)
    (repeat nil)))

(defun next-window-repeat (count)
  "Select the next window.
With a prefix arg N, select the Nth next window.
A negative prefix arg reverses the direction."
  (interactive "p")
  (require 'repeat)
  (repeat-command `(lambda () (interactive) (other-window ',count))))

(defun previous-window-repeat (count)
  "Select the previous window.
With a prefix arg N, select the Nth previous window.
A negative prefix arg reverses the direction."
  (interactive "p")
  (require 'repeat)
  (repeat-command `(lambda () (interactive) (other-window ',(- count)))))

(global-set-key (kbd "C-x <C-right>") 'next-window-repeat)
(global-set-key (kbd "C-x <C-left>")  'previous-window-repeat)

The problem with what you did is that you bind C-x <right> to other-window, and other-window does not read any key after it has switched you to the other window - it is done. So you have to hit C-x <right> again, to invoke other-window again.

In command other-window-repeat, repeat-command invokes other-window, and then if the last key is hit again, it invokes other-window again...

4
  • I notice that with this solution I cannot perform something like right, right, left, while Hydra allows this behavior. Commented May 12, 2016 at 21:16
  • Correct. With this code you need to interject C-x to change direction: C-x right right C-x left C-x right...
    – Drew
    Commented May 12, 2016 at 22:03
  • Using exactly this code I got void function repeat-command (both in emacs 24.5.1 and 25.0.50.5).
    – JeanPierre
    Commented May 13, 2016 at 7:21
  • @JeanPierre: Oops; sorry. I accidentally deleted the definition of repeat-command the last time I edited it. Should be OK now. Thx.
    – Drew
    Commented May 14, 2016 at 1:44
0

Another approach -- Use any key (e.g., C-x o) for a command that reads the up/down arrow keys to move among the windows. For this you will need library Do Re Mi (doremi.el). (This code is also in doremi-cmd.el.)

(defun doremi-windows+ ()
  "Use up and down arrow keys to cycle among windows of selected frame.
You can use `C-g' to quit and return to the originally selected window."
  (interactive)
  (unless (require 'doremi) (error "You need library `doremi.el' for this command")) 
  (let ((sel-win  (selected-window)))
    (condition-case nil
        (doremi-windows-1)
      (quit (select-window sel-win)))))

(defun doremi-windows-1 ()
  "Helper-function for `doremi-windows+'."
  (doremi (lambda (newval) (select-window newval 'norecord) newval)
          (selected-window)
          nil
          nil
          (reverse (window-list))))

(global-set-key (kbd "C-x o") 'doremi-windows+)
0

Yet another approach -- Similar to the behavior of the answer that uses library Do Re Mi (doremi.el), but using library Icicles instead.

Multi-command icicle-select-window lets you move among windows by cycling using the up/down arrow keys, but by default you need to hold Control pressed while doing that. (And you need to hit RET to end the command to choose the last window selected.)

The reason is this: You can also select windows by name, using completion. Each window is given the name of its buffer (windows showing the same buffer are uniquified with a numerical suffix). And besides completing a name you can cycle among the names (completion candidates) using the arrow keys (without Control). So: arrow keys to cycle among names; Control + arrow keys to cycle among them and select the windows at the same time.

So you can bind, say, C-x o in icicle-mode-map to command icicle-select-window, then use C-x o C-<down> C-<down> C-<down>... to successively select windows.

I said "by default" for the use of Control because you can use M-g in the minibuffer to flip its use, so that instead of needing to use Control + arrow key to act on a completion candidate you can use just the arrow key, and instead of using just the arrow key to cycle among window names you use Control + arrow key.

In that case, you would use just C-x o <down> <down> <down>... (the same as for Do Re Mi).

You can roll this alternative behavior into its own command this way:

(defun my-icy-select-window ()
  "Same as `icicle-select-window' but act without holding `Control'."
  (interactive)
  (let ((orig  icicle-use-C-for-actions-flag))
    (when orig (icicle-toggle-C-for-actions))   ; Same as `M-g`
    (icicle-select-window)
    (when orig (icicle-toggle-C-for-actions)))) ; Same as `M-g`

To bind C-x o (or any other key) to, say, my-icy-select-window you customize user option icicle-top-level-key-bindings to add an entry for it. (Do not try to use define-key with icicle-mode-map.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.