Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15389781
D21360.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D21360.id.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
@@ -228,6 +228,10 @@
'ArcanistGoLintLinterTestCase' => 'lint/linter/__tests__/ArcanistGoLintLinterTestCase.php',
'ArcanistGoTestResultParser' => 'unit/parser/ArcanistGoTestResultParser.php',
'ArcanistGoTestResultParserTestCase' => 'unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php',
+ 'ArcanistGridCell' => 'console/grid/ArcanistGridCell.php',
+ 'ArcanistGridColumn' => 'console/grid/ArcanistGridColumn.php',
+ 'ArcanistGridRow' => 'console/grid/ArcanistGridRow.php',
+ 'ArcanistGridView' => 'console/grid/ArcanistGridView.php',
'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php',
'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php',
'ArcanistHardpoint' => 'hardpoint/ArcanistHardpoint.php',
@@ -1246,6 +1250,10 @@
'ArcanistGoLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistGoTestResultParser' => 'ArcanistTestResultParser',
'ArcanistGoTestResultParserTestCase' => 'PhutilTestCase',
+ 'ArcanistGridCell' => 'Phobject',
+ 'ArcanistGridColumn' => 'Phobject',
+ 'ArcanistGridRow' => 'Phobject',
+ 'ArcanistGridView' => 'Phobject',
'ArcanistHLintLinter' => 'ArcanistExternalLinter',
'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistHardpoint' => 'Phobject',
diff --git a/src/console/grid/ArcanistGridCell.php b/src/console/grid/ArcanistGridCell.php
new file mode 100644
--- /dev/null
+++ b/src/console/grid/ArcanistGridCell.php
@@ -0,0 +1,56 @@
+<?php
+
+final class ArcanistGridCell
+ extends Phobject {
+
+ private $key;
+ private $content;
+ private $contentWidth;
+ private $contentHeight;
+
+ public function setKey($key) {
+ $this->key = $key;
+ return $this;
+ }
+
+ public function getKey() {
+ return $this->key;
+ }
+
+ public function setContent($content) {
+ $this->content = $content;
+ return $this;
+ }
+
+ public function getContent() {
+ return $this->content;
+ }
+
+ public function getContentDisplayWidth() {
+ $lines = $this->getContentDisplayLines();
+
+ $width = 0;
+ foreach ($lines as $line) {
+ $width = max($width, phutil_utf8_console_strlen($line));
+ }
+
+ return $width;
+ }
+
+ public function getContentDisplayLines() {
+ $content = $this->getContent();
+ $content = tsprintf('%B', $content);
+ $content = phutil_string_cast($content);
+
+ $lines = phutil_split_lines($content, false);
+
+ $result = array();
+ foreach ($lines as $line) {
+ $result[] = tsprintf('%R', $line);
+ }
+
+ return $result;
+ }
+
+
+}
diff --git a/src/console/grid/ArcanistGridColumn.php b/src/console/grid/ArcanistGridColumn.php
new file mode 100644
--- /dev/null
+++ b/src/console/grid/ArcanistGridColumn.php
@@ -0,0 +1,41 @@
+<?php
+
+final class ArcanistGridColumn
+ extends Phobject {
+
+ private $key;
+ private $alignment = self::ALIGNMENT_LEFT;
+ private $displayWidth;
+
+ const ALIGNMENT_LEFT = 'align.left';
+ const ALIGNMENT_CENTER = 'align.center';
+ const ALIGNMENT_RIGHT = 'align.right';
+
+ public function setKey($key) {
+ $this->key = $key;
+ return $this;
+ }
+
+ public function getKey() {
+ return $this->key;
+ }
+
+ public function setAlignment($alignment) {
+ $this->alignment = $alignment;
+ return $this;
+ }
+
+ public function getAlignment() {
+ return $this->alignment;
+ }
+
+ public function setDisplayWidth($display_width) {
+ $this->displayWidth = $display_width;
+ return $this;
+ }
+
+ public function getDisplayWidth() {
+ return $this->displayWidth;
+ }
+
+}
diff --git a/src/console/grid/ArcanistGridRow.php b/src/console/grid/ArcanistGridRow.php
new file mode 100644
--- /dev/null
+++ b/src/console/grid/ArcanistGridRow.php
@@ -0,0 +1,40 @@
+<?php
+
+final class ArcanistGridRow
+ extends Phobject {
+
+ private $cells;
+
+ public function setCells(array $cells) {
+ $cells = id(new PhutilArrayCheck())
+ ->setInstancesOf('ArcanistGridCell')
+ ->setUniqueMethod('getKey')
+ ->setContext($this, 'setCells')
+ ->checkValue($cells);
+
+ $this->cells = $cells;
+
+ return $this;
+ }
+
+ public function getCells() {
+ return $this->cells;
+ }
+
+ public function hasCell($key) {
+ return isset($this->cells[$key]);
+ }
+
+ public function getCell($key) {
+ if (!isset($this->cells[$key])) {
+ throw new Exception(
+ pht(
+ 'Row has no cell "%s".\n',
+ $key));
+ }
+
+ return $this->cells[$key];
+ }
+
+
+}
diff --git a/src/console/grid/ArcanistGridView.php b/src/console/grid/ArcanistGridView.php
new file mode 100644
--- /dev/null
+++ b/src/console/grid/ArcanistGridView.php
@@ -0,0 +1,247 @@
+<?php
+
+final class ArcanistGridView
+ extends Phobject {
+
+ private $rows = array();
+ private $columns = array();
+
+ private $displayWidths = array();
+
+ public function setColumns(array $columns) {
+ assert_instances_of($columns, 'ArcanistGridColumn');
+ $this->columns = $columns;
+ return $this;
+ }
+
+ public function getColumns() {
+ return $this->columns;
+ }
+
+ public function newColumn($key) {
+ $column = id(new ArcanistGridColumn())
+ ->setKey($key);
+
+ $this->columns[$key] = $column;
+
+ return $column;
+ }
+
+ public function newRow(array $cells) {
+ assert_instances_of($cells, 'ArcanistGridCell');
+
+ $row = id(new ArcanistGridRow())
+ ->setCells($cells);
+
+ $this->rows[] = $row;
+
+ return $row;
+ }
+
+ public function drawGrid() {
+ $columns = $this->getColumns();
+ if (!$columns) {
+ throw new Exception(
+ pht(
+ 'Can not draw a grid with no columns!'));
+ }
+
+ $rows = array();
+ foreach ($this->rows as $row) {
+ $rows[] = $this->drawRow($row);
+ }
+
+ $rows = phutil_glue($rows, tsprintf("\n"));
+
+ return tsprintf("%s\n", $rows);
+ }
+
+ private function getDisplayWidth($key) {
+ if (!isset($this->displayWidths[$key])) {
+ $column = $this->getColumn($key);
+
+ $width = $column->getDisplayWidth();
+ if ($width === null) {
+ $width = 1;
+ foreach ($this->getRows() as $row) {
+ if (!$row->hasCell($key)) {
+ continue;
+ }
+
+ $cell = $row->getCell($key);
+ $width = max($width, $cell->getContentDisplayWidth());
+ }
+ }
+
+ $this->displayWidths[$key] = $width;
+ }
+
+ return $this->displayWidths[$key];
+ }
+
+ public function getColumn($key) {
+ if (!isset($this->columns[$key])) {
+ throw new Exception(
+ pht(
+ 'Grid has no column "%s".',
+ $key));
+ }
+
+ return $this->columns[$key];
+ }
+
+ public function getRows() {
+ return $this->rows;
+ }
+
+ private function drawRow(ArcanistGridRow $row) {
+ $columns = $this->getColumns();
+
+ $cells = $row->getCells();
+
+ $out = array();
+ $widths = array();
+ foreach ($columns as $column_key => $column) {
+ $display_width = $this->getDisplayWidth($column_key);
+
+ $cell = idx($cells, $column_key);
+ if ($cell) {
+ $content = $cell->getContentDisplayLines();
+ } else {
+ $content = array('');
+ }
+
+ foreach ($content as $line_key => $line) {
+ $line_width = phutil_utf8_console_strlen($line);
+
+ if ($line_width === $display_width) {
+ continue;
+ }
+
+ if ($line_width < $display_width) {
+ $line = $this->padContentLineToWidth(
+ $line,
+ $line_width,
+ $display_width,
+ $column->getAlignment());
+ } else if ($line_width > $display_width) {
+ $line = $this->truncateContentLineToWidth(
+ $line,
+ $line_width,
+ $display_width,
+ $column->getAlignment());
+ }
+
+ $content[$line_key] = $line;
+ }
+
+ $out[] = $content;
+ $widths[] = $display_width;
+ }
+
+ return $this->drawRowLayout($out, $widths);
+ }
+
+ private function drawRowLayout(array $raw_cells, array $display_widths) {
+ $line_count = 0;
+ foreach ($raw_cells as $key => $cells) {
+ $raw_cells[$key] = array_values($cells);
+ $line_count = max($line_count, count($cells));
+ }
+
+ $line_head = '';
+ $cell_separator = ' ';
+ $line_tail = '';
+
+ $out = array();
+ $cell_count = count($raw_cells);
+ for ($ii = 0; $ii < $line_count; $ii++) {
+ $line = array();
+ for ($jj = 0; $jj < $cell_count; $jj++) {
+ if (isset($raw_cells[$jj][$ii])) {
+ $raw_line = $raw_cells[$jj][$ii];
+ } else {
+ $display_width = $display_widths[$jj];
+ $raw_line = str_repeat(' ', $display_width);
+ }
+ $line[] = $raw_line;
+ }
+
+ $line = array(
+ $line_head,
+ phutil_glue($line, $cell_separator),
+ $line_tail,
+ );
+
+ $out[] = $line;
+ }
+
+ $out = phutil_glue($out, tsprintf("\n"));
+
+ return $out;
+ }
+
+ private function padContentLineToWidth(
+ $line,
+ $src_width,
+ $dst_width,
+ $alignment) {
+
+ $delta = ($dst_width - $src_width);
+
+ switch ($alignment) {
+ case ArcanistGridColumn::ALIGNMENT_LEFT:
+ $head = null;
+ $tail = str_repeat(' ', $delta);
+ break;
+ case ArcanistGridColumn::ALIGNMENT_CENTER:
+ $head_delta = (int)floor($delta / 2);
+ $tail_delta = (int)ceil($delta / 2);
+
+ if ($head_delta) {
+ $head = str_repeat(' ', $head_delta);
+ } else {
+ $head = null;
+ }
+
+ if ($tail_delta) {
+ $tail = str_repeat(' ', $tail_delta);
+ } else {
+ $tail = null;
+ }
+ break;
+ case ArcanistGridColumn::ALIGNMENT_RIGHT:
+ $head = str_repeat(' ', $delta);
+ $tail = null;
+ break;
+ default:
+ throw new Exception(
+ pht(
+ 'Unknown column alignment "%s".',
+ $alignment));
+ }
+
+ $result = array();
+
+ if ($head !== null) {
+ $result[] = $head;
+ }
+
+ $result[] = $line;
+
+ if ($tail !== null) {
+ $result[] = $tail;
+ }
+
+ return $result;
+ }
+
+ private function truncateContentLineToWidth(
+ $line,
+ $src_width,
+ $dst_width,
+ $alignment) {
+ return $line;
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mar 16 2025, 5:38 AM (5 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7387461
Default Alt Text
D21360.id.diff (10 KB)
Attached To
Mode
D21360: Introduce "GridView", an updated version of "ConsoleTableView"
Attached
Detach File
Event Timeline
Log In to Comment