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

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

Issue 2656683003: Revert of DevTools: Console: Provide autocompletions for Maps (Closed)
Patch Set: Created 3 years, 11 months 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 Components.JavaScriptAutocomplete = {}; 5 Components.JavaScriptAutocomplete = {};
6 6
7 /** @typedef {{title:(string|undefined), items:Array<string>}} */ 7 /** @typedef {{title:(string|undefined), items:Array<string>}} */
8 Components.JavaScriptAutocomplete.CompletionGroup; 8 Components.JavaScriptAutocomplete.CompletionGroup;
9 9
10 /** 10 /**
11 * @param {string} text 11 * @param {string} text
12 * @param {string} query 12 * @param {string} query
13 * @param {boolean=} force 13 * @param {boolean=} force
14 * @return {!Promise<!UI.SuggestBox.Suggestions>} 14 * @return {!Promise<!UI.SuggestBox.Suggestions>}
15 */ 15 */
16 Components.JavaScriptAutocomplete.completionsForTextInCurrentContext = function( text, query, force) { 16 Components.JavaScriptAutocomplete.completionsForTextInCurrentContext = function( text, query, force) {
17 var clippedExpression = Components.JavaScriptAutocomplete._clipExpression(text , true);
18 var mapCompletionsPromise = Components.JavaScriptAutocomplete._mapCompletions( text, query);
19 return Components.JavaScriptAutocomplete.completionsForExpression(clippedExpre ssion, query, force)
20 .then(completions => mapCompletionsPromise.then(mapCompletions => mapCompl etions.concat(completions)));
21 };
22
23 /**
24 * @param {string} text
25 * @param {boolean=} allowEndingBracket
26 * @return {string}
27 */
28 Components.JavaScriptAutocomplete._clipExpression = function(text, allowEndingBr acket) {
29 var index; 17 var index;
30 var stopChars = new Set('=:({;,!+-*/&|^<>`'.split('')); 18 var stopChars = new Set('=:({;,!+-*/&|^<>`'.split(''));
31 var whiteSpaceChars = new Set(' \r\n\t'.split('')); 19 var whiteSpaceChars = new Set(' \r\n\t'.split(''));
32 var continueChars = new Set('[. \r\n\t'.split('')); 20 var continueChars = new Set('[. \r\n\t'.split(''));
33 21
34 for (index = text.length - 1; index >= 0; index--) { 22 for (index = text.length - 1; index >= 0; index--) {
23 // Pass less stop characters to rangeOfWord so the range will be a more comp lete expression.
35 if (stopChars.has(text.charAt(index))) 24 if (stopChars.has(text.charAt(index)))
36 break; 25 break;
37 if (whiteSpaceChars.has(text.charAt(index)) && !continueChars.has(text.charA t(index - 1))) 26 if (whiteSpaceChars.has(text.charAt(index)) && !continueChars.has(text.charA t(index - 1)))
38 break; 27 break;
39 } 28 }
40 var clippedExpression = text.substring(index + 1).trim(); 29 var clippedExpression = text.substring(index + 1).trim();
41 var bracketCount = 0; 30 var bracketCount = 0;
42 31
43 index = clippedExpression.length - 1; 32 index = clippedExpression.length - 1;
44 while (index >= 0) { 33 while (index >= 0) {
45 var character = clippedExpression.charAt(index); 34 var character = clippedExpression.charAt(index);
46 if (character === ']') 35 if (character === ']')
47 bracketCount++; 36 bracketCount++;
48 // Allow an open bracket at the end for property completion. 37 // Allow an open bracket at the end for property completion.
49 if (character === '[' && (index < clippedExpression.length - 1 || !allowEndi ngBracket)) { 38 if (character === '[' && index < clippedExpression.length - 1) {
50 bracketCount--; 39 bracketCount--;
51 if (bracketCount < 0) 40 if (bracketCount < 0)
52 break; 41 break;
53 } 42 }
54 index--; 43 index--;
55 } 44 }
56 return clippedExpression.substring(index + 1).trim(); 45 clippedExpression = clippedExpression.substring(index + 1).trim();
46
47 return Components.JavaScriptAutocomplete.completionsForExpression(clippedExpre ssion, query, force);
57 }; 48 };
58 49
59 /** 50 /**
60 * @param {string} text
61 * @param {string} query
62 * @return {!Promise<!UI.SuggestBox.Suggestions>}
63 */
64 Components.JavaScriptAutocomplete._mapCompletions = function(text, query) {
65 var mapMatch = text.match(/\.\s*(get|set|delete)\s*\(\s*$/);
66 var executionContext = UI.context.flavor(SDK.ExecutionContext);
67 if (!executionContext || !mapMatch)
68 return Promise.resolve([]);
69
70 var clippedExpression = Components.JavaScriptAutocomplete._clipExpression(text .substring(0, mapMatch.index));
71 var fulfill;
72 var promise = new Promise(x => fulfill = x);
73 executionContext.evaluate(clippedExpression, 'completion', true, true, false, false, false, evaluated);
74 return promise;
75
76 /**
77 * @param {?SDK.RemoteObject} result
78 * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
79 */
80 function evaluated(result, exceptionDetails) {
81 if (!result || !!exceptionDetails || result.subtype !== 'map') {
82 fulfill([]);
83 return;
84 }
85 result.getOwnPropertiesPromise().then(extractEntriesProperty);
86 }
87
88 /**
89 * @param {!{properties: ?Array<!SDK.RemoteObjectProperty>, internalProperties : ?Array<!SDK.RemoteObjectProperty>}} properties
90 */
91 function extractEntriesProperty(properties) {
92 var internalProperties = properties.internalProperties || [];
93 var entriesProperty = internalProperties.find(property => property.name === '[[Entries]]');
94 if (!entriesProperty) {
95 fulfill([]);
96 return;
97 }
98 entriesProperty.value.callFunctionJSONPromise(getEntries).then(keysObj => go tKeys(Object.keys(keysObj)));
99 }
100
101 /**
102 * @suppressReceiverCheck
103 * @this {!Array<{key:?, value:?}>}
104 * @return {!Object}
105 */
106 function getEntries() {
107 var result = {__proto__: null};
108 for (var i = 0; i < this.length; i++) {
109 if (typeof this[i].key === 'string')
110 result[this[i].key] = true;
111 }
112 return result;
113 }
114
115 /**
116 * @param {!Array<string>} rawKeys
117 */
118 function gotKeys(rawKeys) {
119 var caseSensitivePrefix = [];
120 var caseInsensitivePrefix = [];
121 var caseSensitiveAnywhere = [];
122 var caseInsensitiveAnywhere = [];
123 var quoteChar = '"';
124 if (query.startsWith('\''))
125 quoteChar = '\'';
126 var endChar = ')';
127 if (mapMatch[0].indexOf('set') !== -1)
128 endChar = ', ';
129
130 var sorter = rawKeys.length < 1000 ? String.naturalOrderComparator : undefin ed;
131 var keys = rawKeys.sort(sorter).map(key => quoteChar + key + quoteChar + end Char);
132
133 for (var key of keys) {
134 if (key.length < query.length)
135 continue;
136 if (query.length && key.toLowerCase().indexOf(query.toLowerCase()) === -1)
137 continue;
138 // Substitute actual newlines with newline characters. @see crbug.com/4984 21
139 var title = key.split('\n').join('\\n');
140
141 if (key.startsWith(query))
142 caseSensitivePrefix.push({title: title, priority: 4});
143 else if (key.toLowerCase().startsWith(query.toLowerCase()))
144 caseInsensitivePrefix.push({title: title, priority: 3});
145 else if (key.indexOf(query) !== -1)
146 caseSensitiveAnywhere.push({title: title, priority: 2});
147 else
148 caseInsensitiveAnywhere.push({title: title, priority: 1});
149 }
150 var suggestions = caseSensitivePrefix.concat(caseInsensitivePrefix, caseSens itiveAnywhere, caseInsensitiveAnywhere);
151 if (suggestions.length)
152 suggestions[0].subtitle = Common.UIString('Keys');
153 fulfill(suggestions);
154 }
155 };
156
157 /**
158 * @param {string} expressionString 51 * @param {string} expressionString
159 * @param {string} query 52 * @param {string} query
160 * @param {boolean=} force 53 * @param {boolean=} force
161 * @return {!Promise<!UI.SuggestBox.Suggestions>} 54 * @return {!Promise<!UI.SuggestBox.Suggestions>}
162 */ 55 */
163 Components.JavaScriptAutocomplete.completionsForExpression = function(expression String, query, force) { 56 Components.JavaScriptAutocomplete.completionsForExpression = function(expression String, query, force) {
164 var executionContext = UI.context.flavor(SDK.ExecutionContext); 57 var executionContext = UI.context.flavor(SDK.ExecutionContext);
165 if (!executionContext) 58 if (!executionContext)
166 return Promise.resolve([]); 59 return Promise.resolve([]);
167 60
168 var lastIndex = expressionString.length - 1; 61 var lastIndex = expressionString.length - 1;
169 62
170 var dotNotation = (expressionString[lastIndex] === '.'); 63 var dotNotation = (expressionString[lastIndex] === '.');
171 var bracketNotation = (expressionString.length > 1 && expressionString[lastInd ex] === '['); 64 var bracketNotation = (expressionString.length > 1 && expressionString[lastInd ex] === '[');
172 65
173 if (dotNotation || bracketNotation) 66 if (dotNotation || bracketNotation)
174 expressionString = expressionString.substr(0, lastIndex); 67 expressionString = expressionString.substr(0, lastIndex);
175 else 68 else
176 expressionString = ''; 69 expressionString = '';
177 70
178 // User is entering float value, do not suggest anything. 71 // User is entering float value, do not suggest anything.
179 if ((expressionString && !isNaN(expressionString)) || (!expressionString && qu ery && !isNaN(query))) 72 if ((expressionString && !isNaN(expressionString)) || (!expressionString && qu ery && !isNaN(query)))
180 return Promise.resolve([]); 73 return Promise.resolve([]);
181 74
182 75
183 if (!query && !expressionString && !force) 76 if (!query && !expressionString && !force)
184 return Promise.resolve([]); 77 return Promise.resolve([]);
185 78
186 var fulfill; 79 var fufill;
187 var promise = new Promise(x => fulfill = x); 80 var promise = new Promise(x => fufill = x);
188 var selectedFrame = executionContext.debuggerModel.selectedCallFrame(); 81 var selectedFrame = executionContext.debuggerModel.selectedCallFrame();
189 if (!expressionString && selectedFrame) 82 if (!expressionString && selectedFrame)
190 variableNamesInScopes(selectedFrame, receivedPropertyNames); 83 variableNamesInScopes(selectedFrame, receivedPropertyNames);
191 else 84 else
192 executionContext.evaluate(expressionString, 'completion', true, true, false, false, false, evaluated); 85 executionContext.evaluate(expressionString, 'completion', true, true, false, false, false, evaluated);
193 86
194 return promise; 87 return promise;
195 /** 88 /**
196 * @param {?SDK.RemoteObject} result 89 * @param {?SDK.RemoteObject} result
197 * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails 90 * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
198 */ 91 */
199 function evaluated(result, exceptionDetails) { 92 function evaluated(result, exceptionDetails) {
200 if (!result || !!exceptionDetails) { 93 if (!result || !!exceptionDetails) {
201 fulfill([]); 94 fufill([]);
202 return; 95 return;
203 } 96 }
204 97
205 /** 98 /**
206 * @param {?SDK.RemoteObject} object 99 * @param {?SDK.RemoteObject} object
207 * @return {!Promise<?SDK.RemoteObject>} 100 * @return {!Promise<?SDK.RemoteObject>}
208 */ 101 */
209 function extractTarget(object) { 102 function extractTarget(object) {
210 if (!object) 103 if (!object)
211 return Promise.resolve(/** @type {?SDK.RemoteObject} */ (null)); 104 return Promise.resolve(/** @type {?SDK.RemoteObject} */ (null));
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 212
320 /** 213 /**
321 * @param {?SDK.RemoteObject} result 214 * @param {?SDK.RemoteObject} result
322 * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails 215 * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
323 */ 216 */
324 function receivedPropertyNamesFromEval(result, exceptionDetails) { 217 function receivedPropertyNamesFromEval(result, exceptionDetails) {
325 executionContext.target().runtimeAgent().releaseObjectGroup('completion'); 218 executionContext.target().runtimeAgent().releaseObjectGroup('completion');
326 if (result && !exceptionDetails) 219 if (result && !exceptionDetails)
327 receivedPropertyNames(/** @type {!Object} */ (result.value)); 220 receivedPropertyNames(/** @type {!Object} */ (result.value));
328 else 221 else
329 fulfill([]); 222 fufill([]);
330 } 223 }
331 224
332 /** 225 /**
333 * @param {?Object} object 226 * @param {?Object} object
334 */ 227 */
335 function receivedPropertyNames(object) { 228 function receivedPropertyNames(object) {
336 executionContext.target().runtimeAgent().releaseObjectGroup('completion'); 229 executionContext.target().runtimeAgent().releaseObjectGroup('completion');
337 if (!object) { 230 if (!object) {
338 fulfill([]); 231 fufill([]);
339 return; 232 return;
340 } 233 }
341 var propertyGroups = /** @type {!Array<!Components.JavaScriptAutocomplete.Co mpletionGroup>} */ (object); 234 var propertyGroups = /** @type {!Array<!Components.JavaScriptAutocomplete.Co mpletionGroup>} */ (object);
342 var includeCommandLineAPI = (!dotNotation && !bracketNotation); 235 var includeCommandLineAPI = (!dotNotation && !bracketNotation);
343 if (includeCommandLineAPI) { 236 if (includeCommandLineAPI) {
344 const commandLineAPI = [ 237 const commandLineAPI = [
345 'dir', 238 'dir',
346 'dirxml', 239 'dirxml',
347 'keys', 240 'keys',
348 'values', 241 'values',
349 'profile', 242 'profile',
350 'profileEnd', 243 'profileEnd',
351 'monitorEvents', 244 'monitorEvents',
352 'unmonitorEvents', 245 'unmonitorEvents',
353 'inspect', 246 'inspect',
354 'copy', 247 'copy',
355 'clear', 248 'clear',
356 'getEventListeners', 249 'getEventListeners',
357 'debug', 250 'debug',
358 'undebug', 251 'undebug',
359 'monitor', 252 'monitor',
360 'unmonitor', 253 'unmonitor',
361 'table', 254 'table',
362 '$', 255 '$',
363 '$$', 256 '$$',
364 '$x' 257 '$x'
365 ]; 258 ];
366 propertyGroups.push({items: commandLineAPI}); 259 propertyGroups.push({items: commandLineAPI});
367 } 260 }
368 fulfill(Components.JavaScriptAutocomplete._completionsForQuery( 261 fufill(Components.JavaScriptAutocomplete._completionsForQuery(
369 dotNotation, bracketNotation, expressionString, query, propertyGroups)); 262 dotNotation, bracketNotation, expressionString, query, propertyGroups));
370 } 263 }
371 }; 264 };
372 265
373 /** 266 /**
374 * @param {boolean} dotNotation 267 * @param {boolean} dotNotation
375 * @param {boolean} bracketNotation 268 * @param {boolean} bracketNotation
376 * @param {string} expressionString 269 * @param {string} expressionString
377 * @param {string} query 270 * @param {string} query
378 * @param {!Array<!Components.JavaScriptAutocomplete.CompletionGroup>} propert yGroups 271 * @param {!Array<!Components.JavaScriptAutocomplete.CompletionGroup>} propert yGroups
(...skipping 13 matching lines...) Expand all
392 'break', 'case', 'catch', 'continue', 'default', 'delete', 'do', 'else', 'finally', 285 'break', 'case', 'catch', 'continue', 'default', 'delete', 'do', 'else', 'finally',
393 'for', 'function', 'if', 'in', 'instanceof', 'new', 'return ', 'switch', 'this', 286 'for', 'function', 'if', 'in', 'instanceof', 'new', 'return ', 'switch', 'this',
394 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with' 287 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with'
395 ]; 288 ];
396 propertyGroups.push({title: Common.UIString('keywords'), items: keywords}); 289 propertyGroups.push({title: Common.UIString('keywords'), items: keywords});
397 } 290 }
398 291
399 var result = []; 292 var result = [];
400 var lastGroupTitle; 293 var lastGroupTitle;
401 for (var group of propertyGroups) { 294 for (var group of propertyGroups) {
402 group.items.sort(itemComparator.bind(null, group.items.length > 1000)); 295 group.items.sort(itemComparator);
403 var caseSensitivePrefix = []; 296 var caseSensitivePrefix = [];
404 var caseInsensitivePrefix = []; 297 var caseInsensitivePrefix = [];
405 var caseSensitiveAnywhere = []; 298 var caseSensitiveAnywhere = [];
406 var caseInsensitiveAnywhere = []; 299 var caseInsensitiveAnywhere = [];
407 300
408 for (var property of group.items) { 301 for (var property of group.items) {
409 // Assume that all non-ASCII characters are letters and thus can be used a s part of identifier. 302 // Assume that all non-ASCII characters are letters and thus can be used a s part of identifier.
410 if (!bracketNotation && !/^[a-zA-Z_$\u008F-\uFFFF][a-zA-Z0-9_$\u008F-\uFFF F]*$/.test(property)) 303 if (!bracketNotation && !/^[a-zA-Z_$\u008F-\uFFFF][a-zA-Z0-9_$\u008F-\uFFF F]*$/.test(property))
411 continue; 304 continue;
412 305
(...skipping 23 matching lines...) Expand all
436 caseSensitivePrefix.concat(caseInsensitivePrefix, caseSensitiveAnywhere, caseInsensitiveAnywhere); 329 caseSensitivePrefix.concat(caseInsensitivePrefix, caseSensitiveAnywhere, caseInsensitiveAnywhere);
437 if (structuredGroup.length && group.title !== lastGroupTitle) { 330 if (structuredGroup.length && group.title !== lastGroupTitle) {
438 structuredGroup[0].subtitle = group.title; 331 structuredGroup[0].subtitle = group.title;
439 lastGroupTitle = group.title; 332 lastGroupTitle = group.title;
440 } 333 }
441 result = result.concat(structuredGroup); 334 result = result.concat(structuredGroup);
442 } 335 }
443 return result; 336 return result;
444 337
445 /** 338 /**
446 * @param {boolean} naturalOrder
447 * @param {string} a 339 * @param {string} a
448 * @param {string} b 340 * @param {string} b
449 * @return {number} 341 * @return {number}
450 */ 342 */
451 function itemComparator(naturalOrder, a, b) { 343 function itemComparator(a, b) {
452 var aStartsWithUnderscore = a.startsWith('_'); 344 var aStartsWithUnderscore = a.startsWith('_');
453 var bStartsWithUnderscore = b.startsWith('_'); 345 var bStartsWithUnderscore = b.startsWith('_');
454 if (aStartsWithUnderscore && !bStartsWithUnderscore) 346 if (aStartsWithUnderscore && !bStartsWithUnderscore)
455 return 1; 347 return 1;
456 if (bStartsWithUnderscore && !aStartsWithUnderscore) 348 if (bStartsWithUnderscore && !aStartsWithUnderscore)
457 return -1; 349 return -1;
458 return naturalOrder ? String.naturalOrderComparator(a, b) : a.localeCompare( b); 350 return String.naturalOrderComparator(a, b);
459 } 351 }
460 }; 352 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698