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.

 
Copyright © 2002-2023 Rick Mohr