Substituting Actions

So far the spoken words in our alternative sets have been substituted directly into our keystroke sequences. Actually it is more common to substitute a different set of actions than the spoken words.

For example, suppose we want "Move Back" to move the cursor left and "Move Forward" to move the cursor right. We can specify that this way:

Vocola: Move (Back=Left | Forward=Right) = {$1};

Say: Move Back     Sent: {Left}

Say: Move Forward  Sent: {Right}

The alternative set (Back=Left | Forward=Right) means you can say either "Back" or "Forward", but the value substituted on the right hand side will be Left or Right.

Here's another example. Mozilla's Thunderbird Mailer has several options for sorting messages. This command allows you to change the sort by saying "Sort by Date", "Sort by Sender", or "Sort by Subject":

Vocola: Sort by (Date=e | Sender=n | Subject=b) = {Alt+v}s $1;

Say: Sort by Date    Sent: {Alt+v}se

Say: Sort by Sender  Sent: {Alt+v}sn

This alternative set allows you to say "Date", "Sender", or "Subject", and substitutes e, n, or b into the keystroke sequence. (The keystroke {Alt+v} opens the "View" menu, s opens the "Sort by" sub-menu, and the final letter chooses the sort option.)

Alternative sets with substitution provide an easy way to define voice shortcuts for items such as files, folders, URLs, or email addresses. For example, we can define the variable <address> to contain a list of email addresses and shortcuts to invoke them:

Vocola: <address> := ( Pat = [email protected]

                     | Listen = [email protected]
                     | Voice Coder = [email protected]
                     );
        Address <address> = $1 {Enter};

Say: Address Bill         Sent: [email protected]{Enter}

Say: Address Voice Coder  Sent: [email protected]{Enter}

The command Address <address> allows you to say, for example, "Address Bill" or "Address Voice Coder" to insert the desired email address. The list can be modified over time to add new addresses.

An alternative and its substitution (e.g., Listen = [email protected]) is actually a mini-command—"when I say this, send these keystrokes". As with a command, the left-hand side may be an alternative set and the right-hand side may contain a sequence of actions. Prior to version 2.9, the left-hand side was not allowed to contain variables or ranges, and the right-hand side was not allowed to contain references.

Variables may be defined in any order — you do not need to define a variable before you reference it. Variables may also be defined in terms of other variables as long as you do not create a recursive loop where a variable is defined, however indirectly, in terms of itself.

Here's a more complicated example that uses these features. This command opens a file from a list of favorite files, then possibly goes to an interesting position:

Vocola: open <my_file> [<position>] = openFile($1) $2;

	<position> := ( end			   = {ctrl+end}
                      | line 1..99		   = {ctrl+home}{down_$1}
                      | line 1..99 character 1..80 = {ctrl+home}{down_$1}{right_$2}
                      | at <my_landmark>           = moveToLandmark($1)
                      );
        <my_file>     := ( foo = ~/foo.txt | ... );
        <my_landmark> := ( contents | ... )

Here openFile and moveToLandmark are assumed to be user-defined Vocola functions (see this section on defining your own functions) that open a file and move to a landmark within it respectively.

References (i.e., $1) refer to the nth top level variable or alternative list in the command whose actions they belong to, ignoring optional indicators. Consider, for example, the following command:

Vocola: foo <a> [<b> (<c> <d>=$2$1)] 1..10 = ...;

Here in the command's actions (the ... part), $1 refers to <a>, $2 refers to <b>, $3 refers to the entire alternative list (<c> <d>=$2$1), and $4 refers to 1..10. It is not possible to refer to <c> in the outer command's actions. In the inner command, <c> <d>=$2$1, $1 refers to <c> as you would expect.

Normally alternatives do not require actions; however, alternatives containing a variable or inline list plus one or more other terms require an action assignment to tell Vocola how to combine the inputs. For example, the following alternative requires an assignment: <motion> := <direction> 1..10 = {$1_$2};
 
Copyright © 2002-2023 Rick Mohr