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

Unified 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 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
new file mode 100644
index 0000000000000000000000000000000000000000..b33e5f61d791715315e270ff0b75c4661a563c1f
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js
@@ -0,0 +1,282 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+WebInspector.JavaScriptAutocomplete = {};
+
+/**
+ * @param {!Element} proxyElement
+ * @param {!Range} wordRange
+ * @param {boolean} force
+ * @param {function(!Array.<string>, number=)} completionsReadyCallback
+ */
+WebInspector.JavaScriptAutocomplete.completionsForTextPromptInCurrentContext = function(proxyElement, wordRange, force, completionsReadyCallback) {
+ var expressionRange = wordRange.cloneRange();
+ expressionRange.collapse(true);
+ expressionRange.setStartBefore(proxyElement);
+ WebInspector.JavaScriptAutocomplete.completionsForTextInCurrentContext(expressionRange.toString(), wordRange.toString(), force)
+ .then(completionsReadyCallback);
+};
+
+/**
+ * @param {string} text
+ * @param {string} completionsPrefix
+ * @param {boolean=} force
+ * @return {!Promise<!Array<string>>}
+ */
+WebInspector.JavaScriptAutocomplete.completionsForTextInCurrentContext = function(text, completionsPrefix, force) {
+ var index;
+ var stopChars = new Set(' =:({;,!+-*/&|^<>`'.split(''));
+ for (index = text.length - 1; index >= 0; index--) {
+ // Pass less stop characters to rangeOfWord so the range will be a more complete expression.
+ if (stopChars.has(text.charAt(index)))
+ break;
+ }
+ var clippedExpression = text.substring(index + 1);
+ var bracketCount = 0;
+
+ index = clippedExpression.length - 1;
+ while (index >= 0) {
+ var character = clippedExpression.charAt(index);
+ if (character === ']')
+ bracketCount++;
+ // Allow an open bracket at the end for property completion.
+ if (character === '[' && index < clippedExpression.length - 1) {
+ bracketCount--;
+ if (bracketCount < 0)
+ break;
+ }
+ index--;
+ }
+ clippedExpression = clippedExpression.substring(index + 1);
+
+ return WebInspector.JavaScriptAutocomplete.completionsForExpression(clippedExpression, completionsPrefix, force);
+};
+
+
+ /**
+ * @param {string} expressionString
+ * @param {string} prefix
+ * @param {boolean=} force
+ * @return {!Promise<!Array<string>>}
+ */
+WebInspector.JavaScriptAutocomplete.completionsForExpression = function(expressionString, prefix, force) {
+ var executionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
+ if (!executionContext)
+ return Promise.resolve([]);
+
+ var lastIndex = expressionString.length - 1;
+
+ var dotNotation = (expressionString[lastIndex] === '.');
+ var bracketNotation = (expressionString[lastIndex] === '[');
+
+ if (dotNotation || bracketNotation)
+ expressionString = expressionString.substr(0, lastIndex);
+
+ // User is entering float value, do not suggest anything.
+ if (expressionString && !isNaN(expressionString))
+ return Promise.resolve([]);
+
+ if (!prefix && !expressionString && !force)
+ return Promise.resolve([]);
+
+ var fufill;
+ var promise = new Promise(x => fufill = x);
+ if (!expressionString && executionContext.debuggerModel.selectedCallFrame())
+ executionContext.debuggerModel.selectedCallFrame().variableNames(receivedPropertyNames);
+ else
+ executionContext.evaluate(expressionString, 'completion', true, true, false, false, false, evaluated);
+
+ return promise;
+ /**
+ * @param {?WebInspector.RemoteObject} result
+ * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
+ */
+ function evaluated(result, exceptionDetails) {
+ if (!result || !!exceptionDetails) {
+ fufill([]);
+ return;
+ }
+
+ /**
+ * @param {?WebInspector.RemoteObject} object
+ * @return {!Promise<?WebInspector.RemoteObject>}
+ */
+ function extractTarget(object) {
+ if (!object)
+ return Promise.resolve(/** @type {?WebInspector.RemoteObject} */(null));
+ if (object.type !== 'object' || object.subtype !== 'proxy')
+ return Promise.resolve(/** @type {?WebInspector.RemoteObject} */(object));
+ return object.getOwnPropertiesPromise().then(extractTargetFromProperties).then(extractTarget);
+ }
+
+ /**
+ * @param {!{properties: ?Array<!WebInspector.RemoteObjectProperty>, internalProperties: ?Array<!WebInspector.RemoteObjectProperty>}} properties
+ * @return {?WebInspector.RemoteObject}
+ */
+ function extractTargetFromProperties(properties) {
+ var internalProperties = properties.internalProperties || [];
+ var target = internalProperties.find(property => property.name === '[[Target]]');
+ return target ? target.value : null;
+ }
+
+ /**
+ * @param {string=} type
+ * @return {!Object}
+ * @suppressReceiverCheck
+ * @this {Object}
+ */
+ function getCompletions(type) {
+ var object;
+ if (type === 'string')
+ object = new String('');
+ else if (type === 'number')
+ object = new Number(0);
+ else if (type === 'boolean')
+ object = new Boolean(false);
+ else
+ object = this;
+
+ var resultSet = { __proto__: null };
+ 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 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;
+ }
+ }
+ } catch (e) {
+ }
+ return resultSet;
+ }
+
+ /**
+ * @param {?WebInspector.RemoteObject} object
+ */
+ function completionsForObject(object) {
+ if (!object)
+ receivedPropertyNames(null);
+ else if (object.type === 'object' || object.type === 'function')
+ object.callFunctionJSON(
+ getCompletions, [WebInspector.RemoteObject.toCallArgument(object.subtype)],
+ receivedPropertyNames);
+ else if (object.type === 'string' || object.type === 'number' || object.type === 'boolean')
+ executionContext.evaluate(
+ '(' + getCompletions + ')("' + result.type + '")', 'completion', false, true, true, false, false,
+ receivedPropertyNamesFromEval);
+ }
+
+ extractTarget(result).then(completionsForObject);
+ }
+
+ /**
+ * @param {?WebInspector.RemoteObject} result
+ * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
+ */
+ function receivedPropertyNamesFromEval(result, exceptionDetails) {
+ executionContext.target().runtimeAgent().releaseObjectGroup('completion');
+ if (result && !exceptionDetails)
+ receivedPropertyNames(/** @type {!Object} */(result.value));
+ else
+ fufill([]);
+ }
+
+ /**
+ * @param {?Object} propertyNames
+ */
+ function receivedPropertyNames(propertyNames) {
+ executionContext.target().runtimeAgent().releaseObjectGroup('completion');
+ if (!propertyNames) {
+ fufill([]);
+ return;
+ }
+ var includeCommandLineAPI = (!dotNotation && !bracketNotation);
+ if (includeCommandLineAPI) {
+ const commandLineAPI = [
+ 'dir',
+ 'dirxml',
+ 'keys',
+ 'values',
+ 'profile',
+ 'profileEnd',
+ 'monitorEvents',
+ 'unmonitorEvents',
+ 'inspect',
+ 'copy',
+ 'clear',
+ 'getEventListeners',
+ 'debug',
+ 'undebug',
+ 'monitor',
+ 'unmonitor',
+ 'table',
+ '$',
+ '$$',
+ '$x'
+ ];
+ for (var i = 0; i < commandLineAPI.length; ++i)
+ propertyNames[commandLineAPI[i]] = true;
+ }
+ fufill(WebInspector.JavaScriptAutocomplete._completionsForPrefix(
+ dotNotation, bracketNotation, expressionString, prefix, Object.keys(propertyNames)));
+ }
+};
+
+ /**
+ * @param {boolean} dotNotation
+ * @param {boolean} bracketNotation
+ * @param {string} expressionString
+ * @param {string} prefix
+ * @param {!Array.<string>} properties
+ * @return {!Array<string>}
+ */
+WebInspector.JavaScriptAutocomplete._completionsForPrefix = function(dotNotation, bracketNotation, expressionString, prefix, properties) {
+ if (bracketNotation) {
+ if (prefix.length && prefix[0] === '\'')
+ var quoteUsed = '\'';
+ else
+ var quoteUsed = '"';
+ }
+
+ var results = [];
+
+ if (!expressionString) {
+ const keywords = [
+ 'break', 'case', 'catch', 'continue', 'default', 'delete', 'do', 'else', 'finally',
+ 'for', 'function', 'if', 'in', 'instanceof', 'new', 'return', 'switch', 'this',
+ 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with'
+ ];
+ properties = properties.concat(keywords);
+ }
+
+ properties.sort();
+
+ for (var i = 0; i < properties.length; ++i) {
+ var property = properties[i];
+
+ // Assume that all non-ASCII characters are letters and thus can be used as part of identifier.
+ if (dotNotation && !/^[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 (property.length < prefix.length)
+ continue;
+ if (prefix.length && !property.startsWith(prefix))
+ continue;
+
+ // Substitute actual newlines with newline characters. @see crbug.com/498421
+ results.push(property.split('\n').join('\\n'));
+ }
+ return results;
+};

Powered by Google App Engine
This is Rietveld 408576698