17

The documentation says in section 18.4 Widgets, that a "widget’s job is simply to perform some small action". But I cannot find a general description how to invoke these actions, i.e. how to call a widget.

I've seen in examples (for example see this Q&A) that widgets can bin bound to keys using bindkey KEY WIDGET. Then one can call the widget using KEY.

I wanted to toggle set-local-history and I tried:

$ zle set-local-history 1
zle: widgets can only be called when ZLE is active

zle -h not work, but I've found a description of the arguments here. But it does not seem there is something like --call.

What am I doing wrong? How is it possible to call the widget without bindkey? How can I print the current status? (set-local-history toggles the state)

lindhe
  • 235
lumbric
  • 848

2 Answers2

13

You can execute widget by the widget execute-named-cmd, which is bound to ESC-x (emacs bindings) or : (vi bindings):

execute-named-cmd (ESC-x) (:) (unbound)

Read the name of an editor command and execute it.

This opens up a mini-buffer below the command line, where you can start zle widgets. (Autocompletion is available!):

$ [ESC-x]
execute: set-[TAB]
set-local-history  set-mark-command

To query the state of zle (including local history), use the variable $ZLE_STATE (only accessible inside widget functions):

ZLE_STATE (scalar)

Contains a set of space-separated words that describe the current zle state.

Currently, the states shown are the insert mode as set by the overwrite-mode or vi-replace widgets and whether history commands will visit imported entries as controlled by the set-local-history widget. The string contains insert if characters to be inserted on the command line move existing characters to the right or overwrite if characters to be inserted overwrite existing characters. It contains localhistory if only local history commands will be visited or globalhistory if imported history commands will also be visited.

The substrings are sorted in alphabetical order so that if you want to test for two specific substrings in a future-proof way, you can do match by doing:

if [[ $ZLE_STATE == *globalhistory*insert* ]]; then ...; fi

All quotes from man zshzle.

mpy
  • 27,793
  • 1
    Uh yes, I think I have seen both quotes already, but I did not understand the value in the three braces. The man page says: "These special parameters are always available in widget functions, but are not in any way special outside ZLE." That means, to get ZLE_STATE, I need to define a function and a custom widget, right? – lumbric Dec 23 '13 at 10:09
  • @lumbric : You're right, ZLE_STATE is defined only inside widget functions. I refined my answer. What is your goal? [Wild guess: To indicate local/global history in my prompt I use a widget to (i.) set an shell variable (this is possible inside widgets) and (ii.) execute zle set-local-history.] – mpy Dec 23 '13 at 10:29
  • My primary goal was to understand the concept of zle widgets. Playing around with set-local-history, I wanted to know if it is currently set to global or local. I thought there must be a we to get the current status (similar to calling "setopt" to get the currently enabled options). My original goal was solved already in this Q&A. – lumbric Dec 23 '13 at 15:44
  • 1
    I would expect the string in the if test should be "*globalhistory*insert*" instead of "*insert*globalhistory*", based on reading the sentence before the example? – Volker Siegel Sep 12 '14 at 18:53
  • @VolkerSiegel: A very good point, thanks! I checked with the source code and tried the given example myself, concluding that the example in the man page is wrong, not the statement ("sorted alphabetically"). I edited my answer and will send a path to the zsh-workers mailing list. – mpy Sep 13 '14 at 12:24
  • Does anyone know why you can't call widgets directly without some key binding? Seems rather arbitrary to me and took me a while to accept it until I found this response. – dedeibel Jul 30 '16 at 15:58
  • @dedeibel: This is possbile with the zle-widget execute-named-cmd, which is bound to ALT-x when using emacs bindings. – mpy Aug 06 '16 at 09:22
  • Thanks @mpy but I'll count this as key-binding. I don't understand why someone just can't type "my-widget-function". – dedeibel Aug 19 '16 at 10:52
  • @dedeibel: Because the widget can act on the current command line. -- Why do you need a widget, isn't a normal shell dunction suitable? It would be best if you describe you particular use-case in a new question. – mpy Aug 19 '16 at 18:21
  • @mpy There is no real use case. I just spent a lot of time to realize it was not possible and I still don't understand that limitation. Seems arbitrary. Hoped for a technical explanation - could not find something in the docs. Sorry if I caused confusion and long discussion. – dedeibel Aug 19 '16 at 20:54
2

If you're using tmux you can call the bound key with send-keys.

Examples:

# Current pane
$ tmux send-keys C-r

# Some targeted pane
$ tmux send-keys -t SESSION_NAME:WINDOW_NUMBER.PANE_NUMBER C-z
Eyal Levin
  • 529
  • 5
  • 15