Yaffs site version 1.1
[yaffs-website] / vendor / consolidation / output-formatters / src / Transformations / Wrap / CalculateWidths.php
1 <?php
2 namespace Consolidation\OutputFormatters\Transformations\Wrap;
3
4 use Symfony\Component\Console\Helper\TableStyle;
5
6 /**
7  * Calculate column widths for table cells.
8  *
9  * Influenced by Drush and webmozart/console.
10  */
11 class CalculateWidths
12 {
13     public function __construct()
14     {
15     }
16
17     /**
18      * Given the total amount of available space, and the width of
19      * the columns to place, calculate the optimum column widths to use.
20      */
21     public function calculate($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths)
22     {
23         // First, check to see if all columns will fit at their full widths.
24         // If so, do no further calculations. (This may be redundant with
25         // the short column width calculation.)
26         if ($dataWidths->totalWidth() <= $availableWidth) {
27             return $dataWidths->enforceMinimums($minimumWidths);
28         }
29
30         // Get the short columns first. If there are none, then distribute all
31         // of the available width among the remaining columns.
32         $shortColWidths = $this->getShortColumns($availableWidth, $dataWidths, $minimumWidths);
33         if ($shortColWidths->isEmpty()) {
34             return $this->distributeLongColumns($availableWidth, $dataWidths, $minimumWidths);
35         }
36
37         // If some short columns were removed, then account for the length
38         // of the removed columns and make a recursive call (since the average
39         // width may be higher now, if the removed columns were shorter in
40         // length than the previous average).
41         $availableWidth -= $shortColWidths->totalWidth();
42         $remainingWidths = $dataWidths->removeColumns($shortColWidths->keys());
43         $remainingColWidths = $this->calculate($availableWidth, $remainingWidths, $minimumWidths);
44
45         return $shortColWidths->combine($remainingColWidths);
46     }
47
48     /**
49      * Calculate the longest cell data from any row of each of the cells.
50      */
51     public function calculateLongestCell($rows)
52     {
53         return $this->calculateColumnWidths(
54             $rows,
55             function ($cell) {
56                 return strlen($cell);
57             }
58         );
59     }
60
61     /**
62      * Calculate the longest word and longest line in the provided data.
63      */
64     public function calculateLongestWord($rows)
65     {
66         return $this->calculateColumnWidths(
67             $rows,
68             function ($cell) {
69                 return static::longestWordLength($cell);
70             }
71         );
72     }
73
74     protected function calculateColumnWidths($rows, callable $fn)
75     {
76         $widths = [];
77
78         // Examine each row and find the longest line length and longest
79         // word in each column.
80         foreach ($rows as $rowkey => $row) {
81             foreach ($row as $colkey => $cell) {
82                 $value = $fn($cell);
83                 if ((!isset($widths[$colkey]) || ($widths[$colkey] < $value))) {
84                     $widths[$colkey] = $value;
85                 }
86             }
87         }
88
89         return new ColumnWidths($widths);
90     }
91
92     /**
93      * Return all of the columns whose longest line length is less than or
94      * equal to the average width.
95      */
96     public function getShortColumns($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths)
97     {
98         $averageWidth = $dataWidths->averageWidth($availableWidth);
99         $shortColWidths = $dataWidths->findShortColumns($averageWidth);
100         return $shortColWidths->enforceMinimums($minimumWidths);
101     }
102
103     /**
104      * Distribute the remainig space among the columns that were not
105      * included in the list of "short" columns.
106      */
107     public function distributeLongColumns($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths)
108     {
109         // First distribute the remainder without regard to the minimum widths.
110         $result = $dataWidths->distribute($availableWidth);
111
112         // Find columns that are shorter than their minimum width.
113         $undersized = $result->findUndersizedColumns($minimumWidths);
114
115         // Nothing too small? Great, we're done!
116         if ($undersized->isEmpty()) {
117             return $result;
118         }
119
120         // Take out the columns that are too small and redistribute the rest.
121         $availableWidth -= $undersized->totalWidth();
122         $remaining = $dataWidths->removeColumns($undersized->keys());
123         $distributeRemaining = $this->distributeLongColumns($availableWidth, $remaining, $minimumWidths);
124
125         return $undersized->combine($distributeRemaining);
126     }
127
128     /**
129      * Return the length of the longest word in the string.
130      * @param string $str
131      * @return int
132      */
133     protected static function longestWordLength($str)
134     {
135         $words = preg_split('#[ /-]#', $str);
136         $lengths = array_map(function ($s) {
137             return strlen($s);
138         }, $words);
139         return max($lengths);
140     }
141 }