1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-22 06:42:41 +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:
epriestley 2020-04-12 08:30:53 -07:00
parent 088b157444
commit 5fc50c226a
10 changed files with 184 additions and 8 deletions

View file

@ -162,6 +162,8 @@ phutil_register_library_map(array(
'ArcanistDifferentialDependencyGraph' => 'differential/ArcanistDifferentialDependencyGraph.php',
'ArcanistDifferentialRevisionHash' => 'differential/constants/ArcanistDifferentialRevisionHash.php',
'ArcanistDifferentialRevisionStatus' => 'differential/constants/ArcanistDifferentialRevisionStatus.php',
'ArcanistDisplayRef' => 'ref/ArcanistDisplayRef.php',
'ArcanistDisplayRefInterface' => 'ref/ArcanistDisplayRefInterface.php',
'ArcanistDoubleQuoteXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDoubleQuoteXHPASTLinterRule.php',
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDoubleQuoteXHPASTLinterRuleTestCase.php',
'ArcanistDownloadWorkflow' => 'workflow/ArcanistDownloadWorkflow.php',
@ -441,6 +443,7 @@ phutil_register_library_map(array(
'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php',
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTautologicalExpressionXHPASTLinterRule.php',
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTautologicalExpressionXHPASTLinterRuleTestCase.php',
'ArcanistTerminalStringInterface' => 'xsprintf/ArcanistTerminalStringInterface.php',
'ArcanistTestResultParser' => 'unit/parser/ArcanistTestResultParser.php',
'ArcanistTestXHPASTLintSwitchHook' => 'lint/linter/__tests__/ArcanistTestXHPASTLintSwitchHook.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_signal_name' => 'future/exec/execx.php',
'phutil_get_system_locale' => 'utils/utf8.php',
'phutil_glue' => 'utils/utils.php',
'phutil_hashes_are_identical' => 'utils/utils.php',
'phutil_http_parameter_pair' => 'utils/utils.php',
'phutil_ini_decode' => 'utils/utils.php',
@ -1137,6 +1141,10 @@ phutil_register_library_map(array(
'ArcanistDifferentialDependencyGraph' => 'AbstractDirectedGraph',
'ArcanistDifferentialRevisionHash' => 'Phobject',
'ArcanistDifferentialRevisionStatus' => 'Phobject',
'ArcanistDisplayRef' => array(
'Phobject',
'ArcanistTerminalStringInterface',
),
'ArcanistDoubleQuoteXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDownloadWorkflow' => 'ArcanistWorkflow',
@ -1461,7 +1469,10 @@ phutil_register_library_map(array(
'ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUserAbortException' => 'ArcanistUsageException',
'ArcanistUserConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistUserRef' => 'ArcanistRef',
'ArcanistUserRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistUserSymbolHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
'ArcanistUserSymbolRef' => 'ArcanistSymbolRef',
'ArcanistUserSymbolRefInspector' => 'ArcanistRefInspector',

View 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);
}
}

View file

@ -0,0 +1,8 @@
<?php
interface ArcanistDisplayRefInterface {
public function getDisplayRefObjectName();
public function getDisplayRefTitle();
}

View file

@ -5,4 +5,8 @@ abstract class ArcanistRef
abstract public function getRefDisplayName();
final public function newDisplayRef() {
return id(new ArcanistDisplayRef())
->setRef($this);
}
}

View file

@ -36,4 +36,6 @@ abstract class ArcanistSymbolRef
return $symbol;
}
}

View file

@ -1,7 +1,9 @@
<?php
final class ArcanistUserRef
extends ArcanistRef {
extends ArcanistRef
implements
ArcanistDisplayRefInterface {
private $parameters;
@ -21,6 +23,7 @@ final class ArcanistUserRef
$parameters['fields'] = array(
'username' => idx($parameters, 'userName'),
'realName' => idx($parameters, 'realName'),
);
return self::newFromConduit($parameters);
@ -30,4 +33,24 @@ final class ArcanistUserRef
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;
}
}

View file

@ -1930,3 +1930,31 @@ function phutil_is_noninteractive() {
function phutil_encode_log($message) {
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);
}

View file

@ -93,9 +93,9 @@ EOTEXT
$list = array();
foreach ($all_refs as $ref) {
$out = $this->describeRef($ref, 0);
$list[] = implode('', $out);
$list[] = $out;
}
$list = implode("\n", $list);
$list = phutil_glue($list, "\n");
echo tsprintf('%B', $list);
@ -106,6 +106,7 @@ EOTEXT
$indent = str_repeat(' ', $depth);
$out = array();
$out[] = tsprintf(
"%s+ [%s] %s\n",
$indent,

View file

@ -0,0 +1,7 @@
<?php
interface ArcanistTerminalStringInterface {
public function newTerminalString();
}

View file

@ -16,23 +16,47 @@ final class PhutilTerminalString extends Phobject {
}
public function applyWrap() {
$string = (string)$this;
$string = phutil_string_cast($this);
$string = phutil_console_wrap($string);
return new self($string);
}
public function applyIndent($depth, $with_prefix = true) {
$string = (string)$this;
$string = phutil_string_cast($this);
$string = phutil_console_wrap($string, $depth, $with_prefix);
return new self($string);
}
public static function escapeStringValue($value, $allow_whitespace) {
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;
if ($escape_map === null) {