2034 lines
124 KiB
HTML
2034 lines
124 KiB
HTML
<!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'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 -->
|
||
<link rel="stylesheet" href="./theme/catppuccin.css">
|
||
<link rel="stylesheet" href="./theme/catppuccin-highlight.css">
|
||
|
||
</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>
|
||
<li role="none"><button role="menuitem" class="theme" id="latte">Latte</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="frappe">Frappé</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="macchiato">Macchiato</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="mocha">Mocha</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'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 "\eOA" up-line-or-history
|
||
bindkey "\eOB" down-line-or-history
|
||
bindkey "\eOC" forward-char
|
||
bindkey "\eOD" 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'
|
||
"^?" 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<ESC>xba<TAB>w<TAB></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><TAB></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><ESC>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><ESC>4<ESC>b</code>'. The `<code><ESC>b</code>' on its own would take you one word
|
||
backwards. The `<code><ESC>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><ESC>-<ESC>1<ESC>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><ESC>-<ESC>4<ESC>\f</code>' is a pointless way of
|
||
executing the same as `<code><ESC>4<ESC>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> *?_-.[]~=/&;!#$%^(){}<>
|
||
</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//[&.;]}
|
||
% print $WORDCHARS
|
||
*?_-[]~=/!#$%^(){}<>
|
||
</code></pre>
|
||
<p>shows that the operation has removed those three characters in the
|
||
group, i.e. `<code>&</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>"`'\@</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><ESC>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<</code> and <code>\e></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></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><ESC></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 \
|
||
<Key>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<Key>Left: string(0x1b) string("[159q") \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 "\C-x\C-z" "\eqsuspend\n"
|
||
</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 "\e[OA" 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></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<ESC><RET>
|
||
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<ESC><RET>
|
||
print Fuzzy logic rules<ESC><RET>
|
||
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> print<ESC>q<ESC>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 "\e]2;Executing $BUFFER\a"
|
||
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 && -n $word2 ]]; then
|
||
LBUFFER="$pat1$word2$ws1"
|
||
RBUFFER="$ws2$word1$pat2"
|
||
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="${(q)bufwords[-1]}"
|
||
# Take substring of RBUFFER to skip over first character,
|
||
# which is the one under the cursor.
|
||
bufwords=(${(z)RBUFFER[2,-1]})
|
||
wordpat2="${(q)bufwords[1]}"
|
||
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="[^${(q)wc}a-zA-Z0-9]#"
|
||
# and a word character is anything else.
|
||
wordpat1="[${(q)wc}a-zA-Z0-9]##"
|
||
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 && -n $word2 ]]; then
|
||
LBUFFER="$pat1$word2$ws1"
|
||
RBUFFER="$ws2$word1$pat2"
|
||
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 "ASCII code (o -> oct, x -> hex) [$mode]: "
|
||
read -k key
|
||
case $key in
|
||
(o) base=8 mode=oct
|
||
zle -R "ASCII code [$mode]: "
|
||
read -k key
|
||
;;
|
||
(x) base=16 mode=hex
|
||
zle -R "ASCII code [$mode]: "
|
||
read -k key
|
||
;;
|
||
esac
|
||
# Now we are looking for numbers in that base.
|
||
# Loop until newline or return.
|
||
while [[ '#key' -ne '##\n' && '#key' -ne '##\r' ]]; do
|
||
if [[ '#key' -eq '##^?' || '#key' -eq '##^h' ]]; then
|
||
# Delete a character
|
||
[[ -n $code ]] && code=${code[1,-2]}
|
||
elif [[ ($mode == hex && $key != [0-9a-fA-f]) ||
|
||
($mode == dec && $key != [0-9]) ||
|
||
($mode == oct && $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="${code}${key}"
|
||
fi
|
||
char=
|
||
if [[ -n $code ]]; then
|
||
# Work out the character using the
|
||
# numbers typed so far.
|
||
(( x = ${base}#${code} ))
|
||
if (( x > 255 )); then
|
||
zle beep
|
||
code=${code[1,-2]}
|
||
[[ -n $code ]] && (( x = ${base}#${code} ))
|
||
fi
|
||
[[ -n $code ]] && eval char=\$\'\\x${x##???}\'
|
||
fi
|
||
|
||
# Prompt for any more digits, showing
|
||
# the character as it would be inserted.
|
||
zle -R "ASCII code [$mode]: $code${char:+ = $char}"
|
||
read -k key || return 1
|
||
done
|
||
# If aborted with no code, return
|
||
[[ -z $code ]] && 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 < 0 || x > 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>
|
||
|
||
|
||
|
||
|
||
<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>
|