2011-01-14 20:00:11 -08:00
|
|
|
<?php
|
|
|
|
|
2011-02-19 11:36:08 -08:00
|
|
|
/**
|
|
|
|
* Powers shell-completion scripts.
|
|
|
|
*
|
|
|
|
* @group workflow
|
|
|
|
*/
|
2012-01-31 12:07:05 -08:00
|
|
|
final class ArcanistShellCompleteWorkflow extends ArcanistBaseWorkflow {
|
2011-01-14 20:00:11 -08:00
|
|
|
|
Make Arcanist workflow names explicit
Summary:
Currently, adding a new workflow requires you to override ArcanistConfiguration, which is messy. Instead, just load everything that extends ArcanistBaseWorkflow.
Remove all the rules tying workflow names to class names through arcane incantations.
This has a very small performance cost in that we need to load every Workflow class every time now, but we don't hit __init__ and such anymore and it was pretty negligible on my machine (98ms vs 104ms or something).
Test Plan: Ran "arc help", "arc which", "arc diff", etc.
Reviewers: edward, vrana, btrahan
Reviewed By: edward
CC: aran, zeeg
Differential Revision: https://secure.phabricator.com/D3691
2012-10-17 08:35:03 -07:00
|
|
|
public function getWorkflowName() {
|
|
|
|
return 'shell-complete';
|
|
|
|
}
|
|
|
|
|
2012-03-05 10:02:37 -08:00
|
|
|
public function getCommandSynopses() {
|
2011-01-14 20:00:11 -08:00
|
|
|
return phutil_console_format(<<<EOTEXT
|
|
|
|
**shell-complete** __--current__ __N__ -- [__argv__]
|
2012-03-05 10:02:37 -08:00
|
|
|
EOTEXT
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCommandHelp() {
|
|
|
|
return phutil_console_format(<<<EOTEXT
|
2011-01-14 20:00:11 -08:00
|
|
|
Supports: bash, etc.
|
|
|
|
Implements shell completion. To use shell completion, source the
|
|
|
|
appropriate script from 'resources/shell/' in your .shellrc.
|
|
|
|
EOTEXT
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getArguments() {
|
|
|
|
return array(
|
|
|
|
'current' => array(
|
|
|
|
'help' => 'Current term in the argument list being completed.',
|
|
|
|
'param' => 'cursor_position',
|
|
|
|
),
|
|
|
|
'*' => 'argv',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function shouldShellComplete() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run() {
|
|
|
|
|
|
|
|
$pos = $this->getArgument('current');
|
|
|
|
$argv = $this->getArgument('argv', array());
|
|
|
|
$argc = count($argv);
|
|
|
|
if ($pos === null) {
|
|
|
|
$pos = $argc - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine which revision control system the working copy uses, so we
|
|
|
|
// can filter out commands and flags which aren't supported. If we can't
|
|
|
|
// figure it out, just return all flags/commands.
|
|
|
|
$vcs = null;
|
|
|
|
|
|
|
|
// We have to build our own because if we requiresWorkingCopy() we'll throw
|
|
|
|
// if we aren't in a .arcconfig directory. We probably still can't do much,
|
|
|
|
// but commands can raise more detailed errors.
|
2011-12-23 23:48:46 -08:00
|
|
|
$working_copy = ArcanistWorkingCopyIdentity::newFromPath(getcwd());
|
2011-01-14 20:00:11 -08:00
|
|
|
if ($working_copy->getProjectRoot()) {
|
|
|
|
$repository_api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity(
|
|
|
|
$working_copy);
|
|
|
|
$vcs = $repository_api->getSourceControlSystemName();
|
|
|
|
}
|
|
|
|
|
|
|
|
$arc_config = $this->getArcanistConfiguration();
|
|
|
|
|
|
|
|
if ($pos == 1) {
|
|
|
|
$workflows = $arc_config->buildAllWorkflows();
|
|
|
|
|
|
|
|
$complete = array();
|
|
|
|
foreach ($workflows as $name => $workflow) {
|
|
|
|
if (!$workflow->shouldShellComplete()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$supported = $workflow->getSupportedRevisionControlSystems();
|
|
|
|
|
|
|
|
$ok = (in_array('any', $supported)) ||
|
|
|
|
(in_array($vcs, $supported));
|
|
|
|
if (!$ok) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$complete[] = $name;
|
|
|
|
}
|
|
|
|
|
2012-02-21 13:16:52 -08:00
|
|
|
// Also permit autocompletion of "arc alias" commands.
|
2012-04-10 11:29:25 -07:00
|
|
|
foreach (
|
|
|
|
ArcanistAliasWorkflow::getAliases($working_copy) as $key => $value) {
|
2012-02-21 13:16:52 -08:00
|
|
|
$complete[] = $key;
|
|
|
|
}
|
|
|
|
|
2011-01-14 20:00:11 -08:00
|
|
|
echo implode(' ', $complete)."\n";
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
$workflow = $arc_config->buildWorkflow($argv[1]);
|
|
|
|
if (!$workflow) {
|
2012-02-21 13:16:52 -08:00
|
|
|
list($new_command, $new_args) = ArcanistAliasWorkflow::resolveAliases(
|
|
|
|
$argv[1],
|
|
|
|
$arc_config,
|
2012-04-10 11:29:25 -07:00
|
|
|
array_slice($argv, 2),
|
|
|
|
$working_copy);
|
2012-02-21 13:16:52 -08:00
|
|
|
if ($new_command) {
|
|
|
|
$workflow = $arc_config->buildWorkflow($new_command);
|
|
|
|
}
|
|
|
|
if (!$workflow) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
$argv = array_merge(
|
|
|
|
array($argv[0]),
|
|
|
|
array($new_command),
|
|
|
|
$new_args);
|
|
|
|
}
|
2011-01-14 20:00:11 -08:00
|
|
|
}
|
2012-02-21 13:16:52 -08:00
|
|
|
|
2011-01-14 20:00:11 -08:00
|
|
|
$arguments = $workflow->getArguments();
|
|
|
|
|
|
|
|
$prev = idx($argv, $pos - 1, null);
|
|
|
|
if (!strncmp($prev, '--', 2)) {
|
|
|
|
$prev = substr($prev, 2);
|
|
|
|
} else {
|
|
|
|
$prev = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($prev !== null &&
|
|
|
|
isset($arguments[$prev]) &&
|
|
|
|
isset($arguments[$prev]['param'])) {
|
|
|
|
|
|
|
|
$type = idx($arguments[$prev], 'paramtype');
|
|
|
|
switch ($type) {
|
|
|
|
case 'file':
|
|
|
|
echo "FILE\n";
|
|
|
|
break;
|
|
|
|
case 'complete':
|
|
|
|
echo implode(' ', $workflow->getShellCompletions($argv))."\n";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
echo "ARGUMENT\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
} else {
|
2011-02-18 22:17:41 -08:00
|
|
|
|
2011-01-14 20:00:11 -08:00
|
|
|
$output = array();
|
|
|
|
foreach ($arguments as $argument => $spec) {
|
|
|
|
if ($argument == '*') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ($vcs &&
|
|
|
|
isset($spec['supports']) &&
|
|
|
|
!in_array($vcs, $spec['supports'])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$output[] = '--'.$argument;
|
|
|
|
}
|
2011-02-18 22:17:41 -08:00
|
|
|
|
2011-02-16 11:51:06 -08:00
|
|
|
$cur = idx($argv, $pos, '');
|
|
|
|
$any_match = false;
|
2012-04-23 14:09:29 -07:00
|
|
|
|
|
|
|
if (strlen($cur)) {
|
|
|
|
foreach ($output as $possible) {
|
|
|
|
if (!strncmp($possible, $cur, strlen($cur))) {
|
|
|
|
$any_match = true;
|
|
|
|
}
|
2011-02-16 11:51:06 -08:00
|
|
|
}
|
|
|
|
}
|
2011-02-18 22:17:41 -08:00
|
|
|
|
2011-02-16 11:51:06 -08:00
|
|
|
if (!$any_match && isset($arguments['*'])) {
|
2012-04-23 14:09:29 -07:00
|
|
|
// TODO: This is mega hacktown but something else probably breaks
|
|
|
|
// if we use a rich argument specification; fix it when we move to
|
|
|
|
// PhutilArgumentParser since everything will need to be tested then
|
|
|
|
// anyway.
|
|
|
|
if ($arguments['*'] == 'branch' && isset($repository_api)) {
|
|
|
|
$branches = $repository_api->getAllBranches();
|
|
|
|
$branches = ipull($branches, 'name');
|
|
|
|
$output = $branches;
|
|
|
|
} else {
|
|
|
|
$output = array("FILE");
|
|
|
|
}
|
2011-02-16 11:51:06 -08:00
|
|
|
}
|
2012-04-23 14:09:29 -07:00
|
|
|
|
|
|
|
echo implode(' ', $output)."\n";
|
|
|
|
|
2011-01-14 20:00:11 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|