Previous
|
Up
|
Next
|
The Main Loop |
Primitives and EEL Subroutines |
Defining Language Modes |
Epsilon User's Manual and Reference >
Primitives and EEL Subroutines >
Input Primitives >
Binding Primitives
Epsilon lets each buffer have a different set of key bindings
appropriate to editing the type of text in that buffer. For
instance, while in a buffer with EEL source code, a certain key could
indent the current function. The same key might indent a paragraph
in a buffer with text.
A key table stores a set of key bindings. A key table is an array,
with one entry for each key on the keyboard. Each entry in the array
contains an index into the name table. (See The Name Table.) If the value of a particular entry is negative
or zero, it means the key is undefined according to that table. The
file eel.h defines a macro called NUMKEYS that provides the
number of bindable keys on the keyboard. A key table, then, is an
array of NUMKEYS short ints.
buffer short *mode_keys;
short *root_keys;
keytable reg_tab, c_tab;
Epsilon uses two key tables in its search for the binding of a key.
First it looks in the key table referenced by the buffer-specific
variable mode_keys. If the entry for the key is negative,
Epsilon considers the command unbound and signals an error. If the
entry for the key is 0 , as it usually is, Epsilon uses the entry
in the key table referenced by the variable root_keys instead.
If the resulting entry is zero or negative, Epsilon considers the key
unbound. If it finds an entry for the key that is a positive number,
Epsilon considers that number the key's binding. The number is
actually an index into the name table.
Most entries in a key table refer to commands, but an entry may also
refer to a subroutine (if it takes no arguments), to a keyboard
macro, or to another key table. For example, the entry for Ctrl-X in
the default key table refers to a key table named cx_tab ,
which contains the Ctrl-X commands. The entry for the
find-file command bound to Ctrl-X Ctrl-F appears in the
cx_tab key table.
Normally in Epsilon the root_keys variable points to the
reg_tab array. The mode_keys variable points to one
of the many mode-specific tables, such as c_tab for C mode.
int new_table(char *name)
int make_anon_keytable() /* control.e */
short *index_table(int index)
Key tables are usually defined with the keytable keyword as
described in Key Tables. If a key table's name is not
known when the routine is compiled, the new_table( ) primitive
can be used. It makes a new key table with the given name. All
entries in it are 0 .
The make_anon_keytable( ) subroutine defined in control.e
calls new_table( ), first choosing an unused name for the table.
The index_table( ) function takes a name table index and
retrieves the key table it refers to.
fix_key_table(short *ftab, int fval, short *ttab, int tval)
set_case_indirect(short *tab)
set_list_keys(short *tab)
The fix_key_table( ) subroutine copies key table information
from one key table to another. For each key in ftab bound to
the function fval , the subroutine binds that key in ttab to
the function tval .
The set_case_indirect( ) subroutine sets the upper case
letter keys in a key table to indirect through their lower case
equivalents. The set_list_keys( ) subroutine does that, and
also sets the "n" and "p" keys to move up or down by lines.
do_topkey()
run_topkey()
When Epsilon is ready to execute a key in its main loop, it calls the
primitive do_topkey( ). This primitive
searches the key tables for the command bound to the current key, as
described above. When it has found the name table index, it calls
do_command( ), below, to interpret the command.
The run_topkey( ) subroutine provides a wrapper around
do_topkey( ) that resets iter and similar variables like
the main loop does. An EEL subroutine that wants to retrieve keys
itself and execute them as if the user typed them at command level
can call this subroutine.
do_command(int index)
user short last_index;
The do_command( ) primitive executes the command or other
item with the supplied name table index. If the index is invalid,
then the quick_abort( ) primitive is called. Otherwise, the
index is copied to the last_index variable, so the help system
can find the name of the current command (among other uses).
If the name table index refers to a command or subroutine, Epsilon
calls the function. When it returns, Epsilon checks the
iter variable. If it is two or more, Epsilon proceeds to call
the same function repeatedly, decrementing iter each time, so
that it calls the function a total of iter times. See The Main Loop.
short *table_keys;
int table_count;
table_prompt() /* control.e */
If the entry in the name table that do_command( ) is to execute
contains another table, Epsilon gets another key. First, Epsilon
updates the primitive array table_keys. It contains the
prefix keys entered so far in the current command, and
table_count contains their number. Next, Epsilon calls the
EEL subroutine table_prompt( ) if it exists to display a prompt
for the new key. The version of this subroutine that's provided with
Epsilon uses mention( ), so the message may not appear
immediately. Epsilon then calls the EEL subroutine getkey( )
to read a new key and clears the echo area of the prompt. Epsilon
then interprets the key just as the do_topkey( ) primitive
would, but using the new key table. If both mode_keys and
root_keys provided a table as the entry for the first key, the
values from each are used as the new mode and root key tables.
do_again()
The do_again( ) primitive reinterprets a key using the same
pair of mode and root tables that were used previously. The value in
the variable key may, of course, be different. Epsilon uses
this primitive in commands such as alt-prefix.
Epsilon handles EEL subroutines without parameters in the name table
in the same way as commands, as described above. If the entry is for
a keyboard macro, the only other legal name table entry, Epsilon goes
into a recursive edit level and begins processing the keys in the
macro. It saves the macro internally so that future requests for a
key will return characters from the macro, as described in Keys. It also saves the value of iter, so the macro
will iterate properly. When the macro runs out of keys, Epsilon
automatically exits the recursive edit level, and returns from the
call to do_again( ). (When macro-runs-immediately is
nonzero, running a macro doesn't enter a recursive edit level, but
returns immediately. Future key requests will still come from the
macro until it's exhausted.)
short ignore_kbd_macro;
Epsilon provides a way for a keyboard macro to suspend itself and
get input from the user, then continue. Set the
ignore_kbd_macro variable nonzero to get keyboard input even
when a macro is running. The pause-macro command uses this
variable.
short *ask_key(char *pr, char *keyname) /* basic.e */
short key_binding[30]; // ask_key() puts key info here
The ask_key( ) subroutine defined in basic.e duplicates the
logic of the main loop in getting the sequence of keys that make up a
command. However, it prompts for the sequence and doesn't run the
command at the end. Commands like bind-to-key
that ask for a key and accept a sequence of key table keys
use it.
The ask_key( ) subroutine returns a pointer to the entry in the
key table that was finally reached. The value pointed to is the name
table index of the command the key sequence invokes.
This subroutine stores the key sequence in the keyname parameter
in text form (as "Ctrl-X f", for example). It also copies the key
sequence into the global variable key_binding . The key
sequence is in macro format, so in the example of Ctrl-X f,
key_binding[1] would hold CTRL('X') , key_binding[2] would
hold 'f' , and key_binding[0] would hold 3, the total number
of entries in the array.
full_getkey(char *pr, int code) /* basic.e */
/* for full_getkey() */
#define ALTIFY_KEY 1
#define CTRLIFY_KEY 2
The full_getkey( ) subroutine defined in basic.e gets a single
key from the keyboard, but recognizes the prefix keys <Esc> and
Ctrl-^. The ask_key( ) subroutine uses it, as well as the
commands bound to the prefix keys above. It takes a prompt to
display and a bit pattern (from eel.h) to make it act as if certain
of the above keys had already been typed. For example, the
ctrl-prefix command calls this subroutine with the value
CTRLIFY_KEY . It leaves the key that results in the key
primitive.
name_macro(char *name, short *keys)
Epsilon has no internal mechanism for capturing keyboard keys to
build a macro (this is done in the getkey( ) subroutine defined
in control.e), but once a macro has been built Epsilon can name it and
make it accessible with the name_macro( ) function. It takes the
name of the macro to create, and the sequence of keys making up
the macro in an array of short ints. This array is in the same
format that get_keycode( ) uses. That is, the first element of
the array contains the number of valid elements in the array
(including the first one). The actual keys in the macro follow. The
name_macro( ) primitive makes a copy of the macro it is given,
so the array can be reused once the macro has been defined.
short *get_macro(int index)
The get_macro( ) primitive can retrieve the keys in a defined
keyboard macro. It takes the name table index of a macro, and
returns a pointer to the array containing the macro.
int list_bindings(int start, short *modetable,
short *roottable, int find)
The list_bindings( ) primitive quickly steps through a pair of
key tables, looking for entries that have a certain name table index.
It takes mode and root key tables, the name table index to find, and
either -1 to start at the beginning of the key tables, or the
value it returned on a previous call. It returns the index into the
key table, or -1 if there are no more matching entries. For
each position in the tables, Epsilon looks at the value in the mode
key table, unless it is zero. In that case, it uses the root table.
In addition to the matches, list_bindings( ) also stops on each
name table index corresponding to a key table, since these must
normally be searched also. For example, the following file
defines a command that counts the number of separate bindings of any
command.
#include "eel.h"
command count_bindings()
{
char cmd[80];
get_cmd(cmd, "Count bindings of command", "");
if (*cmd)
say("The %s command has %d bindings", cmd,
find_some(mode_keys,
root_keys, find_index(cmd)));
}
/* count bindings to index in table */
int find_some(modetable, roottable, index)
short *modetable, *roottable;
{
int i, total = 0, found;
i = list_bindings(-1, modetable, roottable, index);
while (i != -1) {
found = (modetable[i]
? modetable[i] : roottable[i]);
if (found == index)
total++;
else
total += find_some(index_table(found),
index_table(found), index);
i = list_bindings(i, modetable, roottable, index);
}
return total;
}
Previous
|
Up
|
Next
|
The Main Loop |
Primitives and EEL Subroutines |
Defining Language Modes |
Copyright (C) 1984, 2020 by Lugaru Software Ltd. All rights reserved.
|