mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 16:22:42 +01:00
Add some support code for printing refs to stdout
Summary: Ref T13490. Make terminal strings work more like HTML does in Phabricator, and make it easier to display refs. Test Plan: Added some display code, ran `arc inspect` to hit it, saw a nice ref printed. Maniphest Tasks: T13490 Differential Revision: https://secure.phabricator.com/D21093
This commit is contained in:
parent
088b157444
commit
5fc50c226a
10 changed files with 184 additions and 8 deletions
|
@ -162,6 +162,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistDifferentialDependencyGraph' => 'differential/ArcanistDifferentialDependencyGraph.php',
|
'ArcanistDifferentialDependencyGraph' => 'differential/ArcanistDifferentialDependencyGraph.php',
|
||||||
'ArcanistDifferentialRevisionHash' => 'differential/constants/ArcanistDifferentialRevisionHash.php',
|
'ArcanistDifferentialRevisionHash' => 'differential/constants/ArcanistDifferentialRevisionHash.php',
|
||||||
'ArcanistDifferentialRevisionStatus' => 'differential/constants/ArcanistDifferentialRevisionStatus.php',
|
'ArcanistDifferentialRevisionStatus' => 'differential/constants/ArcanistDifferentialRevisionStatus.php',
|
||||||
|
'ArcanistDisplayRef' => 'ref/ArcanistDisplayRef.php',
|
||||||
|
'ArcanistDisplayRefInterface' => 'ref/ArcanistDisplayRefInterface.php',
|
||||||
'ArcanistDoubleQuoteXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDoubleQuoteXHPASTLinterRule.php',
|
'ArcanistDoubleQuoteXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDoubleQuoteXHPASTLinterRule.php',
|
||||||
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDoubleQuoteXHPASTLinterRuleTestCase.php',
|
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDoubleQuoteXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistDownloadWorkflow' => 'workflow/ArcanistDownloadWorkflow.php',
|
'ArcanistDownloadWorkflow' => 'workflow/ArcanistDownloadWorkflow.php',
|
||||||
|
@ -441,6 +443,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php',
|
'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php',
|
||||||
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTautologicalExpressionXHPASTLinterRule.php',
|
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTautologicalExpressionXHPASTLinterRule.php',
|
||||||
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTautologicalExpressionXHPASTLinterRuleTestCase.php',
|
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTautologicalExpressionXHPASTLinterRuleTestCase.php',
|
||||||
|
'ArcanistTerminalStringInterface' => 'xsprintf/ArcanistTerminalStringInterface.php',
|
||||||
'ArcanistTestResultParser' => 'unit/parser/ArcanistTestResultParser.php',
|
'ArcanistTestResultParser' => 'unit/parser/ArcanistTestResultParser.php',
|
||||||
'ArcanistTestXHPASTLintSwitchHook' => 'lint/linter/__tests__/ArcanistTestXHPASTLintSwitchHook.php',
|
'ArcanistTestXHPASTLintSwitchHook' => 'lint/linter/__tests__/ArcanistTestXHPASTLintSwitchHook.php',
|
||||||
'ArcanistTextLinter' => 'lint/linter/ArcanistTextLinter.php',
|
'ArcanistTextLinter' => 'lint/linter/ArcanistTextLinter.php',
|
||||||
|
@ -915,6 +918,7 @@ phutil_register_library_map(array(
|
||||||
'phutil_get_library_root_for_path' => 'init/lib/moduleutils.php',
|
'phutil_get_library_root_for_path' => 'init/lib/moduleutils.php',
|
||||||
'phutil_get_signal_name' => 'future/exec/execx.php',
|
'phutil_get_signal_name' => 'future/exec/execx.php',
|
||||||
'phutil_get_system_locale' => 'utils/utf8.php',
|
'phutil_get_system_locale' => 'utils/utf8.php',
|
||||||
|
'phutil_glue' => 'utils/utils.php',
|
||||||
'phutil_hashes_are_identical' => 'utils/utils.php',
|
'phutil_hashes_are_identical' => 'utils/utils.php',
|
||||||
'phutil_http_parameter_pair' => 'utils/utils.php',
|
'phutil_http_parameter_pair' => 'utils/utils.php',
|
||||||
'phutil_ini_decode' => 'utils/utils.php',
|
'phutil_ini_decode' => 'utils/utils.php',
|
||||||
|
@ -1137,6 +1141,10 @@ phutil_register_library_map(array(
|
||||||
'ArcanistDifferentialDependencyGraph' => 'AbstractDirectedGraph',
|
'ArcanistDifferentialDependencyGraph' => 'AbstractDirectedGraph',
|
||||||
'ArcanistDifferentialRevisionHash' => 'Phobject',
|
'ArcanistDifferentialRevisionHash' => 'Phobject',
|
||||||
'ArcanistDifferentialRevisionStatus' => 'Phobject',
|
'ArcanistDifferentialRevisionStatus' => 'Phobject',
|
||||||
|
'ArcanistDisplayRef' => array(
|
||||||
|
'Phobject',
|
||||||
|
'ArcanistTerminalStringInterface',
|
||||||
|
),
|
||||||
'ArcanistDoubleQuoteXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistDoubleQuoteXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistDownloadWorkflow' => 'ArcanistWorkflow',
|
'ArcanistDownloadWorkflow' => 'ArcanistWorkflow',
|
||||||
|
@ -1461,7 +1469,10 @@ phutil_register_library_map(array(
|
||||||
'ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistUserAbortException' => 'ArcanistUsageException',
|
'ArcanistUserAbortException' => 'ArcanistUsageException',
|
||||||
'ArcanistUserConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
|
'ArcanistUserConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
|
||||||
'ArcanistUserRef' => 'ArcanistRef',
|
'ArcanistUserRef' => array(
|
||||||
|
'ArcanistRef',
|
||||||
|
'ArcanistDisplayRefInterface',
|
||||||
|
),
|
||||||
'ArcanistUserSymbolHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
|
'ArcanistUserSymbolHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
|
||||||
'ArcanistUserSymbolRef' => 'ArcanistSymbolRef',
|
'ArcanistUserSymbolRef' => 'ArcanistSymbolRef',
|
||||||
'ArcanistUserSymbolRefInspector' => 'ArcanistRefInspector',
|
'ArcanistUserSymbolRefInspector' => 'ArcanistRefInspector',
|
||||||
|
|
68
src/ref/ArcanistDisplayRef.php
Normal file
68
src/ref/ArcanistDisplayRef.php
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistDisplayRef
|
||||||
|
extends Phobject
|
||||||
|
implements
|
||||||
|
ArcanistTerminalStringInterface {
|
||||||
|
|
||||||
|
private $ref;
|
||||||
|
|
||||||
|
public function setRef(ArcanistRef $ref) {
|
||||||
|
$this->ref = $ref;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRef() {
|
||||||
|
return $this->ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newTerminalString() {
|
||||||
|
$ref = $this->getRef();
|
||||||
|
|
||||||
|
if ($ref instanceof ArcanistDisplayRefInterface) {
|
||||||
|
$object_name = $ref->getDisplayRefObjectName();
|
||||||
|
$title = $ref->getDisplayRefTitle();
|
||||||
|
} else {
|
||||||
|
$object_name = null;
|
||||||
|
$title = $ref->getRefDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($object_name !== null) {
|
||||||
|
$reserve_width = phutil_utf8_console_strlen($object_name) + 1;
|
||||||
|
} else {
|
||||||
|
$reserve_width = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$marker_width = 6;
|
||||||
|
$display_width = phutil_console_get_terminal_width();
|
||||||
|
|
||||||
|
$usable_width = ($display_width - $marker_width - $reserve_width);
|
||||||
|
|
||||||
|
// If the terminal is extremely narrow, don't degrade so much that the
|
||||||
|
// output is completely unusable.
|
||||||
|
$usable_width = max($usable_width, 16);
|
||||||
|
|
||||||
|
// TODO: This should truncate based on console display width, not
|
||||||
|
// glyphs, but there's currently no "setMaximumConsoleCharacterWidth()".
|
||||||
|
|
||||||
|
$title = id(new PhutilUTF8StringTruncator())
|
||||||
|
->setMaximumGlyphs($usable_width)
|
||||||
|
->truncateString($title);
|
||||||
|
|
||||||
|
if ($object_name !== null) {
|
||||||
|
if (strlen($title)) {
|
||||||
|
$display_text = tsprintf('**%s** %s', $object_name, $title);
|
||||||
|
} else {
|
||||||
|
$display_text = tsprintf('**%s**', $object_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$display_text = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ref = $this->getRef();
|
||||||
|
return tsprintf(
|
||||||
|
"<bg:cyan>** * **</bg> %s\n",
|
||||||
|
$display_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
src/ref/ArcanistDisplayRefInterface.php
Normal file
8
src/ref/ArcanistDisplayRefInterface.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface ArcanistDisplayRefInterface {
|
||||||
|
|
||||||
|
public function getDisplayRefObjectName();
|
||||||
|
public function getDisplayRefTitle();
|
||||||
|
|
||||||
|
}
|
|
@ -5,4 +5,8 @@ abstract class ArcanistRef
|
||||||
|
|
||||||
abstract public function getRefDisplayName();
|
abstract public function getRefDisplayName();
|
||||||
|
|
||||||
|
final public function newDisplayRef() {
|
||||||
|
return id(new ArcanistDisplayRef())
|
||||||
|
->setRef($this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,4 +36,6 @@ abstract class ArcanistSymbolRef
|
||||||
return $symbol;
|
return $symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class ArcanistUserRef
|
final class ArcanistUserRef
|
||||||
extends ArcanistRef {
|
extends ArcanistRef
|
||||||
|
implements
|
||||||
|
ArcanistDisplayRefInterface {
|
||||||
|
|
||||||
private $parameters;
|
private $parameters;
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ final class ArcanistUserRef
|
||||||
|
|
||||||
$parameters['fields'] = array(
|
$parameters['fields'] = array(
|
||||||
'username' => idx($parameters, 'userName'),
|
'username' => idx($parameters, 'userName'),
|
||||||
|
'realName' => idx($parameters, 'realName'),
|
||||||
);
|
);
|
||||||
|
|
||||||
return self::newFromConduit($parameters);
|
return self::newFromConduit($parameters);
|
||||||
|
@ -30,4 +33,24 @@ final class ArcanistUserRef
|
||||||
return idxv($this->parameters, array('fields', 'username'));
|
return idxv($this->parameters, array('fields', 'username'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRealName() {
|
||||||
|
var_dump($this->parameters);
|
||||||
|
|
||||||
|
return idxv($this->parameters, array('fields', 'realName'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayRefObjectName() {
|
||||||
|
return '@'.$this->getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayRefTitle() {
|
||||||
|
$real_name = $this->getRealName();
|
||||||
|
|
||||||
|
if (strlen($real_name)) {
|
||||||
|
$real_name = sprintf('(%s)', $real_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $real_name;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1930,3 +1930,31 @@ function phutil_is_noninteractive() {
|
||||||
function phutil_encode_log($message) {
|
function phutil_encode_log($message) {
|
||||||
return addcslashes($message, "\0..\37\\\177..\377");
|
return addcslashes($message, "\0..\37\\\177..\377");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a value in between each pair of elements in a list.
|
||||||
|
*
|
||||||
|
* Keys in the input list are preserved.
|
||||||
|
*/
|
||||||
|
function phutil_glue(array $list, $glue) {
|
||||||
|
if (!$list) {
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
$last_key = last_key($list);
|
||||||
|
|
||||||
|
$keys = array();
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
$tmp = $list;
|
||||||
|
|
||||||
|
foreach ($list as $key => $ignored) {
|
||||||
|
$keys[] = $key;
|
||||||
|
if ($key !== $last_key) {
|
||||||
|
$tmp[] = $glue;
|
||||||
|
$keys[] = last_key($tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_select_keys($tmp, $keys);
|
||||||
|
}
|
||||||
|
|
|
@ -93,9 +93,9 @@ EOTEXT
|
||||||
$list = array();
|
$list = array();
|
||||||
foreach ($all_refs as $ref) {
|
foreach ($all_refs as $ref) {
|
||||||
$out = $this->describeRef($ref, 0);
|
$out = $this->describeRef($ref, 0);
|
||||||
$list[] = implode('', $out);
|
$list[] = $out;
|
||||||
}
|
}
|
||||||
$list = implode("\n", $list);
|
$list = phutil_glue($list, "\n");
|
||||||
|
|
||||||
echo tsprintf('%B', $list);
|
echo tsprintf('%B', $list);
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ EOTEXT
|
||||||
$indent = str_repeat(' ', $depth);
|
$indent = str_repeat(' ', $depth);
|
||||||
|
|
||||||
$out = array();
|
$out = array();
|
||||||
|
|
||||||
$out[] = tsprintf(
|
$out[] = tsprintf(
|
||||||
"%s+ [%s] %s\n",
|
"%s+ [%s] %s\n",
|
||||||
$indent,
|
$indent,
|
||||||
|
|
7
src/xsprintf/ArcanistTerminalStringInterface.php
Normal file
7
src/xsprintf/ArcanistTerminalStringInterface.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface ArcanistTerminalStringInterface {
|
||||||
|
|
||||||
|
public function newTerminalString();
|
||||||
|
|
||||||
|
}
|
|
@ -16,23 +16,47 @@ final class PhutilTerminalString extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyWrap() {
|
public function applyWrap() {
|
||||||
$string = (string)$this;
|
$string = phutil_string_cast($this);
|
||||||
$string = phutil_console_wrap($string);
|
$string = phutil_console_wrap($string);
|
||||||
return new self($string);
|
return new self($string);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyIndent($depth, $with_prefix = true) {
|
public function applyIndent($depth, $with_prefix = true) {
|
||||||
$string = (string)$this;
|
$string = phutil_string_cast($this);
|
||||||
$string = phutil_console_wrap($string, $depth, $with_prefix);
|
$string = phutil_console_wrap($string, $depth, $with_prefix);
|
||||||
return new self($string);
|
return new self($string);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function escapeStringValue($value, $allow_whitespace) {
|
public static function escapeStringValue($value, $allow_whitespace) {
|
||||||
if ($value instanceof PhutilTerminalString) {
|
if ($value instanceof PhutilTerminalString) {
|
||||||
return (string)$value;
|
return phutil_string_cast($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = (string)$value;
|
if ($value instanceof ArcanistTerminalStringInterface) {
|
||||||
|
$value = $value->newTerminalString();
|
||||||
|
return self::escapeStringValue($value, $allow_whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (!$value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = array();
|
||||||
|
|
||||||
|
foreach ($value as $part) {
|
||||||
|
$part = self::escapeStringValue($part, $allow_whitespace);
|
||||||
|
$parts[] = $part;
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('', $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = phutil_string_cast($value);
|
||||||
|
|
||||||
static $escape_map;
|
static $escape_map;
|
||||||
if ($escape_map === null) {
|
if ($escape_map === null) {
|
||||||
|
|
Loading…
Reference in a new issue