Completed
Pull Request — master (#87)
by Stephen
01:03
created

CompletionCommand::createDefinition()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 9.456
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Stecman\Component\Symfony\Console\BashCompletion;
4
5
use Symfony\Component\Console\Command\Command as SymfonyCommand;
6
use Symfony\Component\Console\Input\InputDefinition;
7
use Symfony\Component\Console\Input\InputInterface;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Output\OutputInterface;
10
11
class CompletionCommand extends SymfonyCommand
12
{
13
    /**
14
     * @var CompletionHandler
15
     */
16
    protected $handler;
17
18
    protected function configure()
19
    {
20
        $this
21
            ->setName('_completion')
22
            ->setDefinition($this->createDefinition())
23
            ->setDescription('BASH completion hook.')
24
            ->setHelp(<<<END
25
To enable BASH completion, run:
26
27
    <comment>eval `[program] _completion -g`</comment>.
28
29
Or for an alias:
30
31
    <comment>eval `[program] _completion -g -p [alias]`</comment>.
32
33
END
34
            );
35
36
        // Hide this command from listing if supported
37
        // Command::setHidden() was not available before Symfony 3.2.0
38
        if (method_exists($this, 'setHidden')) {
39
            $this->setHidden(true);
40
        }
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function getNativeDefinition()
47
    {
48
        return $this->createDefinition();
49
    }
50
51
    /**
52
     * Ignore user-defined global options
53
     *
54
     * Any global options defined by user-code are meaningless to this command.
55
     * Options outside of the core defaults are ignored to avoid name and shortcut conflicts.
56
     */
57
    public function mergeApplicationDefinition($mergeArgs = true)
58
    {
59
        // Get current application options
60
        $appDefinition = $this->getApplication()->getDefinition();
61
        $originalOptions = $appDefinition->getOptions();
62
63
        // Temporarily replace application options with a filtered list
64
        $appDefinition->setOptions(
65
            $this->filterApplicationOptions($originalOptions)
66
        );
67
68
        parent::mergeApplicationDefinition($mergeArgs);
69
70
        // Restore original application options
71
        $appDefinition->setOptions($originalOptions);
72
    }
73
74
    /**
75
     * Reduce the passed list of options to the core defaults (if they exist)
76
     *
77
     * @param InputOption[] $appOptions
78
     * @return InputOption[]
79
     */
80
    protected function filterApplicationOptions(array $appOptions)
81
    {
82
        return array_filter($appOptions, function(InputOption $option) {
83
            static $coreOptions = array(
84
                'help' => true,
85
                'quiet' => true,
86
                'verbose' => true,
87
                'version' => true,
88
                'ansi' => true,
89
                'no-ansi' => true,
90
                'no-interaction' => true,
91
            );
92
93
            return isset($coreOptions[$option->getName()]);
94
        });
95
    }
96
97
    protected function execute(InputInterface $input, OutputInterface $output)
98
    {
99
        $this->handler = new CompletionHandler($this->getApplication());
100
        $handler = $this->handler;
101
102
        if ($input->getOption('generate-hook')) {
103
            global $argv;
104
            $program = $argv[0];
105
106
            $factory = new HookFactory();
107
            $alias = $input->getOption('program');
108
            $multiple = (bool)$input->getOption('multiple');
109
110
            if (!$alias) {
111
                $alias = basename($program);
112
            }
113
114
            $hook = $factory->generateHook(
115
                $input->getOption('shell-type') ?: $this->getShellType(),
116
                $program,
117
                $alias,
118
                $multiple
119
            );
120
121
            $output->write($hook, true);
122
        } else {
123
            $handler->setContext(new EnvironmentCompletionContext());
124
            $output->write($this->runCompletion(), true);
0 ignored issues
show
Documentation introduced by
$this->runCompletion() is of type array<integer,string>, but the function expects a string|object<Symfony\Co...onsole\Output\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
125
        }
126
    }
127
128
    /**
129
     * Run the completion handler and return a filtered list of results
130
     *
131
     * @deprecated - This will be removed in 1.0.0 in favour of CompletionCommand::configureCompletion
132
     *
133
     * @return string[]
134
     */
135
    protected function runCompletion()
136
    {
137
        $this->configureCompletion($this->handler);
138
        return $this->handler->runCompletion();
139
    }
140
141
    /**
142
     * Configure the CompletionHandler instance before it is run
143
     *
144
     * @param CompletionHandler $handler
145
     */
146
    protected function configureCompletion(CompletionHandler $handler)
0 ignored issues
show
Unused Code introduced by
The parameter $handler is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
147
    {
148
        // Override this method to configure custom value completions
149
    }
150
151
    /**
152
     * Determine the shell type for use with HookFactory
153
     *
154
     * @return string
155
     */
156
    protected function getShellType()
157
    {
158
        if (!getenv('SHELL')) {
159
            throw new \RuntimeException('Could not read SHELL environment variable. Please specify your shell type using the --shell-type option.');
160
        }
161
162
        return basename(getenv('SHELL'));
163
    }
164
165
    protected function createDefinition()
166
    {
167
        return new InputDefinition(array(
168
            new InputOption(
169
                'generate-hook',
170
                'g',
171
                InputOption::VALUE_NONE,
172
                'Generate BASH code that sets up completion for this application.'
173
            ),
174
            new InputOption(
175
                'program',
176
                'p',
177
                InputOption::VALUE_REQUIRED,
178
                "Program name that should trigger completion\n<comment>(defaults to the absolute application path)</comment>."
179
            ),
180
            new InputOption(
181
                'multiple',
182
                'm',
183
                InputOption::VALUE_NONE,
184
                "Generated hook can be used for multiple applications."
185
            ),
186
            new InputOption(
187
                'shell-type',
188
                null,
189
                InputOption::VALUE_OPTIONAL,
190
                'Set the shell type (zsh or bash). Otherwise this is determined automatically.'
191
            ),
192
        ));
193
    }
194
}
195