Skip to content

Latest commit

Β 

History

History
181 lines (139 loc) Β· 6.91 KB

line_movement.md

File metadata and controls

181 lines (139 loc) Β· 6.91 KB

Line Movement

Effectively moving around on the command line might be the single biggest time saver. Most of the time you're typing but you'll also be doing a fair deal of line editing and movement.

If you're using arrows to move back and forth you can save a lot of time learning some basic line movement keyboard shortcuts.

Your line movement will depend on your loaded keymaps and the widgets you have bound to different keys. More information about custom widgets can be found in the zle section.

You can manually set your keymap mode with

# emacs mode
bindkey -e

# vi mode
bindkey -v

For the examples below I'll be using vi mode for movement.

If your $EDITOR or $VISUAL environment variables start with vi when the shell starts your keymap mode is automatically set to vi

Keybindings have special characters to represent them. More info can be found in bindkey.

For reference:

  • ^ = Ctrl
  • ^[ = Alt
  • \e or \E = Escape

If you want to figure out how a key sequence should be represented you can try xxd or echo " $keypress". The key letter you press is not case sensitive. So ^a is the same as ^A.

Basic movement

I may like vi mode for my keymap but I'm not a monster. Let's set the emacs begining and end of line keyboard shortcuts and reverse search.

bindkey works by default on your main keymap. In vi mode that is viins so these keybindings work when typing but not in vimcmd mode. To explicitly set a keymap mode use bindkey -M $mode.

bindkey '^r' history-incremental-search-backward
bindkey '^a' beginning-of-line
bindkey '^e' end-of-line
# Also fix annoying vi backspace
bindkey '^?' backward-delete-char

Now I have four ways to get to the begining and end of a command line. I can press Escape,^ or Ctrl+a for the begining of the line, and Escape,$ or Ctrl+e for the end of the line.

With vi mode you have to press escape to enter vicmd mode to enter standard vi commands. The ^ and $ are standard vi commands for beginning and end of a line.

We also probably want some other useful keyboard shortcuts so we don't have to go back and forth between (vicmd) and vi-insert (viins) modes. I personally like these.

bindkey '^[b' vi-backward-blank-word
bindkey '^[w' vi-forward-blank-word

To find widgets you can use, remember to use zle -la to list all widgets and alt+x or esc,: to try the widget with execute-named-cmd.

Modifying Text

Remember, you can use any emacs or vi commands depending on what keymap you're using. You don't have to bind keys to use them.

If you want some additional functionallity check out the examples below.

In general you'll be binding widgets to keyboard shortcuts. There are many *-kill-* widgets available that will let you kill words, lines, or letters.

If you don't want to feel like a murderer you can also try the *-yank-* and *-push-* widgets too.

Advance Word Movements and Modifications

When jumping between words (for example [^f and [^b for forward and backwards in emacs mode). The shell uses a few different things to define what a "word" is. By default you can echo $WORDCHARS to see all the special characters the shell will include as a single word. For example the default is:

$ echo $WORDCHARS
*?_-.[]~=/&;!#$%^(){}<>

This means that any alphanumeric character plus any of the above will be combined to be a single word. Notice how / is included in the above. This means foo/bar-bazz will be one word to be acted upon.

If you are coming from bash and want your jump/delete word functions to stop at / and - you can add this in your .zshrc:

autoload -U select-word-style
select-word-style bash

Without it [^D will delete a full directory path. For example:

## Without
$ cd /project/example/delete
## Press [^D from front beginning of line
$  /project/example/delete
## Press [^D again
$

## With select-word-style bash
$ cd /project/example/delete
## Press [^D from front beginning of line
$  /project/example/delete
## Press [^D again
$ /example/delete

You can learn about the available word styles and their behavior here (search for select-word-syle). But here is a quick explanation:

$ select-word-style
Usage: select-word-style word-style
where word-style is one of the characters in parentheses:
(b)ash:       Word characters are alphanumerics only
(n)ormal:     Word characters are alphanumerics plus $WORDCHARS
(s)hell:      Words are command arguments using shell syntax
(w)hitespace: Words are whitespace-delimited
(d)efault:    Use default, no special handling (usually same as `n')
(q)uit:       Quit without setting a new style

One important thing to note is that any select-word-style that is not normal will may not respect $WORDCHARS. When in normal select-word-style all alphanumeric characters plus anything in $WORDCHARS is used by zsh to determine when to stop its action. If you want even more control feel free to set the var directly. This can then be used to make your backwards jump different than your forwards jump. For example if I want my backward delete to delete a whole directory path I can set this:

## with word-style set to `normal` but $WORDCHARS=''
default-backward-delete-word () {
  local WORDCHARS="*?_[]~=/&;!#$%^(){}<>"
  zle backward-delete-word
}
zle -N default-backward-delete-word
bindkey '^W' default-backward-delete-word

Yank current command and paste

For example, let's say you have a long command line typed up but you forgot you needed to run a command first or look up some information. Normally you would push ctrl+c to cancel the command, run your command, and then use your mouse to select, copy, and paste the long command to the next prompt. Or maybe you open a new terminal, run your command, and come back.

What if I told you there was a better way? Check out the push-input widget.

Let's bind it to ctrl+q and see what it does.

You can also use yank-pop widget to keep a ring of yanked commands you can cycle through.

# re-sets yank and kill shortcuts to bash/emacs mode
bindkey -M viins '^P' push-line-or-edit
bindkey -M viins '^Y' yank
# in order to use the below you must first yank without hitting enter
# subsequent alt-y combos will cycle through
# kill ring
bindkey -M viins '\ey' yank-pop
bindkey -M viins '^U' backward-kill-line

Matching deliminators

There's a handy plugin called autopair that can automatically match your brackets and quotes in your terminal. It works similarly to an IDE and loads an autopair-insert, autopair-close, and autopair-delete widget.

There's also an included surround widget but I had difficulty using it. YMMV.


Previous: completions | home | Next: navigation