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

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

Issue 2557763003: DevTools: sort completions by prototype. (Closed)
Patch Set: rebaselined Created 4 years 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js
diff --git a/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js b/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js
index b17ac6f8ec5ddd70ff4a37a9879c3e3a3195e138..56aac0ccf049102d266bc8b9ffa432079bde1721 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js
@@ -4,6 +4,9 @@
Components.JavaScriptAutocomplete = {};
+/** @typedef {{title:(string|undefined), items:Array<string>}} */
+Components.JavaScriptAutocomplete.CompletionGroup;
+
/**
* @param {string} text
* @param {string} query
@@ -39,13 +42,12 @@ Components.JavaScriptAutocomplete.completionsForTextInCurrentContext = function(
return Components.JavaScriptAutocomplete.completionsForExpression(clippedExpression, query, force);
};
-
/**
- * @param {string} expressionString
- * @param {string} query
- * @param {boolean=} force
- * @return {!Promise<!UI.SuggestBox.Suggestions>}
- */
+ * @param {string} expressionString
+ * @param {string} query
+ * @param {boolean=} force
+ * @return {!Promise<!UI.SuggestBox.Suggestions>}
+ */
Components.JavaScriptAutocomplete.completionsForExpression = function(expressionString, query, force) {
var executionContext = UI.context.flavor(SDK.ExecutionContext);
if (!executionContext)
@@ -75,7 +77,7 @@ Components.JavaScriptAutocomplete.completionsForExpression = function(expression
var fufill;
var promise = new Promise(x => fufill = x);
if (!expressionString && executionContext.debuggerModel.selectedCallFrame())
- executionContext.debuggerModel.selectedCallFrame().variableNames(receivedPropertyNames);
+ variableNamesInScopes(executionContext.debuggerModel.selectedCallFrame(), receivedPropertyNames);
else
executionContext.evaluate(expressionString, 'completion', true, true, false, false, false, evaluated);
@@ -129,23 +131,32 @@ Components.JavaScriptAutocomplete.completionsForExpression = function(expression
else
object = this;
- var resultSet = {__proto__: null};
+ var result = [];
try {
for (var o = object; o; o = Object.getPrototypeOf(o)) {
if ((type === 'array' || type === 'typedarray') && o === object && ArrayBuffer.isView(o) && o.length > 9999)
continue;
+
+ var group = {items: [], __proto__: null};
+ try {
+ if (typeof o === 'object' && o.constructor && o.constructor.name)
+ group.title = o.constructor.name;
+ } catch (ee) {
+ // we could break upon cross origin check.
+ }
+ result[result.length] = group;
var names = Object.getOwnPropertyNames(o);
var isArray = Array.isArray(o);
for (var i = 0; i < names.length; ++i) {
// Skip array elements indexes.
if (isArray && /^[0-9]/.test(names[i]))
continue;
- resultSet[names[i]] = true;
+ group.items[group.items.length] = names[i];
}
}
} catch (e) {
}
- return resultSet;
+ return result;
}
/**
@@ -168,6 +179,35 @@ Components.JavaScriptAutocomplete.completionsForExpression = function(expression
}
/**
+ * @param {!SDK.DebuggerModel.CallFrame} callFrame
+ * @param {function(!Array<!Components.JavaScriptAutocomplete.CompletionGroup>)} callback
+ */
+ function variableNamesInScopes(callFrame, callback) {
+ var result = [{items: ['this']}];
+
+ /**
+ * @param {string} name
+ * @param {?Array<!SDK.RemoteObjectProperty>} properties
+ */
+ function propertiesCollected(name, properties) {
+ var group = {title: name, items: []};
+ result.push(group);
+ for (var i = 0; properties && i < properties.length; ++i)
+ group.items.push(properties[i].name);
+ if (--pendingRequests === 0)
+ callback(result);
+ }
+
+ var scopeChain = callFrame.scopeChain();
+ var pendingRequests = scopeChain.length;
+ for (var i = 0; i < scopeChain.length; ++i) {
+ var scope = scopeChain[i];
+ var object = scope.object();
+ object.getAllProperties(false, propertiesCollected.bind(null, scope.typeName()));
+ }
+ }
+
+ /**
* @param {?SDK.RemoteObject} result
* @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
*/
@@ -180,14 +220,15 @@ Components.JavaScriptAutocomplete.completionsForExpression = function(expression
}
/**
- * @param {?Object} propertyNames
+ * @param {?Object} object
*/
- function receivedPropertyNames(propertyNames) {
+ function receivedPropertyNames(object) {
executionContext.target().runtimeAgent().releaseObjectGroup('completion');
- if (!propertyNames) {
+ if (!object) {
fufill([]);
return;
}
+ var propertyGroups = /** @type {!Array<!Components.JavaScriptAutocomplete.CompletionGroup>} */ (object);
var includeCommandLineAPI = (!dotNotation && !bracketNotation);
if (includeCommandLineAPI) {
const commandLineAPI = [
@@ -212,11 +253,10 @@ Components.JavaScriptAutocomplete.completionsForExpression = function(expression
'$$',
'$x'
];
- for (var i = 0; i < commandLineAPI.length; ++i)
- propertyNames[commandLineAPI[i]] = true;
+ propertyGroups.push({items: commandLineAPI});
}
fufill(Components.JavaScriptAutocomplete._completionsForQuery(
- dotNotation, bracketNotation, expressionString, query, Object.keys(propertyNames)));
+ dotNotation, bracketNotation, expressionString, query, propertyGroups));
}
};
@@ -225,11 +265,11 @@ Components.JavaScriptAutocomplete.completionsForExpression = function(expression
* @param {boolean} bracketNotation
* @param {string} expressionString
* @param {string} query
- * @param {!Array.<string>} properties
+ * @param {!Array<!Components.JavaScriptAutocomplete.CompletionGroup>} propertyGroups
* @return {!UI.SuggestBox.Suggestions}
*/
Components.JavaScriptAutocomplete._completionsForQuery = function(
- dotNotation, bracketNotation, expressionString, query, properties) {
+ dotNotation, bracketNotation, expressionString, query, propertyGroups) {
if (bracketNotation) {
if (query.length && query[0] === '\'')
var quoteUsed = '\'';
@@ -243,46 +283,52 @@ Components.JavaScriptAutocomplete._completionsForQuery = function(
'for', 'function', 'if', 'in', 'instanceof', 'new', 'return', 'switch', 'this',
'throw', 'try', 'typeof', 'var', 'void', 'while', 'with'
];
- properties = properties.concat(keywords);
+ propertyGroups.push({title: Common.UIString('keywords'), items: keywords});
}
- properties.sort();
+ var result = [];
+ var lastGroupTitle;
+ for (var group of propertyGroups) {
+ group.items.sort();
+ var caseSensitivePrefix = [];
+ var caseInsensitivePrefix = [];
+ var caseSensitiveAnywhere = [];
+ var caseInsensitiveAnywhere = [];
- var caseSensitivePrefix = [];
- var caseInsensitivePrefix = [];
- var caseSensitiveAnywhere = [];
- var caseInsensitiveAnywhere = [];
- for (var i = 0; i < properties.length; ++i) {
- var property = properties[i];
+ for (var property of group.items) {
+ // Assume that all non-ASCII characters are letters and thus can be used as part of identifier.
+ if (!bracketNotation && !/^[a-zA-Z_$\u008F-\uFFFF][a-zA-Z0-9_$\u008F-\uFFFF]*$/.test(property))
+ continue;
- // Assume that all non-ASCII characters are letters and thus can be used as part of identifier.
- if (!bracketNotation && !/^[a-zA-Z_$\u008F-\uFFFF][a-zA-Z0-9_$\u008F-\uFFFF]*$/.test(property))
- continue;
+ if (bracketNotation) {
+ if (!/^[0-9]+$/.test(property))
+ property = quoteUsed + property.escapeCharacters(quoteUsed + '\\') + quoteUsed;
+ property += ']';
+ }
- if (bracketNotation) {
- if (!/^[0-9]+$/.test(property))
- property = quoteUsed + property.escapeCharacters(quoteUsed + '\\') + quoteUsed;
- property += ']';
- }
+ if (property.length < query.length)
+ continue;
+ if (query.length && property.toLowerCase().indexOf(query.toLowerCase()) === -1)
+ continue;
+ // Substitute actual newlines with newline characters. @see crbug.com/498421
+ var prop = property.split('\n').join('\\n');
- if (property.length < query.length)
- continue;
- if (query.length && property.toLowerCase().indexOf(query.toLowerCase()) === -1)
- continue;
- // Substitute actual newlines with newline characters. @see crbug.com/498421
- var prop = property.split('\n').join('\\n');
-
- if (property.startsWith(query))
- caseSensitivePrefix.push(prop);
- else if (property.toLowerCase().startsWith(query.toLowerCase()))
- caseInsensitivePrefix.push(prop);
- else if (property.indexOf(query) !== -1)
- caseSensitiveAnywhere.push(prop);
- else
- caseInsensitiveAnywhere.push(prop);
+ if (property.startsWith(query))
+ caseSensitivePrefix.push({title: prop, priority: 4});
+ else if (property.toLowerCase().startsWith(query.toLowerCase()))
+ caseInsensitivePrefix.push({title: prop, priority: 3});
+ else if (property.indexOf(query) !== -1)
+ caseSensitiveAnywhere.push({title: prop, priority: 2});
+ else
+ caseInsensitiveAnywhere.push({title: prop, priority: 1});
+ }
+ var structuredGroup =
+ caseSensitivePrefix.concat(caseInsensitivePrefix, caseSensitiveAnywhere, caseInsensitiveAnywhere);
+ if (structuredGroup.length && group.title !== lastGroupTitle) {
+ structuredGroup[0].subtitle = group.title;
+ lastGroupTitle = group.title;
+ }
+ result = result.concat(structuredGroup);
}
- return caseSensitivePrefix.concat(caseInsensitivePrefix)
- .concat(caseSensitiveAnywhere)
- .concat(caseInsensitiveAnywhere)
- .map(completion => ({title: completion}));
+ return result;
};

Powered by Google App Engine
This is Rietveld 408576698