| OLD | NEW |
| (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 { |
| 15 var expressionRange = wordRange.cloneRange(); |
| 16 expressionRange.collapse(true); |
| 17 expressionRange.setStartBefore(proxyElement); |
| 18 WebInspector.JavaScriptAutocomplete.completionsForTextInCurrentContext(expre
ssionRange.toString(), wordRange.toString(), force).then(completionsReadyCallbac
k); |
| 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 { |
| 29 var index; |
| 30 var stopChars = new Set(" =:({;,!+-*/&|^<>`".split("")); |
| 31 for (index = text.length - 1; index >= 0; index--) { |
| 32 // Pass less stop characters to rangeOfWord so the range will be a more
complete expression. |
| 33 if (stopChars.has(text.charAt(index))) |
| 34 break; |
| 35 } |
| 36 var clippedExpression = text.substring(index + 1); |
| 37 var bracketCount = 0; |
| 38 |
| 39 index = clippedExpression.length - 1; |
| 40 while (index >= 0) { |
| 41 var character = clippedExpression.charAt(index); |
| 42 if (character === "]") |
| 43 bracketCount++; |
| 44 // Allow an open bracket at the end for property completion. |
| 45 if (character === "[" && index < clippedExpression.length - 1) { |
| 46 bracketCount--; |
| 47 if (bracketCount < 0) |
| 48 break; |
| 49 } |
| 50 index--; |
| 51 } |
| 52 clippedExpression = clippedExpression.substring(index + 1); |
| 53 |
| 54 return WebInspector.JavaScriptAutocomplete.completionsForExpression(clippedE
xpression, completionsPrefix, force); |
| 55 }; |
| 56 |
| 57 |
| 58 /** |
| 59 * @param {string} expressionString |
| 60 * @param {string} prefix |
| 61 * @param {boolean=} force |
| 62 * @return {!Promise<!Array<string>>} |
| 63 */ |
| 64 WebInspector.JavaScriptAutocomplete.completionsForExpression = function(expressi
onString, prefix, force) |
| 65 { |
| 66 var executionContext = WebInspector.context.flavor(WebInspector.ExecutionCon
text); |
| 67 if (!executionContext) |
| 68 return Promise.resolve([]); |
| 69 |
| 70 var lastIndex = expressionString.length - 1; |
| 71 |
| 72 var dotNotation = (expressionString[lastIndex] === "."); |
| 73 var bracketNotation = (expressionString[lastIndex] === "["); |
| 74 |
| 75 if (dotNotation || bracketNotation) |
| 76 expressionString = expressionString.substr(0, lastIndex); |
| 77 |
| 78 // User is entering float value, do not suggest anything. |
| 79 if (expressionString && !isNaN(expressionString)) |
| 80 return Promise.resolve([]); |
| 81 |
| 82 if (!prefix && !expressionString && !force) |
| 83 return Promise.resolve([]); |
| 84 |
| 85 var fulfill; |
| 86 var promise = new Promise(x => fulfill = x); |
| 87 |
| 88 if (!expressionString && executionContext.debuggerModel.selectedCallFrame()) |
| 89 executionContext.debuggerModel.selectedCallFrame().variableNames(receive
dPropertyNames); |
| 90 else |
| 91 executionContext.evaluate(expressionString, "completion", true, true, fa
lse, false, false, evaluated); |
| 92 |
| 93 return promise; |
| 94 /** |
| 95 * @param {?WebInspector.RemoteObject} result |
| 96 * @param {!RuntimeAgent.ExceptionDetails=} exceptionDetails |
| 97 */ |
| 98 function evaluated(result, exceptionDetails) |
| 99 { |
| 100 if (!result || !!exceptionDetails) { |
| 101 fulfill([]); |
| 102 return; |
| 103 } |
| 104 |
| 105 /** |
| 106 * @param {?WebInspector.RemoteObject} object |
| 107 * @return {!Promise<?WebInspector.RemoteObject>} |
| 108 */ |
| 109 function extractTarget(object) |
| 110 { |
| 111 if (!object) |
| 112 return Promise.resolve(/** @type {?WebInspector.RemoteObject} */
(null)); |
| 113 if (object.type !== "object" || object.subtype !== "proxy") |
| 114 return Promise.resolve(/** @type {?WebInspector.RemoteObject} */
(object)); |
| 115 return object.getOwnPropertiesPromise().then(extractTargetFromProper
ties).then(extractTarget); |
| 116 } |
| 117 |
| 118 /** |
| 119 * @param {!{properties: ?Array<!WebInspector.RemoteObjectProperty>, int
ernalProperties: ?Array<!WebInspector.RemoteObjectProperty>}} properties |
| 120 * @return {?WebInspector.RemoteObject} |
| 121 */ |
| 122 function extractTargetFromProperties(properties) |
| 123 { |
| 124 var internalProperties = properties.internalProperties || []; |
| 125 var target = internalProperties.find(property => property.name === "
[[Target]]"); |
| 126 return target ? target.value : null; |
| 127 } |
| 128 |
| 129 /** |
| 130 * @param {string=} type |
| 131 * @return {!Object} |
| 132 * @suppressReceiverCheck |
| 133 * @this {Object} |
| 134 */ |
| 135 function getCompletions(type) |
| 136 { |
| 137 var object; |
| 138 if (type === "string") |
| 139 object = new String(""); |
| 140 else if (type === "number") |
| 141 object = new Number(0); |
| 142 else if (type === "boolean") |
| 143 object = new Boolean(false); |
| 144 else |
| 145 object = this; |
| 146 |
| 147 var resultSet = { __proto__: null }; |
| 148 try { |
| 149 for (var o = object; o; o = Object.getPrototypeOf(o)) { |
| 150 if ((type === "array" || type === "typedarray") && o === obj
ect && ArrayBuffer.isView(o) && o.length > 9999) |
| 151 continue; |
| 152 var names = Object.getOwnPropertyNames(o); |
| 153 var isArray = Array.isArray(o); |
| 154 for (var i = 0; i < names.length; ++i) { |
| 155 // Skip array elements indexes. |
| 156 if (isArray && /^[0-9]/.test(names[i])) |
| 157 continue; |
| 158 resultSet[names[i]] = true; |
| 159 } |
| 160 } |
| 161 } catch (e) { |
| 162 } |
| 163 return resultSet; |
| 164 } |
| 165 |
| 166 /** |
| 167 * @param {?WebInspector.RemoteObject} object |
| 168 */ |
| 169 function completionsForObject(object) |
| 170 { |
| 171 if (!object) |
| 172 receivedPropertyNames(null); |
| 173 else if (object.type === "object" || object.type === "function") |
| 174 object.callFunctionJSON(getCompletions, [WebInspector.RemoteObje
ct.toCallArgument(object.subtype)], receivedPropertyNames); |
| 175 else if (object.type === "string" || object.type === "number" || obj
ect.type === "boolean") |
| 176 executionContext.evaluate("(" + getCompletions + ")(\"" + result
.type + "\")", "completion", false, true, true, false, false, receivedPropertyNa
mesFromEval); |
| 177 } |
| 178 |
| 179 extractTarget(result).then(completionsForObject); |
| 180 } |
| 181 |
| 182 /** |
| 183 * @param {?WebInspector.RemoteObject} result |
| 184 * @param {!RuntimeAgent.ExceptionDetails=} exceptionDetails |
| 185 */ |
| 186 function receivedPropertyNamesFromEval(result, exceptionDetails) |
| 187 { |
| 188 executionContext.target().runtimeAgent().releaseObjectGroup("completion"
); |
| 189 if (result && !exceptionDetails) |
| 190 receivedPropertyNames(/** @type {!Object} */(result.value)); |
| 191 else |
| 192 fulfill([]); |
| 193 } |
| 194 |
| 195 /** |
| 196 * @param {?Object} propertyNames |
| 197 */ |
| 198 function receivedPropertyNames(propertyNames) |
| 199 { |
| 200 executionContext.target().runtimeAgent().releaseObjectGroup("completion"
); |
| 201 if (!propertyNames) { |
| 202 fulfill([]); |
| 203 return; |
| 204 } |
| 205 var includeCommandLineAPI = (!dotNotation && !bracketNotation); |
| 206 if (includeCommandLineAPI) { |
| 207 const commandLineAPI = ["dir", "dirxml", "keys", "values", "profile"
, "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", |
| 208 "getEventListeners", "debug", "undebug", "monitor", "unmonitor",
"table", "$", "$$", "$x"]; |
| 209 for (var i = 0; i < commandLineAPI.length; ++i) |
| 210 propertyNames[commandLineAPI[i]] = true; |
| 211 } |
| 212 fulfill(WebInspector.JavaScriptAutocomplete._completionsForPrefix(dotNot
ation, bracketNotation, expressionString, prefix, Object.keys(propertyNames))); |
| 213 } |
| 214 }; |
| 215 |
| 216 /** |
| 217 * @param {boolean} dotNotation |
| 218 * @param {boolean} bracketNotation |
| 219 * @param {string} expressionString |
| 220 * @param {string} prefix |
| 221 * @param {!Array.<string>} properties |
| 222 * @return {!Array<string>} |
| 223 */ |
| 224 WebInspector.JavaScriptAutocomplete._completionsForPrefix = function(dotNotation
, bracketNotation, expressionString, prefix, properties) { |
| 225 if (bracketNotation) { |
| 226 if (prefix.length && prefix[0] === "'") |
| 227 var quoteUsed = "'"; |
| 228 else |
| 229 var quoteUsed = "\""; |
| 230 } |
| 231 |
| 232 var results = []; |
| 233 |
| 234 if (!expressionString) { |
| 235 const keywords = ["break", "case", "catch", "continue", "default", "dele
te", "do", "else", "finally", "for", "function", "if", "in", |
| 236 "instanceof", "new", "return", "switch", "this", "th
row", "try", "typeof", "var", "void", "while", "with"]; |
| 237 properties = properties.concat(keywords); |
| 238 } |
| 239 |
| 240 properties.sort(); |
| 241 |
| 242 for (var i = 0; i < properties.length; ++i) { |
| 243 var property = properties[i]; |
| 244 |
| 245 // Assume that all non-ASCII characters are letters and thus can be used
as part of identifier. |
| 246 if (dotNotation && !/^[a-zA-Z_$\u008F-\uFFFF][a-zA-Z0-9_$\u008F-\uFFFF]*
$/.test(property)) |
| 247 continue; |
| 248 |
| 249 if (bracketNotation) { |
| 250 if (!/^[0-9]+$/.test(property)) |
| 251 property = quoteUsed + property.escapeCharacters(quoteUsed + "\\
") + quoteUsed; |
| 252 property += "]"; |
| 253 } |
| 254 |
| 255 if (property.length < prefix.length) |
| 256 continue; |
| 257 if (prefix.length && !property.startsWith(prefix)) |
| 258 continue; |
| 259 |
| 260 // Substitute actual newlines with newline characters. @see crbug.com/49
8421 |
| 261 results.push(property.split("\n").join("\\n")); |
| 262 } |
| 263 return results; |
| 264 }; |
| OLD | NEW |