summaryrefslogtreecommitdiffstats
path: root/webkit/glue
diff options
context:
space:
mode:
authoryurys@google.com <yurys@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-14 15:38:35 +0000
committeryurys@google.com <yurys@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-14 15:38:35 +0000
commitd766b0ae675565263b2d9e11421cf585bdac3e3d (patch)
tree1dff517e1a0e06b9aabb4b8f499ad1e0717d6954 /webkit/glue
parent036de96c90c89cc2dbe69363ebff0d7521645995 (diff)
downloadchromium_src-d766b0ae675565263b2d9e11421cf585bdac3e3d.zip
chromium_src-d766b0ae675565263b2d9e11421cf585bdac3e3d.tar.gz
chromium_src-d766b0ae675565263b2d9e11421cf585bdac3e3d.tar.bz2
DevTools: support autocompletion when script is paused
Review URL: http://codereview.chromium.org/277001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28961 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r--webkit/glue/devtools/js/debugger_agent.js92
-rw-r--r--webkit/glue/devtools/js/devtools.js24
-rw-r--r--webkit/glue/devtools/js/tests.js69
3 files changed, 176 insertions, 9 deletions
diff --git a/webkit/glue/devtools/js/debugger_agent.js b/webkit/glue/devtools/js/debugger_agent.js
index 64c76f9..9ea0ae7f 100644
--- a/webkit/glue/devtools/js/debugger_agent.js
+++ b/webkit/glue/devtools/js/debugger_agent.js
@@ -538,6 +538,98 @@ devtools.DebuggerAgent.prototype.resolveScope = function(scope, callback) {
/**
+ * Sends 'scopes' request for the frame object to resolve all variables
+ * available in the frame.
+ * @param {number} callFrameId Id of call frame whose variables need to
+ * be resolved.
+ * @param {function(Object)} callback Callback to be called when all frame
+ * variables are resolved.
+ */
+devtools.DebuggerAgent.prototype.resolveFrameVariables_ = function(
+ callFrameId, callback) {
+ var result = {};
+
+ var frame = this.callFrames_[callFrameId];
+ if (!frame) {
+ callback(result);
+ return;
+ }
+
+ var waitingResponses = 0;
+ function scopeResponseHandler(msg) {
+ waitingResponses--;
+
+ if (msg.isSuccess()) {
+ var properties = msg.getBody().object.properties;
+ for (var j = 0; j < properties.length; j++) {
+ result[properties[j].name] = true;
+ }
+ }
+
+ // When all scopes are resolved invoke the callback.
+ if (waitingResponses == 0) {
+ callback(result);
+ }
+ };
+
+ for (var i = 0; i < frame.scopeChain.length; i++) {
+ var scope = frame.scopeChain[i].objectId;
+ if (scope.type == devtools.DebuggerAgent.ScopeType.Global) {
+ // Do not resolve global scope since it takes for too long.
+ // TODO(yurys): allow to send only property names in the response.
+ continue;
+ }
+ var cmd = new devtools.DebugCommand('scope', {
+ 'frameNumber': scope.frameNumber,
+ 'number': scope.index,
+ 'compactFormat': true
+ });
+ devtools.DebuggerAgent.sendCommand_(cmd);
+ this.requestSeqToCallback_[cmd.getSequenceNumber()] =
+ scopeResponseHandler;
+ waitingResponses++;
+ }
+};
+
+/**
+ * Evaluates the expressionString to an object in the call frame and reports
+ * all its properties.
+ * @param{string} expressionString Expression whose properties should be
+ * collected.
+ * @param{number} callFrameId The frame id.
+ * @param{function(Object result,bool isException)} reportCompletions Callback
+ * function.
+ */
+devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame = function(
+ expressionString, callFrameId, reportCompletions) {
+ if (expressionString) {
+ expressionString = 'var obj = ' + expressionString +
+ '; var names = {}; for (var n in obj) { names[n] = true; };' +
+ 'names;';
+ this.evaluateInCallFrame(
+ callFrameId,
+ expressionString,
+ function(result) {
+ var names = {};
+ if (!result.isException) {
+ var props = result.value.objectId.properties;
+ // Put all object properties into the map.
+ for (var i = 0; i < props.length; i++) {
+ names[props[i].name] = true;
+ }
+ }
+ reportCompletions(names, result.isException);
+ });
+ } else {
+ this.resolveFrameVariables_(callFrameId,
+ function(result) {
+ reportCompletions(result, false /* isException */);
+ });
+ }
+};
+
+
+/**
* Sets up callbacks that deal with profiles processing.
*/
devtools.DebuggerAgent.prototype.setupProfilerProcessorCallbacks = function() {
diff --git a/webkit/glue/devtools/js/devtools.js b/webkit/glue/devtools/js/devtools.js
index 522e698..16ff6da 100644
--- a/webkit/glue/devtools/js/devtools.js
+++ b/webkit/glue/devtools/js/devtools.js
@@ -427,12 +427,18 @@ WebInspector.ResourcesPanel.prototype._createResourceView = function(
};
})();
-// Temporary workaround for a patch from WebKit bug 30328.
-// TODO(mnaganov): Remove when after WebKit roll.
-if (!('addProfile' in WebInspector)) {
- WebInspector.addProfile = function(profile) {
- WebInspector.__fullProfiles = WebInspector.__fullProfiles || {};
- WebInspector.__fullProfiles[profile.uid] = profile;
- WebInspector.addProfileHeader(profile);
- };
-}
+
+
+(function() {
+var orig = InjectedScriptAccess.getCompletions;
+InjectedScriptAccess.getCompletions = function(expressionString,
+ includeInspectorCommandLineAPI, callFrameId, reportCompletions) {
+ if (goog.isDef(callFrameId)) {
+ devtools.tools.getDebuggerAgent().resolveCompletionsOnFrame(
+ expressionString, callFrameId, reportCompletions);
+ } else {
+ return orig.apply(this, arguments);
+ }
+};
+})();
+
diff --git a/webkit/glue/devtools/js/tests.js b/webkit/glue/devtools/js/tests.js
index b547c77..ca8fc5e 100644
--- a/webkit/glue/devtools/js/tests.js
+++ b/webkit/glue/devtools/js/tests.js
@@ -667,6 +667,75 @@ TestSuite.prototype.testEvalOnCallFrame = function() {
/**
+ * Tests that console auto completion works when script execution is paused.
+ */
+TestSuite.prototype.testCompletionOnPause = function() {
+ this.showPanel('scripts');
+ var test = this;
+ this._executeCodeWhenScriptsAreParsed(
+ 'handleClick()',
+ ['completion_on_pause.html$']);
+
+ this._waitForScriptPause(
+ {
+ functionsOnStack: ['innerFunction', 'handleClick',
+ '(anonymous function)'],
+ lineNumber: 9,
+ lineText: ' debugger;'
+ },
+ showConsole);
+
+ function showConsole() {
+ test.addSniffer(WebInspector.console, 'afterShow', testLocalsCompletion);
+ WebInspector.showConsole();
+ }
+
+ function testLocalsCompletion() {
+ checkCompletions(
+ 'th',
+ ['parameter1', 'closureLocal', 'p', 'createClosureLocal'],
+ testThisCompletion);
+ }
+
+ function testThisCompletion() {
+ checkCompletions(
+ 'this.',
+ ['field1', 'field2', 'm'],
+ testFieldCompletion);
+ }
+
+ function testFieldCompletion() {
+ checkCompletions(
+ 'this.field1.',
+ ['id', 'name'],
+ function() {
+ test.releaseControl();
+ });
+ }
+
+ function checkCompletions(expression, expectedProperties, callback) {
+ test.addSniffer(WebInspector.console, '_reportCompletions',
+ function(bestMatchOnly, completionsReadyCallback, dotNotation,
+ bracketNotation, prefix, result, isException) {
+ test.assertTrue(!isException,
+ 'Exception while collecting completions');
+ for (var i = 0; i < expectedProperties.length; i++) {
+ var name = expectedProperties[i];
+ test.assertTrue(result[name], 'Name ' + name +
+ ' not found among the completions: ' +
+ JSON.stringify(result));
+ }
+ test.releaseControl();
+ });
+ WebInspector.console.prompt.text = expression;
+ WebInspector.console.prompt.autoCompleteSoon();
+ }
+
+ this.takeControl();
+};
+
+
+/**
* Tests that inspected page doesn't hang on reload if it contains a syntax
* error and DevTools window is open.
*/