Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13955152
D14136.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
D14136.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -125,14 +125,18 @@
'PhutilCodeSnippetContextFreeGrammar' => 'grammar/code/PhutilCodeSnippetContextFreeGrammar.php',
'PhutilCommandString' => 'xsprintf/PhutilCommandString.php',
'PhutilConsole' => 'console/PhutilConsole.php',
+ 'PhutilConsoleBlock' => 'console/view/PhutilConsoleBlock.php',
+ 'PhutilConsoleConcatenatedView' => 'console/view/PhutilConsoleConcatenatedView.php',
'PhutilConsoleFormatter' => 'console/PhutilConsoleFormatter.php',
+ 'PhutilConsoleList' => 'console/view/PhutilConsoleList.php',
'PhutilConsoleMessage' => 'console/PhutilConsoleMessage.php',
'PhutilConsoleProgressBar' => 'console/PhutilConsoleProgressBar.php',
'PhutilConsoleServer' => 'console/PhutilConsoleServer.php',
'PhutilConsoleServerChannel' => 'console/PhutilConsoleServerChannel.php',
'PhutilConsoleStdinNotInteractiveException' => 'console/PhutilConsoleStdinNotInteractiveException.php',
'PhutilConsoleSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilConsoleSyntaxHighlighter.php',
- 'PhutilConsoleTable' => 'console/PhutilConsoleTable.php',
+ 'PhutilConsoleTable' => 'console/view/PhutilConsoleTable.php',
+ 'PhutilConsoleView' => 'console/view/PhutilConsoleView.php',
'PhutilConsoleWrapTestCase' => 'console/__tests__/PhutilConsoleWrapTestCase.php',
'PhutilContextFreeGrammar' => 'grammar/PhutilContextFreeGrammar.php',
'PhutilCowsay' => 'utils/PhutilCowsay.php',
@@ -635,14 +639,18 @@
'PhutilCodeSnippetContextFreeGrammar' => 'PhutilContextFreeGrammar',
'PhutilCommandString' => 'Phobject',
'PhutilConsole' => 'Phobject',
+ 'PhutilConsoleBlock' => 'PhutilConsoleView',
+ 'PhutilConsoleConcatenatedView' => 'PhutilConsoleView',
'PhutilConsoleFormatter' => 'Phobject',
+ 'PhutilConsoleList' => 'PhutilConsoleView',
'PhutilConsoleMessage' => 'Phobject',
'PhutilConsoleProgressBar' => 'Phobject',
'PhutilConsoleServer' => 'Phobject',
'PhutilConsoleServerChannel' => 'PhutilChannelChannel',
'PhutilConsoleStdinNotInteractiveException' => 'Exception',
'PhutilConsoleSyntaxHighlighter' => 'Phobject',
- 'PhutilConsoleTable' => 'Phobject',
+ 'PhutilConsoleTable' => 'PhutilConsoleView',
+ 'PhutilConsoleView' => 'Phobject',
'PhutilConsoleWrapTestCase' => 'PhutilTestCase',
'PhutilContextFreeGrammar' => 'Phobject',
'PhutilCowsay' => 'Phobject',
diff --git a/src/console/PhutilConsoleFormatter.php b/src/console/PhutilConsoleFormatter.php
--- a/src/console/PhutilConsoleFormatter.php
+++ b/src/console/PhutilConsoleFormatter.php
@@ -42,6 +42,24 @@
}
public static function formatString($format /* ... */) {
+ $args = func_get_args();
+ $args[0] = self::interpretFormat($args[0]);
+ return call_user_func_array('sprintf', $args);
+ }
+
+ public static function replaceColorCode($matches) {
+ $codes = self::$colorCodes;
+ $offset = 30 + $codes[$matches[2]];
+ $default = 39;
+ if ($matches[1] == 'bg') {
+ $offset += 10;
+ $default += 10;
+ }
+
+ return chr(27).'['.$offset.'m'.$matches[3].chr(27).'['.$default.'m';
+ }
+
+ public static function interpretFormat($format) {
$colors = implode('|', array_keys(self::$colorCodes));
// Sequence should be preceded by start-of-string or non-backslash
@@ -74,24 +92,7 @@
}
// Remove backslash escaping
- $format = preg_replace('/\\\\(\*\*.*\*\*|__.*__|##.*##)/sU', '\1', $format);
-
- $args = func_get_args();
- $args[0] = $format;
-
- return call_user_func_array('sprintf', $args);
- }
-
- public static function replaceColorCode($matches) {
- $codes = self::$colorCodes;
- $offset = 30 + $codes[$matches[2]];
- $default = 39;
- if ($matches[1] == 'bg') {
- $offset += 10;
- $default += 10;
- }
-
- return chr(27).'['.$offset.'m'.$matches[3].chr(27).'['.$default.'m';
+ return preg_replace('/\\\\(\*\*.*\*\*|__.*__|##.*##)/sU', '\1', $format);
}
}
diff --git a/src/console/view/PhutilConsoleBlock.php b/src/console/view/PhutilConsoleBlock.php
new file mode 100644
--- /dev/null
+++ b/src/console/view/PhutilConsoleBlock.php
@@ -0,0 +1,45 @@
+<?php
+
+final class PhutilConsoleBlock extends PhutilConsoleView {
+
+ private $items = array();
+
+ public function addParagraph($item) {
+ $this->items[] = array(
+ 'type' => 'paragraph',
+ 'item' => $item,
+ );
+ return $this;
+ }
+
+ public function addList(PhutilConsoleList $list) {
+ $this->items[] = array(
+ 'type' => 'list',
+ 'item' => $list,
+ );
+ return $this;
+ }
+
+ protected function drawView() {
+ $output = array();
+
+ foreach ($this->items as $spec) {
+ $type = $spec['type'];
+ $item = $spec['item'];
+
+ switch ($type) {
+ case 'paragraph':
+ $item = phutil_console_wrap($item)."\n";
+ break;
+ case 'list':
+ $item = $item;
+ break;
+ }
+
+ $output[] = $item;
+ }
+
+ return $this->drawLines($output);
+ }
+
+}
diff --git a/src/console/view/PhutilConsoleConcatenatedView.php b/src/console/view/PhutilConsoleConcatenatedView.php
new file mode 100644
--- /dev/null
+++ b/src/console/view/PhutilConsoleConcatenatedView.php
@@ -0,0 +1,22 @@
+<?php
+
+final class PhutilConsoleConcatenatedView extends PhutilConsoleView {
+
+ private $items = array();
+
+ public function addItem($item) {
+ $this->items[] = $item;
+ return $this;
+ }
+
+ protected function drawView() {
+ $output = array();
+
+ foreach ($this->items as $item) {
+ $output[] = $this->flattenView($item);
+ }
+
+ return implode('', $output);
+ }
+
+}
diff --git a/src/console/view/PhutilConsoleList.php b/src/console/view/PhutilConsoleList.php
new file mode 100644
--- /dev/null
+++ b/src/console/view/PhutilConsoleList.php
@@ -0,0 +1,42 @@
+<?php
+
+final class PhutilConsoleList extends PhutilConsoleView {
+
+ private $items = array();
+ private $wrap = true;
+
+ public function addItem($item) {
+ $this->items[] = $item;
+ return $this;
+ }
+
+ public function addItems(array $items) {
+ foreach ($items as $item) {
+ $this->addItem($item);
+ }
+ return $this;
+ }
+
+ public function getItems() {
+ return $this->items;
+ }
+
+ public function setWrap($wrap) {
+ $this->wrap = $wrap;
+ return $this;
+ }
+
+ protected function drawView() {
+ $output = array();
+ foreach ($this->getItems() as $item) {
+ if ($this->wrap) {
+ $item = phutil_console_wrap($item, 8);
+ }
+ $item = ' - '.$item;
+ $output[] = $item;
+ }
+
+ return $this->drawLines($output);
+ }
+
+}
diff --git a/src/console/PhutilConsoleTable.php b/src/console/view/PhutilConsoleTable.php
rename from src/console/PhutilConsoleTable.php
rename to src/console/view/PhutilConsoleTable.php
--- a/src/console/PhutilConsoleTable.php
+++ b/src/console/view/PhutilConsoleTable.php
@@ -22,7 +22,7 @@
* ->setBorders(true)
* ->draw();
*/
-final class PhutilConsoleTable extends Phobject {
+final class PhutilConsoleTable extends PhutilConsoleView {
private $columns = array();
private $data = array();
@@ -30,30 +30,15 @@
private $borders = false;
private $padding = 1;
private $showHeader = true;
- private $console;
const ALIGN_LEFT = 'left';
const ALIGN_CENTER = 'center';
const ALIGN_RIGHT = 'right';
-/* -( Console )------------------------------------------------------------ */
-
- protected function getConsole() {
- if ($this->console) {
- return $this->console;
- }
- return PhutilConsole::getConsole();
- }
-
- public function setConsole(PhutilConsole $console) {
- $this->console = $console;
- return $this;
- }
-
-
/* -( Configuration )------------------------------------------------------ */
+
public function setBorders($borders) {
$this->borders = $borders;
return $this;
@@ -103,19 +88,19 @@
/* -( Drawing )------------------------------------------------------------ */
- public function draw() {
- $console = $this->getConsole();
-
- $console->writeOut('%s', $this->getHeader());
- $console->writeOut('%s', $this->getBody());
- $console->writeOut('%s', $this->getFooter());
+ protected function drawView() {
+ return $this->drawLines(
+ array_merge(
+ $this->getHeader(),
+ $this->getBody(),
+ $this->getFooter()));
}
private function getHeader() {
- $output = '';
+ $output = array();
if ($this->borders) {
- $output .= $this->formatSeparator('=');
+ $output[] = $this->formatSeparator('=');
}
if (!$this->showHeader) {
@@ -133,45 +118,45 @@
idx($column, 'align', self::ALIGN_LEFT));
}
- $columns[] = PhutilConsoleFormatter::formatString(
+ $columns[] = tsprintf(
'**%s**',
$column_str);
}
- $output .= $this->formatRow($columns);
+ $output[] = $this->formatRow($columns);
if ($this->borders) {
- $output .= $this->formatSeparator('=');
+ $output[] = $this->formatSeparator('=');
}
return $output;
}
private function getBody() {
- $output = '';
+ $output = array();
foreach ($this->data as $data) {
$columns = array();
foreach ($this->columns as $key => $column) {
if (!$this->shouldAddSpacing($key, $column)) {
- $columns[] = (string)idx($data, $key, '');
+ $columns[] = idx($data, $key, '');
} else {
$columns[] = $this->alignString(
- (string)idx($data, $key, ''),
+ idx($data, $key, ''),
$this->getWidth($key),
idx($column, 'align', self::ALIGN_LEFT));
}
}
- $output .= $this->formatRow($columns);
+ $output[] = $this->formatRow($columns);
}
return $output;
}
private function getFooter() {
- $output = '';
+ $output = array();
if ($this->borders) {
$columns = array();
@@ -180,7 +165,11 @@
$columns[] = str_repeat('=', $this->getWidth($column));
}
- $output .= '+'.implode('+', $columns)."+\n";
+ $output[] = array(
+ '+',
+ $this->implode('+', $columns),
+ '+',
+ );
}
return $output;
@@ -258,7 +247,11 @@
$left_padding = str_repeat(' ', $num_left_padding);
$right_padding = str_repeat(' ', $num_right_padding);
- return $left_padding.$string.$right_padding;
+ return array(
+ $left_padding,
+ $string,
+ $right_padding,
+ );
}
/**
@@ -272,9 +265,13 @@
if ($this->borders) {
$separator = $padding.'|'.$padding;
- return '|'.$padding.implode($separator, $columns).$padding."|\n";
+ return array(
+ '|'.$padding,
+ $this->implode($separator, $columns),
+ $padding.'|',
+ );
} else {
- return implode($padding, $columns)."\n";
+ return $this->implode($padding, $columns);
}
}
@@ -291,7 +288,11 @@
$columns[] = str_repeat($string, $this->getWidth($column));
}
- return $separator.implode($separator, $columns).$separator."\n";
+ return array(
+ $separator,
+ $this->implode($separator, $columns),
+ $separator,
+ );
}
}
diff --git a/src/console/view/PhutilConsoleView.php b/src/console/view/PhutilConsoleView.php
new file mode 100644
--- /dev/null
+++ b/src/console/view/PhutilConsoleView.php
@@ -0,0 +1,112 @@
+<?php
+
+abstract class PhutilConsoleView extends Phobject {
+
+ private $console;
+
+ abstract protected function drawView();
+
+ final public function setConsole(PhutilConsole $console) {
+ $this->console = $console;
+ return $this;
+ }
+
+ final public function getConsole() {
+ if ($this->console) {
+ return $this->console;
+ }
+ return PhutilConsole::getConsole();
+ }
+
+
+ /**
+ * Draw a view to the console.
+ *
+ * @return this
+ * @task draw
+ */
+ final public function draw() {
+ $string = $this->drawConsoleString();
+
+ $console = $this->getConsole();
+ $console->writeOut('%s', $string);
+
+ return $this;
+ }
+
+
+ /**
+ * Draw a view to a string and return it.
+ *
+ * @return string Console-printable string.
+ * @task draw
+ */
+ final public function drawConsoleString() {
+ $view = $this->drawView();
+ $parts = $this->reduceView($view);
+
+ $out = array();
+ foreach ($parts as $part) {
+ $out[] = PhutilTerminalString::escapeStringValue($part, true);
+ }
+
+ return implode('', $out);
+ }
+
+
+ /**
+ * Reduce a view to a list of simple, unnested parts.
+ *
+ * @param wild Any drawable view.
+ * @return list<wild> List of unnested drawables.
+ * @task draw
+ */
+ private function reduceView($view) {
+ if ($view instanceof PhutilConsoleView) {
+ $view = $view->drawView();
+ return $this->reduceView($view);
+ }
+
+ if (is_array($view)) {
+ $parts = array();
+ foreach ($view as $item) {
+ foreach ($this->reduceView($item) as $part) {
+ $parts[] = $part;
+ }
+ }
+ return $parts;
+ }
+
+ return array($view);
+ }
+
+/* -( Drawing Utilities )-------------------------------------------------- */
+
+
+ /**
+ * @param list<wild> List of views, one per line.
+ * @return wild Each view rendered on a separate line.
+ */
+ final protected function drawLines(array $parts) {
+ $result = array();
+ foreach ($parts as $part) {
+ if ($part !== null) {
+ $result[] = $part;
+ $result[] = "\n";
+ }
+ }
+
+ return $result;
+ }
+
+ final protected function implode($separator, array $items) {
+ $result = array();
+ foreach ($items as $item) {
+ $result[] = $item;
+ $result[] = $separator;
+ }
+ array_pop($result);
+ return $result;
+ }
+
+}
diff --git a/src/xsprintf/tsprintf.php b/src/xsprintf/tsprintf.php
--- a/src/xsprintf/tsprintf.php
+++ b/src/xsprintf/tsprintf.php
@@ -15,6 +15,7 @@
*/
function tsprintf($pattern /* , ... */) {
$args = func_get_args();
+ $args[0] = PhutilConsoleFormatter::interpretFormat($args[0]);
$string = xsprintf('xsprintf_terminal', null, $args);
return new PhutilTerminalString($string);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Oct 15, 12:21 AM (3 w, 6 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6710573
Default Alt Text
D14136.diff (14 KB)
Attached To
Mode
D14136: Introduce PhutilConsoleView for rendering elements to the console
Attached
Detach File
Event Timeline
Log In to Comment