Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Issue 959: Enable auto-completion of built-in members

  • Loading branch information...
commit cd315da08fd7d717f35778b22f96cb82cc682985 1 parent df926d8
Simon Lindholm authored October 13, 2012
404  extension/content/firebug/console/autoCompleter.js
@@ -4,7 +4,6 @@ define([
4 4
     "firebug/lib/object",
5 5
     "firebug/firebug",
6 6
     "firebug/lib/domplate",
7  
-    "firebug/chrome/reps",
8 7
     "firebug/lib/locale",
9 8
     "firebug/lib/events",
10 9
     "firebug/lib/wrapper",
@@ -13,14 +12,11 @@ define([
13 12
     "firebug/lib/array",
14 13
     "firebug/editor/editor"
15 14
 ],
16  
-function(Obj, Firebug, Domplate, FirebugReps, Locale, Events, Wrapper, Dom, Str, Arr, Editor) {
  15
+function(Obj, Firebug, Domplate, Locale, Events, Wrapper, Dom, Str, Arr, Editor) {
17 16
 
18 17
 // ********************************************************************************************* //
19 18
 // Constants
20 19
 
21  
-const Cc = Components.classes;
22  
-const Ci = Components.interfaces;
23  
-
24 20
 const kwActions = ["throw", "return", "in", "instanceof", "delete", "new",
25 21
                    "typeof", "void", "yield"];
26 22
 const reOpenBracket = /[\[\(\{]/;
@@ -44,7 +40,9 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
44 40
     this.completionBase = {
45 41
         pre: null,
46 42
         expr: null,
47  
-        candidates: []
  43
+        forceShowPopup: false,
  44
+        candidates: [],
  45
+        hiddenCandidates: []
48 46
     };
49 47
     this.completions = null;
50 48
 
@@ -79,7 +77,9 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
79 77
         this.completionBase = {
80 78
             pre: null,
81 79
             expr: null,
82  
-            candidates: []
  80
+            forceShowPopup: false,
  81
+            candidates: [],
  82
+            hiddenCandidates: []
83 83
         };
84 84
         this.completions = null;
85 85
 
@@ -94,6 +94,7 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
94 94
     this.hideForExpression = function()
95 95
     {
96 96
         this.completionBase.candidates = [];
  97
+        this.completionBase.hiddenCandidates = [];
97 98
         this.completions = null;
98 99
 
99 100
         this.showCompletions(false);
@@ -183,14 +184,17 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
183 184
         var prevCompletions = this.completions;
184 185
 
185 186
         // We only need to calculate a new candidate list if the expression has
186  
-        // changed (we can ignore this.completionBase.pre since completions do not
  187
+        // changed (we can ignore completionBase.pre since completions do not
187 188
         // depend upon that).
188 189
         if (preExpr !== this.completionBase.expr)
189 190
         {
190 191
             this.completionBase.expr = preExpr;
191  
-            this.completionBase.candidates = autoCompleteEval(context, preExpr, spreExpr,
  192
+            var ev = autoCompleteEval(context, preExpr, spreExpr,
192 193
                 this.options.includeCurrentScope);
193 194
             prevCompletions = null;
  195
+            this.completionBase.candidates = ev.completions;
  196
+            this.completionBase.hiddenCandidates = ev.hiddenCompletions;
  197
+            this.completionBase.forceShowPopup = false;
194 198
         }
195 199
 
196 200
         this.createCompletions(prop, prevCompletions);
@@ -205,9 +209,6 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
205 209
      */
206 210
     this.createCompletions = function(prefix, prevCompletions)
207 211
     {
208  
-        var candidates = this.completionBase.candidates;
209  
-        var valid = [], ciValid = [];
210  
-
211 212
         if (!this.completionBase.expr && !prefix)
212 213
         {
213 214
             // Don't complete "".
@@ -215,31 +216,41 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
215 216
             return;
216 217
         }
217 218
 
  219
+        var clist = [
  220
+            this.completionBase.candidates,
  221
+            this.completionBase.hiddenCandidates
  222
+        ], cind = 0;
  223
+        var valid = [], ciValid = [];
218 224
         var lowPrefix = prefix.toLowerCase();
219  
-        for (var i = 0; i < candidates.length; ++i)
  225
+        while (ciValid.length === 0 && cind < 2)
220 226
         {
221  
-            // Mark a candidate as matching if it matches the prefix case-
222  
-            // insensitively, and shares its upper-case characters.
223  
-            var name = candidates[i];
224  
-            if (!Str.hasPrefix(name.toLowerCase(), lowPrefix))
225  
-                continue;
226  
-
227  
-            var fail = false;
228  
-            for (var j = 0; j < prefix.length; ++j)
  227
+            var candidates = clist[cind];
  228
+            for (var i = 0; i < candidates.length; ++i)
229 229
             {
230  
-                var ch = prefix.charAt(j);
231  
-                if (ch !== ch.toLowerCase() && ch !== name.charAt(j))
  230
+                // Mark a candidate as matching if it matches the prefix case-
  231
+                // insensitively, and shares its upper-case characters.
  232
+                var name = candidates[i];
  233
+                if (!Str.hasPrefix(name.toLowerCase(), lowPrefix))
  234
+                    continue;
  235
+
  236
+                var fail = false;
  237
+                for (var j = 0; j < prefix.length; ++j)
232 238
                 {
233  
-                    fail = true;
234  
-                    break;
  239
+                    var ch = prefix.charAt(j);
  240
+                    if (ch !== ch.toLowerCase() && ch !== name.charAt(j))
  241
+                    {
  242
+                        fail = true;
  243
+                        break;
  244
+                    }
  245
+                }
  246
+                if (!fail)
  247
+                {
  248
+                    ciValid.push(name);
  249
+                    if (Str.hasPrefix(name, prefix))
  250
+                        valid.push(name);
235 251
                 }
236 252
             }
237  
-            if (!fail)
238  
-            {
239  
-                ciValid.push(name);
240  
-                if (Str.hasPrefix(name, prefix))
241  
-                    valid.push(name);
242  
-            }
  253
+            ++cind;
243 254
         }
244 255
 
245 256
         if (ciValid.length > 0)
@@ -250,18 +261,16 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
250 261
 
251 262
             this.completions = {
252 263
                 list: (hasMatchingCase ? valid : ciValid),
253  
-                prefix: prefix
  264
+                prefix: prefix,
  265
+                hidePopup: (cind === 2)
254 266
             };
255 267
             this.completions.index = this.pickDefaultCandidate(prevCompletions);
256 268
 
257 269
             if (hasMatchingCase)
258 270
             {
259 271
                 var find = valid[this.completions.index];
260  
-                this.completions = {
261  
-                    list: ciValid,
262  
-                    prefix: prefix,
263  
-                    index: ciValid.indexOf(find)
264  
-                };
  272
+                this.completions.list = ciValid;
  273
+                this.completions.index = ciValid.indexOf(find);
265 274
             }
266 275
         }
267 276
         else
@@ -290,7 +299,7 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
290 299
 
291 300
         // Special-case certain expressions.
292 301
         var special = {
293  
-            "": ["document", "console", "window", "parseInt", "undefined"],
  302
+            "": ["document", "console", "frames", "window", "parseInt", "undefined"],
294 303
             "window.": ["console"],
295 304
             "location.": ["href"],
296 305
             "document.": ["getElementById", "addEventListener", "createElement",
@@ -312,12 +321,32 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
312 321
             }
313 322
         }
314 323
 
  324
+        // 'prototype' is a good default if it exists.
  325
+        ind = list.indexOf("prototype");
  326
+        if (ind !== -1)
  327
+            return ind;
  328
+
315 329
         ind = 0;
316 330
         for (var i = 1; i < list.length; ++i)
317 331
         {
318 332
             if (list[i].length < list[ind].length)
319 333
                 ind = i;
320 334
         }
  335
+
  336
+        // Avoid some completions in favor of others.
  337
+        var replacements = {
  338
+            "toSource": "toString",
  339
+            "toFixed": "toString",
  340
+            "watch": "toString",
  341
+            "pattern": "parentNode"
  342
+        };
  343
+        if (replacements.hasOwnProperty(list[ind]))
  344
+        {
  345
+            var ind2 = list.indexOf(replacements[list[ind]]);
  346
+            if (ind2 !== -1)
  347
+                return ind2;
  348
+        }
  349
+
321 350
         return ind;
322 351
     };
323 352
 
@@ -378,12 +407,16 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
378 407
     {
379 408
         this.completionBox.value = this.getCompletionBoxValue();
380 409
 
381  
-        var show = this.showCompletionPopup ||
382  
-            (this.completionPopup && this.completionPopup.state === "open");
383  
-        if (show && this.completions && this.completions.list.length > 1)
  410
+        if (this.completions && (this.completionBase.forceShowPopup ||
  411
+            (this.completions.list.length > 1 && this.showCompletionPopup &&
  412
+             !this.completions.hidePopup)))
  413
+        {
384 414
             this.popupCandidates(cycling);
  415
+        }
385 416
         else
  417
+        {
386 418
             this.closePopup();
  419
+        }
387 420
     };
388 421
 
389 422
     /**
@@ -498,20 +531,24 @@ Firebug.JSAutoCompleter = function(textBox, completionBox, options)
498 531
             // does not close itself and prevent event propagation on keypress.
499 532
             // (Unless the popup is only open due to Ctrl+Space, in which case
500 533
             // that's precisely what we want.)
501  
-            if (this.showCompletionPopup)
  534
+            if (!this.forceShowPopup)
502 535
                 this.closePopup();
503 536
         }
504 537
         else if (event.keyCode === KeyEvent.DOM_VK_SPACE && Events.isControl(event))
505 538
         {
506  
-            // Force-show the completion popup.
507 539
             if (!this.completions)
508 540
             {
509 541
                 // If completions have been hidden, show them again.
510 542
                 this.hide();
511 543
                 this.complete(context);
512 544
             }
513  
-            if (this.completionPopup && this.completions)
  545
+
  546
+            if (this.completions && !this.isPopupOpen())
  547
+            {
  548
+                // Force-show the completion popup.
  549
+                this.completionBase.forceShowPopup = true;
514 550
                 this.popupCandidates(false);
  551
+            }
515 552
         }
516 553
     };
517 554
 
@@ -1271,8 +1308,7 @@ function killCompletions(expr, origExpr)
1271 1308
 }
1272 1309
 
1273 1310
 // Types the autocompletion knows about, some of their non-enumerable properties,
1274  
-// and the return types of some member functions, included in the Firebug.CommandLine
1275  
-// object to make it more easily extensible.
  1311
+// and the return types of some member functions.
1276 1312
 
1277 1313
 var AutoCompletionKnownTypes = {
1278 1314
     "void": {
@@ -1457,9 +1493,8 @@ var AutoCompletionKnownTypes = {
1457 1493
         "tan": "|Number"
1458 1494
     },
1459 1495
     "Number": {
1460  
-        // There are also toFixed and valueOf, but they are left out because
1461  
-        // they steal focus from toString by being shorter (in the case of
1462  
-        // toFixed), and because they are used very seldom.
  1496
+        "valueOf": "|Number",
  1497
+        "toFixed": "|String",
1463 1498
         "toExponential": "|String",
1464 1499
         "toPrecision": "|String",
1465 1500
         "toLocaleString": "|String",
@@ -1535,77 +1570,173 @@ function getTypeExtractionExpression(command)
1535 1570
     return ret;
1536 1571
 }
1537 1572
 
1538  
-function propChainBuildComplete(out, context, tempExpr, result)
  1573
+/**
  1574
+ * Compare two property names a and b with a custom sort order. The comparison
  1575
+ * is lexicographical, but treats _ as higher than other letters in the
  1576
+ * beginning of the word, so that:
  1577
+ *  $ < AutoCompleter < add_widget < additive < _ < _priv < __proto__
  1578
+ * @return -1, 0 or 1 depending on whether (a < b), (a == b) or (a > b).
  1579
+ */
  1580
+function comparePropertyNames(lhs, rhs)
1539 1581
 {
1540  
-    var complete = null, command = null;
1541  
-    if (tempExpr.fake)
  1582
+    var len = Math.min(lhs.length, rhs.length);
  1583
+    for (var i = 0; i < len; ++i)
1542 1584
     {
1543  
-        var name = tempExpr.value.val;
1544  
-        complete = getFakeCompleteKeys(name);
1545  
-        if (!getKnownType(name)._fb_ignorePrototype)
1546  
-            command = name + ".prototype";
  1585
+        var u1 = (lhs.charAt(i) === "_");
  1586
+        var u2 = (rhs.charAt(i) === "_");
  1587
+        if (!u1 && !u2)
  1588
+            break;
  1589
+        if (!u1 || !u2)
  1590
+            return (u1 ? 1 : -1);
1547 1591
     }
1548  
-    else
  1592
+
  1593
+    if (lhs < rhs)
  1594
+        return -1;
  1595
+    return (lhs === rhs ? 0 : 1);
  1596
+}
  1597
+
  1598
+function propertiesToHide(expr, obj)
  1599
+{
  1600
+    var ret = [];
  1601
+
  1602
+    // __{define,lookup}[SG]etter__ appear as own properties on lots of DOM objects.
  1603
+    ret.push("__defineGetter__", "__defineSetter__",
  1604
+        "__lookupGetter__", "__lookupSetter__");
  1605
+
  1606
+    // function.caller/argument are deprecated and ugly.
  1607
+    if (typeof obj === "function")
  1608
+        ret.push("caller", "arguments");
  1609
+
  1610
+    if (Object.prototype.toString.call(obj) === "[object String]")
1549 1611
     {
1550  
-        if (typeof result === "string")
1551  
-        {
1552  
-            // Strings only have indices as properties, use the fake object
1553  
-            // completions instead.
1554  
-            tempExpr.fake = true;
1555  
-            tempExpr.value = getKnownTypeInfo("String");
1556  
-            propChainBuildComplete(out, context, tempExpr);
1557  
-            return;
1558  
-        }
1559  
-        else if (FirebugReps.Arr.isArray(result, context.window))
1560  
-            complete = nonNumericKeys(result);
1561  
-        else
1562  
-            complete = Arr.keys(result);
1563  
-        command = getTypeExtractionExpression(tempExpr.command);
  1612
+        // Unused, cluttery.
  1613
+        ret.push("toLocaleLowerCase", "toLocaleUpperCase", "quote", "bold",
  1614
+            "italics", "fixed", "fontsize", "fontcolor", "link", "anchor",
  1615
+            "strike", "small", "big", "blink", "sup", "sub");
1564 1616
     }
1565 1617
 
1566  
-    var done = function()
  1618
+    // Annoying when typing 'document'/'window'.
  1619
+    if (expr === "")
1567 1620
     {
1568  
-        if (out.indexCompletion)
  1621
+        ret.push("Document", "DocumentType", "DocumentFragment",
  1622
+            "DocumentTouch", "DocumentXBL", "DOMTokenList",
  1623
+            "DOMConstructor", "DOMError", "DOMException",
  1624
+            "DOMImplementation", "DOMRequest", "DOMSettableTokenList",
  1625
+            "DOMStringMap", "DOMStringList", "Window", "WindowInternal",
  1626
+            "WindowCollection", "WindowUtils", "WindowPerformance");
  1627
+    }
  1628
+
  1629
+    if (expr === "" || expr === "window.")
  1630
+    {
  1631
+        // Internal Firefox things.
  1632
+        ret.push("getInterface", "Components", "XPCNativeWrapper",
  1633
+            "InstallTrigger", "netscape",
  1634
+            "startProfiling", "stopProfiling", "pauseProfilers",
  1635
+            "resumeProfilers", "dumpProfile");
  1636
+
  1637
+        // Hide ourselves.
  1638
+        ret.push("_FirebugCommandLine", "_firebug");
  1639
+    }
  1640
+
  1641
+    // Old and ugly.
  1642
+    if (expr === "document.")
  1643
+        ret.push("fgColor", "vlinkColor", "linkColor");
  1644
+    if (expr === "document.body.")
  1645
+        ret.push("link", "aLink", "vLink");
  1646
+
  1647
+    // Rather universal and feel like built-ins.
  1648
+    ret.push("valueOf", "toSource", "constructor", "QueryInterface");
  1649
+
  1650
+    return ret;
  1651
+}
  1652
+
  1653
+
  1654
+function setCompletionsFromObject(out, object, context)
  1655
+{
  1656
+    // 'object' is a user-level, non-null object.
  1657
+    try
  1658
+    {
  1659
+        var isObjectPrototype = function(obj)
1569 1660
         {
1570  
-            complete = complete.map(function(x)
  1661
+            // Check if an object is "Object.prototype". This isn't as simple
  1662
+            // as 'obj === context.window.wrappedJSObject.Object.prototype' due
  1663
+            // to cross-window properties, nor just '!Object.getPrototypeOf(obj)'
  1664
+            // because of Object.create.
  1665
+            return !Object.getPrototypeOf(obj) && "hasOwnProperty" in obj;
  1666
+        }
  1667
+
  1668
+        var obj = object;
  1669
+        while (obj !== null)
  1670
+        {
  1671
+            var target = (isObjectPrototype(obj) ?
  1672
+                    out.hiddenCompletions : out.completions);
  1673
+            target.push.apply(target, Object.getOwnPropertyNames(obj));
  1674
+            obj = Object.getPrototypeOf(obj);
  1675
+        }
  1676
+
  1677
+        // As a special case, when completing "Object.prototype." no properties
  1678
+        // should be hidden.
  1679
+        if (isObjectPrototype(object))
  1680
+        {
  1681
+            out.completions = out.hiddenCompletions;
  1682
+            out.hiddenCompletions = [];
  1683
+        }
  1684
+        else
  1685
+        {
  1686
+            // Hide a list of well-chosen annoying properties.
  1687
+            var hide = propertiesToHide(out.spreExpr, object);
  1688
+            var hideMap = Object.create(null);
  1689
+            for (var i = 0; i < hide.length; ++i)
  1690
+                hideMap[hide[i]] = 1;
  1691
+
  1692
+            var newCompletions = [];
  1693
+            out.completions.forEach(function(prop)
1571 1694
             {
1572  
-                x = (out.indexQuoteType === '"') ? Str.escapeJS(x): Str.escapeSingleQuoteJS(x);
1573  
-                return x + out.indexQuoteType + "]";
  1695
+                if (prop in hideMap)
  1696
+                    out.hiddenCompletions.push(prop);
  1697
+                else
  1698
+                    newCompletions.push(prop);
1574 1699
             });
  1700
+            out.completions = newCompletions;
1575 1701
         }
1576 1702
 
1577  
-        // Properties may be taken from several sources, so filter out duplicates.
1578  
-        out.complete = Arr.sortUnique(complete);
1579  
-    };
1580  
-
1581  
-    if (command === null)
  1703
+        // Firefox hides __proto__ - add it back.
  1704
+        if ("__proto__" in object)
  1705
+            out.hiddenCompletions.push("__proto__");
  1706
+    }
  1707
+    catch (exc)
1582 1708
     {
1583  
-        done();
  1709
+        if (FBTrace.DBG_COMMANDLINE)
  1710
+            FBTrace.sysout("autoCompleter.getCompletionsFromPrototypeChain failed", exc);
1584 1711
     }
1585  
-    else
  1712
+}
  1713
+
  1714
+function propChainBuildComplete(out, context, tempExpr, result)
  1715
+{
  1716
+    var done = function(result)
1586 1717
     {
1587  
-        Firebug.CommandLine.evaluate(command, context, context.thisValue, null,
  1718
+        if (result !== undefined && result !== null)
  1719
+            setCompletionsFromObject(out, Object(result), context);
  1720
+    };
  1721
+
  1722
+    if (tempExpr.fake)
  1723
+    {
  1724
+        var name = tempExpr.value.val;
  1725
+        if (getKnownType(name)._fb_ignorePrototype)
  1726
+            return;
  1727
+        var command = name + ".prototype";
  1728
+        Firebug.CommandLine.evaluate(name + ".prototype", context, context.thisValue, null,
1588 1729
             function found(result, context)
1589 1730
             {
1590  
-                if (tempExpr.fake)
1591  
-                {
1592  
-                    complete = complete.concat(Arr.keys(result));
1593  
-                }
1594  
-                else
1595  
-                {
1596  
-                    if (typeof result === "string" && getKnownType(result))
1597  
-                    {
1598  
-                        complete = complete.concat(getFakeCompleteKeys(result));
1599  
-                    }
1600  
-                }
1601  
-                done();
  1731
+                done(result);
1602 1732
             },
1603  
-            function failed(result, context)
1604  
-            {
1605  
-                done();
1606  
-            }
  1733
+            function failed(result, context) { }
1607 1734
         );
1608 1735
     }
  1736
+    else
  1737
+    {
  1738
+        done(result);
  1739
+    }
1609 1740
 }
1610 1741
 
1611 1742
 function evalPropChainStep(step, tempExpr, evalChain, out, context)
@@ -1896,9 +2027,12 @@ function evalPropChain(out, preExpr, origExpr, context)
1896 2027
 
1897 2028
 function autoCompleteEval(context, preExpr, spreExpr, includeCurrentScope)
1898 2029
 {
1899  
-    var out = {};
1900  
-
1901  
-    out.complete = [];
  2030
+    var out = {
  2031
+        spreExpr: spreExpr,
  2032
+        completions: [],
  2033
+        hiddenCompletions: []
  2034
+    };
  2035
+    var indexCompletion = false;
1902 2036
 
1903 2037
     try
1904 2038
     {
@@ -1908,11 +2042,10 @@ function autoCompleteEval(context, preExpr, spreExpr, includeCurrentScope)
1908 2042
 
1909 2043
             // In case of array indexing, remove the bracket and set a flag to
1910 2044
             // escape completions.
1911  
-            out.indexCompletion = false;
1912 2045
             var len = spreExpr.length;
1913 2046
             if (len >= 2 && spreExpr[len-2] === "[" && spreExpr[len-1] === '"')
1914 2047
             {
1915  
-                out.indexCompletion = true;
  2048
+                indexCompletion = true;
1916 2049
                 out.indexQuoteType = preExpr[len-1];
1917 2050
                 spreExpr = spreExpr.substr(0, len-2);
1918 2051
                 preExpr = preExpr.substr(0, len-2);
@@ -1934,7 +2067,7 @@ function autoCompleteEval(context, preExpr, spreExpr, includeCurrentScope)
1934 2067
 
1935 2068
             // Don't auto-complete '.'.
1936 2069
             if (spreExpr === "")
1937  
-                return out.complete;
  2070
+                return out;
1938 2071
 
1939 2072
             evalPropChain(out, spreExpr, preExpr, context);
1940 2073
         }
@@ -1945,32 +2078,53 @@ function autoCompleteEval(context, preExpr, spreExpr, includeCurrentScope)
1945 2078
             var contentView = Wrapper.getContentView(context.window);
1946 2079
             if (context.stopped && includeCurrentScope)
1947 2080
             {
1948  
-                out.complete = Firebug.Debugger.getCurrentFrameKeys(context);
  2081
+                out.completions = Firebug.Debugger.getCurrentFrameKeys(context);
1949 2082
             }
1950 2083
             else if (contentView && contentView.Window &&
1951 2084
                 contentView.constructor.toString() === contentView.Window.toString())
1952 2085
                 // Cross window type pseudo-comparison
1953 2086
             {
1954  
-                out.complete = Arr.keys(contentView); // return is safe
1955  
-
1956  
-                // Add some known window properties
1957  
-                out.complete = out.complete.concat(getFakeCompleteKeys("Window"));
  2087
+                setCompletionsFromObject(out, contentView, context);
1958 2088
             }
1959 2089
             else  // hopefully sandbox in Chromebug
1960 2090
             {
1961  
-                out.complete = Arr.keys(context.global);
  2091
+                setCompletionsFromObject(out, context.global, context);
  2092
+            }
  2093
+        }
  2094
+
  2095
+        // Add "] to properties if we are doing index-completions.
  2096
+        if (indexCompletion)
  2097
+        {
  2098
+            function convertQuotes(x)
  2099
+            {
  2100
+                x = (out.indexQuoteType === '"') ? Str.escapeJS(x): Str.escapeSingleQuoteJS(x);
  2101
+                return x + out.indexQuoteType + "]";
1962 2102
             }
  2103
+            out.completions = out.completions.map(convertQuotes);
  2104
+            out.hiddenCompletions = out.hiddenCompletions.map(convertQuotes);
  2105
+        }
1963 2106
 
1964  
-            // Sort the completions, and avoid duplicates.
1965  
-            out.complete = Arr.sortUnique(out.complete);
  2107
+        // Remove numeric keys.
  2108
+        var rePositiveNumber = /^[1-9][0-9]*$/;
  2109
+        var nonNumeric = function(x)
  2110
+        {
  2111
+            return x !== '0' && !rePositiveNumber.test(x);
1966 2112
         }
  2113
+        out.completions = out.completions.filter(nonNumeric);
  2114
+        out.hiddenCompletions = out.hiddenCompletions.filter(nonNumeric);
  2115
+
  2116
+        // Sort the completions, and avoid duplicates.
  2117
+        // XXX: If we make it possible to show both regular and hidden completions
  2118
+        // at the same time, completions must shadow hiddenCompletions.
  2119
+        out.completions = Arr.sortUnique(out.completions, comparePropertyNames);
  2120
+        out.hiddenCompletions = Arr.sortUnique(out.hiddenCompletions, comparePropertyNames);
1967 2121
     }
1968 2122
     catch (exc)
1969 2123
     {
1970 2124
         if (FBTrace.DBG_ERRORS && FBTrace.DBG_COMMANDLINE)
1971 2125
             FBTrace.sysout("commandLine.autoCompleteEval FAILED", exc);
1972 2126
     }
1973  
-    return out.complete;
  2127
+    return out;
1974 2128
 }
1975 2129
 
1976 2130
 var reValidJSToken = /^[A-Za-z_$][A-Za-z_$0-9]*$/;
@@ -1988,26 +2142,6 @@ function isValidProperty(value)
1988 2142
     return reValidJSToken.test(value);
1989 2143
 }
1990 2144
 
1991  
-const rePositiveNumber = /^[1-9][0-9]*$/;
1992  
-function nonNumericKeys(map)  // keys will be on user-level window objects
1993  
-{
1994  
-    var keys = [];
1995  
-    try
1996  
-    {
1997  
-        for (var name in map)  // enumeration is safe
1998  
-        {
1999  
-            if (! (name === "0" || rePositiveNumber.test(name)) )
2000  
-                keys.push(name);
2001  
-        }
2002  
-    }
2003  
-    catch (exc)
2004  
-    {
2005  
-        // Sometimes we get exceptions trying to iterate properties
2006  
-    }
2007  
-
2008  
-    return keys;  // return is safe
2009  
-}
2010  
-
2011 2145
 function setCursorToEOL(input)
2012 2146
 {
2013 2147
     // textbox version, https://developer.mozilla.org/en/XUL/Property/inputField
2  extension/content/firebug/js/debugger.js
@@ -124,7 +124,7 @@ Firebug.Debugger = Obj.extend(Firebug.ActivableModule,
124 124
 
125 125
     /**
126 126
      * Used by autocomplete in commandLine
127  
-     * @return array of global property names
  127
+     * @return array of locally visible property names for each scope we are in
128 128
      */
129 129
     getCurrentFrameKeys: function(context)  // TODO remote, on bti
130 130
     {

0 notes on commit cd315da

Please sign in to comment.
Something went wrong with that request. Please try again.