.. _intro_zsh_command_line_editing:

Command Line Editing
====================

:literal:`zsh`'s command line editor, :literal:`ZLE`, is quite powerful. It is designed to emulate either emacs or vi; the default is emacs.  To set the bindings for vi mode, type :literal:`bindkey -v`.  If your :literal:`EDITOR` or :literal:`VISUAL` environment variable is vi, :literal:`zsh` will use vi emulation by default.  You can then switch to emacs mode with :literal:`bindkey -e`.

In addition to basic editing, the shell allows you to recall previous lines in the history.  In emacs mode, this is done with :kbd:`Ctrl+P` (control-P) or (on many terminals) with the cursor-up key:

.. code-block:: text
   :caption: History recall with Ctrl+P
   :name: editing_history_ctrl_p

   % ls ~
   -           README      file        mail        pub         tmp
   Mailboxes   bin         func        nicecolors  scr         zsh
   News        etc         iris        notes       src
   % echo foobar
   foobar
   % «Ctrl+P»
   % echo foobar«Ctrl+P»
   % ls ~_

Pressing :kbd:`Ctrl+P` once brings up the previous line (\ :literal:`echo foobar`); pressing it again brings up the line before that (\ :literal:`ls ~`). The cursor is left at the end of the line, allowing you to edit the line if desired before executing it. In many cases, :literal:`ZLE` eliminates the need for the :literal:`fc` command, since it is powerful enough to handle even multiline commands:

.. code-block:: text
   :caption: Recall multiline with Ctrl+P
   :name: editing_history_multiline

   % for i in a b c d e
   > do
   > echo $i
   > done
   a
   b
   c
   d
   e
   % «Ctrl+P»
   % for i in a b c d e 
    do 
    echo $i 
    done_

Now you can just move up to the part you want to change...

.. code-block:: text
   :caption: Edit recalled multiline command
   :name: editing_multiline_cursor

   % for i in _ b c d e
    do 
    echo $i 
    done

change it, and execute the new command.

.. code-block:: text
   :caption: Execute edited multiline loop
   :name: editing_multiline_execute

   % for i in f g h i j
    do 
    echo $i 
    done
   f
   g
   h
   i
   j

Also, you can search the history for a certain command using :kbd:`Esc+P`, this will look for the last command that started with the (part of the) word at the beginning of the current line.  Hitting :kbd:`Esc+P` another time gets you the command before that, etc.

.. code-block:: text
   :caption: History search with Esc+P
   :name: editing_history_search_esc_p

   % set «Esc+P»
   % setopt autolist «Esc+P»
   % setopt nocorrect_

Another way is to do an incremental search, emacs-style:

.. code-block:: text
   :caption: Incremental history search
   :name: editing_incremental_search

   % «Ctrl+R»
   % _
   i-search:
   
   % l_ /usr/bin
   i-search: l
   
   % date > foofile_c
   i-search: le

Suppose you have retrieved an old history event in one of these ways and would like to execute several consecutive old commands starting with this one.  :kbd:`Ctrl+O` will execute the current command and then put the next command from the history into the editor buffer.  Typing :kbd:`Ctrl+O` several times will therefore reexecute several consecutive commands from the history.  Of course, you can edit some of those commands in between.

In addition to completion (see below), :kbd:`Tab` performs expansion if possible.

.. code-block:: text
   :caption: Expand globs with Tab
   :name: editing_glob_expand_tab

   % ls *.c«Tab»
   % ls foofile.c fortune.c rnd.c strfile.c unstr.c_

For example, suppose you have a bunch of weird files in an important directory:

.. code-block:: text
   :caption: List awkward filenames
   :name: editing_weird_filenames

   % ls
     * * *       ; & % $??foo  dspfok        foo.c
     !"foo"!       ` \ `         foo           rrr

You want to remove them, but you don't want to damage :literal:`foo.c`. Here is one way to do this:

.. code-block:: text
   :caption: Expand star with quoting
   :name: editing_expand_star_quoted

   % rm *«Tab»
   % rm \ \ \*\ \*\ \*\ \ \  \!\"foo\"\! \;\ \&\ %\ \$'
   ''
   'foo \`\ \\\ \` dspfok foo foo.c rrr_

When you expand :literal:`*`, :literal:`zsh` inserts the names of all the files into the editing buffer, with proper shell quoting. Now, just move back and remove :literal:`foo.c` from the buffer:

.. code-block:: text
   :caption: Delete all but foo.c
   :name: editing_rm_except_fooc

   % rm \ \ \*\ \*\ \*\ \ \  \!\"foo\"\! \;\ \&\ %\ \$'
   ''
   'foo \`\ \\\ \` dspfok foo _rr

and press return. Everything except :literal:`foo.c` will be deleted from the directory.  If you do not want to actually expand the current word, but would like to see what the matches are, type :kbd:`Ctrl+X`\ g.

.. code-block:: text
   :caption: List matches with Ctrl+X g
   :name: editing_list_matches_ctrl_x_g

   % rm f*«Ctrl+X»g
   foo    foo.c
   % rm f*_

Here's another trick; let's say you have typed this command in:

.. code-block:: text
   :caption: Incomplete gcc command line
   :name: editing_gcc_incomplete

   % gcc -o x.out foob.c -g -Wpointer-arith -Wtrigraphs_

and you forget which library you want.  You need to escape out for a minute and check by typing :literal:`ls /usr/lib`, or some other such command; but you don't want to retype the whole command again, and you can't press return now because the current command is incomplete. In :literal:`zsh`, you can put the line on the :emphasis:`buffer stack`, using :kbd:`Esc+Q`, and type some other commands.  The next time a prompt is printed, the :literal:`gcc` line will be popped off the stack and put in the editing buffer automatically; you can then enter the proper library name and press return (or, :kbd:`Esc+Q` again and look for some other libraries whose names you forgot).

A similar situation: what if you forget the option to gcc that finds bugs using AI techniques?  You could either use :kbd:`Esc+Q` again, and type :literal:`man gcc`, or you could press :kbd:`Esc+H`, which essentially does the same thing; it puts the current line on the buffer stack, and executes the command :literal:`run-help gcc`, where :literal:`run-help` is an alias for :literal:`man`.

Another interesting command is :kbd:`Esc+A`.  This executes the current line, but retains it in the buffer, so that it appears again when the next prompt is printed. Also, the cursor stays in the same place. This is useful for executing a series of similar commands:

.. code-block:: text
   :caption: Repeat similar cc commands
   :name: editing_accept_and_hold

   % cc grok.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out
   % cc fubar.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out
   % cc fooble.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out

The :kbd:`Esc+'` command is useful for managing the shell's quoting conventions.  Let's say you want to print this string:

.. code-block:: text
   :caption: String needing shell quotes
   :name: editing_quote_raw_string

   don't do that; type 'rm -rf \*', with a \ before the *.

All that is necessary is to type it into the editing buffer:

.. code-block:: text
   :caption: Type unquoted awkward string
   :name: editing_quote_typed_line

   % don't do that; type 'rm -rf \*', with a \ before the *.

press :kbd:`Esc+'` (escape-quote):

.. code-block:: text
   :caption: After Esc+' quote-line
   :name: editing_quote_line_result

   % 'don'\''t do that; type '\''rm -rf \*'\'', with a \ before the *.'

then move to the beginning and add the :literal:`echo` command.

.. code-block:: text
   :caption: Echo after quote-line
   :name: editing_quote_echo

   % echo 'don'\''t do that; type '\''rm -rf \*'\'', with a \ before the *.'
   don't do that; type 'rm -rf \*', with a \ before the *.

Let's say you want to create an alias to do this :literal:`echo` command. This can be done by recalling the line with :kbd:`Ctrl+P` and pressing :kbd:`Esc+'` again:

.. code-block:: text
   :caption: Re-quote recalled echo
   :name: editing_quote_for_alias

   % 'echo '\''don'\''\'\'''\''t do that; type '\''\'\'''\''rm -rf
   \*'\''\'\'''\'', with a \ before the *.'\'''

and then move to the beginning and add the command to create an alias.

.. code-block:: text
   :caption: Quoted line as alias
   :name: editing_quote_as_alias

   % alias zoof='echo '\''don'\''\'\'''\''t do that; type '\''\'\'''\''rm
   -rf \*'\''\'\'''\'', with a \ before the *.'\'''
   % zoof
   don't do that; type 'rm -rf \*', with a \ before the *.

If one of these fancy editor commands changes your command line in a way you did not intend, you can undo changes with :kbd:`Ctrl+_`, if you can get it out of your keyboard, or :kbd:`Ctrl+X` :kbd:`Ctrl+U`, otherwise.

Another use of the editor is to edit the value of variables. For example, an easy way to change your path is to use the :literal:`vared` command:

.. code-block:: text
   :caption: Edit PATH with vared
   :name: editing_vared_path

   % vared PATH
   > /u/pfalstad/scr:/u/pfalstad/bin/sun4:/u/maruchck/scr:/u/subbarao/bin:/u/maruc
   hck/bin:/u/subbarao/scripts:/usr/princeton/bin:/usr/ucb:/usr/bin:/bin:/usr/host
   s:/usr/princeton/bin/X11:/./usr/lang:/./usr/etc:/./etc

You can now edit the path.  When you press return, the contents of the edit buffer will be assigned to :literal:`PATH`.
