1010 */
1111final class Terminal
1212{
13- private static $ width ;
13+ /**
14+ * @var array<int, array<string>>
15+ */
16+ private const DESCRIPTORSPEC = [
17+ 1 => ['pipe ' , 'w ' ],
18+ 2 => ['pipe ' , 'w ' ],
19+ ];
1420
15- private static $ stty ;
21+ private static ?int $ width = null ;
22+
23+ private static ?bool $ stty = null ;
1624
1725 public static function getWidth (): int
1826 {
1927 $ width = \getenv ('COLUMNS ' );
2028 if ($ width !== \false) {
2129 return (int ) \trim ($ width );
2230 }
31+
2332 if (self ::$ width === null ) {
2433 self ::initDimensions ();
2534 }
35+
2636 return self ::$ width ?: 80 ;
2737 }
2838
@@ -31,24 +41,26 @@ public static function hasSttyAvailable(): bool
3141 if (self ::$ stty !== null ) {
3242 return self ::$ stty ;
3343 }
44+
3445 if (! \function_exists ('exec ' )) {
3546 return \false;
3647 }
48+
3749 \exec ('stty 2>&1 ' , $ output , $ exitcode );
3850 return self ::$ stty = $ exitcode === 0 ;
3951 }
4052
41- private static function initDimensions ()
53+ private static function initDimensions (): void
4254 {
43- $ dimensions = self ::getConsoleMode ();
55+ $ consoleMode = self ::getConsoleMode ();
4456
4557 if ('\\' === \DIRECTORY_SEPARATOR ) {
46- if (\preg_match ('/ ^( \\ d+)x( \\ d+)(?: \\ (( \\ d+)x( \\ d+) \\ ))?$/ ' , \trim (\getenv ('ANSICON ' )), $ matches )) {
58+ if (\preg_match ('# ^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$# ' , \trim (\getenv ('ANSICON ' )), $ matches )) {
4759 self ::$ width = (int ) $ matches [1 ];
4860 } elseif (! self ::hasVt100Support () && self ::hasSttyAvailable ()) {
4961 self ::initDimensionsUsingStty ();
50- } elseif ($ dimensions ) {
51- self ::$ width = (int ) $ dimensions [0 ];
62+ } elseif ($ consoleMode ) {
63+ self ::$ width = (int ) $ consoleMode [0 ];
5264 }
5365 } else {
5466 self ::initDimensionsUsingStty ();
@@ -62,12 +74,12 @@ private static function hasVt100Support(): bool
6274
6375 private static function initDimensionsUsingStty (): void
6476 {
65- $ sttyString = self ::getSttyColumns ();
77+ $ sttyColumns = self ::getSttyColumns ();
6678
67- if ($ sttyString ) {
68- if (\preg_match ('/ rows.( \\ d+);.columns.( \\ d+);/ i ' , $ sttyString , $ matches )) {
79+ if ($ sttyColumns ) {
80+ if (\preg_match ('# rows.(\d+);.columns.(\d+);# i ' , $ sttyColumns , $ matches )) {
6981 self ::$ width = (int ) $ matches [2 ];
70- } elseif (\preg_match ('/ ;.( \\ d+).rows;.( \\ d+).columns/ i ' , $ sttyString , $ matches )) {
82+ } elseif (\preg_match ('# ;.(\d+).rows;.(\d+).columns# i ' , $ sttyColumns , $ matches )) {
7183 self ::$ width = (int ) $ matches [2 ];
7284 }
7385 }
@@ -76,9 +88,14 @@ private static function initDimensionsUsingStty(): void
7688 private static function getConsoleMode (): ?array
7789 {
7890 $ info = self ::readFromProcess ('mode CON ' );
79- if ($ info === null || ! \preg_match ( ' /--------+ \\ r? \\ n.+?( \\ d+) \\ r? \\ n.+?( \\ d+) \\ r? \\ n/ ' , $ info , $ matches ) ) {
91+ if ($ info === null ) {
8092 return null ;
8193 }
94+
95+ if (! \preg_match ('#--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n# ' , $ info , $ matches )) {
96+ return null ;
97+ }
98+
8299 return [(int ) $ matches [2 ], (int ) $ matches [1 ]];
83100 }
84101
@@ -92,16 +109,14 @@ private static function readFromProcess(string $command): ?string
92109 if (! \function_exists ('proc_open ' )) {
93110 return null ;
94111 }
95- $ descriptorspec = [
96- 1 => ['pipe ' , 'w ' ],
97- 2 => ['pipe ' , 'w ' ],
98- ];
99- $ process = \proc_open ($ command , $ descriptorspec , $ pipes , null , null , [
112+
113+ $ process = \proc_open ($ command , self ::DESCRIPTORSPEC , $ pipes , null , null , [
100114 'suppress_errors ' => \true,
101115 ]);
102116 if (! \is_resource ($ process )) {
103117 return null ;
104118 }
119+
105120 $ info = \stream_get_contents ($ pipes [1 ]);
106121 \fclose ($ pipes [1 ]);
107122 \fclose ($ pipes [2 ]);
0 commit comments