zsh-manual-mdbook/zsh_guide/book/zshguide04.html

2084 lines
124 KiB
HTML
Raw Normal View History

2021-05-17 17:00:52 +02:00
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>The Z-Shell Line Editor - Zsh User&#x27;s Guide</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="zshguide.html">A User's Guide to the Z-Shell</a></li><li class="chapter-item expanded "><a href="zshguide01.html"><strong aria-hidden="true">1.</strong> A short introduction</a></li><li class="chapter-item expanded "><a href="zshguide02.html"><strong aria-hidden="true">2.</strong> What to put in your startup files</a></li><li class="chapter-item expanded "><a href="zshguide03.html"><strong aria-hidden="true">3.</strong> Dealing with basic shell syntax</a></li><li class="chapter-item expanded "><a href="zshguide04.html" class="active"><strong aria-hidden="true">4.</strong> The Z-Shell Line Editor</a></li><li class="chapter-item expanded "><a href="zshguide05.html"><strong aria-hidden="true">5.</strong> Substitutions</a></li><li class="chapter-item expanded "><a href="zshguide06.html"><strong aria-hidden="true">6.</strong> Completion, old and new</a></li><li class="chapter-item expanded "><a href="zshguide07.html"><strong aria-hidden="true">7.</strong> Modules and other bits and pieces Not written</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Zsh User&#x27;s Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
<p><strong>Table of Contents</strong> <em>generated with <a href="https://github.com/thlorenz/doctoc">DocToc</a></em></p>
<ul>
<li><a href="#chapter-4-the-z-shell-line-editor">Chapter 4: The Z-Shell Line Editor</a>
<ul>
<li><a href="#41-introducing-zle">4.1: Introducing zle</a>
<ul>
<li><a href="#411-the-simple-facts">4.1.1: The simple facts</a></li>
<li><a href="#412-vi-mode">4.1.2: Vi mode</a></li>
</ul>
</li>
<li><a href="#42-basic-editing">4.2: Basic editing</a>
<ul>
<li><a href="#421-moving">4.2.1: Moving</a></li>
<li><a href="#422-deleting">4.2.2: Deleting</a></li>
<li><a href="#423-more-deletion">4.2.3: More deletion</a></li>
</ul>
</li>
<li><a href="#43-fancier-editing">4.3: Fancier editing</a>
<ul>
<li><a href="#431-options-controlling-zle">4.3.1: Options controlling zle</a></li>
<li><a href="#432-the-minibuffer-and-extended-commands">4.3.2: The minibuffer and extended commands</a></li>
<li><a href="#433-prefix-digit-arguments">4.3.3: Prefix (digit) arguments</a></li>
<li><a href="#434-words-regions-and-marks">4.3.4: Words, regions and marks</a></li>
<li><a href="#435-regions-and-marks">4.3.5: Regions and marks</a></li>
</ul>
</li>
<li><a href="#44-history-and-searching">4.4: History and searching</a>
<ul>
<li><a href="#441-moving-through-the-history">4.4.1: Moving through the history</a></li>
<li><a href="#442-searching-through-the-history">4.4.2: Searching through the history</a></li>
<li><a href="#443-extracting-words-from-the-history">4.4.3: Extracting words from the history</a></li>
</ul>
</li>
<li><a href="#45-binding-keys-and-handling-keymaps">4.5: Binding keys and handling keymaps</a>
<ul>
<li><a href="#451-simple-key-bindings">4.5.1: Simple key bindings</a></li>
<li><a href="#452-removing-key-bindings">4.5.2: Removing key bindings</a></li>
<li><a href="#453-function-keys-and-so-on">4.5.3: Function keys and so on</a></li>
<li><a href="#454-binding-strings-instead-of-commands">4.5.4: Binding strings instead of commands</a></li>
<li><a href="#455-keymaps">4.5.5: Keymaps</a></li>
</ul>
</li>
<li><a href="#46-advanced-editing">4.6: Advanced editing</a>
<ul>
<li><a href="#461-multi-line-editing">4.6.1: Multi-line editing</a></li>
<li><a href="#462-the-builtin-vared-and-the-function-zed">4.6.2: The builtin vared and the function zed</a></li>
<li><a href="#463-the-buffer-stack">4.6.3: The buffer stack</a></li>
</ul>
</li>
<li><a href="#47-extending-zle">4.7: Extending zle</a>
<ul>
<li><a href="#471-widgets">4.7.1: Widgets</a></li>
<li><a href="#472-executing-other-widgets">4.7.2: Executing other widgets</a></li>
<li><a href="#473-some-special-builtin-widgets-and-their-uses">4.7.3: Some special builtin widgets and their uses</a></li>
<li><a href="#474-special-parameters-normal-text">4.7.4: Special parameters: normal text</a></li>
<li><a href="#475-other-special-parameters">4.7.5: Other special parameters</a></li>
<li><a href="#476-reading-keys-and-using-the-minibuffer">4.7.6: Reading keys and using the minibuffer</a></li>
<li><a href="#477-examples">4.7.7: Examples</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<p><span id="zle"></span><span id="l75"></span></p>
<h1 id="chapter-4-the-z-shell-line-editor"><a class="header" href="#chapter-4-the-z-shell-line-editor">Chapter 4: The Z-Shell Line Editor</a></h1>
<p>The zsh line editor is probably the first part of the shell you ever
used, when you started typing in commands. Even the most basic shells,
such as sh, provide some kind of editing capability, although in that
case probably just what the system itself does --- enter characters,
delete the last character, delete the entire line. Most shells you're
likely to use nowadays do quite a lot more. With zsh you can even extend
the set of editor commands using shell functions.</p>
<p><span id="l76"></span></p>
<h2 id="41-introducing-zle"><a class="header" href="#41-introducing-zle">4.1: Introducing zle</a></h2>
<p>The zsh line editor is usually abbreviated to `zle'. Normally it fires
itself up for any interative shell; you don't have to do anything
special until you decide you need to change its behaviour. If everything
looks OK and you're not interested in how zle is started up, skip to the
next subsection.</p>
<p>Nowadays, zle lives in its own loadable module, <code>zsh/zle</code>, which saves
all the overhead of having an editor if the shell isn't interactive.
However, you normally won't need to worry about that; I'll say more
about modules in <a href="zshguide07.html#ragbag">chapter 7</a>, but the shell
knows when you need zle and gives you it automatically. Usually the
module is in a directory with a name like
`<code>/usr/local/lib/zsh/4.0.4/zsh/zle.so</code>', where the `<code>4.0.4</code>' is the
shell's version number, the same as the value of the parameter
<code>$ZSH_VERSION</code>, and everything after that apart from the suffix `<code>.so</code>'
is the module name. The suffix may be `<code>.sl</code>' (HP-UX) or `<code>.dll</code>'
(Cygwin), but `<code>.so</code>' is by far the most common form. It differs
because zsh keeps the same convention for dynamically loadable
libraries, or `shared objects' in UNIX-speak, as the operating system.</p>
<p>If the shell is badly installed, you sometimes see error messages that
it, or a command such as `bindkey', couldn't be loaded. That means the
shell couldn't find `<code>zsh/zle</code>' anywhere in the module load path, the
array <code>$module_path</code>. Then you need to complain to your system
administrator. If you've just compiled zsh and are having this problem,
it's because you have to install the modules before you run the shell,
even if the shell itself isn't installed. You can do that by saying
`<code>make install.modules</code>'. Then the compiled zsh should run from where
it is.</p>
<p>Note that unlike bash's line editor, readline, which is an entirely
separate library, zle is an integral part of the shell. Hence you
configure it by sticking commands in your <code>.zshrc</code> --- as it's only
useful for an interactive shell, only <code>/etc/zshrc</code> and <code>.zshrc</code> make
sense for this purpose.</p>
<p>One tip if you're looking at the zsh manual using info, either with the
command of that name or <code>\C-h i</code> within Emacs, which I find the most
convenient way: the entry for zle is called `Zsh Line Editor', in full,
not just `Zle'. Have fun looking for `Shell Builtin Commands' (not
`Builtins') while you're at it.</p>
<p><span id="l77"></span></p>
<h3 id="411-the-simple-facts"><a class="header" href="#411-the-simple-facts">4.1.1: The simple facts</a></h3>
<p>As with any editor later than <code>ed</code>, you can move around the line and
change it using various `keystrokes', in other words one or more sets
of keys you type at once. For example, the keystroke to move back a word
is (maybe) <code>ESC b</code>. This means you first hit the escape key; nothing
happens yet. Then you hit `b', and the cursor instantly jumps back to
the start of the word. (I'll have more to say on what zle thinks is a
`word' --- it's not necessarily the same as what the rest of the shell
thinks is a word.)</p>
<p>It will probably help if I introduce the shell's way of describing
keystrokes right away; then when you need to enter them you can just
copy them straight in. The escape key is `<code>\e</code>', so that keystroke
would be `<code>\eb</code>'. Other common keystrokes include holding down the
control key, probably near the bottom left of the keyboard, and typing
another key at the same time. The simplest way of indicate a control key
is just to put `<code>^</code>' in front; so for example `<code>^x^x</code>' means hold down
control, and press `x' twice with control still held down. It has
exactly the same effect as `<code>^X^X</code>'. (You may find each time you do
that it takes you to the start of the line and back to where you were.)</p>
<p>I've already introduced the weasel word `maybe' to try to avoid lying.
This is because actually zle has two modes of operation, one (the
default) like Emacs, the other like vi. If you don't know either of
those venerable UNIX editors, I suggest you stick to Emacs mode, since
it tends to interfere a little less with what you're doing, and
furthermore completion is a little easier. Completion is an offshoot of
zle behaviour which is described in <a href="zshguide06.html#comp">chapter 6</a>
(which, you will notice, is longer than this one).</p>
<p>If you normally use vi, you may have one or both of the environment
variables <code>$EDITOR</code> or <code>$VISUAL</code> set to `<code>vi</code>'. (It all works the same
way if you use `<code>vim</code>' instead, or any editor that happens to contain
`<code>vi</code>' such as `<code>elvis</code>'.) In that case, zle will start up in its
`<code>vi</code>' mode, where the keystrokes are rather different. That's why you
might have found that `<code>\eb</code>' didn't do what I said, even though you
had made no attempt to configure zle. You can make zle always use either
emacs or vi mode by putting either</p>
<pre><code> bindkey -e
</code></pre>
<p>or</p>
<pre><code> bindkey -v
</code></pre>
<p>in your <code>.zshrc</code>. This is just one of many uses of <code>bindkey</code>.</p>
<p>If you're not familiar with this use of the word `bind', it just means
`make a keystroke execute a particular editor command'. Commands have
long-winded names with hyphens which give you quite a good description
of what they do, such as `<code>backward-delete-char</code>'. Normal keys which
correspond to printable characters are usually `bound to
<code>self-insert</code>', a perverse way of saying they do what you expect and
show up the character you typed. However, you can actually bind them to
something else. In vi command mode, this is perfectly normal.</p>
<p>Actually, if you use a windowing system, you might want to say
`<code>bindkey -me</code>', which binds a whole set of `meta' keys. In X Windows,
one of the keys on your keyboard, possibly <code>ALT</code>, may be designated a
`meta' key which has a special effect similar to the control key.
Bindings with the meta key held down are described a bit like they are
in Emacs, `<code>\M-b</code>'. (You can specify control keys similarly, in fact,
like `<code>\C-x</code>', but `<code>^x</code>' is shorter.) Using the `<code>-m</code>' option to
<code>bindkey</code> tells zsh that wherever it binds an escape sequence like
`<code>\eb</code>', it should also bind the corresponding meta sequence like
`<code>\M-b</code>'. Emacs always ties these together, but zsh doesn't --- you can
rebind them separately. and if you want both sequences to be bound to a
new command, you have to bind them both explicitly.</p>
<p>You need to be careful with `<code>bindkey -m</code>', however; the shell can't
tell whether you are typing a character with the top bit set, or
executing a command. This is likely to become worse as the UTF-8
encoding for characters becomes more popular, since a non-ASCII
character then consists of a whole series of bytes with the top bit set.</p>
<p>If you are interested in binding function keys, you may already have
found the key sequences they send apparently don't make any sense; see
<a href="zshguide04.html#fkeys">the section below</a> for more information. This
will introduce the function called <code>zkbd</code> which can make the process
less painful. The function also helps with `meta' and `ALT' keys.</p>
<p><span id="l78"></span></p>
<h3 id="412-vi-mode"><a class="header" href="#412-vi-mode">4.1.2: Vi mode</a></h3>
<p>I'm going to concentrate on Emacs mode for various reasons: firstly,
because I use it myself; secondly, because the most likely reason for
you using vi mode is that you are already familiar with vi and don't
need to be told how it works; thirdly, because most of the commands are
the same in both modes, just bound differently; and finally because if
you <em>don't</em> already know vi, you will quite likely find vi editing mode
rather counterintuitive and difficult to use.</p>
<p>However, here are a few remarks on it just to get it out of the way.
Like the real vi editor, there are two basic modes, insert mode, where
you type in text, and command mode, where the same keystrokes which
insert characters are bound instead to editing commands. Unlike the real
vi, the line editor starts in insert mode on every new command you edit.
This means you can often simply type a line up to the `return' at the
end and forget you are in vi mode at all.</p>
<p>To enter command mode, you hit `escape', again just like normal vi. At
this point you are in the magic world of vi commands, where typing an
ordinary character can have any effect whatsoever. However, the bindings
are similar to normal vi, so `<code>h</code>' and `<code>l</code>' move left and right. When
you want to insert more text, you can use any of the normal vi commands
which allow you to do that, such as `<code>i</code>' (<code>vi-insert</code>) or `<code>a</code>'
(<code>vi-add-next</code>).</p>
<p>Apart from the separate command and insert modes and the completely
different set of key bindings, there is no basic difference between
Emacs mode and vi mode. You can bind keys in both the vi modes --- they
don't <em>have</em> to correspond to <code>self-insert</code> in insert mode. Below, I'll
describe `keymaps', a complete set of descriptions for what all the
keys will do (less impressive than it sounds, since a lot of keys may be
set to `<code>undefined-key</code>, which means they don't do anything useful),
and you will see how to change the behaviour in both modes.</p>
<p><span id="l79"></span></p>
<h2 id="42-basic-editing"><a class="header" href="#42-basic-editing">4.2: Basic editing</a></h2>
<p>If you know Emacs or vi, you will very soon find out how to do simple
commands like moving the cursor, going up and down the history list, and
deleting and copying words. If you don't, you should read the <code>zshzle</code>
manual page for a concise description of what it can do. Here is a
summary for Emacs mode.</p>
<p><span id="l80"></span></p>
<h3 id="421-moving"><a class="header" href="#421-moving">4.2.1: Moving</a></h3>
<p>You can move forwards and backwards along the line using the cursor
keys. The are a variety of different conventions as to what keystrokes
the cursor keys produce. You might naively expect that pressing, say,
cursor right, sends a signal along the lines of `cursor right' to the
application. Unfortunately, there is no such character in the ASCII
character set, so programmes which read input as a string of characters
like zsh have to be given an arbitrary string of characters. (It's
different for programmes which understand other forms of input, like
windowing systems.)</p>
<p>The two most common conventions for cursor keys are where the up key
sends `<code>\e[A</code>' and the other three the same with <code>B</code>, <code>C</code> and <code>D</code> at
the end, and the convention where the `<code>[</code>' is replaced by an `<code>O</code>'
(uppercase letter `O'). In old versions of zsh, the only convention
supported was the first of those two. The second, and any other
convention, were not supported at all and you had to bind the keys
yourself. This was done by something like:</p>
<pre><code> bindkey &quot;\eOA&quot; up-line-or-history
bindkey &quot;\eOB&quot; down-line-or-history
bindkey &quot;\eOC&quot; forward-char
bindkey &quot;\eOD&quot; backward-char
</code></pre>
<p>The shell tries harder now, and provided your system has the correct
information about your terminal (zsh uses an old system called
`termcap' which has largely been superseded by another called
`terminfo') you should be lucky. If the shell thinks your keys are too
perverse --- in particular, if the keystroke it wants to bind the
function too is already defined by zsh --- you will still have to do it
by hand. The list above should serve as a template.</p>
<p>Instead of the cursor keys, traditional Emacs keys are available: <code>^b</code>
and <code>^f</code> for backward and forward, <code>^p</code> and <code>^n</code> for previous line and
next line, so you can continue even if the cursor keys don't work.</p>
<p>Moving longer distances is done by <code>\eb</code> and <code>\ef</code> for a word backwards
or forwards (or, as you saw, <code>\M-b</code> and <code>\M-f</code>), and <code>^a</code> and <code>^e</code> for
the start and the end of the line. That just about exhausts the ones you
will use the most frequently.</p>
<p><span id="l81"></span></p>
<h3 id="422-deleting"><a class="header" href="#422-deleting">4.2.2: Deleting</a></h3>
<p>For deleting, backspace or the delete key will delete backwards. There
is an eternal battle over these keys owing to the fact that on PC
keyboards the key at the top left of the central keyboard section is
`backspace' which is the character <code>^h</code>, while on traditional UNIX
keyboards it is `delete' which is the character 127, often written as
<code>^?</code> (which zsh also understands). When you are in the system's own
primitive line editing mode, as with sh (unless your sh is really bash),
only one of these is `bound', although it's not really a key binding,
it's a translation made by the system's terminal driver, and it's
usually the wrong one. Hence you often find the system prints `<code>^h</code>' on
the screen when you want it to delete. You can change the key using</p>
<pre><code> stty erase '^h'
</code></pre>
<p>but zsh protects you from all that --- both <code>^h</code> (backspace) and <code>^?</code>
(delete) will delete backwards one character. Note, by the way, that zsh
doesn't understand smart names for any keystrokes -- if you try to bind
a key called `<code>backspace</code>' zsh will bind a command to that sequence of
characters, not a key of that name. See comments on `<code>bindkey -s</code>' for
when something like this might even be useful.</p>
<p>To confuse matters further, the key often marked as `Delete' on a 101-
or 102-key PC keyboard in the group of 6 above the cursor keys is
completely different again, and probably doesn't send either of those
sequences. On my keyboard it sends the sequence `<code>\e[3~</code>'. I find it
convenient to have this delete the next charater, which is its tradional
role in the PC world, which I do by</p>
<pre><code> bindkey '\e[3~' delete-char
</code></pre>
<p>However, the tradtional <em>Emacs</em> way of deleting the next character is to
use `<code>^d</code>', which zsh binds for you by default. If you look at the
binding, which you can do by not giving bindkey an editor command to
bind,</p>
<pre><code> % bindkey '^d'
delete-char-or-list
</code></pre>
<p>you'll see it doesn't <em>quite</em> do what I suggested. The `<code>-or-list</code>'
part is for completion, and you'll find out about it in the next
chapter. The first shell I know of to have this odd combination was
tcsh.</p>
<p>Since I enjoy confusion, I might as well point out that usually <code>^d</code> has
another use, which is to tell the terminal driver you've reached the end
of a file. In the case of, say, a file on a disk, the system knows this
by itself, but if you are supplying a stream of characters, the only way
of telling it is to send a special character. The default is usually
<code>^d</code>. You will notice that if you type `<code>^d</code>' at the start of the line,
you see the message</p>
<pre><code> zsh: use 'exit' to exit.
</code></pre>
<p>That's because zsh recognises the <code>^d</code> as end-of-file in that position.
By default the shell warns you; you can turn this off by setting the
option <code>IGNORE_EOF</code>. You can tell the system you don't ever want to send
an end-of-file in this way with <code>stty</code>, again: the following are
equivalent in Linux but your system way want one or the other:</p>
<pre><code> stty eof '^-'
stty eof undef
</code></pre>
<p>Remember that <code>stty</code> is not part of the shell; it's a way of controlling
the state of the system's terminal driver. This means it survives as
long as the terminal or terminal window is still connected, even if you
start a new shell or exit one that isn't the login shell.</p>
<p>By the way, if you need to refer to a character by its number, the
easiest way is probably to use the syntax `<code>\x??</code>', where the `<code>??</code>'
are the two hex digits for the key. In the case of delete, it is
`<code>\x7f</code>'. You can confirm this by:</p>
<pre><code> % bindkey '\x7f'
&quot;^?&quot; backward-delete-char
</code></pre>
<p><span id="l82"></span></p>
<h3 id="423-more-deletion"><a class="header" href="#423-more-deletion">4.2.3: More deletion</a></h3>
<p>You can delete larger areas with `<code>\ed</code>' to delete the next word and
`<code>\e^h</code>' or `<code>\e^?</code>' (escape followed by delete backwards) to delete
the previous word. `<code>^u</code>' usually removes the entire line, before and
after the cursor --- this is not like Emacs, where <code>^u</code> introduces digit
arguments as I will describe in the next subsection. It is, however,
like another of those primitive editing commands the terminal driver
itself provides, this one being known to <code>stty</code> as `<code>kill</code>'. The most
common use of this outside zsh is for deleting your password when you
login, when you know you've typed it wrong but can't see how many
!@?*! characters you've typed, and maybe can't rely on the terminal
agreeing with you as to which of <code>^h</code> or <code>^?</code> will delete a single one.</p>
<p>Strictly speaking, all the keystrokes in the previous paragraph perform
a `kill' (zsh-speak, not to be confused with the <code>stty</code> `kill') rather
than a `delete' (or deletion, as we used to say when we had a distinct
between nouning and verbing). The difference is the same as in Emacs ---
`killed' text is saved for later `yanking' back somewhere else, which
you do with the <code>^y</code> key, whereas `deleted' text as with <code>^?</code> and <code>^d</code>
is gone forever. This is what everyone not brought up under Emacs calls
`cut' and `paste' (although since Emacs dates back to the seventies,
it could be everyone else that's wrong). Another feature borrowed from
Emacs is that if you do multiple `kills' without any other editing in
between, the killed text is joined together and you can yank it all back
in one go. I will say more when I talk about point and mark (another
Emacs idea).</p>
<p>Actually, even deleted text isn't gone forever: zsh has an Emacs-like
editing history, and you can undo the previous commands on the line.
This is usually bound to <code>^xu</code> and <code>^x^u</code>, and there is shorter binding
which is described rather confusingly as `<code>^_</code>' --- confusingly,
because on all not-completely-spaced-out keyboards I've ever used you
actually generate that sequence by holding down control and pressing the
`<code>/</code>' key. Zsh doesn't use <code>^z</code> by default and, if you are used to
Windows, that is another suitable binding for <code>undo</code>.</p>
<p>Zsh scores in one way over Emacs --- it also has `<code>redo</code>', not bound by
default. This means that if you undo to much, you can put back what you
just undid by repeatedly using the <code>redo</code> command.</p>
<p><span id="l83"></span></p>
<h2 id="43-fancier-editing"><a class="header" href="#43-fancier-editing">4.3: Fancier editing</a></h2>
<p><span id="l84"></span></p>
<h3 id="431-options-controlling-zle"><a class="header" href="#431-options-controlling-zle">4.3.1: Options controlling zle</a></h3>
<p>Unlike completion, <code>zle</code> doesn't have many options associated with it;
most of the control is done by key bindings and builtin commands. Only
two are really useful; both control beeps. The option <code>beep</code> can be
unset to tell the shell never to make a noise on an error; the option
<code>histbeep</code> can be unset to disable beeps only in the case of trying to
go back before the first or forward after the last history entry.</p>
<p>The not-very-useful options are <code>zle</code> and <code>singlelinezle</code>. The former
controls whether zle is active at all and isn't that useful because it's
usually on automatically whenever you need it, in other words in
interative shells, and off whenever you don't. It's sometimes useful to
test via `<code>[[ -o zle ]]</code>', however; this lets you make a function do
something cleverer in an interative shell.</p>
<p>The option <code>singlelinezle</code> restricts editing to one line; if it gets too
long, it will be truncated and a `<code>$</code>' printed where the missing bits
are. It's only there for compatibility with ksh and as a safeguard if
your terminal is really screwed up, though even in that case zsh tries
to guess whether everything it needs is available.</p>
<p>Other functions that affect zle include the history functions. These
were described back in <a href="zshguide02.html#init">chapter 2</a>; once you've
set it off, searching through the history works basically the same way
in zle as with the `<code>!</code>' history commands.</p>
<p><span id="l85"></span></p>
<h3 id="432-the-minibuffer-and-extended-commands"><a class="header" href="#432-the-minibuffer-and-extended-commands">4.3.2: The minibuffer and extended commands</a></h3>
<p>The `minibuffer' is yet another Emacs concept; it is a prompt that
appears just under the command line for you to enter some edit required
by the editor itself. Usually, it comes and goes as it pleases and you
don't need to think about it. The most common uses are entering text for
searches, and entering a command which isn't bound to a string. That's
yet another Emacs feature: <code>\ex</code> prompts you to enter the name of a
command. Luckily, since the names tend to be rather long, completion is
available. So typing `<code>echo foo&lt;ESC&gt;xba&lt;TAB&gt;w&lt;TAB&gt;</code>' ends up with:</p>
<pre><code> % echo foo
execute: backward-word
</code></pre>
<p>and hitting return executes that function, taking you to the start of
the <code>foo</code>; you might be able to think of easier ways of doing that. This
does provide a way of running commands you don't often use.</p>
<p>(I hope my notation isn't too confusing. I write things like <code>&lt;TAB&gt;</code>
when I'm showing a single character you hit, to make it stand out from
the surrounding text. However, when I'm not showing text being entered,
I would write that as `<code>\t</code>', which is how you would enter the
character into a key sequence to be bound, or a string to be printed.)</p>
<p>The minibuffer only handles a very limited set of editing commands.
Typing one it doesn't understand usually exits whatever you were trying
to do with the minibuffer, then executes the keystroke. However, in this
particular case, it won't let you exit until you have finished typing a
command; your only other option is to abort. The usual zle abort
character is <code>^g</code>, `<code>send-break</code>'. This is different from the more
drastic <code>^c</code>, which sends the shell itself an interrupt signal. Quite
often they have the same effect in zle, however. (You'll notice <code>^c</code> is
actually `bound to <code>undefined-key</code>', in other words zle doesn't
consider it does anything. However, the terminal driver probably causes
it to send an interrupt, and zle does respond to that.)</p>
<p>Another feature useful with rare commands is `<code>where-is</code>'. Surprise!
it's not bound by default, so typing `<code>&lt;ESC&gt;xwhere-is</code>' is then the way
of runing it. Then you type another editor command at the `<code>Where is:</code>'
prompt, and the shell will tell you what keystrokes, if any, are bound
to it. You can also simply use <code>grep</code> on the output of <code>bindkey</code>, which,
with no arguments, lists all bindings.</p>
<p><span id="l86"></span></p>
<h3 id="433-prefix-digit-arguments"><a class="header" href="#433-prefix-digit-arguments">4.3.3: Prefix (digit) arguments</a></h3>
<p>Many commands can be repeated by giving them a numeric prefix or digit
argument. For example, at the end of a long line of text, type
`<code>&lt;ESC&gt;4&lt;ESC&gt;b</code>'. The `<code>&lt;ESC&gt;b</code>' on its own would take you one word
backwards. The `<code>&lt;ESC&gt;4</code>' passes it the number four and it moves four
words backwards. Generally speaking, this works any time it make sense
to repeat a command. It works for <code>self-insert</code>, too, just repeatedly
inserting the character. If it doesn't work, the prefix argument is
simply ignored.</p>
<p>You can build up long or negative arguments by repeating both the <code>\e</code>
and the digit or `<code>-</code>' after it; for example, `<code>&lt;ESC&gt;-&lt;ESC&gt;1&lt;ESC&gt;0</code>'
specifies minus ten. It varies from command to command how useful
negative numbers are, but they generally switch from backwards to
forwards or similar: `<code>&lt;ESC&gt;-&lt;ESC&gt;4&lt;ESC&gt;\f</code>' is a pointless way of
executing the same as `<code>&lt;ESC&gt;4&lt;ESC&gt;b</code>'.</p>
<p>The shell also has Emacs' `<code>universal-argument</code>' feature, but it's not
bound by default --- in Emacs it is <code>\C-u</code>, but as we've seen that's
already in use. This is an alternative to all those escapes. If you bind
the command to a keystroke (it's absolutely pointless as a shortcut
otherwise), and type that key, then an option minus followed by any
digits are remembered as a prefix. The next keystroke which is not one
of those is then executed as a command, with the prefix formed by the
number typed after <code>universal-argument</code>.</p>
<p>For example, on my keyboard, the key <code>F12</code> sends the key sequence
`<code>\e[[24~</code>' --- see below for how to find out what functions keys send.
Hence I use</p>
<pre><code> bindkey '\e[[24~' universal-argument
</code></pre>
<p>Then if I hit the characters <code>F12</code>, <code>4</code>, <code>0</code>, <code>a</code>, a row of forty `a's
is inserted onto the command line. I'm not claiming this example is
particularly useful.</p>
<p><span id="l87"></span></p>
<h3 id="434-words-regions-and-marks"><a class="header" href="#434-words-regions-and-marks">4.3.4: Words, regions and marks</a></h3>
<p>Words are handled a bit differently in zsh from the way they are in most
editors. First, there is a difference between what Emacs mode and vi
mode consider words. That is to say, there is a difference between the
functions bound by default in those modes; you can use the same
functions in either mode by rebinding the keys.</p>
<p>In both vi and Emacs modes, the same logic about words applies whether
you are moving forward or backward a number of words, or deleting or
killing them; the same amount of text is removed when killing as the
cursor would move in the other case.</p>
<p>In vi mode, words are basically the same as what vi considers words to
be: a sequence of alphanumeric characters together with underscores ---
essentially, characters that can occur in identifiers, and in fact
that's how zsh internally recognises vi `word characters'. There is one
slight oddity about vi's wordwise behaviour, however, which you can
easily see if you type `<code>/a/filename/path/</code>', leave insert mode with
<code>ESC</code>, and use `<code>w</code>' or `<code>b</code>' to go forward or backward by words over
it. It alternates between moving over the characters in a word, and the
characters in the separator `<code>/</code>'.</p>
<p>In Emacs, however, it is done a bit differently. The vi `word
characters' are always considered parts of a word, but there is a
parameter <code>$WORDCHARS</code> which gives a string of characters which are
<em>also</em> part of a word. This is perhaps opposite to what you would
expect; given that alphanumerics are always part of a word, you might
expect there to be a parameter to which you add characters you <em>don't</em>
want to be part of a word. But it's not like that.</p>
<p>Also unlike vi, jumping a word always means jumping to a word character
at the start of a word. There is no extra `turn' used up in jumping
over the non-word characters.</p>
<p>The default value for <code>$WORDCHARS</code> is</p>
<pre><code> *?_-.[]~=/&amp;;!#$%^(){}&lt;&gt;
</code></pre>
<p>i.e. pretty much everything and the kitchen sink. Usually, therefore,
you will want to remove characters which you don't want to be considered
parts of words; `<code>-</code>', `<code>/</code>' and `<code>.</code>' are particularly likely
possibilities. If you want to remove individual characters, you can do
it with some pattern matching trickery (next chapter):</p>
<pre><code> % WORDCHARS=${WORDCHARS//[&amp;.;]}
% print $WORDCHARS
*?_-[]~=/!#$%^(){}&lt;&gt;
</code></pre>
<p>shows that the operation has removed those three characters in the
group, i.e. `<code>&amp;</code>', `<code>.</code>' and `<code>;</code>', from <code>$WORDCHARS</code>. The `<code>//</code>'
indicates a global substitution: any of the characters in the square
brackets is replaced by nothing.</p>
<p>Many other line editors, even those like <code>readline</code> with Emacs bindings,
behave as if only identifier characters were part of a word, i.e. as if
<code>$WORDCHARS</code> was empty. This is very easy to do with a zle shell
function. Recent versions of zsh supply the functions
`<code>bash-forward-word</code>', `<code>bash-kill-word</code>', and a set of other similar
ones, for you to bind to keys in order to have that behaviour.</p>
<p>Other behaviours are also possible by writing functions; for example,
you can jump over real shell words (i.e. individual command arguments)
by using some more substitution trickery, or you can consider only
space-delimited words (though that's not so far from what you get with
<code>$WORDCHARS</code> by adding `<code>&quot;`'\@</code>').</p>
<p><span id="l88"></span></p>
<h3 id="435-regions-and-marks"><a class="header" href="#435-regions-and-marks">4.3.5: Regions and marks</a></h3>
<p>Another useful concept from Emacs is that of regions and marks. In
Emacs-speak `point' is where the cursor is and `mark' is somewhere
where you leave a mark to come back to later. The command to set the
mark at the current point is `<code>^@</code>' as in Emacs, a hieroglyphic which
usually means holding down the control key and pressing the space key.
On some systems, such as the limited version of <code>telnet</code> provided with a
well-known non-UNIX-based windowing system, you can't send this
sequence, and you need to bind a different sequence to
<code>set-mark-command</code>. One possibility is `<code>\e </code>' (escape followed by
space), as in MicroEMACS. (Some X Windows configurations don't allow
<code>^@</code> to work in an xterm, either, though that is usually fixable.)</p>
<p>To continue with Emacs language, the region between point and mark is
described simply as `the region'. In zsh, you can't have this
highlighted, as you might be used to with editors running directly under
windowing systems, so the easiest way to find out the ends of the region
is with <code>^x^x</code>, <code>exchange-point-and-mark</code>, which I mentioned before ---
mark, by default, is left at the beginning of the line, hence the
behaviour you saw above.</p>
<p>Various editing commands --- usually those with `<code>region</code>' in the name
--- operate on this. The most usual are those which kill or copy the
region. Annoyingly, <code>kill-region</code> isn't bound --- in Emacs, it's <code>^w</code>,
but zsh follows the tradition of having that bound to
<code>backward-kill-word</code>, even though that's also available as the
traditional Emacs binding <code>\e^?</code>. So it's probably useful to rebind it.
To copy the region, the usual binding `<code>\ew</code>' works.</p>
<p>You then `yank' back the text copied or killed at another point with
`<code>^y</code>'. The shell implements the `kill ring' feature, which means if
you perform a yank, then type `<code>&lt;ESC&gt;y</code>' (<code>yank-pop</code>) repeatedly, the
shell cycles back through previously killed or copied text, so that you
have more available than just the last one.</p>
<p><span id="l89"></span></p>
<h2 id="44-history-and-searching"><a class="header" href="#44-history-and-searching">4.4: History and searching</a></h2>
<p>Zle has access to the lines saved in the shell's history, as described
in `Setting up history' in <a href="zshguide02.html#init">chapter 2</a>. There are
essentially three ways of retrieving bits of the history: moving back
through it line by line, searching back for a matching line, and
extracting individual words from the history. In fact, the first two are
pretty similar, and there are hybrid commands which allow you to move
back step by step but still matching only particular lines.</p>
<p><span id="l90"></span></p>
<h3 id="441-moving-through-the-history"><a class="header" href="#441-moving-through-the-history">4.4.1: Moving through the history</a></h3>
<p>The simplest behaviour is what you get with the normal cursor key
bindings, `<code>up-line-or-history</code>' and `<code>down-line-or-history</code>'. If you
are in text which fits into a single line (which may be a continuation
line, i.e. it has a new prompt in the form given by <code>$PS2</code> at the start
of the line), this replaces the entire line with the line before or
after in the history. The history is not circular, it has a beginning
and an end. The beginning is the first line still remembered by the
shell (i.e. <code>$HISTSIZE</code> lines back, taking into account that the actual
number of lines present will be modified by the effects of any special
history options you have set to remove unwanted lines); the end is the
line you are typing. You can use <code>\e&lt;</code> and <code>\e&gt;</code> to go to the first and
last line in the history.</p>
<p>The last phrase sounds trivial but isn't quite. Type `<code>echo This is the last line</code>', go back a few lines with the up arrow, and then back down
to the end, and you will see what I mean --- the shell has remembered
the line you were typing, even though it hadn't been entered, so you can
scroll up and down the history and still come back to it.</p>
<p>Of course, you can edit any of the earlier history lines, and hit
`return' so that they are executed --- that's the whole point of being
able to scroll back through the history. What is maybe not so obvious is
that the shell will remember changes you make to these lines, too, until
you hit `return'.</p>
<p>For example, type `<code>echo this is the last line</code>' at a new shell prompt,
but don't hit return. Now hit the up arrow once, and edit the previous
line to say `<code>echo this is the previous line</code>'. If you scroll down and
up, you will see that the shell has kept both of those lines. When you
decide which one to use and hit return, that line is executed and added
to the end of the history, and any changes to previous lines in the
history are forgotten.</p>
<p>Sometimes you don't want to add a new line to history, instead
re-execute a whole series of earlier commands one by one. This can be
done with <code>^o</code>, <code>accept-line-and-down-history</code>. When you hit <code>^o</code> on a
line in the history, that is executed, and the line after it in the
history is shown. So you just need to keep hitting it to keep executing
the commands.</p>
<p>There are two other similar commands I don't use as much,
<code>infer-next-history</code>, bound to <code>^x^n</code>, and
<code>accept-and-infer-next-history</code>, not bound by default. `Inferring' the
next history means that the shell looks at what is in the current line,
whatever its provenance --- you might just have typed it, for example
--- and looks back in the history for a matching line; the `inferred'
next history line is the one following that line. In the first case, you
are simply shown that line; in the second case, the current line is
executed first, then you are shown the inferred line. Feel free to drop
me a line if you find this is the best thing since sliced bread.</p>
<p>One slight confusion about the history is that it can be hard to
remember quite where you are in it, for example, if you were editing a
line and had to scroll back to look for something else. In cases like
this, <code>\e&gt;</code> is your friend, as it takes you the last line. Also,
whenever you hit return, you are guaranteed to be at the end of the
history, even if you were editing a line some back in the history,
unlike certain other systems (though <code>accept-line-and-down-history</code> can
emulate those). So it's usually not too hard to stay unconfused about
what you're editing.</p>
<p><span id="l91"></span></p>
<h3 id="442-searching-through-the-history"><a class="header" href="#442-searching-through-the-history">4.4.2: Searching through the history</a></h3>
<p>Zsh has the commands you would expect to search through the history,
i.e. where you hit a search key and then type in the words to search
for. However, it also has other features, probably more used by the zsh
community, where the search is based on some feature of the current
line, in particular the first word or the line up to the cursor
position. These typically enable you to search backwards more quickly,
since you don't need to tell the shell what you are looking for.</p>
<p><strong>Ordinary searching</strong></p>
<p>The standard search commands, by which I mean the ones your are probably
most familiar with from ordinary text editors (if either Emacs or vi can
be so called), are designed to make Emacs and vi users feel at home.</p>
<p>In Emacs mode, you have incremental search: <code>^r</code> to search backwards ---
this is usually what you want, since you usually start at the end ---
and <code>^s</code> to search forwards. Note that <code>^s</code> is another keystroke which
is often intercepted by the terminal driver; in this case, it usually
freezes output to the terminal until you type <code>^q</code> to turn it back on.
If you don't like this, you can either use `<code>stty stop</code>' and `<code>stty start</code>' to change the characters, or simply `<code>unsetopt flowcontrol</code>' to
turn that feature off altogether. However, the command bound to <code>^s</code>,
<code>history-incremental-search-forward</code>, is also bound to <code>^xs</code>, so you can
use that instead.</p>
<p>As in Emacs, for each character that you type, incremental search takes
you to the nearest history entry that matches all the characters, until
the match fails. Typing the search keystroke again at any point takes
you to the next match for the characters in the minibuffer.</p>
<p>In vi command mode, the keystrokes available by default are the familiar
`<code>/</code>' and `<code>?</code>'. There are various differences from vi, however. First
of all, it is `<code>/</code>' that searches backwards --- this is the one you
will use more often. Secondly, you can't search for regular expressions
(patterns); the only exception is that the character `<code>^</code>' at the start
anchors the search to the start of a line. Everything else is just a
plain string.</p>
<p>The other two standard vi search keystrokes are also present: `<code>n</code>'
searches for the next match of the current string, and `<code>N</code>' does the
same but reverses the direction of the search.</p>
<p><strong>Search for the first word</strong></p>
<p>The next sort of search is probably the most commonly used, but is only
bound in Emacs mode: <code>\ep</code> and <code>\en</code> search forward or backward for the
next history line with the same first word as the current line. So often
to reuse a command you will type just the command name itself, and hit
<code>\ep</code> until the command line you want appears. These commands are called
simply `<code>history-search-backward</code>' and `<code>history-search-forward</code>'; the
name doesn't really describe the function all that well.</p>
<p><strong>Prefix searching</strong></p>
<p>Finally, you can search backwards for a line which has the entire
starting point up to the cursor position the same as the current line.
This gives you a little more control than <code>history-search-</code><em>direction</em>.
The corresponding commands, <code>history-beginning-search-backward</code> and
<code>history-beginning-search-forward</code>, are not bound by default. I find it
useful to have them bound to <code>^xp</code> and <code>^xn</code> since this is similar to
the initial-word searches:</p>
<pre><code> bindkey '^xp' history-beginning-search-backward
bindkey '^xn' history-beginning-search-forward
</code></pre>
<p><strong>Other search commands based on functions</strong></p>
<p>Search commands are one of the types most often customised by writing
shell functions. Some are supplied with the latest versions of the
shell; have a look in the ZLE section of the <code>zshcontrib</code> manual page.
You should find the functions themselves installed somewhere in your
<code>$fpath</code>, typically</p>
<pre><code> /usr/local/share/zsh/$ZSH_VERSION/functions
</code></pre>
<p>or in the subdirectory <code>Zle</code> of that directory, depending how your
version of zsh was installed. If the shell was pre-installed, the most
likely location is</p>
<pre><code> /usr/share/zsh/$ZSH_VERSION/functions/Zle
</code></pre>
<p>These should guide you in writing your own.</p>
<p>One point to note is that when called from a function the
<code>history-search-</code><em>direction</em> and
<code>history-incremental-search-</code><em>direction</em> can take a string argument
specifying what to search for. In the first case, this is just a one off
search, while in the second, you remain in incremental search and the
string is used to prime the minibuffer, so you can edit it. I will later
say much more about writing zle functions, but calling a search command
from a user-defined editing function is as simple as:</p>
<pre><code> zle history-search-backward search-string
</code></pre>
<p>and you can test the return status to see if the search succeeded.</p>
<p><span id="l92"></span></p>
<h3 id="443-extracting-words-from-the-history"><a class="header" href="#443-extracting-words-from-the-history">4.4.3: Extracting words from the history</a></h3>
<p>Sometimes instead of editing a previous line you just want to extract a
word from it into the current line. This is particularly easy if the
word is the last on the line, and the line isn't far back in the
history: just hit <code>\e.</code> repeatedly, and the shell will cycle through the
last word on previous lines. You can give this a prefix argument to pick
the <em>N</em>th from last word on the line just above the last line you picked
a word from. As you can tell from the description, this gets a little
hairy; version 4.1 of the shell will probably provide a slightly more
flexible version.</p>
<p>Although it's strictly not to do with the history, you can copy the
previous word on the current line with <code>copy-prev-word</code>, which for some
reason is bound to <code>\e^_</code>, escape followed (probably) by control and
slash. I have this bound to <code>\e=</code> instead (in some versions of ksh that
key sequence is taken by the equivalent of <code>list-choices</code>). This copies
words delimited by whitespace, but you can copy what the shell would see
as the previous complete argument by using <code>copy-prev-shell-word</code>
instead. This isn't bound by default, as it is newer than the other one,
but it is arguably more useful.</p>
<p>Sometimes you want to complete a word from the history; this is possible
using the completion system, described in the next chapter.</p>
<p><span id="l93"></span></p>
<h2 id="45-binding-keys-and-handling-keymaps"><a class="header" href="#45-binding-keys-and-handling-keymaps">4.5: Binding keys and handling keymaps</a></h2>
<p>There are two topics to cover under the heading of key bindings: first,
how to bind keys themselves, and secondly, keymaps and how to use them.
Manipulating both key bindings and keymaps is done with the <code>bindkey</code>
command. The first topic is the more immediately useful, so I'll start
with that.</p>
<p><span id="l94"></span></p>
<h3 id="451-simple-key-bindings"><a class="header" href="#451-simple-key-bindings">4.5.1: Simple key bindings</a></h3>
<p>You've already seen basic use of <code>bindkey</code> to link editing commands to a
particular sequence of keys. You've seen the shorthand for naming keys,
with <code>\e</code> being escape and <code>^x</code> the character <code>x</code> pressed while the
control key is held down. I even said something about `meta' key
bindings.</p>
<p>Let me now launch into a little more detail. When you bind a key
sequence, which you do with `<code>bindkey</code> <em>key-sequence</em>
<em>editor-command</em>', the <em>key-sequence</em> can consist of as many characters
as you like. It doesn't even matter (much) if some initial set of the
key sequence is already bound. For example, you can do,</p>
<pre><code> bindkey '\eA' backward-word
bindkey '\eAA' beginning-of-line
</code></pre>
<p>Here, I'll follow the shell documentation in referring to <code>\eA</code> as the
prefix of <code>\eAA</code>.</p>
<p>This introduces two points. First, note that the binding for <code>\eA</code> is
distinct from that for <code>\ea</code>; you will see the latter still does
<code>accept-and-hold</code> (in Emacs mode), which means it excutes the current
line, then gives it back to you for editing --- useful for doing a lot
of quite similar tasks. Meanwhile, <code>\eA</code> takes you back a word.</p>
<p>This case sensitivity only applies to alphabetic characters which are a
complete key in their own right, not to those characters with the
control key held down --- <code>^x</code> and <code>^X</code> are identical. (You may have
found there are ways to bind both separately in Emacs when running under
a windowing system, since the windowing system can tell Emacs if the
shift key is held down with the others; it's not that simple if you are
using an ordinary terminal.)</p>
<p>If you entered both those <code>bindkey</code> commands, you may notice that there
is a short pause before <code>\eA</code> takes effect. That's because it's waiting
to see if you type another <code>A</code>. If you do type the extra <code>A</code> during that
pause, you will be taken to the beginning of the line instead. That
pause is how the shell decides whether to execute the prefix on its own.</p>
<p>The time it waits is configurable and is given by the parameter
<code>$KEYTIMEOUT</code>, which is the delay in hundredths of a second. The default
is 40, i.e. four tenths of a second. Its use is usually down to personal
preference; if you don't type very fast, you might want to increase it,
at the expense of a longer delay when you are waiting for the prefix to
be executed. If you are editing on a remote machine over a very slow
link, you also may need to increase it to be able to get full key
sequences which have such a prefix to work at all.</p>
<p>However, the shell only has this ambivalent behaviour if a prefix is
bound in its own right; if the initial key or keys don't mean anything
on their own, it will wait as long as you like for you to type a full
sequence which is bound. This is by far the normal case. The only common
example of a separately bound prefix is in vi insert mode, where <code>&lt;ESC&gt;</code>
takes you back to command mode, while there may be other bindings
starting with <code>\e</code> such as the cursor keys. We'll see below how you can
remove those if they offend your sense of vi purity. (Don't laugh, vi
users are strange.)</p>
<p>Note that if the whole sequence is not bound, after all, the shell will
abort as soon as it reads a complete key sequence which is no longer a
prefix. For example, if you type `<code>\e[</code>', the chances are the shell is
waiting for more, but if you add a `<code>/</code>', say, it will probably decide
you are being silly and abort. The next key you type then starts a new
sequence.</p>
<p><span id="l95"></span></p>
<h3 id="452-removing-key-bindings"><a class="header" href="#452-removing-key-bindings">4.5.2: Removing key bindings</a></h3>
<p>If you want to remove a key binding, you can simply bind it to something
else. Near all uses of the <code>bindkey</code> and <code>zle</code> commands are smart about
removing dead wood in such cases. However you can also use `<code>bindkey -r</code> <em>key-sequence</em>' to remove the binding explicitly. You can also
simply bind the sequence to the command <code>undefined-key</code>; this has
exactly the same effect --- even down to pruning completely any bindings
for long sequences. For example, suppose you bind `<code>\e\C-x\C-x</code>' to a
command, then to <code>undefined-key</code>. All memory that `<code>\e\C-x\C-x</code>' was
ever bound is removed; <code>\e\C-x</code> will no longer be marked as a prefix
key, unless you had some other binding with that prefix.</p>
<p>You can remove all bindings starting with a given prefix by adding the
`<code>-p</code> option. The example given in the manual,</p>
<pre><code> bindkey -rpM viins '\e'
</code></pre>
<p>(except it uses the equivalent form `<code>^[</code>') is amongst the most useful,
as it will remove the annoying delay after you type `<code>\e</code>' to enter vi
command mode. The delay is there because the cursor keys usually also
start with <code>\e</code> and the shell is waiting to see if you actually typed
one of those. So if you can make do without cursor keys in vi insert
mode you may want to consider this.</p>
<p>Note that any binding for the prefix itself is not removed. In this
example, <code>\e</code> stays bound as it was in the <code>viins</code> keymap, presumably to
<code>vi-cmd-mode</code>.</p>
<p>All manipulations like this are specific to one particular keymap. You
need to repeat them with a different <code>-M</code> <em>...</em> option argument, which
is described below, to have the same effect in other keymaps.</p>
<p><span id="l96"></span></p>
<h3 id="453-function-keys-and-so-on"><a class="header" href="#453-function-keys-and-so-on">4.5.3: Function keys and so on</a></h3>
<p><span id="fkeys"></span></p>
<p>It's usually possible to bind the function keys on your keyboard,
including the specially named ones such as `Home' and `Page Up'. It
depends a good deal on how your windowing system or terminal driver
handles them, but these days it's nearly always the case that a well
set-up system will allow the function keys to send a string of
characters to the terminal. To bind the keys you need to find out what
that string is.</p>
<p>Luckily, you are usually aided by the fact that only the first character
of the string is `funny', i.e. does something other than insert a
character. So there is a trick for finding out what the sequence is. In
a shell window, hit <code>^v</code> (if you are using vi bindings, you will need to
be in insert mode), then the function key in question. You will probably
see a string like `<code>^[OP</code>' --- this is what I get from the F1 key. A
note in my <code>.zshrc</code> suggests I used to get `<code>\e[11~</code>', so be prepared
for something different, even if, like me, you are using a standard
xterm terminal emulator. A quick poll of terminal emulators on this
Linux/GNU/XFree86 system suggests these two possibilities are by far the
most popular.</p>
<p>You may even be able to get different sequences by holding down shift or
control as well (after pressing <code>^v</code>, of course). On my keyboard,
combining F1 with shift gives me `<code>^[O2P</code>', with control `<code>^[O5P</code>' and
with both `<code>^[O6P</code>'. Again, your system may do something completely
different.</p>
<p>If you move the cursor back over that `<code>^[</code>', you'll find it's a single
character --- you can position the cursor over the `<code>^</code>', but not the
`<code>[</code>'. This is zsh's way of inserting a real, live escape character
into the line. In fact, if you type</p>
<pre><code> bindkey '
</code></pre>
<p>then <code>^v</code>, the function key, and the other single quote, you have a
perfectly acceptable way of binding the key on the command line. Zsh is
generally quite relaxed about your use of unprintable characters; they
may not show up correctly on your terminal, but the shell is able to
handle all single-byte characters. It doesn't yet have support for those
longer than a single byte, however.</p>
<p>You can also do the same in your <code>.zshrc</code>; the shell will handle strange
characters in input without a murmur. You can also use the two
characters `<code>^[</code>', which is just another way of entering an escape key.
However, the kosher thing to do is to turn it into `<code>\e</code>'. For example,</p>
<pre><code> bindkey '\e[OP' where-is # F1
bindkey '\e[O2P' universal-argument # shift F1
</code></pre>
<p>and so on. Using this, you can give sensible meanings to `Home',
`End', etc. Note the windowing system's sensible way of avoiding the
problem with prefixes --- any extra characters are inserted before the
final character, so the shell can easily tell when the sequence is
complete without having to wait and see if there is more to follow.</p>
<p>There is a utility supplied with zsh called <code>zkbd</code> which can help with
all of this by finding out and remembering the definitions for you. You
can probably use it simply by autoloading it and running it, as it is
usually installed with the other functions. It should be reasonably
self-explanatory, else consult the <code>zshcontrib</code> manual.</p>
<p>If you are using X Windows and are educated enough, you can tinker with
your <code>.Xdefaults</code> file to tweak how keys are interpreted by the terminal
emulator. For example, the following turns the backspace key into a
delete key in anything using a `VT100 widget', which is the basis of
xterm's usual mode of operation:</p>
<pre><code> *VT100.Translations: #override \
&lt;Key&gt;BackSpace: string(0x7F)
</code></pre>
<p>Part of the reason for showing this is that it makes zsh's key binding
system look wonderfully streamlined by comparison. However, tinkering
around at this level gives you very much more control over the use of
key modifiers (shift, alt, meta, control, and maybe even super and hyper
if you're lucky). This is far beyond the scope of this guide --- which I
say, as you probably realise by now, to cover up for not knowing much
about it. Here's another example from Oliver Kiddle, though; it uses
control with the left-cursor key to send an escape sequence: insert</p>
<pre><code> Ctrl&lt;Key&gt;Left: string(0x1b) string(&quot;[159q&quot;) \n\
</code></pre>
<p>into the middle of the example above --- this shows how multiple
definitions are handled. Modern xterms already send special escape
sequences which you can investigate and bind to as I've described.</p>
<p><span id="l97"></span></p>
<h3 id="454-binding-strings-instead-of-commands"><a class="header" href="#454-binding-strings-instead-of-commands">4.5.4: Binding strings instead of commands</a></h3>
<p>It's possible to assign an arbitrary string of characters to a key
sequence instead of an editor command by giving <code>bindkey</code> the option
<code>-s</code>. One of the good things about this is that the string of characters
are reinterpreted by zle, so they can contain active key sequences. In
the old days, this was quite often used as a basic form of macro, to
string together editor commands. For example, the following is a simple
way of moving backward two words by repeating the Emacs mode bindings.
I've used my F1 binding again; yours may be completely different.</p>
<pre><code> bindkey -s '\e[OP' '\eb\eb'
</code></pre>
<p>It's not a good idea to bind a key sequence to another string which
includes itself.</p>
<p>This method has the obvious drawback that if someone comes along and
rebinds `<code>\eb</code>', then F1 will stop working, too. Nowadays, this sort of
task can be done much more flexibly and clearly by writing a
user-defined widget, which is described in a later section. So bindings
of this sort are going a little out of fashion. However, they do provide
quick shortcuts. Two from Oliver Kiddle:</p>
<pre><code> bindkey -s '^[[072q' '^V^I' # Ctrl-Tab
bindkey -s &quot;\C-x\C-z&quot; &quot;\eqsuspend\n&quot;
</code></pre>
<p>You can also quite easily do some of the things you can do with global
aliases.</p>
<p>Remember that `ordinary' characters can be rebound, too; they just
usually happen to have a binding which makes them be inserted directly.
As a particularly pointless example, consider:</p>
<pre><code> bindkey -s secret 'Oh no!'
</code></pre>
<p>If you type `<code>secret</code>' fast enough the letters are swallowed up and
`<code>Oh no!</code>' appears instead. If you pause long enough anywhere in the
middle, the word is inserted just as normal. That's because all parts of
it can be interpreted as prefixes in their own right, so <code>$KEYTIMEOUT</code>
applies at every intervening stage. Less pointlessly, you could use this
as a way of defining abbreviations.</p>
<p><span id="l98"></span></p>
<h3 id="455-keymaps"><a class="header" href="#455-keymaps">4.5.5: Keymaps</a></h3>
<p>So far, all I've said about keymaps is that there are three standard
ones, one for Emacs mode and two for vi mode, and that `<code>bindkey -e</code>'
and `<code>bindkey -v</code>' pick Emacs or vi insert mode bindings. There's no
simple way of picking vi command mode bindings, since that's not usually
directly available but entered by the <code>vi-cmd-mode</code> command, usually
bound to <code>\e</code>, in vi insert mode. (There is a `<code>bindkey -a</code>', but that
doesn't pick the keymap for normal use; it's equivalent to, but less
clear than, `<code>bindkey -M vicmd</code>'.)</p>
<p>Most handling of keymaps is done through <code>bindkey</code>. The keymaps have
short names, <code>emacs</code>, <code>viins</code> and <code>vicmd</code>, for use with <code>bindkey</code>. There
is also a keymap <code>.safe</code> which you don't usually need but which never
changes, so can be used if your experimentation has completely ruined
every other keymap. It only has bindings for <code>self-insert</code> (most keys)
and <code>accept-line</code> (<code>^j</code> and <code>^m</code>), but that's enough to enter commands.</p>
<p>The names are most useful in two places. First, you can use `<code>bindkey -M</code> <em>keymap</em>' to define keys in a particular map:</p>
<pre><code> bindkey -M vicmd &quot;\e[OA&quot; up-line-or-history
</code></pre>
<p>binds the usual up-cursor key in <code>vicmd</code> mode, whatever keymap is
currently set. Actually, any version of the shell which understands the
<code>-M</code> option probably has that bound already.</p>
<p>Secondly, you can force zle to use a particular keymap. This is done in
a slightly non-obvious way: zle always uses the keymap <code>main</code> as the
current keymap (except when it's off in vi command mode, which is
handled a bit specially). To use your own, you need to make <code>main</code> an
alias for that with `<code>bindkey -A</code>'. The order after this is the same as
that after <code>ln</code>: the existing keymap you want to refer to comes first,
then what you want to make an alias for it, in this case <code>main</code>. This
means that</p>
<pre><code> bindkey -A emacs main
</code></pre>
<p>has the same effect as</p>
<pre><code> bindkey -e
</code></pre>
<p>but is more explicit, if a little more baroque. Don't link <code>vicmd</code> to
main, since then you can't use <code>viins</code>, which is bad. Note that
`<code>bindkey -M emacs</code>' doesn't have this effect; it simply lists the
bindings in the <code>emacs</code> keymap.</p>
<p>You can create your own keymaps, too. The easiest way is to copy an
existing keymap, such as</p>
<pre><code> bindkey -N mymap emacs
</code></pre>
<p>which creates (or replaces) <code>mymap</code> and initialises it with the bindings
from <code>emacs</code>. Now you can use <code>mymap</code> just like <code>emacs</code>. The bindings in
each are completely separate. If you finish with a keymap, you can
remove it with `<code>bindkey -D keymap</code>', although you'd better make sure
it's not linked to <code>main</code> first.</p>
<p>You can omit `<code>emacs</code>' to create an empty keymap; this might be
appropriate if your keymap is only going to be used in certain special
places and you want complete control on what goes into it. Currently the
shell isn't very good at letting you apply your own keymaps just in
certain places, however.</p>
<p>There are various other keymaps you might encounter, used in special
circumstances. If you list all keymaps, which is done by `<code>bindkey -l</code>', you may see <code>listscroll</code> and <code>menuselect</code>. These are used by the
new completion system, so if that isn't active, you probably won't see
them. They reside in the module <code>zsh/complist</code>. There will be more about
their effects in <a href="zshguide06.html#comp">chapter 6</a>; <code>listscroll</code> allows
you to move up and down completion lists which more than fill the
terminal window, and <code>menuselect</code> allows you to select items
interactively from a displayed list. You can bind keys in them as with
any other keymap.</p>
<p><span id="l99"></span></p>
<h2 id="46-advanced-editing"><a class="header" href="#46-advanced-editing">4.6: Advanced editing</a></h2>
<p>(In physics, the `advanced wave' is a hypothetical wave which moves
backwards in time. Unfortunately, however useful it would be to meet
deadlines, that's not what I meant by `advanced editing'.)</p>
<p>Here are are a few bits and pieces which go beyond ordinary line editing
of shell commands. Although they haven't been widespread in shells up to
now, I use all of them every day, so they aren't just for the
postgraduate zsh scholar.</p>
<p><span id="l100"></span></p>
<h3 id="461-multi-line-editing"><a class="header" href="#461-multi-line-editing">4.6.1: Multi-line editing</a></h3>
<p>All Bourne-like shells allow you to edit continuation lines; that is, if
the shell can work out for sure that you haven't finished typing, it
will show you a new prompt, given by <code>$PS2</code>, and allow you to continue
where you left off from the previous line. In zsh, you can even see what
it is the shell is waiting for. For a simple example, type
`<code>array=</code>(<code>first</code>' and then `return'. The shell is waiting for the
final parenthesis of the array, and prints `<code>array&gt;</code>' at you, unless
you have altered <code>$PS2</code>. You can continue to add elements to the array
until you close the parentheses.</p>
<p>Shells derived from csh are less happy about continuation lines;
historically, this is because they try to evaluate everything in one go,
and became confused if they couldn't. The original csh didn't have a
particularly sophisticated parser. For once, zsh doesn't have an option
to match the csh behaviour; you just have to get used to the idea that
things work in zsh.</p>
<p>Where zsh improves over other shells is that you aren't just limited to
editing a single continuation line; you can actually edit a whole block
of lines on screen as you would in a full screen editor --- although you
can't scroll off the chunk of lines you're editing, which wouldn't make
sense.</p>
<p>The easiest way of doing this is to hit escape before you type a newline
at the point where you haven't finished typing. Actually, you can do
this any time, even if the line so far is complete. For example,</p>
<pre><code> % print This is line one&lt;ESC&gt;&lt;RET&gt;
print This is line two
</code></pre>
<p>where those angle brackets at the end of the line means you type escape,
then return. Nothing happens, and there is no new prompt; you just type
blithely on. Hit return, unescaped this time, and both lines will be
executed. Note there is no implicit backslash, or anything like that;
when zsh reads the whole caboodle, that escaped carriage return became a
real carriage return, just as the shell would have read it from a
script.</p>
<p>This works because `<code>\e\r</code>' is actually bound to the command
<code>self-insert-unmeta</code>' which means `insert the character you get by
stripping the escape or top bit from what I just typed' --- in other
words, a literal carriage return. You would have got exactly the same
effect by typing <code>^v^j</code>, since the <code>^v</code> likewise escapes the <code>^j</code>
(newline), as it does any other character.</p>
<p>(Aside for the terminally curious only: Why newline here and not
carriage return --- the `enter' key --- as you might expect? That's a
rather grotesque story. It turns out that for mostly historical reasons
UNIX terminal drivers like to swap newline and carriage return, so when
you type carriage return (sent both by that key and by <code>^m</code>, which is
the same as the character represented by <code>\r</code>), it comes out as newline
(on most keyboards, just sent by <code>^j</code>, which is the same as the
character represented by <code>\n</code>). It is the newline character which is the
one you `see' at the end of the line (by virtue of the fact it is the
end of the line). However, <code>^v</code> sees through this and if you type <code>^m</code>
after it, it inserts a literal <code>^m</code>, which just looks like a <code>^m</code>
because that's how zsh outputs it. So that's why that doesn't work.
Actually, <code>self-insert-unmeta</code> would see the <code>^m</code>, too, because that's
what you get when you strip off the <code>\e</code>, but it has a little extra code
to make UNIX users feel at home, and behaves as if it were a newline.
Normally, <code>^j</code> and <code>^m</code> are treated the same way (<code>accept-line</code>), but
the literal characters have different behaviours. If you're now very
confused, just be thankful I haven't told you about the additional
contortions which go on when outputting a newline.)</p>
<p>It probably doesn't seem particularly useful yet, because all you've
done is miss out a new prompt. What makes it so is that you can now go
up and down between the two (or more) lines just using the cursor keys.
I'm assuming you haven't rebound the cursor keys, your terminal isn't a
dumb one which doesn't support cursor up, and the option <code>singlelinezle</code>
isn't in effect --- just unset it if it is, you'll be grateful later.</p>
<p>So for example, type</p>
<pre><code> % if [[ true = false ]]; then&lt;ESC&gt;&lt;RET&gt;
print Fuzzy logic rules&lt;ESC&gt;&lt;RET&gt;
fi
</code></pre>
<p>where I indented that second line just with spaces, because I usually do
inside an `if'. There are no continuation prompts here, just the
original <code>$PS1</code>; that's not a misprint. Now, before hitting return, move
up two lines, and edit <code>false</code> to <code>true</code>. You can see how this can be
useful. Entering functions at the command line is probably a more
typical example.</p>
<p>Suppose you've already gone through a few continuation lines in the
normal way with <code>$PS2</code>'s? You can't scroll back then, even though the
block hasn't yet been edited. There's a magic way of turning all those
continuation lines into a single block: the editor command
<code>push-line-or-edit</code>. If you're not on a continuation line, it acts like
the normal <code>push-line</code> command, which we'll meet below, but for present
purpose you use it when you are on a continuation line. You are
presented with a seamless block of text from the (redrawn) prompt to the
end which you can edit as one. It's quite reasonable to bind
<code>push-line-or-edit</code> instead of <code>push-line</code>, to either <code>^q</code> or <code>\eq</code> (in
Emacs mode, which I will assume, as usual). Be careful with <code>^q</code>, though
--- if the option <code>flowcontrol</code> is set it will probably be swallowed up
by the terminal driver and not get through to the shell, the same
problem I mentioned above for <code>^s</code>.</p>
<p><span id="l101"></span></p>
<h3 id="462-the-builtin-vared-and-the-function-zed"><a class="header" href="#462-the-builtin-vared-and-the-function-zed">4.6.2: The builtin vared and the function zed</a></h3>
<p>I mentioned the <code>vared</code> command in <a href="zshguide03.html#syntax">chapter 3</a>;
it uses the normal line editor to editor a variable, typically a long
one you don't want to have to type in completely like <code>$path</code>, although
you need to remember <em>not</em> to put the `<code>$</code>' in front or the shell will
substitute it before <code>vared</code> is run. However, since it's just a piece of
text like any other input, this, too, can have multiple lines, which you
enter in the same way --- and since a shell parameter can contain
anything at all, you have a pretty general purpose editor. The shell
function `<code>zed</code>' is supplied with the shell and allows you to edit a
file using all the now-familiar commands. Since when editing files you
don't expect a carriage return to dump you out of the editor, just to
insert a new line, zed rebinds carriage return to <code>self-insert-unmeta</code>
(the `<code>-unmeta</code>' here is just to get the swapping behaviour of turning
the carriage return into a newline). To save and exit, you can type
<code>^j</code>, or, if your terminal does something odd with that, you can also
use <code>^x^w</code>, which is designed to look like Emacs' way of writing a file.</p>
<p>If you look at <code>zed</code>, you will see it has a few bells and whistles ---
for example, `<code>zed -f</code>' allows you to edit a function --- but the code
to read a file into a parameter, edit the parameter, and write the
parameter back to the file is extremely simple; all the hard editing
code is already handled within <code>vared</code>. Indeed, <code>zed</code> is essentially a
completely general purpose editor, though it quickly becomes inefficient
with long files, particularly if they are larger than a single screen;
as you would expect, zle was written to cope efficiently with short
chunks of text.</p>
<p>It would probably be nice if you could make key bindings that only
applied within vared by using a special keymap. That may happen one day.</p>
<p>By the way, note that you can edit arrays with vared and it will handle
the different elements sensibly. As usual, whitespace separates
elements; when it presents you with an array which contains whitespace
within elements, vared will precede it with a backslash to show it isn't
a separator. You can insert quoted spaces with backslashes yourself.
Only whitespace characters need this quoting, and only backslashes work.</p>
<p>For example,</p>
<pre><code> array=('one word' 'two or more words')
vared array
</code></pre>
<p>presents you with `<code>one\ word two\ or\ more\ words</code>'. If you add `<code> and\ some\ more.</code>', hit return, and type `<code>print -l $array</code>' to show
one element per line you will see</p>
<pre><code> one word
two or more words
and some more.
</code></pre>
<p>Some older versions of the shell were less careful about spaces within
elements.</p>
<p><span id="l102"></span></p>
<h3 id="463-the-buffer-stack"><a class="header" href="#463-the-buffer-stack">4.6.3: The buffer stack</a></h3>
<p>The mysterious other use for <code>push-line-or-edit</code> will now be explained.
Let's stick to <code>push-line</code>, in fact, since I've already dealt with the
<code>-or-edit</code> bit.</p>
<p>Type</p>
<pre><code> print I was just in the directory
</code></pre>
<p>(no newline). Oh dear, which directory were you just in? You don't want
to interrupt the flow of text to find out. Hit `<code>\eq</code>'; the line you've
been typing disappears --- but don't worry, it hasn't gone. Now type</p>
<pre><code> dirs
</code></pre>
<p>Two things happen: that last line is executed, of course, showing the
list of directories on the directory stack (your use of <code>pushd</code> and
<code>popd</code>), but also the line you got rid of before has reappeared, so you
can continue to edit it.</p>
<p>You may not realise straight away quite how useful this is, but I used
it several times just while I was writing the previous paragraph. For
example, I was alternating directories between the zle source code and
the directory where I keep this guide, and I started typing a `<code>grep</code>'
command before realising I was in the wrong directory. All I need to do
is type <code>\eq</code>, then <code>pushd</code>, to put me where I want to be, and finish
off the <code>grep</code>.</p>
<p>The `buffer stack', which is the jargon for this mechanism, can go as
deep as you like. It's a last-in-first-out (LIFO) stack, so the line
pushed onto it by the most recently typed <code>\eq</code> will reappear first,
followed by the back numbers in reverse order. You can even prime the
buffer stack from a function --- not necessarily a zle function, though
that works too --- with `<code>print -z</code> <em>command-line</em>'.</p>
<p>You can pull something explicitly off the stack, if you want, by typing
<code>\eg</code>, but that has the same effect as clearing the current line and
hitting return. You can of course push the same line multiple times: if
you need to do a whole series of things before executing it, just hit
<code>\eq</code> again each time the line pops back up.</p>
<p>I lied a little bit, to avoid confusion. The cleverness of
<code>push-line-or-edit</code> about multi-line buffers extends to the this case,
too. If you do a normal <code>push-line</code> on a multi-line buffer, only the
current single line is pushed; the command to push the whole lot, which
is probably what you want, is <code>push-input</code>. But if you have
<code>push-line-or-edit</code> bound, you can forget the distinction, since it will
do that for you. If you've been paying attention you can work out the
following sequence (assuming <code>\eq</code> has been rebound to
<code>push-line-or-edit</code>):</p>
<pre><code> % if [[ no = yes ]]; then
then&gt; print&lt;ESC&gt;q&lt;ESC&gt;q
</code></pre>
<p>The first <code>\eq</code> turns the two lines into a single buffer, then the
second pushes the whole lot onto the buffer stack. This saves a lot of
thinking about bindings. Hence I would recommend users of Emacs mode add</p>
<pre><code> bindkey '\eq' push-line-or-edit
</code></pre>
<p>to their <code>.zshrc</code> and forget the distinctions.</p>
<p><span id="l103"></span></p>
<h2 id="47-extending-zle"><a class="header" href="#47-extending-zle">4.7: Extending zle</a></h2>
<p>We now come to the newest and most flexible part of zle, the ability to
create new editing commands, as complicated as you like, using shell
functions. This was originally introduced by Andrew Main (`Zefram') in
zsh 3.1 and so is standard in all versions of zsh 4, although work goes
on.</p>
<p><span id="l104"></span></p>
<h3 id="471-widgets"><a class="header" href="#471-widgets">4.7.1: Widgets</a></h3>
<p>If you don't speak English as you first language, first of all,
congratulations for getting this far. Secondly, you may think of
`widget' only as a technical word applied to the object which realises
some computational idea, like the thing that implements text editing in
a window system, for example. However, to most English speakers,
`widget' is a humorous word for an object, a bit like
`whatyoumacallit' or `thingummybob', as in `where's that clever
widget that undoes the foil and takes out the cork in one go'. Zsh's use
has always seemed to me closer to the second, non-technical version, but
I may be biased by the fact that the internal object introduced by
Zefram to represent a widget, and never seen by the user, is called a
`thingy', which I won't refer to again since you don't need to know.</p>
<p>Anyway, a `widget' is essentially what I've been calling an editor
command up to now, something you can bind to a key sequence. The reason
the more precise terminology is useful is that as soon as you have shell
functions flying around, the word `command' is hopelessly non-specific,
since functions are full of commands which may or may not be widgets. So
I make no apology for using the word.</p>
<p>So now we are introducing a second type of widget: one which, instead of
something handled by code built into the shell, is handled by a function
written by the user. They are completely equivalent; <code>bindkey</code> and
company don't care which it is. All you need to do to create a widget is</p>
<pre><code> zle -N widget-name function-name
</code></pre>
<p>then <em>widget-name</em> can be used in <code>bindkey</code>, or <code>execute-named-cmd</code>, and
the function <em>function-name</em> will be run. If the <code>widget-name</code> and
<code>function-name</code> are the same, which is often the simplest thing to do,
you just need one of them.</p>
<p>You can list the existing widgets by using `<code>zle -l</code>', although often
`<code>zle -lL</code>' is a better choice since the output format is then the same
as the form you would use to define the widget. If you see lots of
`<code>zle -C</code>' widgets when you do that, ignore them for now; they are
completion widgets, handled a bit differently and described in <a href="zshguide06.html#comp">chapter
6</a>.</p>
<p>Now you need to know what should go into the function.</p>
<p><span id="l105"></span></p>
<h3 id="472-executing-other-widgets"><a class="header" href="#472-executing-other-widgets">4.7.2: Executing other widgets</a></h3>
<p>The simplest thing you can do inside a function implementing a widget is
call an existing function. So,</p>
<pre><code> my-widget() {
zle backward-word
}
zle -N my-widget
</code></pre>
<p>creates a widget called <code>my-widget</code> which behaves in every respect
(except speed) like the builtin widget <code>backward-word</code>. You can even
give it a prefix argument, which is passed down; <code>\e3</code> then whatever you
bound the widget to (or <code>\exmy-widget</code>) will go backward three words.</p>
<p>Suppose you wanted to pass your own prefix argument to <code>backward-word</code>,
instead of what the user typed? Or suppose you want to take account of
the prefix argument, but do something different with it? Both are
possible.</p>
<p>Let's take the first of those. You can supply a prefix argument for this
command alone by putting <code>-n</code> <em>argument</em> after the widget name (note
this is not where most options go).</p>
<pre><code> my-widget() {
zle backward-word -n 2
}
</code></pre>
<p>This always goes backwards two words, overriding any numeric argument
given by the user. (You can redefine the function without telling zle
about it, by the way; zle just calls whatever function happens to be
defined when the widget is run.) If you put just <code>-N</code> after the name
instead, it will cancel out any prefix given by the user, without
introducing a new one.</p>
<p>The other part of prefix handling --- intercepting the one the user
specified and maybe modifying it --- introduces one of the most
important parts of user-defined widgets. Zle provides various parameters
which can be read and often written to alter the behaviour of the editor
or even the text being edited. In this case, the parameter is <code>$PREFIX</code>.
For example,</p>
<pre><code> my-widget() {
zle backward-word -n $(( ${NUMERIC:-1} * 2 ))
}
</code></pre>
<p>This uses an arithmetic substitution to provide an argument to
<code>backward-word</code> which is twice what the user gave. Note that
<code>${NUMERIC:-1}</code> notation, which is important: most of the time, you
don't give a numeric argument to a command at all, and in that case zle
naturally enough treats <code>$NUMERIC</code> as if it wasn't set. This would mess
up the arithmetic substitution.</p>
<p>By the way, if you do make an error in a shell function, you won't see
it; you'll just get a beep, unless you've turned that off with <code>setopt nobeep</code>. The output from such functions is junked, since it would mess
up the display. So you should do any basic debugging before turning the
function into a widget, for example, stick a <code>print</code> in front and run it
directly --- you can't execute widgets from outside the editor.</p>
<p>The following also works:</p>
<pre><code> my-widget() {
(( NUMERIC = ${NUMERIC:-1} * 2 ))
zle backward-word
}
</code></pre>
<p>because you can alter <code>$NUMERIC</code> directly, and unless overridden by the
<code>-n</code> argument it is used by any widgets called from the function. If you
called more widgets inside the function --- and you can call as many as
you like --- the same argument would apply to all the ones that didn't
have an explicit <code>-n</code> or <code>-N</code>.</p>
<p>Some widgets allow you to specify non-numeric arguments. At the moment
these are mainly search functions, which you can give an explicit search
string. Usually, however, you want to specify a new search string each
time. The most useful way of using this I can see is to provide an
initial argument for incremental search commands. Later, I'll show you
how you can read in characters in a similar fashion to Emacs mode's <code>^r</code>
binding, <code>history-incremental-search-backwards</code>.</p>
<p><span id="l106"></span></p>
<h3 id="473-some-special-builtin-widgets-and-their-uses"><a class="header" href="#473-some-special-builtin-widgets-and-their-uses">4.7.3: Some special builtin widgets and their uses</a></h3>
<p>There are some things you might want to do with the editor in a zle
function which wouldn't be useful executed directly from zle. One is to
cause an error in the same way as a normal widget does. You can do that
with `<code>zle beep</code>'. However, this doesn't automatically stop your
function at that point; it's up to you to return from it.</p>
<p>It's possible to redefine a builtin widget just by declaring it with
`<code>zle -N</code>' and defining the corresponding function. From now on, all
existing bindings which refer to that widget will cause yours to be run
instead of the builtin one. This happens because zle doesn't actually
care what a widget does until it is run. You can see this by using
<code>bindkey</code> to define a key sequence to call an undefined widget such as
<code>any-old-string</code>. The shell doesn't complain until you actually hit the
key sequence.</p>
<p>Sometimes, however, you want to be sure to call the builtin widget, even
if the behaviour has been redefined. You can do this by putting a `<code>.</code>'
in front of the name of the widget; `<code>zle .up-line-or-history</code>' always
calls the builtin widget usually referred to as <code>up-line-or-history</code>,
even if the latter has been redefined. One use for this is to rebind
`<code>accept-line</code>' to do something whenever zle is about to pass a line up
to the shell, but to accept the line anyway: you write your own widget
<code>accept-line</code>, make sure it calls `<code>zle .accept-line</code> just before it
finishes, and then use `<code>zle -N accept-line</code>. Here's a trivial but not
entirely stupid example:</p>
<pre><code> accept-line() {
print -n &quot;\e]2;Executing $BUFFER\a&quot;
zle .accept-line
}
zle -N accept-line
</code></pre>
<p>Now every time you hit return to execute a command, that <code>print</code> command
will be executed first. As written, it puts `<code>Executing</code>' and then the
contents of the command line (see below) into the title of your xterm
window, assuming it understands the usual xterm escape sequences. In
fact, this particular example is usually handled with the special shell
function (not zle function) `<code>preexec</code>' which is passed a command line
about to be executed as an argument instead of in <code>$BUFFER</code>. There seems
to be a side effect of rebinding <code>accept-line</code> that the return key stops
working in the minibuffer under some circumstances.</p>
<p>Note that to undo the fact that return executes your new widget, you
need to alias <code>accept-line</code> back to <code>.accept-line</code>:</p>
<pre><code> zle -A .accept-line accept-line
</code></pre>
<p>If you have trouble remembering the order, as with most alias or rename
commands in zsh and UNIX generally, including <code>ln</code> and <code>bindkey -A</code>, the
existing command, the one whose properties you want to keep, comes
first, while the new name for it comes second. Also, as with those
commands, it doesn't matter if the second name on the line currently
means something else; that will be replaced by the new meaning.
Afterwards, you don't need to worry about your own <code>accept-line</code> widget;
zle handles the details of removing widgets when they're no longer
referred to. The function's still there, however, since as far as the
rest of the shell is concerned it's just an ordinary shell function
which you need to `<code>unfunction</code>' to remove.</p>
<p>Do remember, however, not to delete a widget which redefines a basic
internal widget by the obvious command</p>
<pre><code> # Noooo!
zle -D accept-line
</code></pre>
<p>which stops the return key having any effect other than complaining
there's no such widget. If you get into real trouble,
`<code>\ex.accept-line</code>' should work, as you can use the `<code>.</code>'-widgets
anywhere you can use any other except where they would redefine or
delete a `<code>.</code>' widget. Use the `<code>zle -A</code>' command above with the
extended-command form of `<code>.accept-line</code>' to return to normality. If
you try to redefine or delete a `<code>.</code>' widget, zle will tell you it's
protected. You can remove any other widget in this way, however, even if
it is still bound to a key sequence; you will then see an error if you
type that sequence.</p>
<p>One point to note about <code>accept-line</code> is that the line isn't passed up
to zsh instantly, only when your own function exits. This is pretty
obvious when you think about it; zle is called from the main shell, and
if your own zle widget hasn't finished executing, the main shell hasn't
got control back yet. But it does mean, for example, that if you modify
the command line after a call to <code>accept-line</code> or <code>.accept-line</code>, those
changes are reflected in the line passed up to the shell:</p>
<pre><code> # Noooo! to this one too.
accept-line() {
zle .accept-line
BUFFER='Ha ha!'
}
</code></pre>
<p>This always returns the string `<code>Ha ha!</code>' to the main shell. This is
not particularly useful unless you are constructing a Samuel Beckett
shell for display at an installation in a Parisian art gallery.</p>
<p><span id="l107"></span></p>
<h3 id="474-special-parameters-normal-text"><a class="header" href="#474-special-parameters-normal-text">4.7.4: Special parameters: normal text</a></h3>
<p>The shell makes various parameters available for easy manipulation of
the command line. You've already seen <code>$NUMERIC</code>. You may wonder what
happens if you have your own parmeter called <code>$NUMERIC</code>; after all, it's
a fairly simple string to use as a name. The good news is you don't need
to worry; when the shell runs a zle function, it simply hides any
existing occurrences of a parameter and makes its special parameters
available. Then when it exits, the original parameter is reenabled. So
all you have to worry about is making sure you don't use these special
parameters for anything else while you are inside a zle widget.</p>
<p>There are four particularly common zle parameters.</p>
<p>First, there are three ways of referring to the text on the command
line: <code>$BUFFER</code> is the entire line as a string, <code>$LBUFFER</code> is the line
left of the cursor position, and <code>$RBUFFER</code> is the line after it
including the character under the cursor, so that the division is always
at the point where the next inserted character would go. Any or all of
these may be empty, and <code>$BUFFER</code> is always the string
<code>$LBUFFER$RBUFFER</code>.</p>
<p>The necessary counterpart to these is <code>$CURSOR</code>, which is the cursor
position with 1 being the first character. If you know how the shell
handles substrings in parameter substitutions, you will be able to see
that <code>$LBUFFER</code> is <code>$BUFFER[1,$CURSOR-1]</code>, while <code>$RBUFFER</code> is
<code>$BUFFER[$CURSOR,-1]</code> (unless you are using the option <code>KSH_ARRAYS</code> for
compatibility of indexes with ksh --- this isn't recommended for
implementing zle or completion widgets as it causes confusion with the
ones supplied with the shell).</p>
<p>The really useful thing about these is that they are modifiable. If you
modify <code>$LBUFFER</code> or <code>$RBUFFER</code>, then <code>$BUFFER</code> and <code>$CURSOR</code> will be
modified appropriately; lengthening or shortening <code>$LBUFFER</code> increases
or decreases <code>$CURSOR</code>. If you modify <code>$BUFFER</code>, you may need to set
<code>$CURSOR</code> yourself as the shell can't tell for sure where the cursor
should be. If you alter <code>$CURSOR</code>, characters will be moved between
<code>$LBUFFER</code> and <code>$RBUFFER</code>, but <code>$BUFFER</code> will remain the same.</p>
<p>This makes tasks along the lines of basic movement and deletion commands
extremely simple, often just a matter of pattern matching. However, it
definitely pays to know about zsh's more sophisticated pattern matching
and parameter substitution features, described in the next chapter. For
example, if you start a widget function with</p>
<pre><code> emulate -L zsh
setopt extendedglob
LBUFFER=${LBUFFER%%[^[:blank:]]##}
</code></pre>
<p>then <code>$LBUFFER</code> contains the line left of the cursor stripped of all the
non-blank characters (usually anything except space or tab) immediately
to the left of the cursor.</p>
<p>This function uses the parameter substitution feature
`<code>${</code><em>param</em><code>%%</code><em>pattern</em><code>}</code>' which removes the longest match of
<em>pattern</em> from the end of <code>$</code><em>param</em>. The `<code>emulate -L zsh</code>' ensures
the shell options are set appropriately for the function and makes all
option settings local, and `<code>setopt extendedglob</code>' which turns on the
extended pattern matching features; it is this that makes the sequence
`<code>##</code>' appearing in the pattern mean `at least one repetition of the
previous pattern element'. The previous pattern element is `anything
except a blank character'. Hence, all occurrences of non-blank
characters are removed from the end of <code>$LBUFFER</code>.</p>
<p>If you want to move the cursor over those characters, you can tweak the
function slightly:</p>
<pre><code> emulate -L zsh
setopt extendedglob
chars=${(M)LBUFFER%%[^[:blank:]]##}
(( CURSOR -= ${#chars} ))
</code></pre>
<p>The string `<code>(M)</code>' has appeared at the start of the parameter
substitution. This is part of zsh's unique system of parameter flags;
this one means `insert the matched portion of the substitution'. In
other words, instead of returning <code>$LBUFFER</code> stripped of non-blank
characters at the end, the substitution returns those very characters
which it would have stripped. To skip over them is now a simple matter
of decreasing <code>$CURSOR</code> by the length of that string.</p>
<p>You'll find if you try these examples that they probably don't do quite
what you want. In particular, they don't handle any blank characters
found next to the non-blank ones which normal word-orientated functions
do. However, you now have enough information to add tests for that
yourself.</p>
<p>If you get more sophisticated, you can then add handling for <code>$NUMERIC</code>.
Remember this isn't set unless the user gave it explicitly, so it's up
to you to treat it as 1 in that case.</p>
<p><span id="l108"></span></p>
<h3 id="475-other-special-parameters"><a class="header" href="#475-other-special-parameters">4.7.5: Other special parameters</a></h3>
<p>A large fraction of what you are likely to want to do can be done with
the parameters we've already met. Here are some hints as to how you
might want to use some of the other parameters available. As always, for
a complete list with rather less in the way of hints see the manual.</p>
<p><code>$KEYS</code> tells you the keys which were used to call the widget; it's a
string of those raw characters, not turned into the <code>bindkey</code> format. In
other words, if it was a single key (including possibly a control key or
a meta key), <code>$KEYS</code> will just contain a single character. So you can
change the widget's behaviour for different keys. Here's a very (very)
simple function like <code>self-insert</code>:</p>
<pre><code> LBUFFER=$LBUFFER$KEYS
</code></pre>
<p>Note this doesn't work very well with <code>\ex</code> extended command handling;
you just get the <code>^m</code> from the end of the line. You need to make sure
any widgets which use <code>$KEYS</code> are sensibly bound. This also doesn't
handle numeric arguments to repeat characters; it's a fairly simple
exercise (particularly given zsh's `<code>repeat</code>' loop) to add that.</p>
<p><code>$WIDGET</code> and <code>$LASTWIDGET</code> tell you the name of the current widget
being executed and the one before that. These don't sound all that
useful at first hearing. However, you can use <code>$WIDGET</code> together with
the fact that a widget doesn't need to have the same name as the
function that defines it. You can define</p>
<pre><code> zle -N this-widget function
zle -N that-widget function
</code></pre>
<p>and test <code>$WIDGET</code> inside <code>function</code> to see if it contains <code>this-widget</code>
or <code>that-widget</code>. If these have a lot of shared code, that is a
considerable simplification without having to write extra functions.</p>
<p><code>$LASTWIDGET</code> tends to be used for a slightly different purpose:
checking whether the last command to be executed was the same as the
current one, or maybe was just friendly with it. Here are edited
highlights of the function <code>up-line-or-beginning-search</code>, a sort of
cross between <code>up-line-or-search</code> and
<code>history-beginning-search-backward</code> which has been added to the shell
distribution for <code>4.1</code>. If there are previous lines in the buffer, it
moves up through them; else if it's the first in a sequence of calls to
this function it remembers the cursor position and looks backwards for a
line with the same text from the start up to that point, and puts the
cursor at the end of the line; else if the same widget has just been
executed, it uses the old cursor position to search for another match
further back in the history.</p>
<pre><code> if [[ $LBUFFER == *$'\n'* ]]; then
zle .up-line-or-history
__searching=''
else
if [[ $LASTWIDGET = $__searching ]]; then
CURSOR=$__savecursor
else
__savecursor=$CURSOR
fi
__searching=$WIDGET
zle .history-beginning-search-backward
zle .end-of-line
fi
</code></pre>
<p>We test <code>$__searching</code> instead of <code>$WIDGET</code> directly to be able to tell
the case when we are moving lines instead of searching. <code>$__savecursor</code>
gives the position for the backward search, after which we put the
cursor at the end of the line. The parameters beginning `<code>__</code>' aren't
local to the function, because we need to test them from the previous
execution, so they have been given underscores in front to try to
distinguish them from other parameters which might be around.</p>
<p>You'll see that the actual function supplied in the distribution is a
little more complicated than this; for one thing, it uses styles set by
the user to decide it's behaviour. Styles are described for use with
completion widgets in <a href="zshguide06.html#comp">chapter 6</a>, but you can use
them exactly the same way in zle functions.</p>
<p>The full version of <code>up-line-or-beginning-search</code> uses another
parameter, <code>$PREBUFFER</code>. This contains any text already absorbed by
<code>zle</code> which you can no longer edit --- in other words, text read in
before the shell prompted with <code>$PS2</code> for the remainder. Testing `<code>[[ -n $PREBUFFER ]]</code>' therefore effectively tests whether you are at the
<code>$PS2</code>. You can use this to implement behaviour after the fashion of
<code>push-line-or-edit</code>.</p>
<p><span id="l109"></span></p>
<h3 id="476-reading-keys-and-using-the-minibuffer"><a class="header" href="#476-reading-keys-and-using-the-minibuffer">4.7.6: Reading keys and using the minibuffer</a></h3>
<p>Every now and then you want the editor to do a sequence of operations
with user input in the middle. This is usually done by a combination of
two commands.</p>
<p>First, you may need to prompt the user in the minibuffer, just like
<code>\ex</code> does. You can do this with `<code>zle -R</code>'. Its basic function is to
redisplay the command line, flushing all the changes you have made in
your function so far, but you can give it a string argument which
appears in the minibuffer, just below the command line. You can give it
a list of other strings after that, which appear in a similar way to
lists of possible completions, but have no special significance to zle
in this case.</p>
<p>To get input back from the user, you can use `<code>read -k</code>' which reads a
single key (not a sequence; no lookup takes place). This command is
always available in the shell, but in this case it is handled by zle
itself. The key is returned as a raw byte. Two facilities of arithmetic
evaluation are useful for handling this key: `<code>#key</code>' returns the ASCII
code for the first character of <code>$key</code>, while `<code>##</code><em>key</em>' returns the
ASCII code for <em>key</em>, which is in the form that <code>bindkey</code> would
understand. For example,</p>
<pre><code> read -k key
if (( #key == ##\C-g )); then
...
</code></pre>
<p>makes the use of arithmetic evaluation. The form on the left turns the
first character in <code>$key</code> into a number, the second turns the literal
bindkey-style string <code>\C-g</code> into a number (ASCII 7, since 1 to 26 are
just <code>\C-a</code> to <code>\C-z</code>). Don't confuse either of these forms with
`<code>$#key</code>', which is the length of the string in the parameter, in this
case almost certainly 1 for a single byte; this form works both inside
and outside arithmetic substitution, the other forms only inside. The
`<code>(( ... ))</code>' form is recommended for arithmetic substitutions whenever
possibly; you can do it with the basic `<code>[[ ... ]]</code>' form, since
`<code>-eq</code>' and similar tests treat both sides as arithmetic, though you
may need extra quoting; however, the only good reason I know for doing
that is to avoid using two types of condition syntax in the same complex
test.</p>
<p>These tricks are only really useful for quite complicated functions. For
an example, look at the function <code>incremental-complete-word</code> supplied
with the zsh source distribution. This function doesn't add to clarity
by using the form `<code>#\\C-g</code>' instead of `<code>##\C-g</code>'; it does the same
thing but the double backslash is very confusing, which is why the other
form was introduced.</p>
<p><span id="l110"></span></p>
<h3 id="477-examples"><a class="header" href="#477-examples">4.7.7: Examples</a></h3>
<p><strong>transpose-words-about-point</strong></p>
<p>This function is a variant on <code>transpose-words</code>. It has various twists.
First, the words in question are always space-delimited, neither shell
words nor words in the <code>$WORDCHARS</code> sense. This makes it fairly
predictable.</p>
<p>Second, it will transpose words about the current point (hence its name)
even if the character under the cursor is not a whitespace character. I
find this useful because I am eternally typing compound words a bit like
`<code>function_name</code>' only to find that what I should have typed was
`<code>name_function</code>'. Now I just position the cursor over the underscore
and execute this widget.</p>
<pre><code> emulate -L zsh
setopt extendedglob
local match mbegin mend pat1 pat2 word1 word2 ws1 ws2
pat1=${LBUFFER%%(#b)([^[:blank:]]##)([[:blank:]]#)}
word1=$match[1]
ws1=$match[2]
match=()
pat2=${RBUFFER##(#b)(?[[:blank:]]#)([^[:blank:]]##)}
ws2=$match[1]
word2=$match[2]
if [[ -n $word1 &amp;&amp; -n $word2 ]]; then
LBUFFER=&quot;$pat1$word2$ws1&quot;
RBUFFER=&quot;$ws2$word1$pat2&quot;
else
zle beep
fi
</code></pre>
<p>The only clever stuff here is the pattern matching. It makes a great
deal of use of `backreferences' an extended globbing feature which is
used in all forms of pattern matching including, as in this case,
parameter substitution. It will be described fully in the next chapter.
The key things to look for are the `<code>(#b)</code>', which activates
backreferences if the option <code>EXTENDED_GLOB</code> is turned on, the
parentheses following that, which mark out the bits you want to refer
to, and the references to elements of the array <code>$match</code>, which store
those bits. The shell also sets <code>$mbegin</code> and <code>$mend</code> to give the
positions of the start and end of those matches, which is why those
parameters are made local; we want to preserve them from being seen
outside the function even though we don't actually use them.</p>
<p>You might also need to know about the `<code>#</code>' characters: one after a
pattern means `zero or more repetitions', and two mean `one or more
repetitions'. Finally, `<code>[:blank:]</code>' in a character class refers to any
blank character; when negated, as in the character class
`<code>[^[:blank:]]</code>', it means any non-blank character. With the `<code>#</code>'s we
match a series blank or non-blank characters. Given that, you can work
out the rest of what's going on.</p>
<p>Here's a more sophisticated version of that. If you found the previous
one heavy going. you probably don't want to look too closely at this.</p>
<pre><code> emulate -L zsh
setopt extendedglob
local wordstyle blankpat wordpat1 wordpat2
local match mbegin mend pat1 pat2 word1 word2 ws1 ws2
zstyle -s ':zle:transpose-words-about-point' word-style wordstyle
case $wordstyle in
(shell) local bufwords
# This splits the line into words as the shell understands them.
bufwords=(${(z)LBUFFER})
wordpat1=&quot;${(q)bufwords[-1]}&quot;
# Take substring of RBUFFER to skip over first character,
# which is the one under the cursor.
bufwords=(${(z)RBUFFER[2,-1]})
wordpat2=&quot;${(q)bufwords[1]}&quot;
blankpat='[[:blank:]]#'
;;
(space) blankpat='[[:blank:]]#'
wordpat1='[^[:blank:]]##'
wordpat2=$wordpat1
;;
(*) local wc=$WORDCHARS
if [[ $wc = (#b)(?*)-(*) ]]; then
# We need to bring any `-' to the front to avoid confusing
# character classes... we get away with `]' since in zsh
# this isn't a pattern character if it's quoted.
wc=-$match[1]$match[2]
fi
# A blank is anything not in the character class consisting
# of alphanumerics and the characters in $wc.
# Quote $wc where necessary, because we don't want those
# characters to be considered as pattern characters later on.
blankpat=&quot;[^${(q)wc}a-zA-Z0-9]#&quot;
# and a word character is anything else.
wordpat1=&quot;[${(q)wc}a-zA-Z0-9]##&quot;
wordpat2=$wordpat1
;;
esac
# The eval makes any special characters in the parameters active.
# In particular, we need the surrounding `[' s to be `real'.
# This is why we quoted the wordpats in the `shell' option, where
# they have to be treated as literal strings at this point.
eval pat1='${LBUFFER%%(#b)('${wordpat1}')('${blankpat}')}'
word1=$match[1]
ws1=$match[2]
match=()
eval pat2='${RBUFFER##(#b)(?'${blankpat}')('${wordpat2}')}'
ws2=$match[1]
word2=$match[2]
if [[ -n $word1 &amp;&amp; -n $word2 ]]; then
LBUFFER=&quot;$pat1$word2$ws1&quot;
RBUFFER=&quot;$ws2$word1$pat2&quot;
else
zle beep
fi
</code></pre>
<p>What has been added is the ability to use a style to define how the
shell finds a `word'. By default, words are the same as what the shell
usually thinks of as a word; this is handled by the branch of the case
statement which uses `<code>$WORDCHARS</code>' and a little extra trickery to get
a pattern which matches the set of characters considered parts of a
word. We used the <code>eval</code>'s because it allowed us to have some bits of
<code>$wordpat1</code> and friends active as pattern characters while others were
quoted.</p>
<p>This introduces two types of parameter expansion flags:
<code>${(q)</code><em>param</em><code>}</code> adds backslashes to quote special characters in
<code>$</code><em>param</em>, so that when the parameter appears after <code>eval</code> the result
is just the original string. <code>${(z)</code><em>param</em><code>}</code> splits the parameter just
as if it were a shell command line being split into a command and words,
so the result is an array; `<code>z</code>' stands for zsh-splitting or just
zplitting as you fancy.</p>
<p>If you set</p>
<pre><code> zstyle ':zle:*' word-style space
</code></pre>
<p>you get back to the behaviour of the original function.</p>
<p>Finally, if you replace `<code>space</code>' with `<code>shell</code>' in that <code>zstyle</code>
command, you will get words as they are split for normal use within the
shell; for example try</p>
<pre><code> echo execute the widget 'between these' 'two quoted expressions'
</code></pre>
<p>and the entire quoted expressions will be transposed. You may find that
if you do this in the middle of a quoted expression, you don't get a
sensible result; that's because the <code>(z)</code>-splitting doesn't know what to
do with the improperly completed quotes to its left and right. Some
versions of the shell have a bug (fixed in 4.0.5) that the expressions
which couldn't be split properly, because the quotes weren't complete,
have an extra space character at the end.</p>
<p><strong>insert-numeric</strong></p>
<p>Here's a widget which allows you to insert an ASCII character which you
know by number. I can't for the life of me remember where it came from,
but it's been lying around apparently for two and a half years (please
do email me if you think you wrote it, otherwise I'll assume I did). You
can give it a numeric prefix (that's the easy part of the function),
else it will prompt you for a number. If you type `<code>x</code>' or `<code>o</code>' the
number is treated as hexadecimal or octal, respectively, else as
decimal.</p>
<pre><code> # Set up standard options.
# Important for portability.
emulate -L zsh
# x must display in hexadecimal
typeset -i 16 x
if (( ${+NUMERIC} )); then
# Numeric prefix given; just use that.
x=$NUMERIC
else
# We need to read the ASCII code.
local msg modes key mode=dec code char
# Prompt for and read a base.
integer base=10
zle -R &quot;ASCII code (o -&gt; oct, x -&gt; hex) [$mode]: &quot;
read -k key
case $key in
(o) base=8 mode=oct
zle -R &quot;ASCII code [$mode]: &quot;
read -k key
;;
(x) base=16 mode=hex
zle -R &quot;ASCII code [$mode]: &quot;
read -k key
;;
esac
# Now we are looking for numbers in that base.
# Loop until newline or return.
while [[ '#key' -ne '##\n' &amp;&amp; '#key' -ne '##\r' ]]; do
if [[ '#key' -eq '##^?' || '#key' -eq '##^h' ]]; then
# Delete a character
[[ -n $code ]] &amp;&amp; code=${code[1,-2]}
elif [[ ($mode == hex &amp;&amp; $key != [0-9a-fA-f]) ||
($mode == dec &amp;&amp; $key != [0-9]) ||
($mode == oct &amp;&amp; $key != [0-7]) ]]; then
# Character not in range, beep
zle beep
elif [[ '#key' -eq '##\C-g' ]]; then
# Abort: returning 1 signals to zle that this
# is an abnormal termination.
return 1
else
code=&quot;${code}${key}&quot;
fi
char=
if [[ -n $code ]]; then
# Work out the character using the
# numbers typed so far.
(( x = ${base}#${code} ))
if (( x &gt; 255 )); then
zle beep
code=${code[1,-2]}
[[ -n $code ]] &amp;&amp; (( x = ${base}#${code} ))
fi
[[ -n $code ]] &amp;&amp; eval char=\$\'\\x${x##???}\'
fi
# Prompt for any more digits, showing
# the character as it would be inserted.
zle -R &quot;ASCII code [$mode]: $code${char:+ = $char}&quot;
read -k key || return 1
done
# If aborted with no code, return
[[ -z $code ]] &amp;&amp; return 0
# Now we have the ASCII code.
(( x = ${base}#${code} ))
fi
# Finally, if we have a single-byte character,
# insert it to the left of the cursor
if (( x &lt; 0 || x &gt; 255 )); then
return 1
else
eval LBUFFER=\$LBUFFER\$\'\\x${x##???}\'
fi
</code></pre>
<p>This shows how to do interactive input. The `<code>zle -R</code>'s prompt the
user, while the `<code>read -k</code>'s accept a character at a time. As an extra
feature, while you are typing the number, the character that would be
inserted if you hit return is shown. The widget also handles deletion
with backspace or the (UNIX-style, not PC-style) delete key.</p>
<p>One blight on this is the way of turning the number in x into a
character, which is done by all those <code>eval</code>s and backslashes. It uses
the feature that e.g. <code>$'\x41'</code> is the character <code>0x41</code> (an ASCII `A').
To use this, we must make sure the character (stored in x) appears as
hexadecimal, and following ksh zsh outputs hexadecimal numbers as
`<code>16#41</code>' or similar. (The new option <code>C_BASES</code> shows hexadecimal
numbers as 0x41 and similar, but here we need the plain number in any
case.) Hence we strip the `<code>16#</code>' and construct our <code>$'\x41'</code>. Now we
need to persuade the shell to interpret this as a quoted string by
passing it to <code>eval</code> with the special characters (<code>$</code>, <code>\</code>, <code>'</code>) quoted
with a backslash so that they aren't interpreted too early.</p>
<p>By the way, note that zsh only handles ordinary 8-bit characters at the
moment. It doesn't matter if some do-gooder on your system has set
things up to use UTF-8 (a UNIX-friendly version of the international
standard for multi-byte characters, Unicode) to appeal to the
international market, I'm afraid zsh is stuck with ISO 8859 and similar
character sets for now.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="zshguide03.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="zshguide05.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="zshguide03.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="zshguide05.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3000/__livereload");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>