Changeset View
Changeset View
Standalone View
Standalone View
src/toolset/workflow/ArcanistShellCompleteWorkflow.php
| Show First 20 Lines • Show All 500 Lines • ▼ Show 20 Lines | if ($is_workflow) { | ||||
| if ($alias->getToolset() !== $this->getToolsetKey()) { | if ($alias->getToolset() !== $this->getToolsetKey()) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| $complete[] = $alias->getTrigger(); | $complete[] = $alias->getTrigger(); | ||||
| } | } | ||||
| // Remove invalid possibilities. For example, if the user has typed | |||||
| // "skun<tab>", it obviously can't complete to "zebra". We don't really | |||||
| // need to do this filtering ourselves: the shell completion will | |||||
| // automatically match things for us even if we emit impossible results. | |||||
| // However, it's a little easier to debug the raw output if we clean it | |||||
| // up here before printing it out. | |||||
epriestley: We now do need to do this ourselves (see below) so I threw this comment away. | |||||
| $partial = $argv[$pos]; | $partial = $argv[$pos]; | ||||
| foreach ($complete as $key => $candidate) { | $complete = $this->getMatches($complete, $partial); | ||||
| if (strncmp($partial, $candidate, strlen($partial))) { | |||||
| unset($complete[$key]); | |||||
| } | |||||
| } | |||||
| if ($complete) { | if ($complete) { | ||||
| return $this->suggestStrings($complete); | return $this->suggestStrings($complete); | ||||
| } else { | } else { | ||||
| return $this->suggestNothing(); | return $this->suggestNothing(); | ||||
| } | } | ||||
| } else { | } else { | ||||
| // TOOLSETS: We should resolve aliases before picking a workflow, so | // TOOLSETS: We should resolve aliases before picking a workflow, so | ||||
| // that if you alias "arc draft" to "arc diff --draft", we can suggest | // that if you alias "arc draft" to "arc diff --draft", we can suggest | ||||
| // other "diff" flags when you type "arc draft --q<tab>". | // other "diff" flags when you type "arc draft --q<tab>". | ||||
| // TOOLSETS: It's possible the workflow isn't in position 1. The user | // TOOLSETS: It's possible the workflow isn't in position 1. The user | ||||
| // may be running "arc --trace diff --dra<tab>", for example. | // may be running "arc --trace diff --dra<tab>", for example. | ||||
| $workflow = idx($workflows, $argv[1]); | $workflow = idx($workflows, $argv[1]); | ||||
| if (!$workflow) { | if (!$workflow) { | ||||
| return $this->suggestNothing(); | return $this->suggestNothing(); | ||||
| } | } | ||||
| $arguments = $workflow->getWorkflowArguments(); | $arguments = $workflow->getWorkflowArguments(); | ||||
| $arguments = mpull($arguments, null, 'getKey'); | $arguments = mpull($arguments, null, 'getKey'); | ||||
| $current = idx($argv, $pos, ''); | |||||
| $argument = null; | $argument = null; | ||||
| $prev = idx($argv, $pos - 1, null); | $prev = idx($argv, $pos - 1, null); | ||||
| if (!strncmp($prev, '--', 2)) { | if (!strncmp($prev, '--', 2)) { | ||||
| $prev = substr($prev, 2); | $prev = substr($prev, 2); | ||||
| $argument = idx($arguments, $prev); | $argument = idx($arguments, $prev); | ||||
| } | } | ||||
| // If the last argument was a "--thing" argument, test if "--thing" is | // If the last argument was a "--thing" argument, test if "--thing" is | ||||
| // a parameterized argument. If it is, the next argument should be a | // a parameterized argument. If it is, the next argument should be a | ||||
| // parameter. | // parameter. | ||||
| if ($argument && strlen($argument->getParameter())) { | if ($argument && strlen($argument->getParameter())) { | ||||
| if ($argument->getIsPathArgument()) { | if ($argument->getIsPathArgument()) { | ||||
| return $this->suggestPaths(); | return $this->suggestPaths($current); | ||||
| } else { | } else { | ||||
| return $this->suggestNothing(); | return $this->suggestNothing(); | ||||
| } | } | ||||
| // TOOLSETS: We can allow workflows and arguments to provide a specific | // TOOLSETS: We can allow workflows and arguments to provide a specific | ||||
| // list of completeable values, like the "--shell" argument for this | // list of completeable values, like the "--shell" argument for this | ||||
| // workflow. | // workflow. | ||||
| } | } | ||||
| $flags = array(); | $flags = array(); | ||||
| $wildcard = null; | $wildcard = null; | ||||
| foreach ($arguments as $argument) { | foreach ($arguments as $argument) { | ||||
| if ($argument->getWildcard()) { | if ($argument->getWildcard()) { | ||||
| $wildcard = $argument; | $wildcard = $argument; | ||||
| continue; | continue; | ||||
| } | } | ||||
| $flags[] = '--'.$argument->getKey(); | $flags[] = '--'.$argument->getKey(); | ||||
| } | } | ||||
| $current = idx($argv, $pos, ''); | $matches = $this->getMatches($flags, $current); | ||||
| $matches = array(); | |||||
| if (strlen($current)) { | |||||
| foreach ($flags as $possible) { | |||||
| if (!strncmp($possible, $current, strlen($current))) { | |||||
| $matches[] = $possible; | |||||
| } | |||||
| } | |||||
| } | |||||
| // If whatever the user is completing does not match the prefix of any | // If whatever the user is completing does not match the prefix of any | ||||
| // flag, try to autcomplete a wildcard argument if it has some kind of | // flag, try to autcomplete a wildcard argument if it has some kind of | ||||
| // meaningful completion. For example, "arc lint READ<tab>" should | // meaningful completion. For example, "arc lint READ<tab>" should | ||||
| // autocomplete a file. | // autocomplete a file. | ||||
| if (!$matches && $wildcard) { | if (!$matches && $wildcard) { | ||||
| // TOOLSETS: There was previously some very questionable support for | // TOOLSETS: There was previously some very questionable support for | ||||
| // autocompleting branches here. This could be moved into Arguments | // autocompleting branches here. This could be moved into Arguments | ||||
| // and Workflows. | // and Workflows. | ||||
| if ($wildcard->getIsPathArgument()) { | if ($wildcard->getIsPathArgument()) { | ||||
| return $this->suggestPaths(); | return $this->suggestPaths($current); | ||||
| } | } | ||||
| } | } | ||||
| return $this->suggestStrings($matches); | return $this->suggestStrings($matches); | ||||
| } | } | ||||
| } | } | ||||
| private function suggestPaths() { | private function suggestPaths($prefix) { | ||||
| echo "FILE\n"; | // NOTE: We are returning a directive to the bash script to run "compgen" | ||||
| // for us rather than running it ourselves. If we run: | |||||
| // | |||||
| // compgen -A file -- %s | |||||
| // | |||||
| // ...from this context, it fails (exits with error code 1 and no output) | |||||
| // if the prefix is "foo\ ", on my machine. See T9116 for some dicussion. | |||||
| echo "<compgen:file>"; | |||||
Done Inline ActionsI've replaced "FILE\n" with slightly more explicit magic, but it's still magic. epriestley: I've replaced "FILE\n" with slightly more explicit magic, but it's still magic. | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| private function suggestNothing() { | private function suggestNothing() { | ||||
| echo "ARGUMENT\n"; | return $this->suggestStrings(array()); | ||||
| return 0; | |||||
| } | } | ||||
Done Inline ActionsInstead of returning magic, we can just return nothing, so this is a slight simplification. epriestley: Instead of returning magic, we can just return nothing, so this is a slight simplification. | |||||
| private function suggestStrings(array $strings) { | private function suggestStrings(array $strings) { | ||||
| echo implode(' ', $strings)."\n"; | sort($strings); | ||||
| echo implode("\n", $strings); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| private function getMatches(array $candidates, $prefix) { | |||||
Done Inline ActionsWe're no longer using compgen -W ... (my goal in removing it is to reduce our reliance on Bash magic) so we now need to do our own matching in all cases. We were doing it in most cases anyway already so this isn't a large change. epriestley: We're no longer using `compgen -W ...` (my goal in removing it is to reduce our reliance on… | |||||
| $matches = array(); | |||||
| if (strlen($prefix)) { | |||||
| foreach ($candidates as $possible) { | |||||
| if (!strncmp($possible, $prefix, strlen($prefix))) { | |||||
| $matches[] = $possible; | |||||
| } | |||||
| } | |||||
| // If we matched nothing, try a case-insensitive match. | |||||
| if (!$matches) { | |||||
| foreach ($candidates as $possible) { | |||||
| if (!strncasecmp($possible, $prefix, strlen($prefix))) { | |||||
| $matches[] = $possible; | |||||
| } | |||||
| } | |||||
| } | |||||
| } else { | |||||
| $matches = $candidates; | |||||
| } | |||||
| return $matches; | |||||
| } | |||||
| } | } | ||||
We now do need to do this ourselves (see below) so I threw this comment away.