## 10.3. Customizing the Editing Modes

As we saw in Chapter 2, you have your choice of either emacs or vi editing modes when editing your command line. Besides the commands available in each mode, you can customize the behavior of the editing modes to suit your needs or environment.

Appendix A discusses a number of third party shells based on the Bourne and Korn shell design. Those shells generally provide command-line editing, as well as the ability to customize the editor via a special built-in command, a special start-up file, or both.

The Korn shell's approach is different. It is based on a paradigm where you program the behavior you want from the shell. This is accomplished via a fake trap, named KEYBD. If it exists, the trap set for KEYBD is evaluated when ksh processes normal command-line input characters.[140] Within the code executed for the trap, two special variables contain the text of the command line and the text being entered that caused the trap. Additional special variables allow you to distinguish between emacs- and vi-modes and indicate the current position on the input line. These variables are listed in Table 10-2.

> [140] Characters for search strings and numeric arguments to vi- and emacs-mode commands do not trigger the KEYBD trap.

#### Table 10-2. Special editing variables

Variable | Meaning
--- | ---
`.sh.edchar` | The character or escape sequence entered by the user that caused the KEYBD trap. The value of `.sh.edchar` at the end of the trap is then used to direct the actions of the built-in editor.
`.sh.edcol` | The position of the cursor on the current input line.
`.sh.edmode` | Equal to ESC in vi-mode, empty otherwise. (Use `[[ -n ${.sh.edmode} ]]` to test it.)
`.sh.edtext` | The text of the current input line.

Upon entering the KEYBD trap, the contents of `.sh.edchar` will be either a single character, ESC followed by a single character, or ESC, [, and a single character. You can assign a new value to `.sh.edchar` to change the input that the current editing mode receives. Thus, the KEYBD trap allows you to interpose a "filter" between what the user enters and what the shell editing modes actually process. The following example is from page 98 of The New KornShell Command and Programming Language.[141] It presents a keybind function that allows you to bind new actions to input key sequences, similar to the built-in bind command of many other shells.

> [141] This is the book on ksh93 written by David Korn and Morris Bolsky and published by Prentice Hall.

>           # Quoted from Page 98 of
>           # The New KornShell Command and Programming Language

>      1    typeset -A Keytable
>      2    trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD
>      3    function keybind # key [action]
>      4    {
>      5         typeset key=$(print -f "%q" "$2")
>      6         case $# in
>      7         2)      Keytable[$1]=' .sh.edchar=${.sh.edmode}'"$key"
>      8                 ;;
>      9         1)      unset Keytable[$1]
>     10                 ;;
>     11         *)      print -u2 "Usage: $0 key [action]"
>     12                 return 2 # usage errors return 2 by default
>     13                 ;;
>     14         esac
>     15    }

This is an interesting function. Let's go through it line by line. Line 1 creates an associative array to act as a table of key/action pairs. Line 2 sets the KEYBD trap. It gets the action out of the associative array and then executes it using eval. Line 3 starts the keybind function, which takes one or two arguments. With two arguments, the second argument is first quoted appropriately (line 5 -- the `key` variable would have been better-named `action`). Line 7 then creates the entry in the array, using `$1` (the user key sequence) as the index, and quoted action as the value to assign to `.sh.edchar`. Note how `${.sh.mode}` is also included. This has the effect of forcing a switch to command mode for the vi editing mode. It is this generated assignment statement that is evaled every time the trap executes.

The rest of the function is mostly bookkeeping: with one argument (line 9), the given entry in the `Keytable` array is removed. If more than two arguments (line 11), keybind prints a message and then returns the (false) value 2.

While somewhat unusual, the KEYBD trap mechanism for dealing with user input is both general and extensible; you can do whatever you want, as just a Simple Matter of Programming. With other shells, you're limited to whatever built-in facilities they provide.

Copyright © 2003 O'Reilly & Associates. All rights reserved.