1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-26 16:52:40 +01:00

Remove command spelling correction from Arcanist

Summary: Fixes T7489. Depends on D16332, which moved this code to libphutil.

Test Plan:
```
$ arc banch --bystatus
(Assuming 'banch' is the British spelling of 'branch'.)
(Assuming '--bystatus' is the British spelling of '--by-status'.)
...
```

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T7489

Differential Revision: https://secure.phabricator.com/D16333
This commit is contained in:
epriestley 2016-07-27 05:39:39 -07:00
parent 1bedfdccd7
commit 06c641f92c
4 changed files with 4 additions and 177 deletions

View file

@ -41,7 +41,6 @@ phutil_register_library_map(array(
'ArcanistBraceFormattingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBraceFormattingXHPASTLinterRule.php', 'ArcanistBraceFormattingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBraceFormattingXHPASTLinterRule.php',
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBraceFormattingXHPASTLinterRuleTestCase.php', 'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBraceFormattingXHPASTLinterRuleTestCase.php',
'ArcanistBranchWorkflow' => 'workflow/ArcanistBranchWorkflow.php', 'ArcanistBranchWorkflow' => 'workflow/ArcanistBranchWorkflow.php',
'ArcanistBritishTestCase' => 'configuration/__tests__/ArcanistBritishTestCase.php',
'ArcanistBrowseWorkflow' => 'workflow/ArcanistBrowseWorkflow.php', 'ArcanistBrowseWorkflow' => 'workflow/ArcanistBrowseWorkflow.php',
'ArcanistBundle' => 'parser/ArcanistBundle.php', 'ArcanistBundle' => 'parser/ArcanistBundle.php',
'ArcanistBundleTestCase' => 'parser/__tests__/ArcanistBundleTestCase.php', 'ArcanistBundleTestCase' => 'parser/__tests__/ArcanistBundleTestCase.php',
@ -456,7 +455,6 @@ phutil_register_library_map(array(
'ArcanistBraceFormattingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistBraceFormattingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBranchWorkflow' => 'ArcanistFeatureWorkflow', 'ArcanistBranchWorkflow' => 'ArcanistFeatureWorkflow',
'ArcanistBritishTestCase' => 'PhutilTestCase',
'ArcanistBrowseWorkflow' => 'ArcanistWorkflow', 'ArcanistBrowseWorkflow' => 'ArcanistWorkflow',
'ArcanistBundle' => 'Phobject', 'ArcanistBundle' => 'Phobject',
'ArcanistBundleTestCase' => 'PhutilTestCase', 'ArcanistBundleTestCase' => 'PhutilTestCase',

View file

@ -144,7 +144,8 @@ class ArcanistConfiguration extends Phobject {
// We haven't found a real command, alias, or unique prefix. Try similar // We haven't found a real command, alias, or unique prefix. Try similar
// spellings. // spellings.
$corrected = self::correctCommandSpelling($command, $all, 2); $corrected = PhutilArgumentSpellingCorrector::newCommandCorrector()
->correctSpelling($command, $all);
if (count($corrected) == 1) { if (count($corrected) == 1) {
$console->writeErr( $console->writeErr(
pht( pht(
@ -183,78 +184,4 @@ class ArcanistConfiguration extends Phobject {
return array_keys($is_prefix); return array_keys($is_prefix);
} }
public static function correctCommandSpelling(
$command,
array $options,
$max_distance) {
// Adjust to the scaled edit costs we use below, so "2" roughly means
// "2 edits".
$max_distance = $max_distance * 3;
// These costs are somewhat made up, but the theory is that it is far more
// likely you will mis-strike a key ("lans" for "land") or press two keys
// out of order ("alnd" for "land") than omit keys or press extra keys.
$matrix = id(new PhutilEditDistanceMatrix())
->setInsertCost(4)
->setDeleteCost(4)
->setReplaceCost(3)
->setTransposeCost(2);
return self::correctSpelling($command, $options, $matrix, $max_distance);
}
public static function correctArgumentSpelling($command, array $options) {
$max_distance = 1;
// We are stricter with arguments - we allow only one inserted or deleted
// character. It is mainly to handle cases like --no-lint versus --nolint
// or --reviewer versus --reviewers.
$matrix = id(new PhutilEditDistanceMatrix())
->setInsertCost(1)
->setDeleteCost(1)
->setReplaceCost(10);
return self::correctSpelling($command, $options, $matrix, $max_distance);
}
public static function correctSpelling(
$input,
array $options,
PhutilEditDistanceMatrix $matrix,
$max_distance) {
$distances = array();
$inputv = str_split($input);
foreach ($options as $option) {
$optionv = str_split($option);
$matrix->setSequences($optionv, $inputv);
$distances[$option] = $matrix->getEditDistance();
}
asort($distances);
$best = min($max_distance, reset($distances));
foreach ($distances as $option => $distance) {
if ($distance > $best) {
unset($distances[$option]);
}
}
// Before filtering, check if we have multiple equidistant matches and
// return them if we do. This prevents us from, e.g., matching "alnd" with
// both "land" and "amend", then dropping "land" for being too short, and
// incorrectly completing to "amend".
if (count($distances) > 1) {
return array_keys($distances);
}
foreach ($distances as $option => $distance) {
if (strlen($option) < $distance) {
unset($distances[$option]);
}
}
return array_keys($distances);
}
} }

View file

@ -1,97 +0,0 @@
<?php
final class ArcanistBritishTestCase extends PhutilTestCase {
public function testCommandCompletion() {
$this->assertCommandCompletion(
array('land'),
'alnd',
array('land', 'amend'));
$this->assertCommandCompletion(
array('branch'),
'brnach',
array('branch', 'browse'));
$this->assertCommandCompletion(
array(),
'test',
array('list', 'unit'));
$this->assertCommandCompletion(
array('list'),
'lists',
array('list'));
$this->assertCommandCompletion(
array('diff'),
'dfif',
array('diff'));
$this->assertCommandCompletion(
array('unit'),
'uint',
array('unit', 'lint', 'list'));
$this->assertCommandCompletion(
array('list', 'lint'),
'nilt',
array('unit', 'lint', 'list'));
}
private function assertCommandCompletion($expect, $input, $commands) {
$result = ArcanistConfiguration::correctCommandSpelling(
$input,
$commands,
2);
sort($result);
sort($expect);
$commands = implode(', ', $commands);
$this->assertEqual(
$expect,
$result,
pht('Correction of %s against: %s', $input, $commands));
}
public function testArgumentCompletion() {
$this->assertArgumentCompletion(
array('nolint'),
'no-lint',
array('nolint', 'nounit'));
$this->assertArgumentCompletion(
array('reviewers'),
'reviewer',
array('reviewers', 'cc'));
$this->assertArgumentCompletion(
array(),
'onlint',
array('nolint'));
$this->assertArgumentCompletion(
array(),
'nolind',
array('nolint'));
}
private function assertArgumentCompletion($expect, $input, $arguments) {
$result = ArcanistConfiguration::correctArgumentSpelling(
$input,
$arguments);
sort($result);
sort($expect);
$arguments = implode(', ', $arguments);
$this->assertEqual(
$expect,
$result,
pht('Correction of %s against: %s', $input, $arguments));
}
}

View file

@ -673,9 +673,8 @@ abstract class ArcanistWorkflow extends Phobject {
} }
if (!array_key_exists($arg_key, $spec)) { if (!array_key_exists($arg_key, $spec)) {
$corrected = ArcanistConfiguration::correctArgumentSpelling( $corrected = PhutilArgumentSpellingCorrector::newFlagCorrector()
$arg_key, ->correctSpelling($arg_key, array_keys($spec));
array_keys($spec));
if (count($corrected) == 1) { if (count($corrected) == 1) {
PhutilConsole::getConsole()->writeErr( PhutilConsole::getConsole()->writeErr(
pht( pht(