Skip to content

Command Completion Generator

Bertie2011 edited this page Aug 29, 2021 · 1 revision

Completion generator is the killer feature of CLIFramework. It compiles information from your application and commands into zsh/bash completion scripts in second.

CLIFramework completion generator supports command argument completion, command name completion, sub-command name completion and command option completion, so you don't have to worry the flexibility.

Adding Completion Support

To help completion generator work, you need to provide more information in your command classes.

Argument Info

You need to define what argument does this command take, what the type is. file path? directory name? ip? email? or address? or, is the argument optional? these information helps the completion generator generates the right script for you.

Here is an example of adding argument info. (copied from phpbrew):

<?php
namespace PhpBrew\Command;
...
class InstallCommand extends Command
{
    ....

    public function arguments($args) {
        $args->add('version')->suggestions(function() {
            $releaseList = ReleaseList::getReadyInstance();
            $releases = $releaseList->getReleases();

            $collection = new ValueCollection;
            foreach($releases as $major => $versions) {
                $collection->group($major, "PHP $major", array_keys($versions));
            }

            $collection->group('pseudo', 'pseudo', array('latest', 'next'));

            return $collection;
        });
        $args->add('variants')->multiple()->suggestions(function() {
            $variants = new VariantBuilder;
            $list = $variants->getVariantNames();
            sort($list);
            return array_map(function($n) { return '+' . $n; }, $list);
        });
    }

In the above example, you shall find out that the value generator doesn't have to be written in ugly zsh, you can just write your favorite PHP code to generate completion results!

When you set closure as the value generator to suggestions/validValues accessor, the closure will be executed every time when the completion function is invoked. The completion items will be retrieved from meta command in the runtime (see CLIFramework\Command\MetaCommand). If you want the suggestion values to be compiled statically, you can just pass plain array to suggestions/validValues accessor, for example:

    public function arguments($args) {

        $args->add('user')
            ->desc('user name')
            ->validValues(['c9s','bar','foo']);

        $args->add('repo')
            ->desc('repository')
            ->validValues(['CLIFramework','GetOptionKit']);
    }

Options

Options can also help the completion generator work. here is an example of using it. (CLIFramework uses GetOptionKit for command option parsing)

    /**
     * @param \GetOptionKit\OptionCollection $opts
     */
    public function options($opts)
    {
        $opts->add('build-dir:','Specify the build directory. '
            . 'the distribution tarball will be extracted to the directory you specified '
            . 'instead of $PHPBREW_ROOT/build/{name}.')
            ->isa('dir')
            ;
        $opts->add('f|force', 'Force the installation (redownloads source).')
            ->defaultValue(false)
            ;

    }

For more details, please see GetOptionKit (https://github.com/c9s/GetOptionKit)

Generating zsh completion script

There is a hidden command named zsh, it's used for generating zsh completion script. if you've checked out CLIFrameworks' code, you can run the demo app to see the output:

php example/demo zsh

You shall see the last line of the output:

.....
.....
compdef _example_demo example/demo

It shows that the completion function will be bound to example/demo, which means you have to type example/demo as the actual command to use the completion.

If you want the completion script to be bound to something else, for example, demo, you can do:

php example/demo zsh --bind demo > demo.zsh
source demo.zsh

Then you can type demo <TAB> to see the completion script interacting with your PHP application.

If you need the PHP program (usually phar files, like composer.phar, phpunit.phar) to be completed in any directory, you can setup the program name for the completion script. (when the completion results are generated dynamically in the runtime, the completion script needs to call your program to generate the results). for example, here is the command that phpbrew generates its own completion script:

bin/phpbrew zsh --bind phpbrew --program phpbrew > completion/zsh/_phpbrew
bin/phpbrew bash --bind phpbrew --program phpbrew > completion/bash/_phpbrew