User defined commands

Defining commands

VPE provides the vpe.define_command function as a way to create commands that invoke Python functions or methods. In other words, you can define commands that are implemented using Python functions (implementation functions). It maps fairly closely to Vim’s :command. Here is a very trival example:

import vpe

def echo_command(info: vpe.CommandInfo, *args):
    vpe.echo_msg(f'Echoing {args}')

vpe.define_command('Echo', echo_command, nargs='*')

This creates a command call ‘Echo’, which takes an arbitrary number of arguments. The ‘echo_command’ function receives these as positional parameters following the initial vpe.CommandInfo argument. The command:

Echo 1 2 three

will print:

Echoing ('1', '2', 'Three')

The vpe.define_command function takes a number of keyword arguments that are analogues of the :command options with the same names.

nargs

May be 0, 1, ‘*’, ‘?’ or ‘+’ (‘0’ and ‘1’ as strings also work).

complete

A string. Any value accepted by :command, except for ‘custom’ and ‘customlist’.

range

Set to True to simply allow the command to take a range. Use ‘%’ to set a default range of the whole file and a number (may be as a string) to set a default count.

count

The same as for :command, except that you can use integers or strings ‘N’.

addr

How special characters in a range are interpreted by Vim.

bang, bar, register, buffer

Boolean values that act like the corresponding :command options.

The implementation of vpe.define_command invokes :command! ... so that any previous command of the same name is replaced. The argument replace=False makes VPE invoke :command ....

CommandInfo

The vpe.CommandInfo argument makes it easy for the called function to determine the details of how the command was invoked. It provides the following attributes.

line1, line2

The start line and end line of the command range.

range

The number of items in the command range: 0, 1 or 2. This requires at least vim 8.0.1089; for earlier versions it is fixed as -1.

count

Any count value supplied (see command-count).

bang

True if the command was invoked with a ‘!’.

mods

The command modifiers (see :command-modifiers). This is a space separated string.

reg

The optional register, if provided.

Functions arguments

Additional arguments can be passed to the command callback function. These are defined using args and kwargs.

def echo_command(info: vpe.CommandInfo, mode, *args, level=0):
    vpe.echo_msg(f'{mode}[{level}]: {args}')

vpe.define_command(
    'Echo',
    echo_command,
    nargs='*',
    args=('info',),
    kwargs={'level': 2})

The command:

Echo 20 30

Will print:

info[2]: ('20', '30')

Notice that args preset using vpe.define_command are passed to the implementation function before those of the Echo command.

The vpe.CommandInfo parameter can be suppressed if desired using the pass_info argument.

def echo_command(mode, *args, level=0):
    vpe.echo_msg(f'{mode}[{level}]: {args}')

vpe.define_command(
    'Echo',
    echo_command,
    nargs='*',
    args=('info',),
    kwargs={'level': 2},
    pass_info=False)

Using decorators

Note

This feature should be considered experimental at the moment. It will not be removed, but detailed behaviour, argument names, etc. may change in the next release.

In a similar way to key mapping, VPE provides a decorator approach to define command implementation functions. The vpe.CommandHandler mixin class is used for this.

class MessageGenerator(vpe.CommandHandler):
    command = vpe.CommandHandler.command

    def __init__(self):
        self.auto_define_commands()

    @command('Echo', nargs='*', args=('info',), kwargs={'level': 2})
    def echo_command(self, mode, *args, level=0):
        vpe.echo_msg(f'{mode}[{level}]: {args}')

message_gen = MessageGenerator()

This can make code easier to read and maintain in some circumstances, but it is not as flexible as vpe.define_command.

Note that the mappings are only created when the self.auto_define_commands() method is invoked. Also note that, by default, the methods do not receive a vpe.CommandInfo object as the first argument. Give the vpe.CommandHandler.command decorator a pass_info=True argument to change this behaviour.

The vpe.CommandHandler.command decorator accepts all the arguments of vpe.define_command except for func.