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

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

Issue 2639703002: DevTools: Console: Provide autocompletions for Maps (Closed)
Patch Set: Use [[Entries]] instead of preview 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) {
17 var index; 29 var index;
18 var stopChars = new Set('=:({;,!+-*/&|^<>`'.split('')); 30 var stopChars = new Set('=:({;,!+-*/&|^<>`'.split(''));
19 var whiteSpaceChars = new Set(' \r\n\t'.split('')); 31 var whiteSpaceChars = new Set(' \r\n\t'.split(''));
20 var continueChars = new Set('[. \r\n\t'.split('')); 32 var continueChars = new Set('[. \r\n\t'.split(''));
21 33
22 for (index = text.length - 1; index >= 0; index--) { 34 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.
24 if (stopChars.has(text.charAt(index))) 35 if (stopChars.has(text.charAt(index)))
25 break; 36 break;
26 if (whiteSpaceChars.has(text.charAt(index)) && !continueChars.has(text.charA t(index - 1))) 37 if (whiteSpaceChars.has(text.charAt(index)) && !continueChars.has(text.charA t(index - 1)))
27 break; 38 break;
28 } 39 }
29 var clippedExpression = text.substring(index + 1).trim(); 40 var clippedExpression = text.substring(index + 1).trim();
30 var bracketCount = 0; 41 var bracketCount = 0;
31 42
32 index = clippedExpression.length - 1; 43 index = clippedExpression.length - 1;
33 while (index >= 0) { 44 while (index >= 0) {
34 var character = clippedExpression.charAt(index); 45 var character = clippedExpression.charAt(index);
35 if (character === ']') 46 if (character === ']')
36 bracketCount++; 47 bracketCount++;
37 // Allow an open bracket at the end for property completion. 48 // Allow an open bracket at the end for property completion.
38 if (character === '[' && index < clippedExpression.length - 1) { 49 if (character === '[' && (index < clippedExpression.length - 1 || !allowEndi ngBracket)) {
39 bracketCount--; 50 bracketCount--;
40 if (bracketCount < 0) 51 if (bracketCount < 0)
41 break; 52 break;
42 } 53 }
43 index--; 54 index--;
44 } 55 }
45 clippedExpression = clippedExpression.substring(index + 1).trim(); 56 return clippedExpression.substring(index + 1).trim();
46
47 return Components.JavaScriptAutocomplete.completionsForExpression(clippedExpre ssion, query, force);
48 }; 57 };
49 58
50 /** 59 /**
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*[gs]et\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), true);
71 var fufill;
72 var promise = new Promise(x => fufill = 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 fufill([]);
83 return;
84 }
85 result.getOwnPropertiesPromise().then(extractEntriesProperty);
luoe 2017/01/19 18:54:21 Can we make this a method in RemoteObject.js as ge
einbinder 2017/01/19 20:21:38 This only gets the entries from maps with keys as
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 fufill([]);
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:?}>}
luoe 2017/01/19 18:54:20 @return ?
einbinder 2017/01/19 20:21:38 Done.
104 */
105 function getEntries() {
106 var result = {__proto__: null};
107 for (var i = 0; i < this.length; i++) {
108 if (typeof this[i].key === 'string')
109 result[this[i].key] = true;
110 }
111 return result;
112 }
113
114 /**
115 * @param {!Array<string>} rawKeys
116 */
117 function gotKeys(rawKeys) {
118 var caseSensitivePrefix = [];
119 var caseInsensitivePrefix = [];
120 var caseSensitiveAnywhere = [];
121 var caseInsensitiveAnywhere = [];
122 var qouteChar = '"';
luoe 2017/01/19 18:54:20 nit: quoteChar
einbinder 2017/01/19 20:21:38 Done.
123 if (query.startsWith('\''))
124 qouteChar = '\'';
125 var endChar = ')';
126 if (mapMatch[0].indexOf('s') !== -1)
127 endChar = ', ';
128
129 var keys = rawKeys.sort(String.naturalOrderComparator).map(key => qouteChar + key + qouteChar + endChar);
130
131 for (var key of keys) {
132 if (key.length < query.length)
133 continue;
134 if (query.length && key.toLowerCase().indexOf(query.toLowerCase()) === -1)
135 continue;
136 // Substitute actual newlines with newline characters. @see crbug.com/4984 21
137 var title = key.split('\n').join('\\n');
138
139 if (key.startsWith(query))
140 caseSensitivePrefix.push({title: title, priority: 4});
141 else if (key.toLowerCase().startsWith(query.toLowerCase()))
142 caseInsensitivePrefix.push({title: title, priority: 3});
143 else if (key.indexOf(query) !== -1)
144 caseSensitiveAnywhere.push({title: title, priority: 2});
145 else
146 caseInsensitiveAnywhere.push({title: title, priority: 1});
147 }
148 var suggestions = caseSensitivePrefix.concat(caseInsensitivePrefix, caseSens itiveAnywhere, caseInsensitiveAnywhere);
149 if (suggestions.length)
150 suggestions[0].subtitle = 'Keys';
151 fufill(suggestions);
152 }
153 };
154
155 /**
51 * @param {string} expressionString 156 * @param {string} expressionString
52 * @param {string} query 157 * @param {string} query
53 * @param {boolean=} force 158 * @param {boolean=} force
54 * @return {!Promise<!UI.SuggestBox.Suggestions>} 159 * @return {!Promise<!UI.SuggestBox.Suggestions>}
55 */ 160 */
56 Components.JavaScriptAutocomplete.completionsForExpression = function(expression String, query, force) { 161 Components.JavaScriptAutocomplete.completionsForExpression = function(expression String, query, force) {
57 var executionContext = UI.context.flavor(SDK.ExecutionContext); 162 var executionContext = UI.context.flavor(SDK.ExecutionContext);
58 if (!executionContext) 163 if (!executionContext)
59 return Promise.resolve([]); 164 return Promise.resolve([]);
60 165
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 function itemComparator(a, b) { 448 function itemComparator(a, b) {
344 var aStartsWithUnderscore = a.startsWith('_'); 449 var aStartsWithUnderscore = a.startsWith('_');
345 var bStartsWithUnderscore = b.startsWith('_'); 450 var bStartsWithUnderscore = b.startsWith('_');
346 if (aStartsWithUnderscore && !bStartsWithUnderscore) 451 if (aStartsWithUnderscore && !bStartsWithUnderscore)
347 return 1; 452 return 1;
348 if (bStartsWithUnderscore && !aStartsWithUnderscore) 453 if (bStartsWithUnderscore && !aStartsWithUnderscore)
349 return -1; 454 return -1;
350 return String.naturalOrderComparator(a, b); 455 return String.naturalOrderComparator(a, b);
351 } 456 }
352 }; 457 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698