The replace_map option in Complete::Util 0.43

This is yet another option for increasing convenience in tab completion, by allowing for spelling corrections. Suppose you have a Perinci::CmdLine CLI script that accepts an argument with values of “mount” or “unmount”:

use Perinci::CmdLine::Lite;

our %SPEC;
$SPEC{my_program} = {
    v => 1.1,
    summary => "Mount or unmount media",
    args => {
        action => {
            schema => ['str*', in=>['mount','unmount']],
            req => 1,
            pos => 0,
        },
        media => {
            summary => 'Media name',
            schema => 'str*',
            req => 1,
            pos => 1,
        },
    },
};
sub my_program {
    ...
}

Perinci::CmdLine::Lite->new(url => '/main/my_program')->run;

This program can be used on the command-line like below:

% my_program mount foo
% my_prograrm unmount foo

And the completion works like below:

% my_program [tab]
mount  unmount

% my_program m[tab]
% my_program mount _

% my_program u[tab]
% my_program unmount _

But what if you type “my_program um” or “my_program umount” (it’s most probably in your muscle memory if you spend a lot of your time on Unix CLI environment. The completion library cannot conveniently produce a unique correct completion for you:

% my_program um[tab]
mount  unmount

Why? By keeping in mind about how the completion library tries to find a match: first, the completion library tries string prefix matching against (‘mount’, ‘unmount’) and fails. Then, it tries word-mode matching (actually it skips it because the word to be completed “um” is just a single “word” and does not contain any dashes or other word separators). Next, it tries char-mode matching and returns (‘mount’, ‘unmount’). The result: no direct completion, no convenience.

We can solve this by using the replace_map option of the complete_array_elem() function. The option was introduced in Complete::Util 0.43. The option allows us to specify spelling variations for array elements.

Let’s modify our program to become:

use Complete::Util qw(complete_array_elem);
use Perinci::CmdLine::Lite;

my $actions = ['mount','unmount'];

our %SPEC;
$SPEC{my_program} = {
    v => 1.1,
    summary => "Mount or unmount media",
    args => {
        action => {
            schema => ['str*', in=>$actions],
            req => 1,
            pos => 0,
            completion => sub {
                my %args = @_;
                my $word = $args{word};
                complete_array_elem(
                    word => $word, array => $actions,
                    replace_map => { unmount => ['umount'] },
                );
            },
        },
        media => {
            summary => 'Media name',
            schema => 'str*',
            req => 1,
            pos => 1,
        },
    },
};
sub my_program {
    ...
}

Perinci::CmdLine::Lite->new(url => '/main/my_program')->run;

We’ve added a custom completion routine for the argument action. With the replace_map option, “umount” (as well as other spelling variations, if they are also specified) is included as a completion candidate. And in the final result, they will be replaced with “unmount”. So now:

% my_program um[tab]
% my_program unmount _

% my_program umount[tab]
% my_program unmount _
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s