13

Is there a way to combine two operations into one keybinding (dont think would work with function).

This is what I'd like to do:

I'd like a keybinding (say Ctrl-X) to -

  1. insert some text, then
  2. invoke the complete or menu-complete, using the inserted text as the basis for the completion

I know that I can (in ~/.inputrc) specify

  • Insertion of text with (C-X: "ls")
  • Execute readline commands (C-SPACE: menu-complete)

But I am not sure how to put these together

nhed
  • 5,774
  • 3
  • 30
  • 44

2 Answers2

19

The trick to this is to call functions which rebinds your keys. In my example I'll use C-b to insert text and to call menu-complete, instead of C-x. You'll have to sacrifice a key, in my example C-t

In .bashrc, or a bash file to be sourced

set_Cb_to_insert_text() {
  bind '"\C-m": accept-line'
  bind '"\C-b":"ls \C-t1"'
  bind -x '"\C-t1":set_Cb_to_complete'
}
set_Cb_to_complete() {
  bind '"\C-m":"\C-t2\C-t3"'
  bind '"\C-b": menu-complete'
  bind '"\C-t2": accept-line'
  bind -x '"\C-t3":set_Cb_to_insert_text'
}
set_Cb_to_insert_text

How this works:

With bind, you can bind keys to do one of three things, but no combination of them:

  • Execute a readline command: bind '"key": command'
  • Execute a series of keystrokes: bind '"key":"keystrokes"'
  • Execute a shell command: bind -x '"key": shell-command'

So if you want to combine these three things, you'll need to bind them each to a separate combination of keystrokes (in my example C-t{1,2,3}) and bind a key to execute all these keystrokes.

In the example:

C-b first inserts ls and 'presses' C-t1, which executes set_Cb_to_complete, which in turn rebinds C-b to menu-complete. It also rebinds C-m, carriage return, or Enter, because it now needs to do two things: Accept the line, and reset C-b to insert ls, by calling the set_Cb_to_insert_text function, which also resets Enter to it's normal use.

The reason I said that C-t had to be "sacrificed", is that if you press C-t, readline will wait to see if you are going to press 1, or 2, or any of the bound key sequences, before it takes any action. But when you first have put C-t to this use, you can use it as an initial key for a huge amount of keystrokes to cover all your readline trickery.

Piece of advice: While you are writing and testing these, bind an alternate key to accept-line, because suddenly something breaks the chain at the wrong place, and you are stuck in a terminal without a way to execute commands :)

aktivb
  • 1,952
  • 2
  • 15
  • 16
  • thank you so much for the idea, example and detailed answer (convoluted, yes, but you worked within the the bash+readline framework and their limitations). Over a year after my post I can only remember vaguely what I was trying to do in the big picture ... so I just verified that your example works but will invest more time recreating what I was trying to previously accomplish - Thanks! – nhed Dec 20 '12 at 19:55
4

This might work for you:

"\ex": menu-complete
"\ez": "ls \ex"

Include these lines in your ~/.inputrc file.

These lines set Alt-x to menu-complete and Alt-z to ls space menu-complete. This will give you the first file in the directory and use Alt-x to cycle through the remainder one at a time.

See here for more examples of macros.

Checkout the readline commands by invoking bind -p or bind -P and bind -s will show the macros you already have. See here for the bind command also you can make one off macros too, see here. Lastly check that the .inputrc file is being read, I had trouble because the environmental variable was set to /etc/Inputrc and my personal version was never being invoked.

BTW steer clear of Control-x as it is already in use for many readline commands.

Radu Rădeanu
  • 2,642
  • 2
  • 26
  • 43
potong
  • 55,640
  • 6
  • 51
  • 83
  • This almost does the trick but requires 2 key combos for the subsequent calls. I already had the knowledge of how to bind text insertion and how to bind menu-complete... If I "Alt-z" a second time I would want the display just to show `ls `, but instead I see `ls ls` ... – nhed Dec 03 '11 at 22:33
  • This would imply (and I may be wrong here), that you want the same key combination to toggle it's action. On reading the documentation of the readline library the only conditional precepts are concerned with `mode` i.e. bash, emacs, ftp... Perhaps in this case you may need to write a new readline function see [here](http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC23). BTW Look at this way ... Alt-x and Alt-z are not a million miles apart (well not on my keyboard) and a key combination for menu-complete comes in handy in general. – potong Dec 04 '11 at 05:33
  • Actually, on my mac, the keycombos you mention are only responding to Esc-x, Esc-z, and at that the trailing "\ex" doesn't seem to actually do anything – nhed Dec 05 '11 at 01:39
  • Sorry I don't have a Mac so I don't know the characters to use for one. But a thought just struck me, if you're an emacs user, keyboard macros are recordable too and you can name them and recall them via the .init file. Perhaps using the `M-x shell` or `M-x terminal` is your best bet - good luck. – potong Dec 05 '11 at 06:09