Title: [155134] trunk/Source/WebInspectorUI
Revision
155134
Author
joep...@webkit.org
Date
2013-09-05 11:01:00 -0700 (Thu, 05 Sep 2013)

Log Message

Web Inspector: Breakpoint Actions
https://bugs.webkit.org/show_bug.cgi?id=120576

Reviewed by Timothy Hatcher.

Give the CodeMirror editor for _javascript_ Breakpoint Actions JS Runtime
completions (like window, document, etc.).

The logic was inside of _javascript_LogViewController but was already
entirely independent. Factor it out into its own class and plug it into
CodeMirrorCompletionController as a "CompletionsProvider".

Because the class hooks into a global event to reset some state, make
it a singleton, so new instances are not leaked.

* UserInterface/Main.html:
* UserInterface/Main.js:
(WebInspector.loaded):
* UserInterface/RuntimeManager.js: Added.
(WebInspector.RuntimeManager):
(WebInspector.RuntimeManager.prototype.evalCallback):
(WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow):
Move eval in window to new RuntimeManager. A slightly cleaner place to this
since it is used both by the console and JS completions provider.

* UserInterface/CodeMirrorCompletionController.js:
(WebInspector.CodeMirrorCompletionController):
(WebInspector.CodeMirrorCompletionController.prototype.setExtendedCompletionProvider):
(WebInspector.CodeMirrorCompletionController.prototype._completeAtCurrentPosition):
Allow a completions provider plugin to completions controller. If one
is available, this supercedes the delegate extend completions path.

* UserInterface/BreakpointActionView.js:
* UserInterface/ConsolePrompt.js:
(WebInspector.ConsolePrompt):
Use the new JS completions provider to get runtime JS completions.
NOTE: ConsolePrompt still needs the delegate path for SQL completions.

* UserInterface/_javascript_LogViewController.js:
(WebInspector._javascript_LogViewController):
(WebInspector._javascript_LogViewController.prototype.consolePromptTextCommitted):
* UserInterface/_javascript_RuntimeCompletionProvider.js: Added.
(WebInspector._javascript_RuntimeCompletionProvider):
(get WebInspector._javascript_RuntimeCompletionProvider.prototype.):
(get WebInspector._javascript_RuntimeCompletionProvider.prototype.completionControllerCompletionsNeeded):
Move the JS completions code to a new class. No changes needed.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (155133 => 155134)


--- trunk/Source/WebInspectorUI/ChangeLog	2013-09-05 18:00:56 UTC (rev 155133)
+++ trunk/Source/WebInspectorUI/ChangeLog	2013-09-05 18:01:00 UTC (rev 155134)
@@ -5,6 +5,55 @@
 
         Reviewed by Timothy Hatcher.
 
+        Give the CodeMirror editor for _javascript_ Breakpoint Actions JS Runtime
+        completions (like window, document, etc.).
+
+        The logic was inside of _javascript_LogViewController but was already
+        entirely independent. Factor it out into its own class and plug it into
+        CodeMirrorCompletionController as a "CompletionsProvider".
+
+        Because the class hooks into a global event to reset some state, make
+        it a singleton, so new instances are not leaked.
+
+        * UserInterface/Main.html:
+        * UserInterface/Main.js:
+        (WebInspector.loaded):
+        * UserInterface/RuntimeManager.js: Added.
+        (WebInspector.RuntimeManager):
+        (WebInspector.RuntimeManager.prototype.evalCallback):
+        (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow):
+        Move eval in window to new RuntimeManager. A slightly cleaner place to this
+        since it is used both by the console and JS completions provider.
+
+        * UserInterface/CodeMirrorCompletionController.js:
+        (WebInspector.CodeMirrorCompletionController):
+        (WebInspector.CodeMirrorCompletionController.prototype.setExtendedCompletionProvider):
+        (WebInspector.CodeMirrorCompletionController.prototype._completeAtCurrentPosition):
+        Allow a completions provider plugin to completions controller. If one
+        is available, this supercedes the delegate extend completions path.
+
+        * UserInterface/BreakpointActionView.js:
+        * UserInterface/ConsolePrompt.js:
+        (WebInspector.ConsolePrompt):
+        Use the new JS completions provider to get runtime JS completions.
+        NOTE: ConsolePrompt still needs the delegate path for SQL completions.
+
+        * UserInterface/_javascript_LogViewController.js:
+        (WebInspector._javascript_LogViewController):
+        (WebInspector._javascript_LogViewController.prototype.consolePromptTextCommitted):
+        * UserInterface/_javascript_RuntimeCompletionProvider.js: Added.
+        (WebInspector._javascript_RuntimeCompletionProvider):
+        (get WebInspector._javascript_RuntimeCompletionProvider.prototype.):
+        (get WebInspector._javascript_RuntimeCompletionProvider.prototype.completionControllerCompletionsNeeded):
+        Move the JS completions code to a new class. No changes needed.
+
+2013-09-05  Joseph Pecoraro  <pecor...@apple.com>
+
+        Web Inspector: Breakpoint Actions
+        https://bugs.webkit.org/show_bug.cgi?id=120576
+
+        Reviewed by Timothy Hatcher.
+
         * UserInterface/Breakpoint.js:
         (WebInspector.Breakpoint):
         (WebInspector.Breakpoint.prototype.get actions):

Modified: trunk/Source/WebInspectorUI/UserInterface/BreakpointActionView.js (155133 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/BreakpointActionView.js	2013-09-05 18:00:56 UTC (rev 155133)
+++ trunk/Source/WebInspectorUI/UserInterface/BreakpointActionView.js	2013-09-05 18:01:00 UTC (rev 155134)
@@ -157,6 +157,7 @@
             this._codeMirror.on("blur", this._codeMirrorBlurred.bind(this));
 
             var completionController = new WebInspector.CodeMirrorCompletionController(this._codeMirror);
+            completionController.addExtendedCompletionProvider("_javascript_", WebInspector._javascript_RuntimeCompletionProvider);
 
             // CodeMirror needs a refresh after the popover displays, to layout, otherwise it doesn't appear.
             setTimeout(function() {

Modified: trunk/Source/WebInspectorUI/UserInterface/CodeMirrorCompletionController.js (155133 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/CodeMirrorCompletionController.js	2013-09-05 18:00:56 UTC (rev 155133)
+++ trunk/Source/WebInspectorUI/UserInterface/CodeMirrorCompletionController.js	2013-09-05 18:01:00 UTC (rev 155134)
@@ -38,6 +38,7 @@
     this._lineNumber = NaN;
     this._prefix = "";
     this._completions = [];
+    this._extendedCompletionProviders = {};
 
     this._suggestionsView = new WebInspector.CompletionSuggestionsView(this);
 
@@ -88,6 +89,11 @@
         return this._delegate;
     },
 
+    addExtendedCompletionProvider: function(modeName, provider)
+    {
+        this._extendedCompletionProviders[modeName] = provider;
+    },
+
     updateCompletions: function(completions, implicitSuffix)
     {
         if (isNaN(this._startOffset) || isNaN(this._endOffset) || isNaN(this._lineNumber))
@@ -498,6 +504,12 @@
             break;
         }
 
+        var extendedCompletionsProvider = this._extendedCompletionProviders[modeName];
+        if (extendedCompletionsProvider) {
+            extendedCompletionsProvider.completionControllerCompletionsNeeded(this, defaultCompletions, baseScanResult ? baseScanResult.string : null, this._prefix, suffix, force);
+            return;
+        }
+
         if (this._delegate && typeof this._delegate.completionControllerCompletionsNeeded === "function")
             this._delegate.completionControllerCompletionsNeeded(this, this._prefix, defaultCompletions, baseScanResult ? baseScanResult.string : null, suffix, force);
         else

Modified: trunk/Source/WebInspectorUI/UserInterface/ConsolePrompt.js (155133 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/ConsolePrompt.js	2013-09-05 18:00:56 UTC (rev 155133)
+++ trunk/Source/WebInspectorUI/UserInterface/ConsolePrompt.js	2013-09-05 18:01:00 UTC (rev 155134)
@@ -53,6 +53,7 @@
     this._codeMirror.addKeyMap(keyMap);
 
     this._completionController = new WebInspector.CodeMirrorCompletionController(this._codeMirror, this);
+    this._completionController.addExtendedCompletionProvider("_javascript_", WebInspector._javascript_RuntimeCompletionProvider);
 
     this._history = [{}];
     this._historyIndex = 0;

Modified: trunk/Source/WebInspectorUI/UserInterface/_javascript_LogViewController.js (155133 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/_javascript_LogViewController.js	2013-09-05 18:00:56 UTC (rev 155133)
+++ trunk/Source/WebInspectorUI/UserInterface/_javascript_LogViewController.js	2013-09-05 18:01:00 UTC (rev 155134)
@@ -59,8 +59,6 @@
     this._promptFindNextKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.Command, "G", this._handleFindNextShortcut.bind(this), this._prompt.element);
     this._promptFindPreviousKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.Command | WebInspector.KeyboardShortcut.Modifier.Shift, "G", this._handleFindPreviousShortcut.bind(this), this._prompt.element);
 
-    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, this._clearLastProperties, this);
-
     this.startNewSession();
 };
 
@@ -234,234 +232,11 @@
 
         text += "\n//# sourceURL=__WebInspectorConsole__\n";
 
-        this._evaluateInInspectedWindow(text, "console", true, false, false, printResult.bind(this));
+        WebInspector.runtimeManager.evaluateInInspectedWindow(text, "console", true, false, false, printResult.bind(this));
     },
 
-    consolePromptCompletionsNeeded: function(prompt, defaultCompletions, base, prefix, suffix, forced)
-    {
-        // Don't allow non-forced empty prefix completions unless the base is that start of property access.
-        if (!forced && !prefix && !/[.[]$/.test(base)) {
-            prompt.updateCompletions(null);
-            return;
-        }
-
-        // If the base ends with an open parentheses or open curly bracket then treat it like there is
-        // no base so we get global object completions.
-        if (/[({]$/.test(base))
-            base = "";
-
-        var lastBaseIndex = base.length - 1;
-        var dotNotation = base[lastBaseIndex] === ".";
-        var bracketNotation = base[lastBaseIndex] === "[";
-
-        if (dotNotation || bracketNotation) {
-            base = base.substring(0, lastBaseIndex);
-
-            // Don't suggest anything for an empty base that is using dot notation.
-            // Bracket notation with an empty base will be treated as an array.
-            if (!base && dotNotation) {
-                prompt.updateCompletions(defaultCompletions);
-                return;
-            }
-
-            // Don't allow non-forced empty prefix completions if the user is entering a number, since it might be a float.
-            // But allow number completions if the base already has a decimal, so "10.0." will suggest Number properties.
-            if (!forced && !prefix && dotNotation && base.indexOf(".") === -1 && parseInt(base, 10) == base) {
-                prompt.updateCompletions(null);
-                return;
-            }
-
-            // An empty base with bracket notation is not property access, it is an array.
-            // Clear the bracketNotation flag so completions are not quoted.
-            if (!base && bracketNotation)
-                bracketNotation = false;
-        }
-
-        // If the base is the same as the last time, we can reuse the property names we have already gathered.
-        // Doing this eliminates delay caused by the async nature of the code below and it only calls getters
-        // and functions once instead of repetitively. Sure, there can be difference each time the base is evaluated,
-        // but this optimization gives us more of a win. We clear the cache after 30 seconds or when stepping in the
-        // debugger to make sure we don't use stale properties in most cases.
-        if (this._lastBase === base && this._lastPropertyNames) {
-            receivedPropertyNames.call(this, this._lastPropertyNames);
-            return;
-        }
-
-        this._lastBase = base;
-        this._lastPropertyNames = null;
-
-        var activeCallFrame = WebInspector.debuggerManager.activeCallFrame;
-        if (!base && activeCallFrame)
-            activeCallFrame.collectScopeChainVariableNames(receivedPropertyNames.bind(this));
-        else
-            this._evaluateInInspectedWindow(base, "completion", true, true, false, evaluated.bind(this));
-
-        function updateLastPropertyNames(propertyNames)
-        {
-            if (this._clearLastPropertiesTimeout)
-                clearTimeout(this._clearLastPropertiesTimeout);
-            this._clearLastPropertiesTimeout = setTimeout(this._clearLastProperties.bind(this), WebInspector._javascript_LogViewController.CachedPropertiesDuration);
-
-            this._lastPropertyNames = propertyNames || {};
-        }
-
-        function evaluated(result, wasThrown)
-        {
-            if (wasThrown || !result || result.type === "undefined" || (result.type === "object" && result.subtype === "null")) {
-                RuntimeAgent.releaseObjectGroup("completion");
-
-                updateLastPropertyNames.call(this, {});
-                prompt.updateCompletions(defaultCompletions);
-
-                return;
-            }
-
-            function getCompletions(primitiveType)
-            {
-                var object;
-                if (primitiveType === "string")
-                    object = new String("");
-                else if (primitiveType === "number")
-                    object = new Number(0);
-                else if (primitiveType === "boolean")
-                    object = new Boolean(false);
-                else
-                    object = this;
-
-                var resultSet = {};
-                for (var o = object; o; o = o.__proto__) {
-                    try {
-                        var names = Object.getOwnPropertyNames(o);
-                        for (var i = 0; i < names.length; ++i)
-                            resultSet[names[i]] = true;
-                    } catch (e) {
-                        // Ignore
-                    }
-                }
-
-                return resultSet;
-            }
-
-            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")
-                this._evaluateInInspectedWindow("(" + getCompletions + ")(\"" + result.type + "\")", "completion", false, true, true, receivedPropertyNamesFromEvaluate.bind(this));
-            else
-                console.error("Unknown result type: " + result.type);
-        }
-
-        function receivedPropertyNamesFromEvaluate(object, wasThrown, result)
-        {
-            receivedPropertyNames.call(this, result && !wasThrown ? result.value : null);
-        }
-
-        function receivedPropertyNames(propertyNames)
-        {
-            propertyNames = propertyNames || {};
-
-            updateLastPropertyNames.call(this, propertyNames);
-
-            RuntimeAgent.releaseObjectGroup("completion");
-
-            if (!base) {
-                const commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$1", "$2", "$3", "$4", "$_"];
-                for (var i = 0; i < commandLineAPI.length; ++i)
-                    propertyNames[commandLineAPI[i]] = true;
-            }
-
-            propertyNames = Object.keys(propertyNames);
-
-            var implicitSuffix = "";
-            if (bracketNotation) {
-                var quoteUsed = prefix[0] === "'" ? "'" : "\"";
-                if (suffix !== "]" && suffix !== quoteUsed)
-                    implicitSuffix = "]";
-            }
-
-            var completions = defaultCompletions;
-            var knownCompletions = completions.keySet();
-
-            for (var i = 0; i < propertyNames.length; ++i) {
-                var property = propertyNames[i];
-
-                if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property))
-                    continue;
-
-                if (bracketNotation) {
-                    if (parseInt(property) != property)
-                        property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + (suffix !== quoteUsed ? quoteUsed : "");
-                }
-
-                if (!property.startsWith(prefix) || property in knownCompletions)
-                    continue;
-
-                completions.push(property);
-                knownCompletions[property] = true;
-            }
-
-            function compare(a, b)
-            {
-                // Try to sort in numerical order first.
-                var numericCompareResult = a - b;
-                if (!isNaN(numericCompareResult))
-                    return numericCompareResult;
-
-                // Not numbers, sort as strings.
-                return a.localeCompare(b);
-            }
-
-            completions.sort(compare);
-
-            prompt.updateCompletions(completions, implicitSuffix);
-        }
-    },
-
     // Private
 
-    _clearLastProperties: function()
-    {
-        if (this._clearLastPropertiesTimeout) {
-            clearTimeout(this._clearLastPropertiesTimeout);
-            delete this._clearLastPropertiesTimeout;
-        }
-
-        // Clear the cache of property names so any changes while stepping or sitting idle get picked up if the same
-        // _expression_ is evaluated again.
-        this._lastPropertyNames = null;
-    },
-
-    _evaluateInInspectedWindow: function(_expression_, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback)
-    {
-        if (!_expression_) {
-            // There is no _expression_, so the completion should happen against global properties.
-            _expression_ = "this";
-        }
-
-        function evalCallback(error, result, wasThrown)
-        {
-            if (error) {
-                console.error(error);
-                callback(null, false);
-                return;
-            }
-
-            if (returnByValue)
-                callback(null, wasThrown, wasThrown ? null : result);
-            else
-                callback(WebInspector.RemoteObject.fromPayload(result), wasThrown);
-        }
-
-        if (WebInspector.debuggerManager.activeCallFrame) {
-            DebuggerAgent.evaluateOnCallFrame(WebInspector.debuggerManager.activeCallFrame.id, _expression_, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, evalCallback);
-            return;
-        }
-
-        // COMPATIBILITY (iOS 6): Execution context identifiers (contextId) did not exist
-        // in iOS 6. Fallback to including the frame identifier (frameId).
-        var contextId = WebInspector.quickConsole.executionContextIdentifier;
-        RuntimeAgent.evaluate.invoke({_expression_: _expression_, objectGroup: objectGroup, includeCommandLineAPI: includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole: doNotPauseOnExceptionsAndMuteConsole, contextId: contextId, frameId: contextId, returnByValue: returnByValue}, evalCallback);
-    },
-
     _handleClearShortcut: function()
     {
         this.clear();

Added: trunk/Source/WebInspectorUI/UserInterface/_javascript_RuntimeCompletionProvider.js (0 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/_javascript_RuntimeCompletionProvider.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/_javascript_RuntimeCompletionProvider.js	2013-09-05 18:01:00 UTC (rev 155134)
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector._javascript_RuntimeCompletionProvider = function()
+{
+    WebInspector.Object.call(this);
+
+    console.assert(!WebInspector._javascript_RuntimeCompletionProvider._instance);
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, this._clearLastProperties, this);
+};
+
+Object.defineProperty(WebInspector, "_javascript_RuntimeCompletionProvider",
+{
+    get: function()
+    {
+        if (!WebInspector._javascript_RuntimeCompletionProvider._instance)
+            WebInspector._javascript_RuntimeCompletionProvider._instance = new WebInspector._javascript_RuntimeCompletionProvider;
+        return WebInspector._javascript_RuntimeCompletionProvider._instance;
+    }
+});
+
+WebInspector._javascript_RuntimeCompletionProvider.prototype = {
+    constructor: WebInspector._javascript_RuntimeCompletionProvider,
+
+    // Protected
+
+    completionControllerCompletionsNeeded: function(completionController, defaultCompletions, base, prefix, suffix, forced)
+    {
+        // Don't allow non-forced empty prefix completions unless the base is that start of property access.
+        if (!forced && !prefix && !/[.[]$/.test(base)) {
+            completionController.updateCompletions(null);
+            return;
+        }
+
+        // If the base ends with an open parentheses or open curly bracket then treat it like there is
+        // no base so we get global object completions.
+        if (/[({]$/.test(base))
+            base = "";
+
+        var lastBaseIndex = base.length - 1;
+        var dotNotation = base[lastBaseIndex] === ".";
+        var bracketNotation = base[lastBaseIndex] === "[";
+
+        if (dotNotation || bracketNotation) {
+            base = base.substring(0, lastBaseIndex);
+
+            // Don't suggest anything for an empty base that is using dot notation.
+            // Bracket notation with an empty base will be treated as an array.
+            if (!base && dotNotation) {
+                completionController.updateCompletions(defaultCompletions);
+                return;
+            }
+
+            // Don't allow non-forced empty prefix completions if the user is entering a number, since it might be a float.
+            // But allow number completions if the base already has a decimal, so "10.0." will suggest Number properties.
+            if (!forced && !prefix && dotNotation && base.indexOf(".") === -1 && parseInt(base, 10) == base) {
+                completionController.updateCompletions(null);
+                return;
+            }
+
+            // An empty base with bracket notation is not property access, it is an array.
+            // Clear the bracketNotation flag so completions are not quoted.
+            if (!base && bracketNotation)
+                bracketNotation = false;
+        }
+
+        // If the base is the same as the last time, we can reuse the property names we have already gathered.
+        // Doing this eliminates delay caused by the async nature of the code below and it only calls getters
+        // and functions once instead of repetitively. Sure, there can be difference each time the base is evaluated,
+        // but this optimization gives us more of a win. We clear the cache after 30 seconds or when stepping in the
+        // debugger to make sure we don't use stale properties in most cases.
+        if (this._lastBase === base && this._lastPropertyNames) {
+            receivedPropertyNames.call(this, this._lastPropertyNames);
+            return;
+        }
+
+        this._lastBase = base;
+        this._lastPropertyNames = null;
+
+        var activeCallFrame = WebInspector.debuggerManager.activeCallFrame;
+        if (!base && activeCallFrame && !this._alwaysEvaluateInWindowContext)
+            activeCallFrame.collectScopeChainVariableNames(receivedPropertyNames.bind(this));
+        else
+            WebInspector.runtimeManager.evaluateInInspectedWindow(base, "completion", true, true, false, evaluated.bind(this));
+
+        function updateLastPropertyNames(propertyNames)
+        {
+            if (this._clearLastPropertiesTimeout)
+                clearTimeout(this._clearLastPropertiesTimeout);
+            this._clearLastPropertiesTimeout = setTimeout(this._clearLastProperties.bind(this), WebInspector._javascript_LogViewController.CachedPropertiesDuration);
+
+            this._lastPropertyNames = propertyNames || {};
+        }
+
+        function evaluated(result, wasThrown)
+        {
+            if (wasThrown || !result || result.type === "undefined" || (result.type === "object" && result.subtype === "null")) {
+                RuntimeAgent.releaseObjectGroup("completion");
+
+                updateLastPropertyNames.call(this, {});
+                completionController.updateCompletions(defaultCompletions);
+
+                return;
+            }
+
+            function getCompletions(primitiveType)
+            {
+                var object;
+                if (primitiveType === "string")
+                    object = new String("");
+                else if (primitiveType === "number")
+                    object = new Number(0);
+                else if (primitiveType === "boolean")
+                    object = new Boolean(false);
+                else
+                    object = this;
+
+                var resultSet = {};
+                for (var o = object; o; o = o.__proto__) {
+                    try {
+                        var names = Object.getOwnPropertyNames(o);
+                        for (var i = 0; i < names.length; ++i)
+                            resultSet[names[i]] = true;
+                    } catch (e) {
+                        // Ignore
+                    }
+                }
+
+                return resultSet;
+            }
+
+            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, receivedPropertyNamesFromEvaluate.bind(this));
+            else
+                console.error("Unknown result type: " + result.type);
+        }
+
+        function receivedPropertyNamesFromEvaluate(object, wasThrown, result)
+        {
+            receivedPropertyNames.call(this, result && !wasThrown ? result.value : null);
+        }
+
+        function receivedPropertyNames(propertyNames)
+        {
+            propertyNames = propertyNames || {};
+
+            updateLastPropertyNames.call(this, propertyNames);
+
+            RuntimeAgent.releaseObjectGroup("completion");
+
+            if (!base) {
+                const commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$1", "$2", "$3", "$4", "$_"];
+                for (var i = 0; i < commandLineAPI.length; ++i)
+                    propertyNames[commandLineAPI[i]] = true;
+            }
+
+            propertyNames = Object.keys(propertyNames);
+
+            var implicitSuffix = "";
+            if (bracketNotation) {
+                var quoteUsed = prefix[0] === "'" ? "'" : "\"";
+                if (suffix !== "]" && suffix !== quoteUsed)
+                    implicitSuffix = "]";
+            }
+
+            var completions = defaultCompletions;
+            var knownCompletions = completions.keySet();
+
+            for (var i = 0; i < propertyNames.length; ++i) {
+                var property = propertyNames[i];
+
+                if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property))
+                    continue;
+
+                if (bracketNotation) {
+                    if (parseInt(property) != property)
+                        property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + (suffix !== quoteUsed ? quoteUsed : "");
+                }
+
+                if (!property.startsWith(prefix) || property in knownCompletions)
+                    continue;
+
+                completions.push(property);
+                knownCompletions[property] = true;
+            }
+
+            function compare(a, b)
+            {
+                // Try to sort in numerical order first.
+                var numericCompareResult = a - b;
+                if (!isNaN(numericCompareResult))
+                    return numericCompareResult;
+
+                // Not numbers, sort as strings.
+                return a.localeCompare(b);
+            }
+
+            completions.sort(compare);
+
+            completionController.updateCompletions(completions, implicitSuffix);
+        }
+    },
+
+    // Private
+
+    _clearLastProperties: function()
+    {
+        if (this._clearLastPropertiesTimeout) {
+            clearTimeout(this._clearLastPropertiesTimeout);
+            delete this._clearLastPropertiesTimeout;
+        }
+
+        // Clear the cache of property names so any changes while stepping or sitting idle get picked up if the same
+        // _expression_ is evaluated again.
+        this._lastPropertyNames = null;
+    }
+};
+
+WebInspector._javascript_RuntimeCompletionProvider.prototype.__proto__ = WebInspector.Object.prototype;

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (155133 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2013-09-05 18:00:56 UTC (rev 155133)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2013-09-05 18:01:00 UTC (rev 155134)
@@ -185,6 +185,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -384,6 +385,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.js (155133 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/Main.js	2013-09-05 18:00:56 UTC (rev 155133)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.js	2013-09-05 18:01:00 UTC (rev 155134)
@@ -73,6 +73,7 @@
     this.cssStyleManager = new WebInspector.CSSStyleManager;
     this.logManager = new WebInspector.LogManager;
     this.issueManager = new WebInspector.IssueManager;
+    this.runtimeManager = new WebInspector.RuntimeManager;
     this.applicationCacheManager = new WebInspector.ApplicationCacheManager;
     this.timelineManager = new WebInspector.TimelineManager;
     this.profileManager = new WebInspector.ProfileManager;
@@ -84,10 +85,6 @@
     // Enable the Console Agent after creating the singleton managers.
     ConsoleAgent.enable();
 
-    // Enable the RuntimeAgent to receive notification of execution contexts.
-    if (RuntimeAgent.enable)
-        RuntimeAgent.enable();
-
     // Register for events.
     this.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Paused, this._debuggerDidPause, this);
     this.domTreeManager.addEventListener(WebInspector.DOMTreeManager.Event.InspectModeStateChanged, this._inspectModeStateChanged, this);

Added: trunk/Source/WebInspectorUI/UserInterface/RuntimeManager.js (0 => 155134)


--- trunk/Source/WebInspectorUI/UserInterface/RuntimeManager.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/RuntimeManager.js	2013-09-05 18:01:00 UTC (rev 155134)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.RuntimeManager = function()
+{
+    WebInspector.Object.call(this);
+
+    // Enable the RuntimeAgent to receive notification of execution contexts.
+    if (RuntimeAgent.enable)
+        RuntimeAgent.enable();
+};
+
+WebInspector.RuntimeManager.prototype = {
+    constructor: WebInspector.RuntimeManager,
+
+    // Public
+
+    evaluateInInspectedWindow: function(_expression_, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback)
+    {
+        if (!_expression_) {
+            // There is no _expression_, so the completion should happen against global properties.
+            _expression_ = "this";
+        }
+
+        function evalCallback(error, result, wasThrown)
+        {
+            if (error) {
+                console.error(error);
+                callback(null, false);
+                return;
+            }
+
+            if (returnByValue)
+                callback(null, wasThrown, wasThrown ? null : result);
+            else
+                callback(WebInspector.RemoteObject.fromPayload(result), wasThrown);
+        }
+
+        if (WebInspector.debuggerManager.activeCallFrame) {
+            DebuggerAgent.evaluateOnCallFrame(WebInspector.debuggerManager.activeCallFrame.id, _expression_, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, evalCallback);
+            return;
+        }
+
+        // COMPATIBILITY (iOS 6): Execution context identifiers (contextId) did not exist
+        // in iOS 6. Fallback to including the frame identifier (frameId).
+        var contextId = WebInspector.quickConsole.executionContextIdentifier;
+        RuntimeAgent.evaluate.invoke({_expression_: _expression_, objectGroup: objectGroup, includeCommandLineAPI: includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole: doNotPauseOnExceptionsAndMuteConsole, contextId: contextId, frameId: contextId, returnByValue: returnByValue}, evalCallback);
+    }
+};
+
+WebInspector.RuntimeManager.prototype.__proto__ = WebInspector.Object.prototype;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to