Chris@13
|
1 <?php
|
Chris@13
|
2
|
Chris@13
|
3 /*
|
Chris@13
|
4 * This file is part of Psy Shell.
|
Chris@13
|
5 *
|
Chris@13
|
6 * (c) 2012-2018 Justin Hileman
|
Chris@13
|
7 *
|
Chris@13
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@13
|
9 * file that was distributed with this source code.
|
Chris@13
|
10 */
|
Chris@13
|
11
|
Chris@13
|
12 namespace Psy\TabCompletion\Matcher;
|
Chris@13
|
13
|
Chris@13
|
14 /**
|
Chris@13
|
15 * Abstract tab completion Matcher.
|
Chris@13
|
16 *
|
Chris@13
|
17 * @author Marc Garcia <markcial@gmail.com>
|
Chris@13
|
18 */
|
Chris@13
|
19 abstract class AbstractMatcher
|
Chris@13
|
20 {
|
Chris@13
|
21 /** Syntax types */
|
Chris@13
|
22 const CONSTANT_SYNTAX = '^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$';
|
Chris@13
|
23 const VAR_SYNTAX = '^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$';
|
Chris@13
|
24 const MISC_OPERATORS = '+-*/^|&';
|
Chris@13
|
25 /** Token values */
|
Chris@13
|
26 const T_OPEN_TAG = 'T_OPEN_TAG';
|
Chris@13
|
27 const T_VARIABLE = 'T_VARIABLE';
|
Chris@13
|
28 const T_OBJECT_OPERATOR = 'T_OBJECT_OPERATOR';
|
Chris@13
|
29 const T_DOUBLE_COLON = 'T_DOUBLE_COLON';
|
Chris@13
|
30 const T_NEW = 'T_NEW';
|
Chris@13
|
31 const T_CLONE = 'T_CLONE';
|
Chris@13
|
32 const T_NS_SEPARATOR = 'T_NS_SEPARATOR';
|
Chris@13
|
33 const T_STRING = 'T_STRING';
|
Chris@13
|
34 const T_WHITESPACE = 'T_WHITESPACE';
|
Chris@13
|
35 const T_AND_EQUAL = 'T_AND_EQUAL';
|
Chris@13
|
36 const T_BOOLEAN_AND = 'T_BOOLEAN_AND';
|
Chris@13
|
37 const T_BOOLEAN_OR = 'T_BOOLEAN_OR';
|
Chris@13
|
38
|
Chris@13
|
39 const T_ENCAPSED_AND_WHITESPACE = 'T_ENCAPSED_AND_WHITESPACE';
|
Chris@13
|
40 const T_REQUIRE = 'T_REQUIRE';
|
Chris@13
|
41 const T_REQUIRE_ONCE = 'T_REQUIRE_ONCE';
|
Chris@13
|
42 const T_INCLUDE = 'T_INCLUDE';
|
Chris@13
|
43 const T_INCLUDE_ONCE = 'T_INCLUDE_ONCE';
|
Chris@13
|
44
|
Chris@13
|
45 /**
|
Chris@13
|
46 * Check whether this matcher can provide completions for $tokens.
|
Chris@13
|
47 *
|
Chris@13
|
48 * @param array $tokens Tokenized readline input
|
Chris@13
|
49 *
|
Chris@13
|
50 * @return bool
|
Chris@13
|
51 */
|
Chris@13
|
52 public function hasMatched(array $tokens)
|
Chris@13
|
53 {
|
Chris@13
|
54 return false;
|
Chris@13
|
55 }
|
Chris@13
|
56
|
Chris@13
|
57 /**
|
Chris@13
|
58 * Get current readline input word.
|
Chris@13
|
59 *
|
Chris@13
|
60 * @param array $tokens Tokenized readline input (see token_get_all)
|
Chris@13
|
61 *
|
Chris@13
|
62 * @return string
|
Chris@13
|
63 */
|
Chris@13
|
64 protected function getInput(array $tokens)
|
Chris@13
|
65 {
|
Chris@13
|
66 $var = '';
|
Chris@17
|
67 $firstToken = \array_pop($tokens);
|
Chris@13
|
68 if (self::tokenIs($firstToken, self::T_STRING)) {
|
Chris@13
|
69 $var = $firstToken[1];
|
Chris@13
|
70 }
|
Chris@13
|
71
|
Chris@13
|
72 return $var;
|
Chris@13
|
73 }
|
Chris@13
|
74
|
Chris@13
|
75 /**
|
Chris@13
|
76 * Get current namespace and class (if any) from readline input.
|
Chris@13
|
77 *
|
Chris@13
|
78 * @param array $tokens Tokenized readline input (see token_get_all)
|
Chris@13
|
79 *
|
Chris@13
|
80 * @return string
|
Chris@13
|
81 */
|
Chris@13
|
82 protected function getNamespaceAndClass($tokens)
|
Chris@13
|
83 {
|
Chris@13
|
84 $class = '';
|
Chris@13
|
85 while (self::hasToken(
|
Chris@13
|
86 [self::T_NS_SEPARATOR, self::T_STRING],
|
Chris@17
|
87 $token = \array_pop($tokens)
|
Chris@13
|
88 )) {
|
Chris@16
|
89 if (self::needCompleteClass($token)) {
|
Chris@16
|
90 continue;
|
Chris@16
|
91 }
|
Chris@16
|
92
|
Chris@13
|
93 $class = $token[1] . $class;
|
Chris@13
|
94 }
|
Chris@13
|
95
|
Chris@13
|
96 return $class;
|
Chris@13
|
97 }
|
Chris@13
|
98
|
Chris@13
|
99 /**
|
Chris@13
|
100 * Provide tab completion matches for readline input.
|
Chris@13
|
101 *
|
Chris@13
|
102 * @param array $tokens information substracted with get_token_all
|
Chris@13
|
103 * @param array $info readline_info object
|
Chris@13
|
104 *
|
Chris@13
|
105 * @return array The matches resulting from the query
|
Chris@13
|
106 */
|
Chris@13
|
107 abstract public function getMatches(array $tokens, array $info = []);
|
Chris@13
|
108
|
Chris@13
|
109 /**
|
Chris@13
|
110 * Check whether $word starts with $prefix.
|
Chris@13
|
111 *
|
Chris@13
|
112 * @param string $prefix
|
Chris@13
|
113 * @param string $word
|
Chris@13
|
114 *
|
Chris@13
|
115 * @return bool
|
Chris@13
|
116 */
|
Chris@13
|
117 public static function startsWith($prefix, $word)
|
Chris@13
|
118 {
|
Chris@17
|
119 return \preg_match(\sprintf('#^%s#', $prefix), $word);
|
Chris@13
|
120 }
|
Chris@13
|
121
|
Chris@13
|
122 /**
|
Chris@13
|
123 * Check whether $token matches a given syntax pattern.
|
Chris@13
|
124 *
|
Chris@13
|
125 * @param mixed $token A PHP token (see token_get_all)
|
Chris@13
|
126 * @param string $syntax A syntax pattern (default: variable pattern)
|
Chris@13
|
127 *
|
Chris@13
|
128 * @return bool
|
Chris@13
|
129 */
|
Chris@13
|
130 public static function hasSyntax($token, $syntax = self::VAR_SYNTAX)
|
Chris@13
|
131 {
|
Chris@17
|
132 if (!\is_array($token)) {
|
Chris@13
|
133 return false;
|
Chris@13
|
134 }
|
Chris@13
|
135
|
Chris@17
|
136 $regexp = \sprintf('#%s#', $syntax);
|
Chris@13
|
137
|
Chris@17
|
138 return (bool) \preg_match($regexp, $token[1]);
|
Chris@13
|
139 }
|
Chris@13
|
140
|
Chris@13
|
141 /**
|
Chris@13
|
142 * Check whether $token type is $which.
|
Chris@13
|
143 *
|
Chris@13
|
144 * @param string $which A PHP token type
|
Chris@13
|
145 * @param mixed $token A PHP token (see token_get_all)
|
Chris@13
|
146 *
|
Chris@13
|
147 * @return bool
|
Chris@13
|
148 */
|
Chris@13
|
149 public static function tokenIs($token, $which)
|
Chris@13
|
150 {
|
Chris@17
|
151 if (!\is_array($token)) {
|
Chris@13
|
152 return false;
|
Chris@13
|
153 }
|
Chris@13
|
154
|
Chris@17
|
155 return \token_name($token[0]) === $which;
|
Chris@13
|
156 }
|
Chris@13
|
157
|
Chris@13
|
158 /**
|
Chris@13
|
159 * Check whether $token is an operator.
|
Chris@13
|
160 *
|
Chris@13
|
161 * @param mixed $token A PHP token (see token_get_all)
|
Chris@13
|
162 *
|
Chris@13
|
163 * @return bool
|
Chris@13
|
164 */
|
Chris@13
|
165 public static function isOperator($token)
|
Chris@13
|
166 {
|
Chris@17
|
167 if (!\is_string($token)) {
|
Chris@13
|
168 return false;
|
Chris@13
|
169 }
|
Chris@13
|
170
|
Chris@17
|
171 return \strpos(self::MISC_OPERATORS, $token) !== false;
|
Chris@13
|
172 }
|
Chris@13
|
173
|
Chris@16
|
174 public static function needCompleteClass($token)
|
Chris@16
|
175 {
|
Chris@17
|
176 return \in_array($token[1], ['doc', 'ls', 'show']);
|
Chris@16
|
177 }
|
Chris@16
|
178
|
Chris@13
|
179 /**
|
Chris@13
|
180 * Check whether $token type is present in $coll.
|
Chris@13
|
181 *
|
Chris@13
|
182 * @param array $coll A list of token types
|
Chris@13
|
183 * @param mixed $token A PHP token (see token_get_all)
|
Chris@13
|
184 *
|
Chris@13
|
185 * @return bool
|
Chris@13
|
186 */
|
Chris@13
|
187 public static function hasToken(array $coll, $token)
|
Chris@13
|
188 {
|
Chris@17
|
189 if (!\is_array($token)) {
|
Chris@13
|
190 return false;
|
Chris@13
|
191 }
|
Chris@13
|
192
|
Chris@17
|
193 return \in_array(\token_name($token[0]), $coll);
|
Chris@13
|
194 }
|
Chris@13
|
195 }
|