diff options
author | yurys@google.com <yurys@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-14 15:38:35 +0000 |
---|---|---|
committer | yurys@google.com <yurys@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-14 15:38:35 +0000 |
commit | d766b0ae675565263b2d9e11421cf585bdac3e3d (patch) | |
tree | 1dff517e1a0e06b9aabb4b8f499ad1e0717d6954 /webkit/glue | |
parent | 036de96c90c89cc2dbe69363ebff0d7521645995 (diff) | |
download | chromium_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.js | 92 | ||||
-rw-r--r-- | webkit/glue/devtools/js/devtools.js | 24 | ||||
-rw-r--r-- | webkit/glue/devtools/js/tests.js | 69 |
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. */ |