12

In ZSH, how can I use bindkey to bind a key sequence to a script?

lindhe
  • 4,236
  • 3
  • 21
  • 35

3 Answers3

12

I think you do not need widget for that:

bindkey -s '\eb' '/path/to/script.sh\n' 

From zsh docs:

As well as ZLE commands, key sequences can be bound to other strings, by using ‘bindkey -s’.

suside
  • 237
  • 3
    That doesn't bind Alt-B to the script, that causes /path/to/script.sh\n to be inserted as if typed. For instance if you type Alt-B after having entered echo, that will just run the echo /path/to/script.sh command and get you back to an empty prompt (with the echo you had entered earlier gone). – Stéphane Chazelas Aug 13 '16 at 07:21
  • 1
    Yes, you are right. But still inserted as if typed is enough in some use cases. – suside Aug 14 '16 at 09:22
  • 5
    Add an enter at the end of the string and the script will get executed after being inserted, bindkey -s '\eb' '/path/to/script.sh^M' – mihai Jun 03 '17 at 22:38
  • 1
    @mihai Thanks for your comment. It works perfectly. – jdhao Jun 13 '19 at 12:49
8

You can define a widget that calls your script:

my-script_widget() my-script its args
zle -N my-script_widget
bindkey '\ej' my-script_widget

But why would you want to call your script directly from the zle?

If it displays anything, it will mess up the display. If you want its output displayed as other widget messages, you can do:

my-script_widget() zle -M "$(my-script its args)"

Or if you want the output inserted at the cursor:

my-script_widget() LBUFFER+=$(my-script its args)
1

To expand a bit on @suside's answer:

Since bindkey -s just sends key sequences, if theres already something on your prompt and you try and use the binding, it just types it in after whats already at the prompt. This can be fixed by sending kill-whole-line to clear the prompt before typing your command/script in.

kill-whole-line is typically bound to ^u (Ctrl+U), see docs. If its not, you can bind it with:

bindkey '^u' kill-whole-line

Then, you can do:

bindkey -s '\eb' '^u/path/to/script.sh^M'

which binds Alt+b to kill the current line before typing your characters, then sending ^M (newline).