Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js

Issue 2471243002: DevTools: Consolidate completion code into JavaScriptAutocomplete.js (Closed)
Patch Set: merge Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 WebInspector.JavaScriptAutocomplete = {};
6
7 /**
8 * @param {!Element} proxyElement
9 * @param {!Range} wordRange
10 * @param {boolean} force
11 * @param {function(!Array.<string>, number=)} completionsReadyCallback
12 */
13 WebInspector.JavaScriptAutocomplete.completionsForTextPromptInCurrentContext = f unction(proxyElement, wordRange, force, completionsReadyCallback) {
14 var expressionRange = wordRange.cloneRange();
15 expressionRange.collapse(true);
16 expressionRange.setStartBefore(proxyElement);
17 WebInspector.JavaScriptAutocomplete.completionsForTextInCurrentContext(express ionRange.toString(), wordRange.toString(), force)
18 .then(completionsReadyCallback);
19 };
20
21 /**
22 * @param {string} text
23 * @param {string} completionsPrefix
24 * @param {boolean=} force
25 * @return {!Promise<!Array<string>>}
26 */
27 WebInspector.JavaScriptAutocomplete.completionsForTextInCurrentContext = functio n(text, completionsPrefix, force) {
28 var index;
29 var stopChars = new Set(' =:({;,!+-*/&|^<>`'.split(''));
30 for (index = text.length - 1; index >= 0; index--) {
31 // Pass less stop characters to rangeOfWord so the range will be a more comp lete expression.
32 if (stopChars.has(text.charAt(index)))
33 break;
34 }
35 var clippedExpression = text.substring(index + 1);
36 var bracketCount = 0;
37
38 index = clippedExpression.length - 1;
39 while (index >= 0) {
40 var character = clippedExpression.charAt(index);
41 if (character === ']')
42 bracketCount++;
43 // Allow an open bracket at the end for property completion.
44 if (character === '[' && index < clippedExpression.length - 1) {
45 bracketCount--;
46 if (bracketCount < 0)
47 break;
48 }
49 index--;
50 }
51 clippedExpression = clippedExpression.substring(index + 1);
52
53 return WebInspector.JavaScriptAutocomplete.completionsForExpression(clippedExp ression, completionsPrefix, force);
54 };
55
56
57 /**
58 * @param {string} expressionString
59 * @param {string} prefix
60 * @param {boolean=} force
61 * @return {!Promise<!Array<string>>}
62 */
63 WebInspector.JavaScriptAutocomplete.completionsForExpression = function(expressi onString, prefix, force) {
64 var executionContext = WebInspector.context.flavor(WebInspector.ExecutionConte xt);
65 if (!executionContext)
66 return Promise.resolve([]);
67
68 var lastIndex = expressionString.length - 1;
69
70 var dotNotation = (expressionString[lastIndex] === '.');
71 var bracketNotation = (expressionString[lastIndex] === '[');
72
73 if (dotNotation || bracketNotation)
74 expressionString = expressionString.substr(0, lastIndex);
75
76 // User is entering float value, do not suggest anything.
77 if (expressionString && !isNaN(expressionString))
78 return Promise.resolve([]);
79
80 if (!prefix && !expressionString && !force)
81 return Promise.resolve([]);
82
83 var fufill;
84 var promise = new Promise(x => fufill = x);
85 if (!expressionString && executionContext.debuggerModel.selectedCallFrame())
86 executionContext.debuggerModel.selectedCallFrame().variableNames(receivedPro pertyNames);
87 else
88 executionContext.evaluate(expressionString, 'completion', true, true, false, false, false, evaluated);
89
90 return promise;
91 /**
92 * @param {?WebInspector.RemoteObject} result
93 * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
94 */
95 function evaluated(result, exceptionDetails) {
96 if (!result || !!exceptionDetails) {
97 fufill([]);
98 return;
99 }
100
101 /**
102 * @param {?WebInspector.RemoteObject} object
103 * @return {!Promise<?WebInspector.RemoteObject>}
104 */
105 function extractTarget(object) {
106 if (!object)
107 return Promise.resolve(/** @type {?WebInspector.RemoteObject} */(null));
108 if (object.type !== 'object' || object.subtype !== 'proxy')
109 return Promise.resolve(/** @type {?WebInspector.RemoteObject} */(object) );
110 return object.getOwnPropertiesPromise().then(extractTargetFromProperties). then(extractTarget);
111 }
112
113 /**
114 * @param {!{properties: ?Array<!WebInspector.RemoteObjectProperty>, interna lProperties: ?Array<!WebInspector.RemoteObjectProperty>}} properties
115 * @return {?WebInspector.RemoteObject}
116 */
117 function extractTargetFromProperties(properties) {
118 var internalProperties = properties.internalProperties || [];
119 var target = internalProperties.find(property => property.name === '[[Targ et]]');
120 return target ? target.value : null;
121 }
122
123 /**
124 * @param {string=} type
125 * @return {!Object}
126 * @suppressReceiverCheck
127 * @this {Object}
128 */
129 function getCompletions(type) {
130 var object;
131 if (type === 'string')
132 object = new String('');
133 else if (type === 'number')
134 object = new Number(0);
135 else if (type === 'boolean')
136 object = new Boolean(false);
137 else
138 object = this;
139
140 var resultSet = { __proto__: null };
141 try {
142 for (var o = object; o; o = Object.getPrototypeOf(o)) {
143 if ((type === 'array' || type === 'typedarray') && o === object && Arr ayBuffer.isView(o) && o.length > 9999)
144 continue;
145 var names = Object.getOwnPropertyNames(o);
146 var isArray = Array.isArray(o);
147 for (var i = 0; i < names.length; ++i) {
148 // Skip array elements indexes.
149 if (isArray && /^[0-9]/.test(names[i]))
150 continue;
151 resultSet[names[i]] = true;
152 }
153 }
154 } catch (e) {
155 }
156 return resultSet;
157 }
158
159 /**
160 * @param {?WebInspector.RemoteObject} object
161 */
162 function completionsForObject(object) {
163 if (!object)
164 receivedPropertyNames(null);
165 else if (object.type === 'object' || object.type === 'function')
166 object.callFunctionJSON(
167 getCompletions, [WebInspector.RemoteObject.toCallArgument(object.subty pe)],
168 receivedPropertyNames);
169 else if (object.type === 'string' || object.type === 'number' || object.ty pe === 'boolean')
170 executionContext.evaluate(
171 '(' + getCompletions + ')("' + result.type + '")', 'completion', false , true, true, false, false,
172 receivedPropertyNamesFromEval);
173 }
174
175 extractTarget(result).then(completionsForObject);
176 }
177
178 /**
179 * @param {?WebInspector.RemoteObject} result
180 * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
181 */
182 function receivedPropertyNamesFromEval(result, exceptionDetails) {
183 executionContext.target().runtimeAgent().releaseObjectGroup('completion');
184 if (result && !exceptionDetails)
185 receivedPropertyNames(/** @type {!Object} */(result.value));
186 else
187 fufill([]);
188 }
189
190 /**
191 * @param {?Object} propertyNames
192 */
193 function receivedPropertyNames(propertyNames) {
194 executionContext.target().runtimeAgent().releaseObjectGroup('completion');
195 if (!propertyNames) {
196 fufill([]);
197 return;
198 }
199 var includeCommandLineAPI = (!dotNotation && !bracketNotation);
200 if (includeCommandLineAPI) {
201 const commandLineAPI = [
202 'dir',
203 'dirxml',
204 'keys',
205 'values',
206 'profile',
207 'profileEnd',
208 'monitorEvents',
209 'unmonitorEvents',
210 'inspect',
211 'copy',
212 'clear',
213 'getEventListeners',
214 'debug',
215 'undebug',
216 'monitor',
217 'unmonitor',
218 'table',
219 '$',
220 '$$',
221 '$x'
222 ];
223 for (var i = 0; i < commandLineAPI.length; ++i)
224 propertyNames[commandLineAPI[i]] = true;
225 }
226 fufill(WebInspector.JavaScriptAutocomplete._completionsForPrefix(
227 dotNotation, bracketNotation, expressionString, prefix, Object.keys(proper tyNames)));
228 }
229 };
230
231 /**
232 * @param {boolean} dotNotation
233 * @param {boolean} bracketNotation
234 * @param {string} expressionString
235 * @param {string} prefix
236 * @param {!Array.<string>} properties
237 * @return {!Array<string>}
238 */
239 WebInspector.JavaScriptAutocomplete._completionsForPrefix = function(dotNotation , bracketNotation, expressionString, prefix, properties) {
240 if (bracketNotation) {
241 if (prefix.length && prefix[0] === '\'')
242 var quoteUsed = '\'';
243 else
244 var quoteUsed = '"';
245 }
246
247 var results = [];
248
249 if (!expressionString) {
250 const keywords = [
251 'break', 'case', 'catch', 'continue', 'default', 'delete', 'do', 'else', ' finally',
252 'for', 'function', 'if', 'in', 'instanceof', 'new', 'return', 'switch', 't his',
253 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with'
254 ];
255 properties = properties.concat(keywords);
256 }
257
258 properties.sort();
259
260 for (var i = 0; i < properties.length; ++i) {
261 var property = properties[i];
262
263 // Assume that all non-ASCII characters are letters and thus can be used as part of identifier.
264 if (dotNotation && !/^[a-zA-Z_$\u008F-\uFFFF][a-zA-Z0-9_$\u008F-\uFFFF]*$/.t est(property))
265 continue;
266
267 if (bracketNotation) {
268 if (!/^[0-9]+$/.test(property))
269 property = quoteUsed + property.escapeCharacters(quoteUsed + '\\') + quo teUsed;
270 property += ']';
271 }
272
273 if (property.length < prefix.length)
274 continue;
275 if (prefix.length && !property.startsWith(prefix))
276 continue;
277
278 // Substitute actual newlines with newline characters. @see crbug.com/498421
279 results.push(property.split('\n').join('\\n'));
280 }
281 return results;
282 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698