Completed
Push — master ( d2ff2c...93fad5 )
by Harry
02:21
created

TerminalDimensions::getWidth()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 15
Code Lines 8

Duplication

Lines 15
Ratio 100 %

Importance

Changes 0
Metric Value
dl 15
loc 15
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 8
nc 12
nop 0
1
<?php
2
3
namespace Graze\DiffRenderer\Terminal;
4
5
/**
6
 * Class TerminalDimensions
7
 *
8
 * Copied from symfony/console/Terminal
9
 */
10
class TerminalDimensions implements DimensionsInterface
11
{
12
    /** @var int|null */
13
    private $width = null;
14
    /** @var int|null */
15
    private $height = null;
16
    /** @var bool */
17
    private $initialised = false;
18
19
    /**
20
     * Gets the terminal width.
21
     *
22
     * @return int
23
     */
24 View Code Duplication
    public function getWidth()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
25
    {
26
        if (null === $this->width && !$this->initialised) {
27
            $this->refreshDimensions();
28
        }
29
30
        if (null === $this->width) {
31
            $width = getenv('COLUMNS');
32
            if (false !== $width) {
33
                $this->width = (int) trim($width);
34
            }
35
        }
36
37
        return $this->width ?: static::DEFAULT_WIDTH;
38
    }
39
40
    /**
41
     * Gets the terminal height.
42
     *
43
     * @return int
44
     */
45 View Code Duplication
    public function getHeight()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
46
    {
47
        if (null === $this->height && !$this->initialised) {
48
            $this->refreshDimensions();
49
        }
50
51
        if (null === $this->height) {
52
            $height = getenv('LINES');
53
            if (false !== $height) {
54
                $this->height = (int) trim($height);
55
            }
56
        }
57
58
        return $this->height ?: static::DEFAULT_HEIGHT;
59
    }
60
61
    /**
62
     * Refresh the current dimensions from the terminal
63
     */
64
    public function refreshDimensions()
65
    {
66
        if ('\\' === DIRECTORY_SEPARATOR) {
67
            if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) {
68
                // extract [w, H] from "wxh (WxH)"
69
                // or [w, h] from "wxh"
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
70
                $this->width = (int) $matches[1];
71
                $this->height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
72
            } elseif (null !== $dimensions = $this->getConsoleMode()) {
73
                // extract [w, h] from "wxh"
74
                $this->width = (int) $dimensions[0];
75
                $this->height = (int) $dimensions[1];
76
            }
77
        } elseif ($sttyString = $this->getSttyColumns()) {
78
            if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
79
                // extract [w, h] from "rows h; columns w;"
80
                $this->width = (int) $matches[2];
81
                $this->height = (int) $matches[1];
82
            } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
83
                // extract [w, h] from "; h rows; w columns"
84
                $this->width = (int) $matches[2];
85
                $this->height = (int) $matches[1];
86
            }
87
        }
88
        $this->initialised = true;
89
    }
90
91
    /**
92
     * Runs and parses mode CON if it's available, suppressing any error output.
93
     *
94
     * @return int[]|null An array composed of the width and the height or null if it could not be parsed
95
     */
96
    private function getConsoleMode()
97
    {
98
        if (!function_exists('proc_open')) {
99
            return null;
100
        }
101
102
        $spec = [
103
            1 => ['pipe', 'w'],
104
            2 => ['pipe', 'w'],
105
        ];
106
        $process = proc_open('mode CON', $spec, $pipes, null, null, ['suppress_errors' => true]);
107
        if (is_resource($process)) {
108
            $info = stream_get_contents($pipes[1]);
109
            fclose($pipes[1]);
110
            fclose($pipes[2]);
111
            proc_close($process);
112
113
            if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
114
                return [(int) $matches[2], (int) $matches[1]];
115
            }
116
        }
117
        return null;
118
    }
119
120
    /**
121
     * Runs and parses stty -a if it's available, suppressing any error output.
122
     *
123
     * @return string|null
124
     */
125
    private function getSttyColumns()
126
    {
127
        if (!function_exists('proc_open')) {
128
            return null;
129
        }
130
131
        $spec = [
132
            1 => ['pipe', 'w'],
133
            2 => ['pipe', 'w'],
134
        ];
135
136
        $process = proc_open('stty -a | grep columns', $spec, $pipes, null, null, ['suppress_errors' => true]);
137
        if (is_resource($process)) {
138
            $info = stream_get_contents($pipes[1]);
139
            fclose($pipes[1]);
140
            fclose($pipes[2]);
141
            proc_close($process);
142
143
            return $info;
144
        }
145
146
        return null;
147
    }
148
}
149