Contextual Commands
We've discussed how to create "global" commands (always enabled) as well as application-specific commands
(enabled when a particular application is active). This page describes how to create window-title-specific
commands, which are enabled only when the active window's title contains particular text.
By specifying all or part of a window's title (case insensitive) in a context statement you can create
commands specific to that window. For example, here are three groups of commands for Microsoft Outlook (from the
application-specific command file outlook.vcl):
$if "Microsoft Outlook";
New Message = {Ctrl+n};
Reply to Message = {Ctrl+r};
Reply to All = {Ctrl+Shift+r};
Forward Message = {Ctrl+f};
$end
$if "Message (Plain Text)";
Send That = {Alt+s};
$end
$if Calendar;
View Month = {Alt+m};
View Work Week = {Alt+r};
$end
|
The context statement $if "Microsoft Outlook"; specifies that subsequent commands should be
active only when "Microsoft Outlook" is part of the title of the active window. When reading mail using Outlook
the main window title is "Inbox - Microsoft Outlook", so the first group of commands above (to create, reply to,
or forward a message) will be enabled.
Similarly, when editing a mail message the window title is "Message (Plain Text)", so the second group of
commands above will be enabled. Finally, the third group of commands above will be enabled when the Outlook
Calendar is displayed.
Note that the text following $if uses the same rules
for quotes and whitespace that apply to Vocola keystroke actions. In
particular you must use quotes if the target text contains a space character, but may omit quotes if it does
not.
Multiple branches
A context statement may have multiple branches, by using $elseif
and $else. For example, if you are a programmer using several languages and your text
editor displays the name of the current file in the window title, you could use a context statement with
multiple branches for a command which "comments out" lines using the comment syntax appropriate to the language
being edited.
$if .css;
Comment <n> [Lines] = Repeat($1, {Home}/*{End}*/{Down}) {Up_$1};
$elseif .cs;
Comment <n> [Lines] = Repeat($1, {Home}//{Down}) {Up_$1};
$else
Comment <n> [Lines] = Repeat($1, "{Home}#{Down}") {Up_$1};
$end
|
If for example you are editing the CSS file site.css the first command above will be
enabled because the window title will contain .css. Saying "Comment 3 Lines" will use
the CSS comment syntax (/* ... */) to comment out 3 lines. If on the other hand you
are editing the C# file Main.cs the second command will be enabled because the window
title will contain .cs. Saying "Comment 3 Lines" will use the C# comment syntax
(//) to comment out 3 lines. Finally, if the window title contains
neither .css nor .cs the third command will be enabled,
and saying "Comment 3 Lines" will use # to comment out 3 lines.
A context statement may contain any number of $elseif clauses and may optionally end
with an $else clause. The final $end is required.
Global Contextual Commands and Multiple Context Choices
Contextual commands don't need to be application-specific. You can also create global contextual commands, as
in this example which could be placed in a global command file:
$if Open;
Go Up = ..{Enter};
Folder List = {Shift+Tab_2}{Down}{PgUp};
$end
|
This defines two commands for use in a "File Open" dialog box, regardless of the current application. Whenever
the window title includes the word Open, you can say "Go Up" to move to the parent
folder or "Folder List" to open the folder hierarchy dropdown at the top of the dialog.
As it happens, "File Chooser" dialog boxes appear with a wide range of titles, such as "Open File", "Save As",
"Browse for Folder", etc. Ideally we want the same set of context-specific commands to be available for all such
dialogs. Vocola supports this by allowing the | character to specify alternatives in
context statements. Here is a similar example with a larger set of context titles and commands:
$if Open | New | Save | File | Attachment | Browse | Directory;
Folder <folder> = {Ctrl+c}$1\{Enter};
Go Up = ..{Enter};
Go Up <n> = Repeat($1, ..\) {Enter};
Folder List = {Shift+Tab_2}{Down}{PgUp};
$end
|
Scope
Each block of a context statement introduces a local naming scope. Functions and variables defined within that
block can only be referenced by statements within that block. Statements in a block may reference functions and
variables defined in any containing block or at the top level of a file.
For example, here is another command for adding comments when programming in different languages. Comments
in Perl, Python, and Vocola use # while comments in Java, C#, C++, and JavaScript
use //. For each group of languages we can define a context block with its
own comment() function:
$if .pl | .py | .vcl | .vch;
comment() := "# ";
New Comment = {End}{Enter} comment();
$elseif .java | .cs | .cpp | .h | .js;
comment() := "// ";
New Comment = {End}{Enter} comment();
$end
|
The "New Comment" command in each block refers to the local comment() function. We
could then create a file called comment.vch containing several general-purpose comment
commands such as "New Comment", "New Comment Above", and "Comment 1..20 Lines" all
using comment(), and include that file in both blocks:
$if .vcl | .vch | .pl | .py;
comment() := "# ";
$include "comment.vch";
$elseif .java | .cs | .cpp | .h | .js;
comment() := "// ";
$include "comment.vch";
$end
|
Now we have a set of comment commands defined once that work for many programming languages using the
appropriate comment syntax for each.