Web Inspector: Save Console Evaluations into Command Line variables $1-$99 ($n)
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Feb 2015 01:15:23 +0000 (01:15 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Feb 2015 01:15:23 +0000 (01:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142061

Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

* inspector/protocol/Debugger.json:
* inspector/protocol/Runtime.json:
Input flag "saveResult" on whether we should try to save a result.
Output int "savedResultIndex" to tell the frontend the saved state.

* inspector/InjectedScriptSource.js:
Handle saving and clearing $1-$99 values.
Include in BasicCommandLineAPI for JSContext inspection.

* inspector/InjectedScriptBase.cpp:
(Inspector::InjectedScriptBase::makeEvalCall):
* inspector/InjectedScriptBase.h:
Allow an optional "savedResultIndex" out value on evals.

* inspector/InjectedScript.cpp:
(Inspector::InjectedScript::evaluate):
(Inspector::InjectedScript::evaluateOnCallFrame):
* inspector/InjectedScript.h:
* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::InspectorDebuggerAgent::evaluateOnCallFrame):
* inspector/agents/InspectorDebuggerAgent.h:
* inspector/agents/InspectorRuntimeAgent.cpp:
(Inspector::InspectorRuntimeAgent::evaluate):
* inspector/agents/InspectorRuntimeAgent.h:
Plumbing for new in and out parameters.

Source/WebCore:

* inspector/CommandLineAPIModuleSource.js:
Replace $1-$4 "inspected objects" with $1-$99 "saved results".

* bindings/js/JSCommandLineAPIHostCustom.cpp:
(WebCore::JSCommandLineAPIHost::inspectedObject):
* inspector/CommandLineAPIHost.cpp:
(WebCore::CommandLineAPIHost::CommandLineAPIHost):
(WebCore::CommandLineAPIHost::InspectableObject::get):
(WebCore::CommandLineAPIHost::addInspectedObject):
(WebCore::CommandLineAPIHost::inspectedObject):
(WebCore::CommandLineAPIHost::clearInspectedObjects): Deleted.
* inspector/CommandLineAPIHost.h:
* inspector/CommandLineAPIHost.idl:
Since we now just save the single $0 inspected object, eliminate
keeping track of a list of 5 values.

Source/WebInspectorUI:

* UserInterface/Controllers/RuntimeManager.js:
(WebInspector.RuntimeManager.prototype.evalCallback):
(WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow):
Add a saveResult parameter for the new protocol command in parameter.

* UserInterface/Views/ConsoleMessageImpl.js:
(WebInspector.ConsoleMessageImpl.prototype._formatMessage):
(WebInspector.ConsoleMessageImpl.prototype._formatParameterAsObject):
(WebInspector.ConsoleMessageImpl.prototype._formatParameterAsArray):
(WebInspector.ConsoleMessageImpl.prototype._rootPropertyPathForObject):
* UserInterface/Views/ObjectTreeView.js:
(WebInspector.ObjectTreeView.prototype.appendTitleSuffix):
For console evaluation results, show a "= $n" when the evaluation was
given a saved result index.

* UserInterface/Views/LogContentView.css:
(.console-saved-variable):
* UserInterface/Views/ObjectPreviewView.css:
(.object-preview-name):
Make $n and class names in previews always non-italics.

* UserInterface/Controllers/JavaScriptLogViewController.js:
(WebInspector.JavaScriptLogViewController.prototype.printResult):
(WebInspector.JavaScriptLogViewController.prototype.consolePromptTextCommitted):
* UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js:
(get WebInspector.JavaScriptRuntimeCompletionProvider.prototype.):
* UserInterface/Controllers/LogManager.js:
(WebInspector.LogManager.prototype.messagesCleared):
(WebInspector.LogManager.prototype._mainResourceDidChange):
Try to provide better autocompletion for $n, by populating autocompletion menus
from $1-$n where n is the maximum saved result index seen. Clear the maximum
when we clear the console.

* UserInterface/Views/ConsoleCommandResult.js:
(WebInspector.ConsoleCommandResult):
(WebInspector.ConsoleCommandResult.clearMaximumSavedResultIndex):
Keep track of the maximum savedResultIndex for console evaluation results.

LayoutTests:

* inspector/debugger/command-line-api-exception-nested-catch.html:
* inspector/debugger/command-line-api-exception.html:
* inspector/model/remote-object-get-properties.html:
* inspector/model/remote-object-weak-collection.html:
* inspector/model/remote-object.html:
Update evaluateInInspectedWindow call sites for new parameter.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@180715 268f45cc-cd09-0410-ab3c-d52691b4dbfc

35 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/debugger/command-line-api-exception-nested-catch.html
LayoutTests/inspector/debugger/command-line-api-exception.html
LayoutTests/inspector/model/remote-object-get-properties.html
LayoutTests/inspector/model/remote-object-weak-collection.html
LayoutTests/inspector/model/remote-object.html
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/InjectedScript.cpp
Source/JavaScriptCore/inspector/InjectedScript.h
Source/JavaScriptCore/inspector/InjectedScriptBase.cpp
Source/JavaScriptCore/inspector/InjectedScriptBase.h
Source/JavaScriptCore/inspector/InjectedScriptSource.js
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h
Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h
Source/JavaScriptCore/inspector/protocol/Debugger.json
Source/JavaScriptCore/inspector/protocol/Runtime.json
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp
Source/WebCore/inspector/CommandLineAPIHost.cpp
Source/WebCore/inspector/CommandLineAPIHost.h
Source/WebCore/inspector/CommandLineAPIHost.idl
Source/WebCore/inspector/CommandLineAPIModuleSource.js
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Controllers/JavaScriptLogViewController.js
Source/WebInspectorUI/UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js
Source/WebInspectorUI/UserInterface/Controllers/LogManager.js
Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Views/ConsoleCommandResult.js
Source/WebInspectorUI/UserInterface/Views/ConsoleMessageImpl.js
Source/WebInspectorUI/UserInterface/Views/LogContentView.css
Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css
Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js

index b45d38c..f1a7ffe 100644 (file)
@@ -1,3 +1,17 @@
+2015-02-26  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Save Console Evaluations into Command Line variables $1-$99 ($n)
+        https://bugs.webkit.org/show_bug.cgi?id=142061
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/debugger/command-line-api-exception-nested-catch.html:
+        * inspector/debugger/command-line-api-exception.html:
+        * inspector/model/remote-object-get-properties.html:
+        * inspector/model/remote-object-weak-collection.html:
+        * inspector/model/remote-object.html:
+        Update evaluateInInspectedWindow call sites for new parameter.
+
 2015-02-26  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] More Debug assertion updates.
index ef59c54..5453f7e 100644 (file)
@@ -16,13 +16,13 @@ function test()
     WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
 
     function dumpCommandLineAPIValue(prefix) {
-        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception", "test", true, true, false, false, function(result, wasThrown) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception", "test", true, true, false, false, false, function(result, wasThrown) {
             InspectorTest.log(prefix + ": $exception => " + result.description);
         });
     }
 
     function checkIfExceptionValueMatchesVariable(varName) {
-        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception === " + varName, "test", true, true, false, false, function(result, wasThrown) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception === " + varName, "test", true, true, false, false, false, function(result, wasThrown) {
             InspectorTest.log("  CATCH: $exception === " + varName + " ? " + result.description);
         });
     }
index d0334db..204e263 100644 (file)
@@ -40,13 +40,13 @@ function test()
     }
 
     function dumpCommandLineAPIValue(prefix) {
-        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception", "test", true, true, false, false, function(result, wasThrown) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception", "test", true, true, false, false, false, function(result, wasThrown) {
             InspectorTest.log(prefix + ": $exception => " + result.description);
         });
     }
 
     function checkIfExceptionValueMatchesCatchVariable() {
-        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception === e", "test", true, true, false, false, function(result, wasThrown) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception === e", "test", true, true, false, false, false, function(result, wasThrown) {
             InspectorTest.log("STEPPED OUT TO CATCH BLOCK: $exception === e ? " + result.description);
         });
     }
index c9bed73..ec785ad 100644 (file)
@@ -73,7 +73,7 @@ function test()
         InspectorTest.log("-----------------------------------------------------");
         InspectorTest.log("EXPRESSION: " + step.expression);
 
-        WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, false, function(remoteObject, wasThrown) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, false, false, function(remoteObject, wasThrown) {
             InspectorTest.assert(remoteObject instanceof WebInspector.RemoteObject);
             InspectorTest.log("type: " + remoteObject.type);
             if (remoteObject.subtype)
index 102bd23..1be4cea 100644 (file)
@@ -53,8 +53,8 @@ function test()
 
         // Run the expression, and then run a garbage collection on a different
         // event loop so no objects are kept alive by the stack.
-        WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, true, function(remoteObject, wasThrown) {
-            WebInspector.runtimeManager.evaluateInInspectedWindow("GCController.collect()", "test", false, true, false, false, function() {
+        WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, true, false, function(remoteObject, wasThrown) {
+            WebInspector.runtimeManager.evaluateInInspectedWindow("GCController.collect()", "test", false, true, false, false, false, function() {
                 InspectorTest.assert(remoteObject instanceof WebInspector.RemoteObject);
                 remoteObject.getCollectionEntries(0, 100, function(entries) {
                     InspectorTest.log("ENTRIES:");
index 8c4de01..bb6204d 100644 (file)
@@ -176,7 +176,7 @@ function test()
         InspectorTest.log("-----------------------------------------------------");
         InspectorTest.log("EXPRESSION: " + step.expression);
 
-        WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, true, function(remoteObject, wasThrown) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, true, false, function(remoteObject, wasThrown) {
             InspectorTest.assert(remoteObject instanceof WebInspector.RemoteObject);
             InspectorTest.log(JSON.stringify(remoteObject, remoteObjectJSONFilter, "  "));
             runNextStep();
index af371ae..4a266a5 100644 (file)
@@ -1,3 +1,36 @@
+2015-02-26  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Save Console Evaluations into Command Line variables $1-$99 ($n)
+        https://bugs.webkit.org/show_bug.cgi?id=142061
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/protocol/Debugger.json:
+        * inspector/protocol/Runtime.json:
+        Input flag "saveResult" on whether we should try to save a result.
+        Output int "savedResultIndex" to tell the frontend the saved state.
+
+        * inspector/InjectedScriptSource.js:
+        Handle saving and clearing $1-$99 values.
+        Include in BasicCommandLineAPI for JSContext inspection.
+
+        * inspector/InjectedScriptBase.cpp:
+        (Inspector::InjectedScriptBase::makeEvalCall):
+        * inspector/InjectedScriptBase.h:
+        Allow an optional "savedResultIndex" out value on evals.
+
+        * inspector/InjectedScript.cpp:
+        (Inspector::InjectedScript::evaluate):
+        (Inspector::InjectedScript::evaluateOnCallFrame):
+        * inspector/InjectedScript.h:
+        * inspector/agents/InspectorDebuggerAgent.cpp:
+        (Inspector::InspectorDebuggerAgent::evaluateOnCallFrame):
+        * inspector/agents/InspectorDebuggerAgent.h:
+        * inspector/agents/InspectorRuntimeAgent.cpp:
+        (Inspector::InspectorRuntimeAgent::evaluate):
+        * inspector/agents/InspectorRuntimeAgent.h:
+        Plumbing for new in and out parameters.
+
 2015-02-26  Filip Pizlo  <fpizlo@apple.com>
 
         The bool returning form of BytecodeGenerator::addVar() can be removed
index 66499ed..53a4e36 100644 (file)
@@ -56,7 +56,7 @@ InjectedScript::~InjectedScript()
 {
 }
 
-void InjectedScript::evaluate(ErrorString& errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown)
+void InjectedScript::evaluate(ErrorString& errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex)
 {
     Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("evaluate"), inspectorEnvironment()->functionCallHandler());
     function.appendArgument(expression);
@@ -64,7 +64,8 @@ void InjectedScript::evaluate(ErrorString& errorString, const String& expression
     function.appendArgument(includeCommandLineAPI);
     function.appendArgument(returnByValue);
     function.appendArgument(generatePreview);
-    makeEvalCall(errorString, function, result, wasThrown);
+    function.appendArgument(saveResult);
+    makeEvalCall(errorString, function, result, wasThrown, savedResultIndex);
 }
 
 void InjectedScript::callFunctionOn(ErrorString& errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown)
@@ -78,7 +79,7 @@ void InjectedScript::callFunctionOn(ErrorString& errorString, const String& obje
     makeEvalCall(errorString, function, result, wasThrown);
 }
 
-void InjectedScript::evaluateOnCallFrame(ErrorString& errorString, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown)
+void InjectedScript::evaluateOnCallFrame(ErrorString& errorString, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex)
 {
     Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("evaluateOnCallFrame"), inspectorEnvironment()->functionCallHandler());
     function.appendArgument(callFrames);
@@ -88,7 +89,8 @@ void InjectedScript::evaluateOnCallFrame(ErrorString& errorString, const Depreca
     function.appendArgument(includeCommandLineAPI);
     function.appendArgument(returnByValue);
     function.appendArgument(generatePreview);
-    makeEvalCall(errorString, function, result, wasThrown);
+    function.appendArgument(saveResult);
+    makeEvalCall(errorString, function, result, wasThrown, savedResultIndex);
 }
 
 void InjectedScript::getFunctionDetails(ErrorString& errorString, const String& functionId, RefPtr<Inspector::Protocol::Debugger::FunctionDetails>* result)
index 14a3cb0..b99854c 100644 (file)
@@ -52,9 +52,9 @@ public:
     InjectedScript(Deprecated::ScriptObject, InspectorEnvironment*);
     virtual ~InjectedScript();
 
-    void evaluate(ErrorString&, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown);
+    void evaluate(ErrorString&, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex);
     void callFunctionOn(ErrorString&, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown);
-    void evaluateOnCallFrame(ErrorString&, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown);
+    void evaluateOnCallFrame(ErrorString&, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex);
     void getFunctionDetails(ErrorString&, const String& functionId, RefPtr<Protocol::Debugger::FunctionDetails>* result);
     void getProperties(ErrorString&, const String& objectId, bool ownProperties, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::PropertyDescriptor>>* result);
     void getDisplayableProperties(ErrorString&, const String& objectId, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::PropertyDescriptor>>* result);
index 83b7d8c..2dd5643 100644 (file)
@@ -112,7 +112,7 @@ void InjectedScriptBase::makeCall(Deprecated::ScriptFunctionCall& function, RefP
         *result = InspectorString::create("Exception while making a call.");
 }
 
-void InjectedScriptBase::makeEvalCall(ErrorString& errorString, Deprecated::ScriptFunctionCall& function, RefPtr<Protocol::Runtime::RemoteObject>* objectResult, Protocol::OptOutput<bool>* wasThrown)
+void InjectedScriptBase::makeEvalCall(ErrorString& errorString, Deprecated::ScriptFunctionCall& function, RefPtr<Protocol::Runtime::RemoteObject>* objectResult, Protocol::OptOutput<bool>* wasThrown, Protocol::OptOutput<int>* savedResultIndex)
 {
     RefPtr<InspectorValue> result;
     makeCall(function, &result);
@@ -127,26 +127,32 @@ void InjectedScriptBase::makeEvalCall(ErrorString& errorString, Deprecated::Scri
         return;
     }
 
-    RefPtr<InspectorObject> resultPair;
-    if (!result->asObject(resultPair)) {
+    RefPtr<InspectorObject> resultTuple;
+    if (!result->asObject(resultTuple)) {
         errorString = ASCIILiteral("Internal error: result is not an Object");
         return;
     }
 
     RefPtr<InspectorObject> resultObject;
-    if (!resultPair->getObject(ASCIILiteral("result"), resultObject)) {
+    if (!resultTuple->getObject(ASCIILiteral("result"), resultObject)) {
         errorString = ASCIILiteral("Internal error: result is not a pair of value and wasThrown flag");
         return;
     }
 
     bool wasThrownValue = false;
-    if (!resultPair->getBoolean(ASCIILiteral("wasThrown"), wasThrownValue)) {
+    if (!resultTuple->getBoolean(ASCIILiteral("wasThrown"), wasThrownValue)) {
         errorString = ASCIILiteral("Internal error: result is not a pair of value and wasThrown flag");
         return;
     }
 
     *objectResult = BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject);
     *wasThrown = wasThrownValue;
+
+    if (savedResultIndex) {
+        int savedIndex = 0;
+        if (resultTuple->getInteger(ASCIILiteral("savedResultIndex"), savedIndex))
+            *savedResultIndex = savedIndex;
+    }
 }
 
 } // namespace Inspector
index cb46303..06c3f56 100644 (file)
@@ -66,7 +66,7 @@ protected:
     const Deprecated::ScriptObject& injectedScriptObject() const;
     Deprecated::ScriptValue callFunctionWithEvalEnabled(Deprecated::ScriptFunctionCall&, bool& hadException) const;
     void makeCall(Deprecated::ScriptFunctionCall&, RefPtr<InspectorValue>* result);
-    void makeEvalCall(ErrorString&, Deprecated::ScriptFunctionCall&, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown);
+    void makeEvalCall(ErrorString&, Deprecated::ScriptFunctionCall&, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Protocol::OptOutput<int>* savedResult = nullptr);
 
 private:
     String m_name;
index 04c9a98..4e25d55 100644 (file)
@@ -58,6 +58,8 @@ var InjectedScript = function()
     this._idToObjectGroupName = {};
     this._objectGroups = {};
     this._modules = {};
+    this._nextSavedResultIndex = 1;
+    this._savedResults = [];
 }
 
 InjectedScript.primitiveTypes = {
@@ -174,13 +176,19 @@ InjectedScript.prototype = {
 
     releaseObjectGroup: function(objectGroupName)
     {
-        if (objectGroupName === "console")
+        if (objectGroupName === "console") {
             delete this._lastResult;
+            this._nextSavedResultIndex = 1;
+            this._savedResults = [];
+        }
+
         var group = this._objectGroups[objectGroupName];
         if (!group)
             return;
+
         for (var i = 0; i < group.length; i++)
             this._releaseObject(group[i]);
+
         delete this._objectGroups[objectGroupName];
     },
 
@@ -320,9 +328,9 @@ InjectedScript.prototype = {
         delete this._idToObjectGroupName[id];
     },
 
-    evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
+    evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult)
     {
-        return this._evaluateAndWrap(InjectedScriptHost.evaluate, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview);
+        return this._evaluateAndWrap(InjectedScriptHost.evaluate, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, saveResult);
     },
 
     callFunctionOn: function(objectId, expression, args, returnByValue, generatePreview)
@@ -376,13 +384,20 @@ InjectedScript.prototype = {
         return undefined;
     },
 
-    _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview)
+    _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, saveResult)
     {
         try {
-            return {
+            this._savedResultIndex = undefined;
+
+            var returnObject = {
                 wasThrown: false,
-                result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI), objectGroup, returnByValue, generatePreview)
+                result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult), objectGroup, returnByValue, generatePreview)
             };
+
+            if (saveResult && this._savedResultIndex)
+                returnObject.savedResultIndex = this._savedResultIndex;
+
+            return returnObject;
         } catch (e) {
             return this._createThrownValue(e, objectGroup);
         }
@@ -400,7 +415,7 @@ InjectedScript.prototype = {
         };
     },
 
-    _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI)
+    _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult)
     {
         var commandLineAPI = null;
         if (injectCommandLineAPI) {
@@ -445,8 +460,8 @@ InjectedScript.prototype = {
             var expressionFunction = evalFunction.call(object, boundExpressionFunctionString);
             var result = expressionFunction.apply(null, parameters);
 
-            if (objectGroup === "console")
-                this._lastResult = result;
+            if (objectGroup === "console" && saveResult)
+                this._saveResult(result);
 
             return result;
         }
@@ -465,8 +480,8 @@ InjectedScript.prototype = {
 
             var result = evalFunction.call(inspectedGlobalObject, expression);
 
-            if (objectGroup === "console")
-                this._lastResult = result;
+            if (objectGroup === "console" && saveResult)
+                this._saveResult(result);
 
             return result;
         } finally {
@@ -493,12 +508,12 @@ InjectedScript.prototype = {
         return result;
     },
 
-    evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
+    evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult)
     {
         var callFrame = this._callFrameForId(topCallFrame, callFrameId);
         if (!callFrame)
             return "Could not find call frame with given id";
-        return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview);
+        return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview, saveResult);
     },
 
     _callFrameForId: function(topCallFrame, callFrameId)
@@ -809,6 +824,32 @@ InjectedScript.prototype = {
             return this._getWeakMapEntries(object, numberToFetch);
 
         throw "unexpected type";
+    },
+
+    _saveResult: function(result)
+    {
+        this._lastResult = result;
+
+        if (result === undefined || result === null)
+            return;
+
+        var existingIndex = this._savedResults.indexOf(result);
+        if (existingIndex !== -1) {
+            this._savedResultIndex = existingIndex;
+            return;
+        }
+
+        this._savedResultIndex = this._nextSavedResultIndex;
+        this._savedResults[this._nextSavedResultIndex++] = result;
+
+        // $n is limited from $1-$99. $0 is special.
+        if (this._nextSavedResultIndex >= 100)
+            this._nextSavedResultIndex = 1;
+    },
+
+    _savedResult: function(index)
+    {
+        return this._savedResults[index];
     }
 }
 
@@ -1117,10 +1158,35 @@ InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeOb
     };
 }
 
+
+function slice(array, index)
+{
+    var result = [];
+    for (var i = index || 0; i < array.length; ++i)
+        result.push(array[i]);
+    return result;
+}
+
+function bind(func, thisObject, var_args)
+{
+    var args = slice(arguments, 2);
+    return function(var_args) {
+        return func.apply(thisObject, args.concat(slice(arguments)));
+    }
+}
+
 function BasicCommandLineAPI()
 {
     this.$_ = injectedScript._lastResult;
     this.$exception = injectedScript._exceptionValue;
+
+    // $1-$99
+    for (var i = 1; i <= injectedScript._savedResults.length; ++i) {
+        var member = "$" + i;
+        if (member in inspectedGlobalObject)
+            continue;
+        this.__defineGetter__("$" + i, bind(injectedScript._savedResult, injectedScript, i));
+    }
 }
 
 return injectedScript;
index 2acbcf4..65889ae 100644 (file)
@@ -551,7 +551,7 @@ void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString& errorString, cons
         errorString = ASCIILiteral("Internal error. Could not change pause on exceptions state");
 }
 
-void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown)
+void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex)
 {
     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
     if (injectedScript.hasNoValue()) {
@@ -566,7 +566,7 @@ void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const
         muteConsole();
     }
 
-    injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, &result, wasThrown);
+    injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, saveResult ? *saveResult : false, &result, wasThrown, savedResultIndex);
 
     if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) {
         unmuteConsole();
index c1d797c..7948640 100644 (file)
@@ -84,7 +84,7 @@ public:
     virtual void stepInto(ErrorString&) override;
     virtual void stepOut(ErrorString&) override;
     virtual void setPauseOnExceptions(ErrorString&, const String& pauseState) override;
-    virtual void evaluateOnCallFrame(ErrorString&, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown) override;
+    virtual void evaluateOnCallFrame(ErrorString&, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) override;
     virtual void setOverlayMessage(ErrorString&, const String*) override;
 
     bool isPaused();
index de42d23..694955f 100644 (file)
@@ -114,7 +114,7 @@ void InspectorRuntimeAgent::parse(ErrorString&, const String& expression, Inspec
     }
 }
 
-void InspectorRuntimeAgent::evaluate(ErrorString& errorString, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* const returnByValue, const bool* generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown)
+void InspectorRuntimeAgent::evaluate(ErrorString& errorString, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* const returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex)
 {
     InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
     if (injectedScript.hasNoValue())
@@ -126,7 +126,7 @@ void InspectorRuntimeAgent::evaluate(ErrorString& errorString, const String& exp
     if (asBool(doNotPauseOnExceptionsAndMuteConsole))
         muteConsole();
 
-    injectedScript.evaluate(errorString, expression, objectGroup ? *objectGroup : String(), asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), &result, wasThrown);
+    injectedScript.evaluate(errorString, expression, objectGroup ? *objectGroup : String(), asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), asBool(saveResult), &result, wasThrown, savedResultIndex);
 
     if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
         unmuteConsole();
index 678f0c7..4b97763 100644 (file)
@@ -60,7 +60,7 @@ public:
     virtual void enable(ErrorString&) override { m_enabled = true; }
     virtual void disable(ErrorString&) override { m_enabled = false; }
     virtual void parse(ErrorString&, const String& expression, Inspector::Protocol::Runtime::SyntaxErrorType* result, Inspector::Protocol::OptOutput<String>* message, RefPtr<Inspector::Protocol::Runtime::ErrorRange>&) override final;
-    virtual void evaluate(ErrorString&, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown) override final;
+    virtual void evaluate(ErrorString&, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) override final;
     virtual void callFunctionOn(ErrorString&, const String& objectId, const String& expression, const RefPtr<Inspector::InspectorArray>&& optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown) override final;
     virtual void releaseObject(ErrorString&, const ErrorString& objectId) override final;
     virtual void getProperties(ErrorString&, const String& objectId, const bool* ownProperties, const bool* generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties) override final;
index 112eda7..8c371fb 100644 (file)
                 { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false." },
                 { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state." },
                 { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." },
-                { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }
+                { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." },
+                { "name": "saveResult", "type": "boolean", "optional": true, "description": "Whether the resulting value should be considered for saving in the $n history." }
             ],
             "returns": [
                 { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." },
-                { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }
+                { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." },
+                { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the result was saved, this is the $n index that can be used to access the value." }
             ],
             "description": "Evaluates expression on a given call frame."
         },
index 1bdd31f..ca4ab53 100644 (file)
                 { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state." },
                 { "name": "contextId", "$ref": "Runtime.ExecutionContextId", "optional": true, "description": "Specifies in which isolated context to perform evaluation. Each content script lives in an isolated context and this parameter may be used to specify one of those contexts. If the parameter is omitted or 0 the evaluation will be performed in the context of the inspected page." },
                 { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." },
-                { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }
+                { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." },
+                { "name": "saveResult", "type": "boolean", "optional": true, "description": "Whether the resulting value should be considered for saving in the $n history." }
             ],
             "returns": [
                 { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." },
-                { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }
+                { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." },
+                { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the result was saved, this is the $n index that can be used to access the value." }
             ],
             "description": "Evaluates expression on global object."
         },
index 6bdf8d7..ce124e6 100644 (file)
@@ -1,3 +1,26 @@
+2015-02-26  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Save Console Evaluations into Command Line variables $1-$99 ($n)
+        https://bugs.webkit.org/show_bug.cgi?id=142061
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/CommandLineAPIModuleSource.js:
+        Replace $1-$4 "inspected objects" with $1-$99 "saved results".
+
+        * bindings/js/JSCommandLineAPIHostCustom.cpp:
+        (WebCore::JSCommandLineAPIHost::inspectedObject):
+        * inspector/CommandLineAPIHost.cpp:
+        (WebCore::CommandLineAPIHost::CommandLineAPIHost):
+        (WebCore::CommandLineAPIHost::InspectableObject::get):
+        (WebCore::CommandLineAPIHost::addInspectedObject):
+        (WebCore::CommandLineAPIHost::inspectedObject):
+        (WebCore::CommandLineAPIHost::clearInspectedObjects): Deleted.
+        * inspector/CommandLineAPIHost.h:
+        * inspector/CommandLineAPIHost.idl:
+        Since we now just save the single $0 inspected object, eliminate
+        keeping track of a list of 5 values.
+
 2015-02-26  Gyuyoung Kim  <gyuyoung.kim@samsung.com>
 
         Remove unnecessary create() factory functions in CDMFoo, NamedNodeMap
index 741622f..da52cec 100644 (file)
@@ -57,10 +57,7 @@ namespace WebCore {
 
 JSValue JSCommandLineAPIHost::inspectedObject(ExecState* exec)
 {
-    if (exec->argumentCount() < 1)
-        return jsUndefined();
-
-    CommandLineAPIHost::InspectableObject* object = impl().inspectedObject(exec->uncheckedArgument(0).toInt32(exec));
+    CommandLineAPIHost::InspectableObject* object = impl().inspectedObject();
     if (!object)
         return jsUndefined();
 
index 8870885..3b976da 100644 (file)
@@ -67,7 +67,7 @@ CommandLineAPIHost::CommandLineAPIHost()
     , m_domStorageAgent(nullptr)
     , m_databaseAgent(nullptr)
 {
-    m_defaultInspectableObject = std::make_unique<InspectableObject>();
+    m_inspectedObject = std::make_unique<InspectableObject>();
 }
 
 CommandLineAPIHost::~CommandLineAPIHost()
@@ -118,26 +118,16 @@ void CommandLineAPIHost::copyText(const String& text)
 Deprecated::ScriptValue CommandLineAPIHost::InspectableObject::get(JSC::ExecState*)
 {
     return Deprecated::ScriptValue();
-};
-
-void CommandLineAPIHost::addInspectedObject(std::unique_ptr<CommandLineAPIHost::InspectableObject> object)
-{
-    m_inspectedObjects.insert(0, WTF::move(object));
-    while (m_inspectedObjects.size() > 5)
-        m_inspectedObjects.removeLast();
 }
 
-void CommandLineAPIHost::clearInspectedObjects()
+void CommandLineAPIHost::addInspectedObject(std::unique_ptr<CommandLineAPIHost::InspectableObject> object)
 {
-    m_inspectedObjects.clear();
+    m_inspectedObject = WTF::move(object);
 }
 
-CommandLineAPIHost::InspectableObject* CommandLineAPIHost::inspectedObject(unsigned index)
+CommandLineAPIHost::InspectableObject* CommandLineAPIHost::inspectedObject()
 {
-    if (index >= m_inspectedObjects.size())
-        return m_defaultInspectableObject.get();
-
-    return m_inspectedObjects[index].get();
+    return m_inspectedObject.get();
 }
 
 String CommandLineAPIHost::databaseIdImpl(Database* database)
index 877ef0b..b1231ae 100644 (file)
@@ -89,8 +89,7 @@ public:
         virtual ~InspectableObject() { }
     };
     void addInspectedObject(std::unique_ptr<InspectableObject>);
-    void clearInspectedObjects();
-    InspectableObject* inspectedObject(unsigned index);
+    InspectableObject* inspectedObject();
     void inspectImpl(RefPtr<Inspector::InspectorValue>&& objectToInspect, RefPtr<Inspector::InspectorValue>&& hints);
 
     void getEventListenersImpl(Node*, Vector<EventListenerInfo>& listenersArray);
@@ -107,8 +106,7 @@ private:
     InspectorDOMStorageAgent* m_domStorageAgent;
     InspectorDatabaseAgent* m_databaseAgent;
 
-    Vector<std::unique_ptr<InspectableObject>> m_inspectedObjects;
-    std::unique_ptr<InspectableObject> m_defaultInspectableObject;
+    std::unique_ptr<InspectableObject> m_inspectedObject; // $0
 };
 
 } // namespace WebCore
index 262bb43..5a16155 100644 (file)
@@ -37,7 +37,7 @@
     void clearConsoleMessages();
     void copyText(DOMString text);
     [Custom] void inspect(any objectId, any hints);
-    [Custom] any inspectedObject(int num);
+    [Custom] any inspectedObject();
     [Custom] Array getEventListeners(Node node);
     [Custom] DOMString databaseId(any database);
     [Custom] DOMString storageId(any storage);
index abfc7ce..d88e1df 100644 (file)
@@ -115,12 +115,16 @@ function CommandLineAPI(commandLineAPIImpl, callFrame)
         this[member].toString = customToStringMethod(member);
     }
 
-    for (var i = 0; i < 5; ++i) {
+    // $0
+    this.__defineGetter__("$0", bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl));
+
+    // $1-$99
+    for (var i = 1; i <= injectedScript._savedResults.length; ++i) {
         var member = "$" + i;
         if (member in inspectedWindow || inScopeVariables(member))
             continue;
 
-        this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i));
+        this.__defineGetter__("$" + i, bind(injectedScript._savedResult, injectedScript, i));
     }
 
     this.$_ = injectedScript._lastResult;
@@ -305,12 +309,9 @@ CommandLineAPIImpl.prototype = {
         return CommandLineAPIHost.getEventListeners(node);
     },
 
-    /**
-     * @param {number} num
-     */
-    _inspectedObject: function(num)
+    _inspectedObject: function()
     {
-        return CommandLineAPIHost.inspectedObject(num);
+        return CommandLineAPIHost.inspectedObject();
     },
 
     /**
index 1c36958..7db7006 100644 (file)
@@ -1,5 +1,50 @@
 2015-02-26  Joseph Pecoraro  <pecoraro@apple.com>
 
+        Web Inspector: Save Console Evaluations into Command Line variables $1-$99 ($n)
+        https://bugs.webkit.org/show_bug.cgi?id=142061
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Controllers/RuntimeManager.js:
+        (WebInspector.RuntimeManager.prototype.evalCallback):
+        (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow):
+        Add a saveResult parameter for the new protocol command in parameter.
+
+        * UserInterface/Views/ConsoleMessageImpl.js:
+        (WebInspector.ConsoleMessageImpl.prototype._formatMessage):
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsObject):
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsArray):
+        (WebInspector.ConsoleMessageImpl.prototype._rootPropertyPathForObject):
+        * UserInterface/Views/ObjectTreeView.js:
+        (WebInspector.ObjectTreeView.prototype.appendTitleSuffix):
+        For console evaluation results, show a "= $n" when the evaluation was
+        given a saved result index.
+
+        * UserInterface/Views/LogContentView.css:
+        (.console-saved-variable):
+        * UserInterface/Views/ObjectPreviewView.css:
+        (.object-preview-name):
+        Make $n and class names in previews always non-italics.
+
+        * UserInterface/Controllers/JavaScriptLogViewController.js:
+        (WebInspector.JavaScriptLogViewController.prototype.printResult):
+        (WebInspector.JavaScriptLogViewController.prototype.consolePromptTextCommitted):
+        * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js:
+        (get WebInspector.JavaScriptRuntimeCompletionProvider.prototype.):
+        * UserInterface/Controllers/LogManager.js:
+        (WebInspector.LogManager.prototype.messagesCleared):
+        (WebInspector.LogManager.prototype._mainResourceDidChange):
+        Try to provide better autocompletion for $n, by populating autocompletion menus
+        from $1-$n where n is the maximum saved result index seen. Clear the maximum
+        when we clear the console.
+
+        * UserInterface/Views/ConsoleCommandResult.js:
+        (WebInspector.ConsoleCommandResult):
+        (WebInspector.ConsoleCommandResult.clearMaximumSavedResultIndex):
+        Keep track of the maximum savedResultIndex for console evaluation results.
+
+2015-02-26  Joseph Pecoraro  <pecoraro@apple.com>
+
         Web Inspector: Set/Map appear as lossless when they have lossy entries
         https://bugs.webkit.org/show_bug.cgi?id=142050
 
index 36630b9..b754752 100644 (file)
@@ -222,17 +222,17 @@ WebInspector.JavaScriptLogViewController.prototype = {
         var commandMessage = new WebInspector.ConsoleCommand(text);
         this._appendConsoleMessage(commandMessage, true);
 
-        function printResult(result, wasThrown)
+        function printResult(result, wasThrown, savedResultIndex)
         {
             if (!result || this._cleared)
                 return;
 
-            this._appendConsoleMessage(new WebInspector.ConsoleCommandResult(result, wasThrown, commandMessage), true);
+            this._appendConsoleMessage(new WebInspector.ConsoleCommandResult(result, wasThrown, commandMessage, savedResultIndex), true);
         }
 
         text += "\n//# sourceURL=__WebInspectorConsole__\n";
 
-        WebInspector.runtimeManager.evaluateInInspectedWindow(text, "console", true, false, false, true, printResult.bind(this));
+        WebInspector.runtimeManager.evaluateInInspectedWindow(text, "console", true, false, false, true, true, printResult.bind(this));
     },
 
     // Private
index 713f961..16816d6 100644 (file)
@@ -104,7 +104,7 @@ WebInspector.JavaScriptRuntimeCompletionProvider.prototype = {
         if (!base && activeCallFrame && !this._alwaysEvaluateInWindowContext)
             activeCallFrame.collectScopeChainVariableNames(receivedPropertyNames.bind(this));
         else
-            WebInspector.runtimeManager.evaluateInInspectedWindow(base, "completion", true, true, false, false, evaluated.bind(this));
+            WebInspector.runtimeManager.evaluateInInspectedWindow(base, "completion", true, true, false, false, false, evaluated.bind(this));
 
         function updateLastPropertyNames(propertyNames)
         {
@@ -155,7 +155,7 @@ WebInspector.JavaScriptRuntimeCompletionProvider.prototype = {
             if (result.type === "object" || result.type === "function")
                 result.callFunctionJSON(getCompletions, undefined, receivedPropertyNames.bind(this));
             else if (result.type === "string" || result.type === "number" || result.type === "boolean")
-                WebInspector.runtimeManager.evaluateInInspectedWindow("(" + getCompletions + ")(\"" + result.type + "\")", "completion", false, true, true, false, receivedPropertyNamesFromEvaluate.bind(this));
+                WebInspector.runtimeManager.evaluateInInspectedWindow("(" + getCompletions + ")(\"" + result.type + "\")", "completion", false, true, true, false, false, receivedPropertyNamesFromEvaluate.bind(this));
             else
                 console.error("Unknown result type: " + result.type);
         }
@@ -174,11 +174,15 @@ WebInspector.JavaScriptRuntimeCompletionProvider.prototype = {
             RuntimeAgent.releaseObjectGroup("completion");
 
             if (!base) {
-                var commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$1", "$2", "$3", "$4", "$_"];
+                var commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$_"];
                 if (WebInspector.debuggerManager.paused && WebInspector.debuggerManager.pauseReason === WebInspector.DebuggerManager.PauseReason.Exception)
                     commandLineAPI.push("$exception");
                 for (var i = 0; i < commandLineAPI.length; ++i)
                     propertyNames[commandLineAPI[i]] = true;
+
+                // FIXME: Due to caching, sometimes old $n values show up as completion results even though they are not available. We should clear that proactively.
+                for (var i = 1; i <= WebInspector.ConsoleCommandResult.maximumSavedResultIndex; ++i)
+                    propertyNames["$" + i] = true;
             }
 
             propertyNames = Object.keys(propertyNames);
index f10bc0c..f59125b 100644 (file)
@@ -59,6 +59,8 @@ WebInspector.LogManager.prototype = {
     {
         // Called from WebInspector.ConsoleObserver.
 
+        WebInspector.ConsoleCommandResult.clearMaximumSavedResultIndex();
+
         // We don't want to clear messages on reloads. We can't determine that easily right now.
         // FIXME: <rdar://problem/13767079> Console.messagesCleared should include a reason
         this._shouldClearMessages = true;
@@ -97,6 +99,8 @@ WebInspector.LogManager.prototype = {
         else
             this.dispatchEventToListeners(WebInspector.LogManager.Event.SessionStarted);
 
+        WebInspector.ConsoleCommandResult.clearMaximumSavedResultIndex();
+
         delete this._shouldClearMessages;
     }
 };
index 52c0061..f7106a4 100644 (file)
@@ -41,14 +41,14 @@ WebInspector.RuntimeManager.prototype = {
 
     // Public
 
-    evaluateInInspectedWindow: function(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, callback)
+    evaluateInInspectedWindow: function(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, saveResult, callback)
     {
         if (!expression) {
             // There is no expression, so the completion should happen against global properties.
             expression = "this";
         }
 
-        function evalCallback(error, result, wasThrown)
+        function evalCallback(error, result, wasThrown, savedResultIndex)
         {
             this.dispatchEventToListeners(WebInspector.RuntimeManager.Event.DidEvaluate);
 
@@ -59,22 +59,24 @@ WebInspector.RuntimeManager.prototype = {
             }
 
             if (returnByValue)
-                callback(null, wasThrown, wasThrown ? null : result);
+                callback(null, wasThrown, wasThrown ? null : result, savedResultIndex);
             else
-                callback(WebInspector.RemoteObject.fromPayload(result), wasThrown);
+                callback(WebInspector.RemoteObject.fromPayload(result), wasThrown, savedResultIndex);
         }
 
         if (WebInspector.debuggerManager.activeCallFrame) {
             // COMPATIBILITY (iOS 6): "generatePreview" did not exist.
-            DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression: expression, objectGroup: objectGroup, includeCommandLineAPI: includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole: doNotPauseOnExceptionsAndMuteConsole, returnByValue: returnByValue, generatePreview: generatePreview}, evalCallback.bind(this));
+            // COMPATIBILITY (iOS 8): "saveResult" did not exist.
+            DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression: expression, objectGroup: objectGroup, includeCommandLineAPI: includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole: doNotPauseOnExceptionsAndMuteConsole, returnByValue: returnByValue, generatePreview: generatePreview, saveResult: saveResult}, evalCallback.bind(this));
             return;
         }
 
         // COMPATIBILITY (iOS 6): Execution context identifiers (contextId) did not exist
         // in iOS 6. Fallback to including the frame identifier (frameId).
         // COMPATIBILITY (iOS 6): "generatePreview" did not exist.
+        // COMPATIBILITY (iOS 8): "saveResult" did not exist.
         var contextId = WebInspector.quickConsole.executionContextIdentifier;
-        RuntimeAgent.evaluate.invoke({expression: expression, objectGroup: objectGroup, includeCommandLineAPI: includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole: doNotPauseOnExceptionsAndMuteConsole, contextId: contextId, frameId: contextId, returnByValue: returnByValue, generatePreview: generatePreview}, evalCallback.bind(this));
+        RuntimeAgent.evaluate.invoke({expression: expression, objectGroup: objectGroup, includeCommandLineAPI: includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole: doNotPauseOnExceptionsAndMuteConsole, contextId: contextId, frameId: contextId, returnByValue: returnByValue, generatePreview: generatePreview, saveResult: saveResult}, evalCallback.bind(this));
     },
 
     getPropertiesForRemoteObject: function(objectId, callback)
index d3f3459..bdf94ef 100644 (file)
@@ -27,7 +27,7 @@
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <!--
-    These resouces should match the order and groups used in Main.html.
+    These resources should match the order and groups used in Main.html.
     -->
     <script src="Base/WebInspector.js"></script>
     <script src="Base/Object.js"></script>
index 236c81c..82b0898 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ConsoleCommandResult = function(result, wasThrown, originatingCommand)
+WebInspector.ConsoleCommandResult = function(result, wasThrown, originatingCommand, savedResultIndex)
 {
     var level = (wasThrown ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log);
     this.originatingCommand = originatingCommand;
+    this.savedResultIndex = savedResultIndex;
+
+    if (this.savedResultIndex && this.savedResultIndex > WebInspector.ConsoleCommandResult.maximumSavedResultIndex)
+        WebInspector.ConsoleCommandResult.maximumSavedResultIndex = this.savedResultIndex;
 
     WebInspector.ConsoleMessageImpl.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, "", null, WebInspector.ConsoleMessage.MessageType.Result, undefined, undefined, undefined, undefined, [result]);
 };
 
+WebInspector.ConsoleCommandResult.maximumSavedResultIndex = 0;
+
+WebInspector.ConsoleCommandResult.clearMaximumSavedResultIndex = function()
+{
+    WebInspector.ConsoleCommandResult.maximumSavedResultIndex = 0;
+}
+
 WebInspector.ConsoleCommandResult.prototype = {
     constructor: WebInspector.ConsoleCommandResult,
 
index 759d6ac..4deaef1 100644 (file)
@@ -125,6 +125,16 @@ WebInspector.ConsoleMessageImpl.prototype = {
 
         this._formattedMessage.appendChild(messageText);
 
+        if (this.savedResultIndex) {
+            var savedVariableElement = document.createElement("span");
+            savedVariableElement.className = "console-saved-variable";
+            savedVariableElement.textContent = " = $" + this.savedResultIndex;
+            if (this._objectTree)
+                this._objectTree.appendTitleSuffix(savedVariableElement);
+            else
+                this._formattedMessage.appendChild(savedVariableElement);
+        }
+
         if (this._shouldDumpStackTrace()) {
             var ol = document.createElement("ol");
             ol.className = "outline-disclosure";
@@ -296,9 +306,8 @@ WebInspector.ConsoleMessageImpl.prototype = {
 
     _formatParameterAsObject: function(obj, elem, forceExpansion)
     {
-        // FIXME: Intialize component with "$n" instead of "obj". Or, an existing property path.
-        var objectTree = new WebInspector.ObjectTreeView(obj, WebInspector.ObjectTreeView.Mode.Properties, null, forceExpansion);
-        elem.appendChild(objectTree.element);
+        this._objectTree = new WebInspector.ObjectTreeView(obj, WebInspector.ObjectTreeView.Mode.Properties, this._rootPropertyPathForObject(obj), forceExpansion);
+        elem.appendChild(this._objectTree.element);
     },
 
     _formatParameterAsString: function(output, elem)
@@ -315,9 +324,16 @@ WebInspector.ConsoleMessageImpl.prototype = {
 
     _formatParameterAsArray: function(arr, elem)
     {
-        // FIXME: Intialize component with "$n" instead of "obj". Or, an existing property path.
-        var objectTree = new WebInspector.ObjectTreeView(arr, WebInspector.ObjectTreeView.Mode.Properties);
-        elem.appendChild(objectTree.element);
+        this._objectTree = new WebInspector.ObjectTreeView(arr, WebInspector.ObjectTreeView.Mode.Properties, this._rootPropertyPathForObject(arr));
+        elem.appendChild(this._objectTree.element);
+    },
+
+    _rootPropertyPathForObject: function(object)
+    {
+        if (!this.savedResultIndex)
+            return null;
+
+        return new WebInspector.PropertyPath(object, "$" + this.savedResultIndex);
     },
 
     _userProvidedColumnNames: function(columnNamesArgument)
index 3731440..ce0b78d 100644 (file)
     color: rgb(0, 128, 255);
 }
 
+.console-saved-variable {
+    font-style: normal;
+    color: hsl(0, 0%, 67%);
+}
+
 .console-messages a {
     color: rgb(33%, 33%, 33%);
     cursor: pointer;
index 7ca5ea2..8c48bff 100644 (file)
@@ -32,7 +32,7 @@ WebInspector.ObjectTreeView = function(object, mode, propertyPath, forceExpandin
 
     this._object = object;
     this._mode = mode || WebInspector.ObjectTreeView.Mode.Properties;
-    this._propertyPath = propertyPath || new WebInspector.PropertyPath(this._object, "obj");
+    this._propertyPath = propertyPath || new WebInspector.PropertyPath(this._object, "this");
     this._expanded = false;
     this._hasLosslessPreview = false;
 
@@ -186,6 +186,14 @@ WebInspector.ObjectTreeView.prototype = {
         this._untrackWeakEntries();
     },
 
+    appendTitleSuffix: function(suffixElement)
+    {
+        if (this._previewView)
+            this._previewView.element.appendChild(suffixElement);
+        else
+            this._titleElement.appendChild(suffixElement);
+    },
+
     // Protected
 
     update: function()