wiki:HemlockProgrammer/Commands

Version 1 (modified by rme, 6 years ago) (diff)

--

7. Commands

7.1. Introduction

The way that the user tells Hemlock to do something is by invoking a command. Commands have three attributes:

name
A command's name provides a way to refer to it. Command names are usually capitalized words separated by spaces, such as Forward Word.
documentation
The documentation for a command is used by on-line help facilities.
function
A command is implemented by a Lisp function, which is callable from Lisp.

*command-names* [Variable]

Holds a string-table (page 69) associating command names to command objects. Whenever a new command is defined it is entered in this table.

7.1.1. Defining Commands

defcommand{command-name | (command-name function-name)} lambda-list command-doc function-doc {form}* [Macro]

Defines a command named name. defcommand creates a function to implement the command from the lambda-list and form’s supplied. The lambda-list must specify one required argument, see section 7.4, which by convention is typically named p. If the caller does not specify function-name, defcommand creates the command name by replacing all spaces with hyphens and appending "-command". Function-doc becomes the documentation for the function and should primarily describe issues involved in calling the command as a function, such as what any additional arguments are. Command-doc becomes the command documentation for the command.

make-command name documentation function [Function]

Defines a new command named name, with command documentation documentation and function function. The command in entered in the string-table *command-names* (page 27), with the command object as its value. Normally command implementors will use the defcommandmacro, but this permits access to the command definition mechanism at a lower level, which is occasionally useful.

commandp command [Function]

Returns t if command is a command object, otherwise nil.

command-documentation command [Function]

command-function command [Function]

command-name command [Function]

Returns the documentation, function, or name for command. These may be set with setf.

7.1.2. Command Documentation

Command documentation is a description of what the command does when it is invoked as an extended command or from a key. Command documentation may be either a string or a function. If the documentation is a string then the first line should briefly summarize the command, with remaining lines filling the details. Example:

(defcommand "Forward Character" (p)
  "Move the point forward one character.
   With prefix argument move that many characters, with negative
   argument go backwards."
  "Move the point of the current buffer forward p characters."
. . .)

Command documentation may also be a function of one argument. The function is called with either :short or :full, indicating that the function should return a short documentation string or do something to document the command fully.

7.2. The Command Interpreter

The command interpreter is a function which reads key-events (see section 7.2.1) from the keyboard and dispatches to different commands on the basis of what the user types. When the command interpreter executes a command, we say it invokes the command. The command interpreter also provides facilities for communication between commands contiguously running commands, such as a last command type register. It also takes care of resetting communication mechanisms, clearing the echo area, displaying partial keys typed slowly by the user, etc.

*invoke-hook* [Variable]

This variable contains a function the command interpreter calls when it wants to invoke a command. The function receives the command and the prefix argument as arguments. The initial value is a function which simply funcalls the command-function of the command with the supplied prefix argument. This is useful for implementing keyboard macros and similar things.

Command Abort Hook [Hemlock Variable]

The command interpreter invokes the function in this variable whenever someone aborts a command (for example, if someone called editor-error).

When Hemlock initially starts the command interpreter is in control, but commands may read from the keyboard themselves and assign whatever interpretation they will to the key-events read. Commands may call the command interpreter recursively using the function recursive-edit (page 32).

7.2.1. Editor Input

The canonical representation of editor input is a key-event structure. Users can bind commands to keys (see section 7.2.2), which are non-zero length sequences of key-events. A key-event consists of an identifying token known as akeysymand a field of bits representing modifiers. Users define keysyms, integers between 0 and 65535 inclusively, by supplying names that reflect the legends on their keyboard’s keys. Users define modifier names similarly, but the system chooses the bit and mask for recognizing the modifier. You can use keysym and modifier names to textually specify key-events and Hemlock keys in a#ksyntax. The following are some examples:

#k"C-u"
#k"Control-u"
#k"c-m-z"
#k"control-x meta-d"
#k"a"
#k"A"
#k"Linefeed"

This is convenient for use within code and in init files containingbind-keycalls.

The #k syntax is delimited by double quotes, but the system parses the contents rather than reading it as a Common Lisp string. Within the double quotes, spaces separate multiple key-events. A single key-event optionally starts with modifier names terminated by hyphens. Modifier names are alphabetic sequences of characters which the system uses case-insensitively. Following modifiers is a keysym name, which is case-insensitive if it consists of multiple characters, but if the name consists of only a single character, then it is case-sensitive.

You can escape special characters---hyphen, double quote, open angle bracket, close angle bracket, and space---with a backslash, and you can specify a backslash by using two contiguously. You can use angle brackets to enclose a keysym name with many special characters in it. Between angle brackets appearing in a keysym name position, there are only two special characters, the closing angle bracket and backslash.

For more information on key-events see section 18.1.

7.2.2. Binding Commands to Keys

The command interpreter determines which command to invoke on the basis ofkey bindings. A key binding is an association between a command and a sequence of key-events (see section 7.2.1). A sequence of key-events is called a key and is represented by a single key-event or a sequence (list or vector) of key-events.

Since key bindings may be local to a mode or buffer, the current environment (page 21) determines the set of key bindings in effect at any given time. When the command interpreter tries to find the binding for a key, it first checks if there is a local binding in thecurrent-buffer (page 9), then if there is a binding in each of the minor modes and the major mode for the current buffer (page 35), and finally checks to see if there is a global binding. If no binding is found, then the command interpreter beeps or flashes the screen to indicate this.

bind-keyname key &optional kind where [Function]

This function associates command name and keyin some environment. Key is either a key-event or a sequence of key-events. There are three possible values of kind:

:global
The default, make a global key binding.
:mode
Make a mode specific key binding in the mode whose name is where.
:buffer
Make a binding which is local to buffer where.

This processes key for key translations before establishing the binding. See section 7.2.3.

If the key is some prefix of a key binding which already exists in the specified place, then the new one will override the old one, effectively deleting it.

ext:do-alpha-key-events is useful for setting up bindings in certain new modes.

command-bindings command [Function]

This function returns a list of the places where command is bound. A place is specified as a list of the key (always a vector), the kind of binding, and where (either the mode or buffer to which the binding is local, or nil if it is a global).

delete-key-bindingkey &optional kind where [Function]

This function removes the binding of key in some place. Key is either a key-event or a sequence of key-events. kind is the kind of binding to delete, one of :global(the default), :mode or :buffer. If kind is :mode, where is the mode name, and if kind is :buffer, then where is the buffer.

This function signals an error if key is unbound.

This processes key for key translations before deleting the binding. See section 7.2.3.

get-command key &optional kind where [Function]

This function returns the command bound to key, returning nil if it is unbound. Key is either a key-event or a sequence of key-events. If key is an initial subsequence of some keys, then this returns the keyword :prefix. There are four cases of kind:

:current
Return the current binding of key using the current buffer’s search list. If there are any transparent key bindings forkey, then they are returned in a list as a second value.
:global
Return the global binding of key. This is the default.
:mode
Return the binding of key in the mode named where.
:buffer
Return the binding of key local to the buffer where.

This processes key for key translations before looking for any binding. See section 7.2.3.

map-bindings function kind &optional where [Function]

This function maps over the key bindings in some place. For each binding, this passes function the key and the command bound to it. Kind and wher eare the same as in bind-key. The key is not guaranteed to remain valid after a given iteration.

7.2.3. Key Translation

Key translation is a process that the command interpreter applies to keys before doing anything else. There are two kinds of key translations: substitution and bit-prefix. In either case, the command interpreter translates a key when a specified key-event sequence appears in a key.

In a substitution translation, the system replaces the matched subsequence with another key-event sequence. Key translation is not recursively applied to the substituted key-events.

In a bit-prefix translation, the system removes the matched subsequence and effectively sets the specified bits in the next key-event in the key.

While translating a key, if the system encounters an incomplete final subsequence of key-events, it aborts the translation process. This happens when those last key-events form a prefix of some translation. It also happens when they translate to a bit-prefix, but there is no following key-event to which the system can apply the indicated modifier. If there is a binding for this partially untranslated key, then the command interpreter will invoke that command; otherwise, it will wait for the user to type more key-events.

key-translation key [Function]

This form is setf-able and allows users to register key translations that the command interpreter will use as users type key-events.

This function returns the key translation for key, returning ni lif there is none. Key is either a key-event or a sequence of key-events. If key is a prefix of a translation, then this returns :prefix.

A key translation is either a key or modifier specification. The bits translations have a list form: (:bits {bit-name}*).

Whenever key appears as a subsequence of a key argument to the binding manipulation functions, that portion will be replaced with the translation.

7.2.4. Transparent Key Bindings

Key bindings local to a mode may betransparent. A transparent key binding does not shadow less local key bindings, but rather indicates that the bound command should be invoked before the first normal key binding. Transparent key bindings are primarily useful for implementing minor modes such as auto fill and word abbreviation. There may be several transparent key bindings for a given key, in which case all of the commands bound are invoked in the order they were found. If there no normal key binding for a key typed, then the command interpreter acts as though the key is unbound even if there are transparent key bindings.

The :transparent-p argument to defmode (page 36) determines whether the key bindings in a mode are transparent or not.

7.2.5. Interactive

Hemlock supports keyboard macros. A user may enter a mode where the editor records his actions, and when the user exits this mode, the command Last Keyboard Macro plays back the actions. Some commands behave differently when invoked as part of the definition of a keyboard macro. For example, when used in a keyboard macro, a command that message’s useless user confirmation will slow down the repeated invocations of Last Keyboard Macro because the command will pause on each execution to make sure the user sees the message. This can be eliminated with the use of interactive. As another example, some commands conditionally signal an editor-error versus simply beeping the device depending on whether it executes on behalf of the user or a keyboard macro.

interactive [Function]

This returns t when the user invoked the command directly.

7.3. Command Types

In many editors the behavior of a command depends on the kind of command invoked before it. Hemlock provides a mechanism to support this known as command type.

last-command-type [Function]

This returns the command type of the last command invoked. If this is set with setf, the supplied value becomes the value of last-command-type until the next command completes. If the previous command did not set last-command-type, then its value is nil. Normally a command type is a keyword. The command type is not cleared after a command is invoked due to a transparent key binding.

7.4. Command Arguments

There are three ways in which a command may be invoked: It may be bound to a key which has been typed, it may be invoked as an extended command, or it may be called as a Lisp function. Ideally commands should be written in such a way that they will behave sensibly no matter which way they are invoked. The functions which implement commands must obey certain conventions about argument passing if the command is to function properly.

7.4.1. The Prefix Argument

Whenever a command is invoked it is passed as its first argument what is known as the prefix argument. The prefix argument is always either an integer or nil. When a command uses this value it is usually as a repeat count, or some conceptually similar function.

prefix-argument [Function]

This function returns the current value of the prefix argument. When set with setf, the new value becomes the prefix argument for the next command. If the prefix argument is not set by the previous command then the prefix argument for a command is nil. The prefix argument is not cleared after a command is invoked due to a transparent key binding.

7.4.2. Lisp Arguments

It is often desirable to call commands from Lisp code, in which case arguments which would otherwise be prompted for are passed as optional arguments following the prefix argument. A command should prompt for any arguments not supplied.

7.5. Recursive Edits

use-buffer buffer {form}* [Macro]

The effect of this is similar to setting the current-buffer to buffer during the evaluation of forms. There are restrictions placed on what the code can expect about its environment. In particular, the value of any global binding of a Hemlock variable which is also a mode local variable of some mode is ill-defined; if the variable has a global binding it will be bound, but the value may not be the global value. It is also impossible to nest use-buffer’s in different buffers. The reason for using use-buffer is that it may be significantly faster than changing current-buffer to buffer and back.

recursive-edit &optional handle-abort [Function]

Enter Recursive Edit Hook [Hemlock Variable]

recursive-edit invokes the command interpreter. The command interpreter will read from the keyboard and invoke commands until it is terminated with either exit-recursive-edit or abort-recursive-edit.

Normally, an editor-error or C-g aborts the command in progress and returns control to the top-level command loop. If recursive-edit is used with handle-abort true, then editor-error or C-g will only abort back to the recursive command loop. Before the command interpreter is entered the hook Enter Recursive Edit Hook is invoked.

in-recursive-edit [Function]

This returns whether the calling point is dynamically within a recursive edit context.

exit-recursive-edit &optional values-list [Function]

Exit Recursive Edit Hook [Hemlock Variable]

exit-recursive-edit exits a recursive edit returning as multiple values each element of values-list, which defaults to nil. This invokes Exit Recursive Edit Hook after exiting the command interpreter. If no recursive edit is in progress, then this signals an error.

abort-recursive-edit &restargs [Function]

Abort Recursive Edit Hook [Hemlock Variable]

abort-recursive-edit terminates a recursive edit by applying editor-error (page 60) to args after exiting the command interpreter. This invokes Abort Recursive Edit Hook with args before aborting the recursive edit. If no recursive edit is in progress, then this signals an error.