4 namespace Stecman\Component\Symfony\Console\BashCompletion;
7 * Command line context for completion
9 * Represents the current state of the command line that is being completed
11 class CompletionContext
14 * The current contents of the command line as a single string
16 * Bash equivalent: COMP_LINE
20 protected $commandLine;
23 * The index of the user's cursor relative to the start of the command line.
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
28 * Bash equivalent: COMP_POINT
32 protected $charIndex = 0;
35 * An array containing the individual words in the current command line.
37 * This is not set until $this->splitCommand() is called, when it is populated by
38 * $commandLine exploded by $wordBreaks
40 * Bash equivalent: COMP_WORDS
44 protected $words = null;
47 * The index in $this->words containing the word at the current cursor position.
49 * This is not set until $this->splitCommand() is called.
51 * Bash equivalent: COMP_CWORD
55 protected $wordIndex = null;
58 * Characters that $this->commandLine should be split on to get a list of individual words
60 * Bash equivalent: COMP_WORDBREAKS
64 protected $wordBreaks = "'\"()= \t\n";
67 * Set the whole contents of the command line as a string
69 * @param string $commandLine
71 public function setCommandLine($commandLine)
73 $this->commandLine = $commandLine;
78 * Return the current command line verbatim as a string
82 public function getCommandLine()
84 return $this->commandLine;
88 * Return the word from the command line that the cursor is currently in
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.
95 public function getCurrentWord()
97 if (isset($this->words[$this->wordIndex])) {
98 return $this->words[$this->wordIndex];
105 * Return a word by index from the command line
107 * @see $words, $wordBreaks
111 public function getWordAtIndex($index)
113 if (isset($this->words[$index])) {
114 return $this->words[$index];
121 * Get the contents of the command line, exploded into words based on the configured word break characters
123 * @see $wordBreaks, setWordBreaks
126 public function getWords()
128 if ($this->words === null) {
129 $this->splitCommand();
136 * Get the index of the word the cursor is currently in
138 * @see getWords, getCurrentWord
141 public function getWordIndex()
143 if ($this->wordIndex === null) {
144 $this->splitCommand();
147 return $this->wordIndex;
151 * Get the character index of the user's cursor on the command line
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.
159 public function getCharIndex()
161 return $this->charIndex;
165 * Set the cursor position as a character index relative to the start of the command line
169 public function setCharIndex($index)
171 $this->charIndex = $index;
176 * Set characters to use as split points when breaking the command line into words
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.
182 * @param string $charList - a single string containing all of the characters to break words on
184 public function setWordBreaks($charList)
186 $this->wordBreaks = $charList;
191 * Split the command line into words using the configured word break characters
195 protected function splitCommand()
197 $this->words = array();
198 $this->wordIndex = null;
201 $breaks = preg_quote($this->wordBreaks);
203 if (!preg_match_all("/([^$breaks]*)([$breaks]*)/", $this->commandLine, $matches)) {
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];
216 if ($this->wordIndex === null && $cursor >= $this->charIndex) {
217 $this->wordIndex = $index;
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));
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);
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
232 $this->words[] = $word;
239 $this->words[] = $word;
243 if ($this->wordIndex > count($this->words) - 1) {
244 $this->wordIndex = count($this->words) - 1;
249 * Reset the computed words so that $this->splitWords is forced to run again
251 protected function reset()
254 $this->wordIndex = null;