Completed
Push — master ( 1688fd...eb1d12 )
by Marcel
02:19
created

Multiline::getLineIndexByCharacterPosition()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 12
rs 9.2
cc 4
eloc 8
nc 3
nop 1
1
<?php
2
namespace nochso\Omni;
3
4
/**
5
 * Multiline string class for working with lines of text.
6
 */
7
final class Multiline extends ArrayCollection
8
{
9
    /**
10
     * @var \nochso\Omni\EOL
11
     */
12
    private $eol;
13
14
    /**
15
     * Create a new Multiline object from a string.
16
     *
17
     * First the input string is split into lines by the detected end-of-line
18
     * character. Afterwards any extra EOL chars will be trimmed.
19
     *
20
     * @see \nochso\Omni\EOL
21
     *
22
     * @param string $input      A string to split into a Multiline object
23
     * @param string $defaultEol Default end-of-line type to split the input by. This is a fallback in case it could
24
     *                           not be detected from the input string. Optional, defaults to `EOL::EOL_LF` i.e. "\n".
25
     *                           See the `EOL::EOL_*` class constants.
26
     *
27
     * @return \nochso\Omni\Multiline
28
     */
29
    public static function create($input, $defaultEol = \nochso\Omni\EOL::EOL_LF)
30
    {
31
        $eol = EOL::detectDefault($input, $defaultEol);
32
        $lines = explode($eol, $input);
33
        $multiline = new self($lines);
34
        // Remove left-over line feeds
35
        $multiline->apply(function ($line) {
36
            return trim($line, "\r\n");
37
        });
38
        $multiline->setEol($eol);
39
        return $multiline;
40
    }
41
42
    /**
43
     * __toString returns a single string using the current EOL style.
44
     *
45
     * @return string
46
     */
47
    public function __toString()
48
    {
49
        return implode((string) $this->eol, $this->list);
50
    }
51
52
    /**
53
     * Get EOL style ending.
54
     *
55
     * @return \nochso\Omni\EOL
56
     */
57
    public function getEol()
58
    {
59
        return $this->eol;
60
    }
61
62
    /**
63
     * getMaxLength of all lines.
64
     *
65
     * @return int
66
     */
67
    public function getMaxLength()
68
    {
69
        $length = 0;
70
        foreach ($this->list as $line) {
71
            $length = max($length, mb_strlen($line));
72
        }
73
        return $length;
74
    }
75
76
    /**
77
     * Set EOL used by this Multiline string.
78
     *
79
     * @param \nochso\Omni\EOL|string $eol Either an `EOL` object or a string ("\r\n" or "\n")
80
     *
81
     * @return $this
82
     */
83
    public function setEol($eol)
84
    {
85
        if (!$eol instanceof EOL) {
86
            $eol = new EOL($eol);
87
        }
88
        $this->eol = $eol;
89
        return $this;
90
    }
91
92
    /**
93
     * Append text to a certain line.
94
     *
95
     * @param string   $text
96
     * @param null|int $index Optional, defaults to the last line. Other
97
     *
98
     * @return $this
99
     */
100
    public function append($text, $index = null)
101
    {
102
        if ($index === null) {
103
            $index = count($this) - 1;
104
        }
105
        $this->list[$index] .= $text;
106
        return $this;
107
    }
108
109
    /**
110
     * Prefix all lines with a string.
111
     *
112
     * @param string $prefix The prefix to add to the start of the string.
113
     *
114
     * @return string
115
     */
116
    public function prefix($prefix)
117
    {
118
        $prefixer = function ($line) use ($prefix) {
119
            return $prefix . $line;
120
        };
121
        return $this->apply($prefixer);
122
    }
123
124
    /**
125
     * Pad all lines to the same length using `str_pad`.
126
     *
127
     * @param int    $length      If length is larger than the maximum line length, all lines will be padded up to the
128
     *                            given length. If length is null, the maximum of all line lengths is used. Optional,
129
     *                            defaults to null.
130
     * @param string $padding     Optional, defaults to a space character. Can be more than one character. The padding
131
     *                            may be truncated if the required number of padding characters can't be evenly
132
     *                            divided.
133
     * @param int    $paddingType Optional argument pad_type can be STR_PAD_RIGHT, STR_PAD_LEFT, or STR_PAD_BOTH.
134
     *                            Defaults to STR_PAD_RIGHT.
135
     *
136
     * @return string
137
     */
138
    public function pad($length = null, $padding = ' ', $paddingType = STR_PAD_RIGHT)
139
    {
140
        if ($length === null) {
141
            $length = $this->getMaxLength();
142
        }
143
        $padder = function ($line) use ($length, $padding, $paddingType) {
144
            return Strings::padMultibyte($line, $length, $padding, $paddingType);
145
        };
146
        return $this->apply($padder);
147
    }
148
149
    /**
150
     * getLineIndexByCharacterPosition returns the line index containing a certain position.
151
     *
152
     * @param int $characterPosition Position of a character as if Multiline was a raw string.
153
     *
154
     * @return int|null The array index of the line containing the character position.
155
     */
156
    public function getLineIndexByCharacterPosition($characterPosition)
157
    {
158
        $position = 0;
159
        foreach ($this->list as $key => $line) {
160
            $length = mb_strlen($line . $this->getEol());
161
            if ($characterPosition >= $position && $characterPosition <= $position + $length) {
162
                return $key;
163
            }
164
            $position += $length;
165
        }
166
        return null;
167
    }
168
}
169