====== Widgets for bindkey ====== Just to hint you at a few widgets, that are already there... ===== Tetris ===== Someone once accused zsh of not being as complete as Emacs, because it lacks Tetris and an adventure game.\\ I like to use ^T (imagine that!) so in my .zshrc file I have: autoload -U tetris zle -N tetris bindkey ^T tetris if you are entering the above into your zshrc with vim, you might have to hit ''^V'' before the ''^T'' (because ''^T'' is already mapped to tab in vim) . In Emacs it's ''C-q C-t'' ===== vi keys - show mode ===== If you are using vi keys and want to know in what mode you currently are, you can use the following: function zle-line-init zle-keymap-select { RPS1="${${KEYMAP/vicmd/-- NORMAL --}/(main|viins)/-- INSERT --}" RPS2=$RPS1 zle reset-prompt } zle -N zle-line-init zle -N zle-keymap-select That adds the desired information to your right side prompt. If you want colors, or you want the information to appear somewhere else, I'm sure you'll figure that one out on your own. :-) ===== Using your $EDITOR ===== ...to modify your commandline: autoload -U edit-command-line zle -N edit-command-line bindkey '\ee' edit-command-line ===== Multiselecting from menus ===== ### menu selection: pick item but stay in the menu ### bind this to 'ESC RETURN' bindkey -M menuselect '\e^M' accept-and-menu-complete ===== How to make a widget changing argument under cursor ===== This is an example of how to make a simple widget that modifies the argument the cursor is currently on (or the previous argument if the cursor is between arguments). To simplify, we'll say "current argument" to refer this. This example will substitute the current argument (which should be a path) by its ''dirname'' and bind the function to Alt-q (which by default does the same thing as Ctrl-q, and so is a free shortcut). ==== Make the widget ==== dirname-previous-word () { autoload -U modify-current-argument modify-current-argument '${ARG:h}' } zle -N dirname-previous-word bindkey '^[q' dirname-previous-word * ''modify-current-argument'' is a ZSH function that does a common task for ZLE widgets that is hard to do by hand. * ''modify-current-argument'' takes an expression, which will be ''eval'' 'ed (so you will likely be escaping it), and then substitutes the "current argument" by the result of the eval'ed expression. * The expression can use the variable ''$ARG'', which contains the value of the so-called "current argument". ==== Put it in a separate file ==== **Warning __/!\__** This part is not certain, and should be tested before relying on it. This will use ''$fpath''. To put the function : - Create an empty directory for putting useful functions (e.g. ''mkdir -p ~/.zsh/functions'') - Create a file named ''dirname-previous-word'' containing the __body__ of the function previously created (lines "autoload ..." and "modify-current-argument ...") in that new directory. To use it, put this into your configuration : - Include that directory into you fpath (e.g. ''fpath=($fpath ~/.zsh/functions'') - Load it with "''autoload -U dirname-previous-word''", and include the lines "''zle -N dirname-previous-word''" and "''bindkey '^[q' dirname-previous-word''" Some notes on ''fpath'' : * A file named X in your ''fpath'' will contain the __body__ of the function X (not the declaration, hence no "''X () {''"), and you will have to do ''autoload X'' * A file named X in your ''fpath'' can contain multiple functions definition. Write ''autoload X; X'', and all of them are loaded and usable then. ==== Another method (more generic) ==== This method still replaces current argument, but gives more liberty on the substitution, for example to do something that just could not fit into a small expression as before. autoload -U split-shell-arguments autoload -U modify-current-argument local res split-shell-arguments ## for positionning on previous argument if cursor is between arguments ## CopyPasta from /usr/share/zsh/functions/Zle/modify-current-argument (maybe BSD license) # Get the index of the word we want. if (( REPLY & 1 )); then # Odd position; need previous word. (( REPLY-- )) # Pretend position was just after the end of it. (( REPLY2 = ${#reply[REPLY]} + 1 )) fi ## EOCopyPasta res=${reply[$REPLY]} res=${res:h} modify-current-argument '$res' In the above code, ''${reply[$REPLY]}'' is the value of the "current argument". We take its dirname of it, set it to the variable ''$res'' and we then use ''modify-current-argument'' to do the final substitution. __Note :__ We escaped ''$res'' when passing it to ''modify-current-argument'' which seems unnecessary, but remember it will be eval'ed, so should ''$res'' contain something ressembling an expression (e.g. with a ''$''), you would be in trouble if you forgot escaping.