2 namespace Consolidation\OutputFormatters\Transformations\Wrap;
4 use Symfony\Component\Console\Helper\TableStyle;
7 * Calculate the width of data in table cells in preparation for word wrapping.
13 public function __construct($widths = [])
15 $this->widths = $widths;
18 public function paddingSpace(
20 $extraPaddingAtEndOfLine = 0,
21 $extraPaddingAtBeginningOfLine = 0
23 return ($extraPaddingAtBeginningOfLine + $extraPaddingAtEndOfLine + (count($this->widths) * $paddingInEachCell));
27 * Find all of the columns that are shorter than the specified threshold.
29 public function findShortColumns($thresholdWidth)
31 $thresholdWidths = array_fill_keys(array_keys($this->widths), $thresholdWidth);
33 return $this->findColumnsUnderThreshold($thresholdWidths);
37 * Find all of the columns that are shorter than the corresponding minimum widths.
39 public function findUndersizedColumns($minimumWidths)
41 return $this->findColumnsUnderThreshold($minimumWidths->widths());
44 protected function findColumnsUnderThreshold(array $thresholdWidths)
47 foreach ($this->widths as $key => $maxLength) {
48 if (isset($thresholdWidths[$key]) && ($maxLength <= $thresholdWidths[$key])) {
49 $shortColWidths[$key] = $maxLength;
53 return new ColumnWidths($shortColWidths);
57 * If the widths specified by this object do not fit within the
58 * provided avaiable width, then reduce them all proportionally.
60 public function adjustMinimumWidths($availableWidth, $dataCellWidths)
62 $result = $this->selectColumns($dataCellWidths->keys());
63 if ($result->isEmpty()) {
66 $numberOfColumns = $dataCellWidths->count();
68 // How many unspecified columns are there?
69 $unspecifiedColumns = $numberOfColumns - $result->count();
70 $averageWidth = $this->averageWidth($availableWidth);
72 // Reserve some space for the columns that have no minimum.
73 // Make sure they collectively get at least half of the average
74 // width for each column. Or should it be a quarter?
75 $reservedSpacePerColumn = ($averageWidth / 2);
76 $reservedSpace = $reservedSpacePerColumn * $unspecifiedColumns;
78 // Calculate how much of the available space is remaining for use by
79 // the minimum column widths after the reserved space is accounted for.
80 $remainingAvailable = $availableWidth - $reservedSpace;
82 // Don't do anything if our widths fit inside the available widths.
83 if ($result->totalWidth() <= $remainingAvailable) {
87 // Shrink the minimum widths if the table is too compressed.
88 return $result->distribute($remainingAvailable);
92 * Return proportional weights
94 public function distribute($availableWidth)
97 $totalWidth = $this->totalWidth();
98 $lastColumn = $this->lastColumn();
99 $widths = $this->widths();
101 // Take off the last column, and calculate proportional weights
102 // for the first N-1 columns.
104 foreach ($widths as $key => $width) {
105 $result[$key] = round(($width / $totalWidth) * $availableWidth);
108 // Give the last column the rest of the available width
109 $usedWidth = $this->sumWidth($result);
110 $result[$lastColumn] = $availableWidth - $usedWidth;
112 return new ColumnWidths($result);
115 public function lastColumn()
117 $keys = $this->keys();
118 return array_pop($keys);
122 * Return the number of columns.
124 public function count()
126 return count($this->widths);
130 * Calculate how much space is available on average for all columns.
132 public function averageWidth($availableWidth)
134 if ($this->isEmpty()) {
135 debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
137 return $availableWidth / $this->count();
141 * Return the available keys (column identifiers) from the calculated
144 public function keys()
146 return array_keys($this->widths);
150 * Set the length of the specified column.
152 public function setWidth($key, $width)
154 $this->widths[$key] = $width;
158 * Return the length of the specified column.
160 public function width($key)
162 return isset($this->widths[$key]) ? $this->widths[$key] : 0;
166 * Return all of the lengths
168 public function widths()
170 return $this->widths;
174 * Return true if there is no data in this object
176 public function isEmpty()
178 return empty($this->widths);
182 * Return the sum of the lengths of the provided widths.
184 public function totalWidth()
186 return static::sumWidth($this->widths());
190 * Return the sum of the lengths of the provided widths.
192 public static function sumWidth($widths)
196 function ($carry, $item) {
197 return $carry + $item;
203 * Ensure that every item in $widths that has a corresponding entry
204 * in $minimumWidths is as least as large as the minimum value held there.
206 public function enforceMinimums($minimumWidths)
209 if ($minimumWidths instanceof ColumnWidths) {
210 $minimumWidths = $minimumWidths->widths();
212 $minimumWidths += $this->widths;
214 foreach ($this->widths as $key => $value) {
215 $result[$key] = max($value, $minimumWidths[$key]);
218 return new ColumnWidths($result);
222 * Remove all of the specified columns from this data structure.
224 public function removeColumns($columnKeys)
226 $widths = $this->widths();
228 foreach ($columnKeys as $key) {
229 unset($widths[$key]);
232 return new ColumnWidths($widths);
236 * Select all columns that exist in the provided list of keys.
238 public function selectColumns($columnKeys)
242 foreach ($columnKeys as $key) {
243 if (isset($this->widths[$key])) {
244 $widths[$key] = $this->width($key);
248 return new ColumnWidths($widths);
252 * Combine this set of widths with another set, and return
253 * a new set that contains the entries from both.
255 public function combine(ColumnWidths $combineWith)
257 // Danger: array_merge renumbers numeric keys; that must not happen here.
258 $combined = $combineWith->widths();
259 foreach ($this->widths() as $key => $value) {
260 $combined[$key] = $value;
262 return new ColumnWidths($combined);