Commands

User-invokable commands can be added to the menus and command palette, optionally with keyboard key-equivalents. These commands invoke a callback registered in the JavaScript execution environment of the extension.

Defining a Command

The extension’s extension.json can include a commands object defining which commands are exposed by the extension.

The commands object can contain several “sections” that commands may be defined:

Example:

{
    "identifier": "com.panic.HTML",
    "name": "HTML",
    "vendor": "Panic Inc.",
    
    "main": "main.js",
    
    "commands": {
        "editor": [
            {
                "title": "Wrap Selection In Tag",
                "command": "wrapSelectionInTag",
                "shortcut": "cmd-<",
                "when": "editorHasFocus",
                "filters": {
                    "syntaxes": ["html"]
                }
            }
        ]
        
    }
}

This defines a command, “Wrap Selection In Tag”, that when invoked by the user will invoke the wrapSelectionInTag command handler registered in the extension’s JavaScript environment. Registration of the command handler is done like so:

// Wraps the current editor selection in a new tag, with placeholders
nova.commands.register("wrapSelectionInTag", (editor) => {
    var selectedRanges = editor.selectedRanges.reverse();
    editor.edit(function(e) {
        for (var range of selectedRanges) {
            var text = editor.getTextInRange(range);
            var newText = "<$[tag]>" + text + "</$[tag]>";
            e.replace(range, newText);
        }
    });
});

Each command can be configured using a number of options:

Shortcut Key Bindings

For commands which allow keyboard access, the shortcut option can be specified to allow the command to be bound to a specific key binding.

A command’s key binding has the following restrictions:

The format of a key binding shortcut is a dash-separated (-) list of one or more modifiers followed by a keycode.

Modifiers

Modifiers are specified using cmd, opt, ctrl, and shift.

Any standard key binding is allowed, provided at least one non-shift modifier key is provided. Modifiers are specified as cmd, opt, ctrl, and shift.

Keycodes

Keycodes may be any valid ASCII character that would be present on a keyboard, as well as several predefined strings for special keys:

Examples

When Clauses

The when and state clauses of extension commands are defined by an expression that determines under what circumstances a command should be enabled or show its active state. The expression format follows a strict subset of standard JavaScript conditional syntax.

The following conditional syntax is supported as of Nova 5:

Examples:

Variables in When Clauses

The set of available variables defined directly by the extension runtime for various contexts in when expressions are:

Editor Context
documentHasPath The document has a path, representing a file on disk (as opposed to an untitled file)
editorHasFocus The editor is the focused pane and is first responder
editorHasSelection The editor has at least one non-zero-length selected range
editorHasMultipleSelections The editor has at least two or more selections (including multiple cursors)
editorSyntax Evaluates the editor syntax name against a string (editorSyntax == 'javascript')
ViewItem Context
viewItem The contextValue for the item(s) that are currently selected

Custom Variables in When Clauses

New in Nova 5.

Any custom variables defined in the nova.workspace.context Configuration object will be available to when and state clauses. This allows commands to be conditionally enabled based on state set from the extension.

Separator Items

For both the Extensions and Editor menu contexts (commands placed within the extensions and editor groups of the commands manifest key), you can optionally include separator items to better group your commands.

To define a separator, add an object with the following form:

{"separator": true}

These can be placed anywhere in your commands array, provided that two separators are not adjacent to each other and they do not appear at the head and tail of the menu.