Minor dependency updates
[yaffs-website] / vendor / stecman / symfony-console-completion / src / CompletionContext.php
1 <?php
2
3
4 namespace Stecman\Component\Symfony\Console\BashCompletion;
5
6 /**
7  * Command line context for completion
8  *
9  * Represents the current state of the command line that is being completed
10  */
11 class CompletionContext
12 {
13     /**
14      * The current contents of the command line as a single string
15      *
16      * Bash equivalent: COMP_LINE
17      *
18      * @var string
19      */
20     protected $commandLine;
21
22     /**
23      * The index of the user's cursor relative to the start of the command line.
24      *
25      * If the current cursor position is at the end of the current command,
26      * the value of this variable is equal to the length of $this->commandLine
27      *
28      * Bash equivalent: COMP_POINT
29      *
30      * @var int
31      */
32     protected $charIndex = 0;
33
34     /**
35      * An array containing the individual words in the current command line.
36      *
37      * This is not set until $this->splitCommand() is called, when it is populated by
38      * $commandLine exploded by $wordBreaks
39      *
40      * Bash equivalent: COMP_WORDS
41      *
42      * @var array|null
43      */
44     protected $words = null;
45
46     /**
47      * The index in $this->words containing the word at the current cursor position.
48      *
49      * This is not set until $this->splitCommand() is called.
50      *
51      * Bash equivalent: COMP_CWORD
52      *
53      * @var int|null
54      */
55     protected $wordIndex = null;
56
57     /**
58      * Characters that $this->commandLine should be split on to get a list of individual words
59      *
60      * Bash equivalent: COMP_WORDBREAKS
61      *
62      * @var string
63      */
64     protected $wordBreaks = "'\"()= \t\n";
65
66     /**
67      * Set the whole contents of the command line as a string
68      *
69      * @param string $commandLine
70      */
71     public function setCommandLine($commandLine)
72     {
73         $this->commandLine = $commandLine;
74         $this->reset();
75     }
76
77     /**
78      * Return the current command line verbatim as a string
79      *
80      * @return string
81      */
82     public function getCommandLine()
83     {
84         return $this->commandLine;
85     }
86
87     /**
88      * Return the word from the command line that the cursor is currently in
89      *
90      * Most of the time this will be a partial word. If the cursor has a space before it,
91      * this will return an empty string, indicating a new word.
92      *
93      * @return string
94      */
95     public function getCurrentWord()
96     {
97         if (isset($this->words[$this->wordIndex])) {
98             return $this->words[$this->wordIndex];
99         }
100
101         return '';
102     }
103
104     /**
105      * Return a word by index from the command line
106      *
107      * @see $words, $wordBreaks
108      * @param int $index
109      * @return string
110      */
111     public function getWordAtIndex($index)
112     {
113         if (isset($this->words[$index])) {
114             return $this->words[$index];
115         }
116
117         return '';
118     }
119
120     /**
121      * Get the contents of the command line, exploded into words based on the configured word break characters
122      *
123      * @see $wordBreaks, setWordBreaks
124      * @return array
125      */
126     public function getWords()
127     {
128         if ($this->words === null) {
129             $this->splitCommand();
130         }
131
132         return $this->words;
133     }
134
135     /**
136      * Get the index of the word the cursor is currently in
137      *
138      * @see getWords, getCurrentWord
139      * @return int
140      */
141     public function getWordIndex()
142     {
143         if ($this->wordIndex === null) {
144             $this->splitCommand();
145         }
146
147         return $this->wordIndex;
148     }
149
150     /**
151      * Get the character index of the user's cursor on the command line
152      *
153      * This is in the context of the full command line string, so includes word break characters.
154      * Note that some shells can only provide an approximation for character index. Under ZSH for
155      * example, this will always be the character at the start of the current word.
156      *
157      * @return int
158      */
159     public function getCharIndex()
160     {
161         return $this->charIndex;
162     }
163
164     /**
165      * Set the cursor position as a character index relative to the start of the command line
166      *
167      * @param int $index
168      */
169     public function setCharIndex($index)
170     {
171         $this->charIndex = $index;
172         $this->reset();
173     }
174
175     /**
176      * Set characters to use as split points when breaking the command line into words
177      *
178      * This defaults to a sane value based on BASH's word break characters and shouldn't
179      * need to be changed unless your completions contain the default word break characters.
180      *
181      * @see wordBreaks
182      * @param string $charList - a single string containing all of the characters to break words on
183      */
184     public function setWordBreaks($charList)
185     {
186         $this->wordBreaks = $charList;
187         $this->reset();
188     }
189
190     /**
191      * Split the command line into words using the configured word break characters
192      *
193      * @return string[]
194      */
195     protected function splitCommand()
196     {
197         $this->words = array();
198         $this->wordIndex = null;
199         $cursor = 0;
200
201         $breaks = preg_quote($this->wordBreaks);
202
203         if (!preg_match_all("/([^$breaks]*)([$breaks]*)/", $this->commandLine, $matches)) {
204             return;
205         }
206
207         // Groups:
208         // 1: Word
209         // 2: Break characters
210         foreach ($matches[0] as $index => $wholeMatch) {
211             // Determine which word the cursor is in
212             $cursor += strlen($wholeMatch);
213             $word = $matches[1][$index];
214             $breaks = $matches[2][$index];
215
216             if ($this->wordIndex === null && $cursor >= $this->charIndex) {
217                 $this->wordIndex = $index;
218
219                 // Find the user's cursor position relative to the end of this word
220                 // The end of the word is the internal cursor minus any break characters that were captured
221                 $cursorWordOffset = $this->charIndex - ($cursor - strlen($breaks));
222
223                 if ($cursorWordOffset < 0) {
224                     // Cursor is inside the word - truncate the word at the cursor
225                     // (This emulates normal BASH completion behaviour I've observed, though I'm not entirely sure if it's useful)
226                     $word = substr($word, 0, strlen($word) + $cursorWordOffset);
227
228                 } elseif ($cursorWordOffset > 0) {
229                     // Cursor is in the break-space after a word
230                     // Push an empty word at the cursor to allow completion of new terms at the cursor, ignoring words ahead
231                     $this->wordIndex++;
232                     $this->words[] = $word;
233                     $this->words[] = '';
234                     continue;
235                 }
236             }
237
238             if ($word !== '') {
239                 $this->words[] = $word;
240             }
241         }
242
243         if ($this->wordIndex > count($this->words) - 1) {
244             $this->wordIndex = count($this->words) - 1;
245         }
246     }
247
248     /**
249      * Reset the computed words so that $this->splitWords is forced to run again
250      */
251     protected function reset()
252     {
253         $this->words = null;
254         $this->wordIndex = null;
255     }
256 }