Backout bug 776875, bug 773347, bug 775031, bug 773565 due to test failures. a=orange
authorRob Campbell <rcampbell@mozilla.com>
Fri, 24 Aug 2012 09:27:30 -0400
changeset 103441 f4596ef17eed20290eb9b62fb2089272544d4ac9
parent 103440 35e5ee61e193771a906a39c7d21e66651cf03ae0
child 103442 ebb525cd2e7018a51b30c4a687fd66505f471828
push id13991
push userryanvm@gmail.com
push dateSun, 26 Aug 2012 02:29:03 +0000
treeherdermozilla-inbound@c4f20a024113 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersorange
bugs776875, 773347, 775031, 773565
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout bug 776875, bug 773347, bug 775031, bug 773565 due to test failures. a=orange
browser/devtools/commandline/CmdAddon.jsm
browser/devtools/commandline/CmdBreak.jsm
browser/devtools/commandline/CmdCalllog.jsm
browser/devtools/commandline/CmdCmd.jsm
browser/devtools/commandline/CmdConsole.jsm
browser/devtools/commandline/CmdCookie.jsm
browser/devtools/commandline/CmdDbg.jsm
browser/devtools/commandline/CmdEcho.jsm
browser/devtools/commandline/CmdExport.jsm
browser/devtools/commandline/CmdJsb.jsm
browser/devtools/commandline/CmdPagemod.jsm
browser/devtools/commandline/CmdRestart.jsm
browser/devtools/commandline/CmdScreenshot.jsm
browser/devtools/commandline/Commands.jsm
browser/devtools/commandline/GcliCommands.jsm
browser/devtools/commandline/GcliCookieCommands.jsm
browser/devtools/commandline/GcliTiltCommands.jsm
browser/devtools/commandline/commandline.css
browser/devtools/commandline/commandlineoutput.xhtml
browser/devtools/commandline/commandlinetooltip.xhtml
browser/devtools/commandline/gcli.css
browser/devtools/commandline/gcli.jsm
browser/devtools/commandline/gclioutput.xhtml
browser/devtools/commandline/gclitooltip.xhtml
browser/devtools/commandline/test/Makefile.in
browser/devtools/commandline/test/browser_cmd_addon.js
browser/devtools/commandline/test/browser_cmd_calllog.js
browser/devtools/commandline/test/browser_cmd_commands.js
browser/devtools/commandline/test/browser_cmd_cookie.js
browser/devtools/commandline/test/browser_cmd_integrate.js
browser/devtools/commandline/test/browser_cmd_jsb.js
browser/devtools/commandline/test/browser_cmd_jsb_script.jsi
browser/devtools/commandline/test/browser_cmd_pagemod_export.html
browser/devtools/commandline/test/browser_cmd_pagemod_export.js
browser/devtools/commandline/test/browser_cmd_pref.js
browser/devtools/commandline/test/browser_cmd_restart.js
browser/devtools/commandline/test/browser_cmd_settings.js
browser/devtools/commandline/test/browser_dbg_cmd.html
browser/devtools/commandline/test/browser_dbg_cmd.js
browser/devtools/commandline/test/browser_dbg_cmd_break.html
browser/devtools/commandline/test/browser_dbg_cmd_break.js
browser/devtools/commandline/test/browser_gcli_addon.js
browser/devtools/commandline/test/browser_gcli_break.html
browser/devtools/commandline/test/browser_gcli_break.js
browser/devtools/commandline/test/browser_gcli_calllog.js
browser/devtools/commandline/test/browser_gcli_commands.js
browser/devtools/commandline/test/browser_gcli_cookie.js
browser/devtools/commandline/test/browser_gcli_dbg.js
browser/devtools/commandline/test/browser_gcli_edit.js
browser/devtools/commandline/test/browser_gcli_inspect.html
browser/devtools/commandline/test/browser_gcli_inspect.js
browser/devtools/commandline/test/browser_gcli_integrate.js
browser/devtools/commandline/test/browser_gcli_jsb.js
browser/devtools/commandline/test/browser_gcli_pagemod_export.js
browser/devtools/commandline/test/browser_gcli_pref.js
browser/devtools/commandline/test/browser_gcli_responsivemode.js
browser/devtools/commandline/test/browser_gcli_restart.js
browser/devtools/commandline/test/browser_gcli_settings.js
browser/devtools/commandline/test/browser_gcli_web.js
browser/devtools/commandline/test/head.js
browser/devtools/commandline/test/helpers.js
browser/devtools/commandline/test/resources.html
browser/devtools/commandline/test/resources_dbg.html
browser/devtools/commandline/test/resources_inpage.js
browser/devtools/commandline/test/resources_inpage1.css
browser/devtools/commandline/test/resources_inpage2.css
browser/devtools/commandline/test/resources_jsb_script.js
browser/devtools/highlighter/CmdInspect.jsm
browser/devtools/highlighter/Makefile.in
browser/devtools/highlighter/test/Makefile.in
browser/devtools/highlighter/test/browser_inspector_cmd_inspect.html
browser/devtools/highlighter/test/browser_inspector_cmd_inspect.js
browser/devtools/highlighter/test/head.js
browser/devtools/highlighter/test/helpers.js
browser/devtools/jar.mn
browser/devtools/responsivedesign/CmdResize.jsm
browser/devtools/responsivedesign/test/Makefile.in
browser/devtools/responsivedesign/test/browser_responsive_cmd.js
browser/devtools/responsivedesign/test/head.js
browser/devtools/responsivedesign/test/helpers.js
browser/devtools/shared/DeveloperToolbar.jsm
browser/devtools/shared/test/Makefile.in
browser/devtools/shared/test/head.js
browser/devtools/shared/test/helpers.js
browser/devtools/shared/test/leakhunt.js
browser/devtools/styleeditor/CmdEdit.jsm
browser/devtools/styleeditor/test/Makefile.in
browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.html
browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js
browser/devtools/styleeditor/test/head.js
browser/devtools/styleeditor/test/helpers.js
browser/devtools/styleeditor/test/resources_inpage.jsi
browser/devtools/styleeditor/test/resources_inpage1.css
browser/devtools/styleeditor/test/resources_inpage2.css
browser/devtools/tilt/CmdTilt.jsm
browser/themes/gnomestripe/devtools/commandline.css
browser/themes/gnomestripe/devtools/gcli.css
browser/themes/gnomestripe/jar.mn
browser/themes/pinstripe/devtools/commandline.css
browser/themes/pinstripe/devtools/gcli.css
browser/themes/pinstripe/jar.mn
browser/themes/winstripe/devtools/commandline.css
browser/themes/winstripe/devtools/gcli.css
browser/themes/winstripe/jar.mn
deleted file mode 100644
--- a/browser/devtools/commandline/CmdAddon.jsm
+++ /dev/null
@@ -1,290 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
-                                  "resource://gre/modules/AddonManager.jsm");
-
-/**
- * 'addon' command.
- */
-gcli.addCommand({
-  name: "addon",
-  description: gcli.lookup("addonDesc")
-});
-
-/**
- * 'addon list' command.
- */
-gcli.addCommand({
-  name: "addon list",
-  description: gcli.lookup("addonListDesc"),
-  params: [{
-    name: 'type',
-    type: {
-      name: 'selection',
-      data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
-    },
-    defaultValue: 'all',
-    description: gcli.lookup("addonListTypeDesc"),
-  }],
-  exec: function(aArgs, context) {
-    function representEnabledAddon(aAddon) {
-      return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
-      getAddonStatus(aAddon) + "]]></li>";
-    }
-
-    function representDisabledAddon(aAddon) {
-      return "<li class=\"gcli-addon-disabled\">" +
-        "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
-        "]]></li>";
-    }
-
-    function getAddonStatus(aAddon) {
-      let operations = [];
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
-        operations.push("PENDING_ENABLE");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
-        operations.push("PENDING_DISABLE");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
-        operations.push("PENDING_UNINSTALL");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
-        operations.push("PENDING_INSTALL");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
-        operations.push("PENDING_UPGRADE");
-      }
-
-      if (operations.length) {
-        return " (" + operations.join(", ") + ")";
-      }
-      return "";
-    }
-
-    /**
-     * Compares two addons by their name. Used in sorting.
-     */
-    function compareAddonNames(aNameA, aNameB) {
-      return String.localeCompare(aNameA.name, aNameB.name);
-    }
-
-    /**
-     * Resolves the promise which is the scope (this) of this function, filling
-     * it with an HTML representation of the passed add-ons.
-     */
-    function list(aType, aAddons) {
-      if (!aAddons.length) {
-        this.resolve(gcli.lookup("addonNoneOfType"));
-      }
-
-      // Separate the enabled add-ons from the disabled ones.
-      let enabledAddons = [];
-      let disabledAddons = [];
-
-      aAddons.forEach(function(aAddon) {
-        if (aAddon.isActive) {
-          enabledAddons.push(aAddon);
-        } else {
-          disabledAddons.push(aAddon);
-        }
-      });
-
-      let header;
-      switch(aType) {
-        case "dictionary":
-          header = gcli.lookup("addonListDictionaryHeading");
-          break;
-        case "extension":
-          header = gcli.lookup("addonListExtensionHeading");
-          break;
-        case "locale":
-          header = gcli.lookup("addonListLocaleHeading");
-          break;
-        case "plugin":
-          header = gcli.lookup("addonListPluginHeading");
-          break;
-        case "theme":
-          header = gcli.lookup("addonListThemeHeading");
-        case "all":
-          header = gcli.lookup("addonListAllHeading");
-          break;
-        default:
-          header = gcli.lookup("addonListUnknownHeading");
-      }
-
-      // Map and sort the add-ons, and create an HTML list.
-      this.resolve(header +
-        "<ol>" +
-        enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
-        disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
-        "</ol>");
-    }
-
-    // Create the promise that will be resolved when the add-on listing has
-    // been finished.
-    let promise = context.createPromise();
-    let types = aArgs.type == "all" ? null : [aArgs.type];
-    AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
-    return promise;
-  }
-});
-
-// We need a list of addon names for the enable and disable commands. Because
-// getting the name list is async we do not add the commands until we have the
-// list.
-AddonManager.getAllAddons(function addonAsync(aAddons) {
-  // We listen for installs to keep our addon list up to date. There is no need
-  // to listen for uninstalls because uninstalled addons are simply disabled
-  // until restart (to enable undo functionality).
-  AddonManager.addAddonListener({
-    onInstalled: function(aAddon) {
-      addonNameCache.push({
-        name: representAddon(aAddon).replace(/\s/g, "_"),
-        value: aAddon.name
-      });
-    },
-    onUninstalled: function(aAddon) {
-      let name = representAddon(aAddon).replace(/\s/g, "_");
-
-      for (let i = 0; i < addonNameCache.length; i++) {
-        if(addonNameCache[i].name == name) {
-          addonNameCache.splice(i, 1);
-          break;
-        }
-      }
-    },
-  });
-
-  /**
-   * Returns a string that represents the passed add-on.
-   */
-  function representAddon(aAddon) {
-    let name = aAddon.name + " " + aAddon.version;
-    return name.trim();
-  }
-
-  let addonNameCache = [];
-
-  // The name parameter, used in "addon enable" and "addon disable."
-  let nameParameter = {
-    name: "name",
-    type: {
-      name: "selection",
-      lookup: addonNameCache
-    },
-    description: gcli.lookup("addonNameDesc")
-  };
-
-  for (let addon of aAddons) {
-    addonNameCache.push({
-      name: representAddon(addon).replace(/\s/g, "_"),
-      value: addon.name
-    });
-  }
-
-  /**
-   * 'addon enable' command.
-   */
-  gcli.addCommand({
-    name: "addon enable",
-    description: gcli.lookup("addonEnableDesc"),
-    params: [nameParameter],
-    exec: function(aArgs, context) {
-      /**
-       * Enables the addon in the passed list which has a name that matches
-       * according to the passed name comparer, and resolves the promise which
-       * is the scope (this) of this function to display the result of this
-       * enable attempt.
-       */
-      function enable(aName, addons) {
-        // Find the add-on.
-        let addon = null;
-        addons.some(function(candidate) {
-          if (candidate.name == aName) {
-            addon = candidate;
-            return true;
-          } else {
-            return false;
-          }
-        });
-
-        let name = representAddon(addon);
-
-        if (!addon.userDisabled) {
-          this.resolve("<![CDATA[" +
-            gcli.lookupFormat("addonAlreadyEnabled", [name]) + "]]>");
-        } else {
-          addon.userDisabled = false;
-          // nl-nl: {$1} is ingeschakeld.
-          this.resolve("<![CDATA[" +
-            gcli.lookupFormat("addonEnabled", [name]) + "]]>");
-        }
-      }
-
-      let promise = context.createPromise();
-      // List the installed add-ons, enable one when done listing.
-      AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
-      return promise;
-    }
-  });
-
-  /**
-   * 'addon disable' command.
-   */
-  gcli.addCommand({
-    name: "addon disable",
-    description: gcli.lookup("addonDisableDesc"),
-    params: [nameParameter],
-    exec: function(aArgs, context) {
-      /**
-       * Like enable, but ... you know ... the exact opposite.
-       */
-      function disable(aName, addons) {
-        // Find the add-on.
-        let addon = null;
-        addons.some(function(candidate) {
-          if (candidate.name == aName) {
-            addon = candidate;
-            return true;
-          } else {
-            return false;
-          }
-        });
-
-        let name = representAddon(addon);
-
-        if (addon.userDisabled) {
-          this.resolve("<![CDATA[" +
-            gcli.lookupFormat("addonAlreadyDisabled", [name]) + "]]>");
-        } else {
-          addon.userDisabled = true;
-          // nl-nl: {$1} is uitgeschakeld.
-          this.resolve("<![CDATA[" +
-            gcli.lookupFormat("addonDisabled", [name]) + "]]>");
-        }
-      }
-
-      let promise = context.createPromise();
-      // List the installed add-ons, disable one when done listing.
-      AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
-      return promise;
-    }
-  });
-  Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdBreak.jsm
+++ /dev/null
@@ -1,170 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                  "resource:///modules/HUDService.jsm");
-
-/**
- * 'break' command
- */
-gcli.addCommand({
-  name: "break",
-  description: gcli.lookup("breakDesc"),
-  manual: gcli.lookup("breakManual")
-});
-
-
-/**
- * 'break list' command
- */
-gcli.addCommand({
-  name: "break list",
-  description: gcli.lookup("breaklistDesc"),
-  returnType: "html",
-  exec: function(args, context) {
-    let win = HUDService.currentContext();
-    let dbg = win.DebuggerUI.getDebugger();
-    if (!dbg) {
-      return gcli.lookup("breakaddDebuggerStopped");
-    }
-    let breakpoints = dbg.breakpoints;
-
-    if (Object.keys(breakpoints).length === 0) {
-      return gcli.lookup("breaklistNone");
-    }
-
-    let reply = gcli.lookup("breaklistIntro");
-    reply += "<ol>";
-    for each (let breakpoint in breakpoints) {
-      let text = gcli.lookupFormat("breaklistLineEntry",
-                                   [breakpoint.location.url,
-                                    breakpoint.location.line]);
-      reply += "<li>" + text + "</li>";
-    };
-    reply += "</ol>";
-    return reply;
-  }
-});
-
-
-/**
- * 'break add' command
- */
-gcli.addCommand({
-  name: "break add",
-  description: gcli.lookup("breakaddDesc"),
-  manual: gcli.lookup("breakaddManual")
-});
-
-/**
- * 'break add line' command
- */
-gcli.addCommand({
-  name: "break add line",
-  description: gcli.lookup("breakaddlineDesc"),
-  params: [
-    {
-      name: "file",
-      type: {
-        name: "selection",
-        data: function() {
-          let win = HUDService.currentContext();
-          let dbg = win.DebuggerUI.getDebugger();
-          let files = [];
-          if (dbg) {
-            let scriptsView = dbg.contentWindow.DebuggerView.Scripts;
-            for each (let script in scriptsView.scriptLocations) {
-              files.push(script);
-            }
-          }
-          return files;
-        }
-      },
-      description: gcli.lookup("breakaddlineFileDesc")
-    },
-    {
-      name: "line",
-      type: { name: "number", min: 1, step: 10 },
-      description: gcli.lookup("breakaddlineLineDesc")
-    }
-  ],
-  returnType: "html",
-  exec: function(args, context) {
-    args.type = "line";
-    let win = HUDService.currentContext();
-    let dbg = win.DebuggerUI.getDebugger();
-    if (!dbg) {
-      return gcli.lookup("breakaddDebuggerStopped");
-    }
-    var promise = context.createPromise();
-    let position = { url: args.file, line: args.line };
-    dbg.addBreakpoint(position, function(aBreakpoint, aError) {
-      if (aError) {
-        promise.resolve(gcli.lookupFormat("breakaddFailed", [aError]));
-        return;
-      }
-      promise.resolve(gcli.lookup("breakaddAdded"));
-    });
-    return promise;
-  }
-});
-
-
-/**
- * 'break del' command
- */
-gcli.addCommand({
-  name: "break del",
-  description: gcli.lookup("breakdelDesc"),
-  params: [
-    {
-      name: "breakid",
-      type: {
-        name: "number",
-        min: 0,
-        max: function() {
-          let win = HUDService.currentContext();
-          let dbg = win.DebuggerUI.getDebugger();
-          if (!dbg) {
-            return gcli.lookup("breakaddDebuggerStopped");
-          }
-          return Object.keys(dbg.breakpoints).length - 1;
-        },
-      },
-      description: gcli.lookup("breakdelBreakidDesc")
-    }
-  ],
-  returnType: "html",
-  exec: function(args, context) {
-    let win = HUDService.currentContext();
-    let dbg = win.DebuggerUI.getDebugger();
-    if (!dbg) {
-      return gcli.lookup("breakaddDebuggerStopped");
-    }
-
-    let breakpoints = dbg.breakpoints;
-    let id = Object.keys(dbg.breakpoints)[args.breakid];
-    if (!id || !(id in breakpoints)) {
-      return gcli.lookup("breakNotFound");
-    }
-
-    let promise = context.createPromise();
-    try {
-      dbg.removeBreakpoint(breakpoints[id], function() {
-        promise.resolve(gcli.lookup("breakdelRemoved"));
-      });
-    } catch (ex) {
-      // If the debugger has been closed already, don't scare the user.
-      promise.resolve(gcli.lookup("breakdelRemoved"));
-    }
-    return promise;
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdCalllog.jsm
+++ /dev/null
@@ -1,103 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                  "resource:///modules/HUDService.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
-  let JsDebugger = {};
-  Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
-
-  let global = Components.utils.getGlobalForObject({});
-  JsDebugger.addDebuggerToGlobal(global);
-
-  return global.Debugger;
-});
-
-let debuggers = [];
-
-/**
- * 'calllog' command
- */
-gcli.addCommand({
-  name: "calllog",
-  description: gcli.lookup("calllogDesc")
-})
-
-/**
- * 'calllog start' command
- */
-gcli.addCommand({
-  name: "calllog start",
-  description: gcli.lookup("calllogStartDesc"),
-
-  exec: function(args, context) {
-    let contentWindow = context.environment.contentDocument.defaultView;
-
-    let dbg = new Debugger(contentWindow);
-    dbg.onEnterFrame = function(frame) {
-      // BUG 773652 -  Make the output from the GCLI calllog command nicer
-      contentWindow.console.log("Method call: " + this.callDescription(frame));
-    }.bind(this);
-
-    debuggers.push(dbg);
-
-    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab;
-    HUDService.activateHUDForContext(tab);
-
-    return gcli.lookup("calllogStartReply");
-  },
-
-  callDescription: function(frame) {
-    let name = "<anonymous>";
-    if (frame.callee.name) {
-      name = frame.callee.name;
-    }
-    else {
-      let desc = frame.callee.getOwnPropertyDescriptor("displayName");
-      if (desc && desc.value && typeof desc.value == "string") {
-        name = desc.value;
-      }
-    }
-
-    let args = frame.arguments.map(this.valueToString).join(", ");
-    return name + "(" + args + ")";
-  },
-
-  valueToString: function(value) {
-    if (typeof value !== "object" || value === null) {
-      return uneval(value);
-    }
-    return "[object " + value.class + "]";
-  }
-});
-
-/**
- * 'calllog stop' command
- */
-gcli.addCommand({
-  name: "calllog stop",
-  description: gcli.lookup("calllogStopDesc"),
-
-  exec: function(args, context) {
-    let numDebuggers = debuggers.length;
-    if (numDebuggers == 0) {
-      return gcli.lookup("calllogStopNoLogging");
-    }
-
-    for (let dbg of debuggers) {
-      dbg.onEnterFrame = undefined;
-    }
-    debuggers = [];
-
-    return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]);
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdCmd.jsm
+++ /dev/null
@@ -1,129 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-let EXPORTED_SYMBOLS = [ "CmdCommands" ];
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-let prefSvc = "@mozilla.org/preferences-service;1";
-XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
-  let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
-  return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
-});
-
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
-                                  "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "console",
-                                  "resource:///modules/devtools/Console.jsm");
-
-const PREF_DIR = "devtools.commands.dir";
-
-/**
- * A place to store the names of the commands that we have added as a result of
- * calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
- * added commands.
- */
-let commands = [];
-
-/**
- * Exported API
- */
-let CmdCommands = {
-  /**
-   * Called to look in a directory pointed at by the devtools.commands.dir pref
-   * for *.mozcmd files which are then loaded.
-   * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
-   * we eval the script from the .mozcmd file. This should be a chrome window.
-   */
-  refreshAutoCommands: function GC_refreshAutoCommands(aSandboxPrincipal) {
-    // First get rid of the last set of commands
-    commands.forEach(function(name) {
-      gcli.removeCommand(name);
-    });
-
-    let dirName = prefBranch.getComplexValue(PREF_DIR,
-                                             Ci.nsISupportsString).data.trim();
-    if (dirName == "") {
-      return;
-    }
-
-    let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
-    dir.initWithPath(dirName);
-    if (!dir.exists() || !dir.isDirectory()) {
-      throw new Error('\'' + dirName + '\' is not a directory.');
-    }
-
-    let en = dir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
-
-    while (true) {
-      let file = en.nextFile;
-      if (!file) {
-        break;
-      }
-      if (file.leafName.match(/.*\.mozcmd$/) && file.isFile() && file.isReadable()) {
-        loadCommandFile(file, aSandboxPrincipal);
-      }
-    }
-  },
-};
-
-/**
- * Load the commands from a single file
- * @param nsIFile aFile The file containing the commands that we should read
- * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
- * we eval the script from the .mozcmd file. This should be a chrome window.
- */
-function loadCommandFile(aFile, aSandboxPrincipal) {
-  NetUtil.asyncFetch(aFile, function refresh_fetch(aStream, aStatus) {
-    if (!Components.isSuccessCode(aStatus)) {
-      console.error("NetUtil.asyncFetch(" + aFile.path + ",..) failed. Status=" + aStatus);
-      return;
-    }
-
-    let source = NetUtil.readInputStreamToString(aStream, aStream.available());
-    aStream.close();
-
-    let sandbox = new Cu.Sandbox(aSandboxPrincipal, {
-      sandboxPrototype: aSandboxPrincipal,
-      wantXrays: false,
-      sandboxName: aFile.path
-    });
-    let data = Cu.evalInSandbox(source, sandbox, "1.8", aFile.leafName, 1);
-
-    if (!Array.isArray(data)) {
-      console.error("Command file '" + aFile.leafName + "' does not have top level array.");
-      return;
-    }
-
-    data.forEach(function(commandSpec) {
-      gcli.addCommand(commandSpec);
-      commands.push(commandSpec.name);
-    });
-  }.bind(this));
-}
-
-/**
- * 'cmd' command
- */
-gcli.addCommand({
-  name: "cmd",
-  get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
-  description: gcli.lookup("cmdDesc")
-});
-
-/**
- * 'cmd refresh' command
- */
-gcli.addCommand({
-  name: "cmd refresh",
-  description: gcli.lookup("cmdRefreshDesc"),
-  get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
-  exec: function Command_cmdRefresh(args, context) {
-    let chromeWindow = context.environment.chromeDocument.defaultView;
-    GcliCommands.refreshAutoCommands(chromeWindow);
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdConsole.jsm
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                  "resource:///modules/HUDService.jsm");
-
-/**
- * 'console' command
- */
-gcli.addCommand({
-  name: "console",
-  description: gcli.lookup("consoleDesc"),
-  manual: gcli.lookup("consoleManual")
-});
-
-/**
- * 'console clear' command
- */
-gcli.addCommand({
-  name: "console clear",
-  description: gcli.lookup("consoleclearDesc"),
-  exec: function Command_consoleClear(args, context) {
-    let window = context.environment.contentDocument.defaultView;
-    let hud = HUDService.getHudByWindow(window);
-    // hud will be null if the web console has not been opened for this window
-    if (hud) {
-      hud.jsterm.clearOutput();
-    }
-  }
-});
-
-/**
- * 'console close' command
- */
-gcli.addCommand({
-  name: "console close",
-  description: gcli.lookup("consolecloseDesc"),
-  exec: function Command_consoleClose(args, context) {
-    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
-    HUDService.deactivateHUDForContext(tab);
-  }
-});
-
-/**
- * 'console open' command
- */
-gcli.addCommand({
-  name: "console open",
-  description: gcli.lookup("consoleopenDesc"),
-  exec: function Command_consoleOpen(args, context) {
-    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
-    HUDService.activateHUDForContext(tab);
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdDbg.jsm
+++ /dev/null
@@ -1,136 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-/**
- * 'dbg' command
- */
-gcli.addCommand({
-  name: "dbg",
-  description: gcli.lookup("dbgDesc"),
-  manual: gcli.lookup("dbgManual")
-});
-
-
-/**
- * 'dbg interrupt' command
- */
-gcli.addCommand({
-  name: "dbg interrupt",
-  description: gcli.lookup("dbgInterrupt"),
-  params: [],
-  exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
-
-    if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
-      let thread = controller.activeThread;
-      if (!thread.paused) {
-        thread.interrupt();
-      }
-    }
-  }
-});
-
-/**
- * 'dbg continue' command
- */
-gcli.addCommand({
-  name: "dbg continue",
-  description: gcli.lookup("dbgContinue"),
-  params: [],
-  exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
-
-    if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
-      let thread = controller.activeThread;
-      if (thread.paused) {
-        thread.resume();
-      }
-    }
-  }
-});
-
-
-/**
- * 'dbg step' command
- */
-gcli.addCommand({
-  name: "dbg step",
-  description: gcli.lookup("dbgStepDesc"),
-  manual: gcli.lookup("dbgStepManual")
-});
-
-
-/**
- * 'dbg step over' command
- */
-gcli.addCommand({
-  name: "dbg step over",
-  description: gcli.lookup("dbgStepOverDesc"),
-  params: [],
-  exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
-
-    if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
-      let thread = controller.activeThread;
-      if (thread.paused) {
-        thread.stepOver();
-      }
-    }
-  }
-});
-
-/**
- * 'dbg step in' command
- */
-gcli.addCommand({
-  name: 'dbg step in',
-  description: gcli.lookup("dbgStepInDesc"),
-  params: [],
-  exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
-
-    if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
-      let thread = controller.activeThread;
-      if (thread.paused) {
-        thread.stepIn();
-      }
-    }
-  }
-});
-
-/**
- * 'dbg step over' command
- */
-gcli.addCommand({
-  name: 'dbg step out',
-  description: gcli.lookup("dbgStepOutDesc"),
-  params: [],
-  exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
-
-    if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
-      let thread = controller.activeThread;
-      if (thread.paused) {
-        thread.stepOut();
-      }
-    }
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdEcho.jsm
+++ /dev/null
@@ -1,29 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'echo' command
- */
-gcli.addCommand({
-  name: "echo",
-  description: gcli.lookup("echoDesc"),
-  params: [
-    {
-      name: "message",
-      type: "string",
-      description: gcli.lookup("echoMessageDesc")
-    }
-  ],
-  returnType: "string",
-  hidden: true,
-  exec: function Command_echo(args, context) {
-    return args.message;
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdExport.jsm
+++ /dev/null
@@ -1,31 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'export' command
- */
-gcli.addCommand({
-  name: "export",
-  description: gcli.lookup("exportDesc"),
-});
-
-/**
- * The 'export html' command. This command allows the user to export the page to
- * HTML after they do DOM changes.
- */
-gcli.addCommand({
-  name: "export html",
-  description: gcli.lookup("exportHtmlDesc"),
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-    let window = document.defaultView;
-    let page = document.documentElement.outerHTML;
-    window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdJsb.jsm
+++ /dev/null
@@ -1,136 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-const XMLHttpRequest =
-  Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "js_beautify",
-                                  "resource:///modules/devtools/Jsbeautify.jsm");
-
-/**
- * jsb command.
- */
-gcli.addCommand({
-  name: 'jsb',
-  description: gcli.lookup('jsbDesc'),
-  returnValue:'string',
-  params: [
-    {
-      name: 'url',
-      type: 'string',
-      description: gcli.lookup('jsbUrlDesc'),
-      manual: 'The URL of the JS to prettify'
-    },
-    {
-      name: 'indentSize',
-      type: 'number',
-      description: gcli.lookup('jsbIndentSizeDesc'),
-      manual: gcli.lookup('jsbIndentSizeManual'),
-      defaultValue: 2
-    },
-    {
-      name: 'indentChar',
-      type: {
-        name: 'selection',
-        lookup: [
-          { name: "space", value: " " },
-          { name: "tab", value: "\t" }
-        ]
-      },
-      description: gcli.lookup('jsbIndentCharDesc'),
-      manual: gcli.lookup('jsbIndentCharManual'),
-      defaultValue: ' ',
-    },
-    {
-      name: 'preserveNewlines',
-      type: 'boolean',
-      description: gcli.lookup('jsbPreserveNewlinesDesc'),
-      manual: gcli.lookup('jsbPreserveNewlinesManual')
-    },
-    {
-      name: 'preserveMaxNewlines',
-      type: 'number',
-      description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
-      manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
-      defaultValue: -1
-    },
-    {
-      name: 'jslintHappy',
-      type: 'boolean',
-      description: gcli.lookup('jsbJslintHappyDesc'),
-      manual: gcli.lookup('jsbJslintHappyManual')
-    },
-    {
-      name: 'braceStyle',
-      type: {
-        name: 'selection',
-        data: ['collapse', 'expand', 'end-expand', 'expand-strict']
-      },
-      description: gcli.lookup('jsbBraceStyleDesc'),
-      manual: gcli.lookup('jsbBraceStyleManual'),
-      defaultValue: "collapse"
-    },
-    {
-      name: 'spaceBeforeConditional',
-      type: 'boolean',
-      description: gcli.lookup('jsbSpaceBeforeConditionalDesc'),
-      manual: gcli.lookup('jsbSpaceBeforeConditionalManual')
-    },
-    {
-      name: 'unescapeStrings',
-      type: 'boolean',
-      description: gcli.lookup('jsbUnescapeStringsDesc'),
-      manual: gcli.lookup('jsbUnescapeStringsManual')
-    }
-  ],
-  exec: function(args, context) {
-    let opts = {
-      indent_size: args.indentSize,
-      indent_char: args.indentChar,
-      preserve_newlines: args.preserveNewlines,
-      max_preserve_newlines: args.preserveMaxNewlines == -1 ?
-                             undefined : args.preserveMaxNewlines,
-      jslint_happy: args.jslintHappy,
-      brace_style: args.braceStyle,
-      space_before_conditional: args.spaceBeforeConditional,
-      unescape_strings: args.unescapeStrings
-    }
-
-    let xhr = new XMLHttpRequest();
-
-    try {
-      xhr.open("GET", args.url, true);
-    } catch(e) {
-      return gcli.lookup('jsbInvalidURL');
-    }
-
-    let promise = context.createPromise();
-
-    xhr.onreadystatechange = function(aEvt) {
-      if (xhr.readyState == 4) {
-        if (xhr.status == 200 || xhr.status == 0) {
-          let browserDoc = context.environment.chromeDocument;
-          let browserWindow = browserDoc.defaultView;
-          let browser = browserWindow.gBrowser;
-  
-          browser.selectedTab = browser.addTab("data:text/plain;base64," +
-            browserWindow.btoa(js_beautify(xhr.responseText, opts)));
-          promise.resolve();
-        }
-        else {
-          promise.resolve("Unable to load page to beautify: " + args.url + " " +
-                          xhr.status + " " + xhr.statusText);
-        }
-      };
-    }
-    xhr.send(null);
-    return promise;
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdPagemod.jsm
+++ /dev/null
@@ -1,264 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'pagemod' command
- */
-gcli.addCommand({
-  name: "pagemod",
-  description: gcli.lookup("pagemodDesc"),
-});
-
-/**
- * The 'pagemod replace' command. This command allows the user to search and
- * replace within text nodes and attributes.
- */
-gcli.addCommand({
-  name: "pagemod replace",
-  description: gcli.lookup("pagemodReplaceDesc"),
-  params: [
-    {
-      name: "search",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceSearchDesc"),
-    },
-    {
-      name: "replace",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceReplaceDesc"),
-    },
-    {
-      name: "ignoreCase",
-      type: "boolean",
-      description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
-    },
-    {
-      name: "selector",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceSelectorDesc"),
-      defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
-    },
-    {
-      name: "root",
-      type: "node",
-      description: gcli.lookup("pagemodReplaceRootDesc"),
-      defaultValue: null,
-    },
-    {
-      name: "attrOnly",
-      type: "boolean",
-      description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
-    },
-    {
-      name: "contentOnly",
-      type: "boolean",
-      description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
-    },
-    {
-      name: "attributes",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceAttributesDesc"),
-      defaultValue: null,
-    },
-  ],
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-    let searchTextNodes = !args.attrOnly;
-    let searchAttributes = !args.contentOnly;
-    let regexOptions = args.ignoreCase ? 'ig' : 'g';
-    let search = new RegExp(escapeRegex(args.search), regexOptions);
-    let attributeRegex = null;
-    if (args.attributes) {
-      attributeRegex = new RegExp(args.attributes, regexOptions);
-    }
-
-    let root = args.root || document;
-    let elements = root.querySelectorAll(args.selector);
-    elements = Array.prototype.slice.call(elements);
-
-    let replacedTextNodes = 0;
-    let replacedAttributes = 0;
-
-    function replaceAttribute() {
-      replacedAttributes++;
-      return args.replace;
-    }
-    function replaceTextNode() {
-      replacedTextNodes++;
-      return args.replace;
-    }
-
-    for (let i = 0; i < elements.length; i++) {
-      let element = elements[i];
-      if (searchTextNodes) {
-        for (let y = 0; y < element.childNodes.length; y++) {
-          let node = element.childNodes[y];
-          if (node.nodeType == node.TEXT_NODE) {
-            node.textContent = node.textContent.replace(search, replaceTextNode);
-          }
-        }
-      }
-
-      if (searchAttributes) {
-        if (!element.attributes) {
-          continue;
-        }
-        for (let y = 0; y < element.attributes.length; y++) {
-          let attr = element.attributes[y];
-          if (!attributeRegex || attributeRegex.test(attr.name)) {
-            attr.value = attr.value.replace(search, replaceAttribute);
-          }
-        }
-      }
-    }
-
-    return gcli.lookupFormat("pagemodReplaceResult",
-                             [elements.length, replacedTextNodes,
-                              replacedAttributes]);
-  }
-});
-
-/**
- * 'pagemod remove' command
- */
-gcli.addCommand({
-  name: "pagemod remove",
-  description: gcli.lookup("pagemodRemoveDesc"),
-});
-
-
-/**
- * The 'pagemod remove element' command.
- */
-gcli.addCommand({
-  name: "pagemod remove element",
-  description: gcli.lookup("pagemodRemoveElementDesc"),
-  params: [
-    {
-      name: "search",
-      type: "string",
-      description: gcli.lookup("pagemodRemoveElementSearchDesc"),
-    },
-    {
-      name: "root",
-      type: "node",
-      description: gcli.lookup("pagemodRemoveElementRootDesc"),
-      defaultValue: null,
-    },
-    {
-      name: 'stripOnly',
-      type: 'boolean',
-      description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
-    },
-    {
-      name: 'ifEmptyOnly',
-      type: 'boolean',
-      description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
-    },
-  ],
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-    let root = args.root || document;
-    let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
-
-    let removed = 0;
-    for (let i = 0; i < elements.length; i++) {
-      let element = elements[i];
-      let parentNode = element.parentNode;
-      if (!parentNode || !element.removeChild) {
-        continue;
-      }
-      if (args.stripOnly) {
-        while (element.hasChildNodes()) {
-          parentNode.insertBefore(element.childNodes[0], element);
-        }
-      }
-      if (!args.ifEmptyOnly || !element.hasChildNodes()) {
-        element.parentNode.removeChild(element);
-        removed++;
-      }
-    }
-
-    return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
-                             [elements.length, removed]);
-  }
-});
-
-/**
- * The 'pagemod remove attribute' command.
- */
-gcli.addCommand({
-  name: "pagemod remove attribute",
-  description: gcli.lookup("pagemodRemoveAttributeDesc"),
-  params: [
-    {
-      name: "searchAttributes",
-      type: "string",
-      description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
-    },
-    {
-      name: "searchElements",
-      type: "string",
-      description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
-    },
-    {
-      name: "root",
-      type: "node",
-      description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
-      defaultValue: null,
-    },
-    {
-      name: "ignoreCase",
-      type: "boolean",
-      description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
-    },
-  ],
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-
-    let root = args.root || document;
-    let regexOptions = args.ignoreCase ? 'ig' : 'g';
-    let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
-    let elements = root.querySelectorAll(args.searchElements);
-    elements = Array.prototype.slice.call(elements);
-
-    let removed = 0;
-    for (let i = 0; i < elements.length; i++) {
-      let element = elements[i];
-      if (!element.attributes) {
-        continue;
-      }
-
-      var attrs = Array.prototype.slice.call(element.attributes);
-      for (let y = 0; y < attrs.length; y++) {
-        let attr = attrs[y];
-        if (attributeRegex.test(attr.name)) {
-          element.removeAttribute(attr.name);
-          removed++;
-        }
-      }
-    }
-
-    return gcli.lookupFormat("pagemodRemoveAttributeResult",
-                             [elements.length, removed]);
-  }
-});
-
-/**
- * Make a given string safe to use  in a regular expression.
- *
- * @param string aString
- *        The string you want to use in a regex.
- * @return string
- *         The equivalent of |aString| but safe to use in a regex.
- */
-function escapeRegex(aString) {
-  return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
-}
deleted file mode 100644
--- a/browser/devtools/commandline/CmdRestart.jsm
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-/**
- * Restart command
- *
- * @param boolean nocache
- *        Disables loading content from cache upon restart.
- *
- * Examples :
- * >> restart
- * - restarts browser immediately
- * >> restart --nocache
- * - restarts immediately and starts Firefox without using cache
- */
-gcli.addCommand({
-  name: "restart",
-  description: gcli.lookup("restartFirefoxDesc"),
-  params: [
-    {
-      name: "nocache",
-      type: "boolean",
-      description: gcli.lookup("restartFirefoxNocacheDesc")
-    }
-  ],
-  returnType: "string",
-  exec: function Restart(args, context) {
-    let canceled = Cc["@mozilla.org/supports-PRBool;1"]
-                     .createInstance(Ci.nsISupportsPRBool);
-    Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
-    if (canceled.data) {
-      return gcli.lookup("restartFirefoxRequestCancelled");
-    }
-
-    // disable loading content from cache.
-    if (args.nocache) {
-      Services.appinfo.invalidateCachesOnRestart();
-    }
-
-    // restart
-    Cc['@mozilla.org/toolkit/app-startup;1']
-      .getService(Ci.nsIAppStartup)
-      .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
-    return gcli.lookup("restartFirefoxRestarting");
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdScreenshot.jsm
+++ /dev/null
@@ -1,134 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
-                                  "resource:///modules/devtools/LayoutHelpers.jsm");
-
-/**
- * 'screenshot' command
- */
-gcli.addCommand({
-  name: "screenshot",
-  description: gcli.lookup("screenshotDesc"),
-  manual: gcli.lookup("screenshotManual"),
-  returnType: "string",
-  params: [
-    {
-      name: "filename",
-      type: "string",
-      description: gcli.lookup("screenshotFilenameDesc"),
-      manual: gcli.lookup("screenshotFilenameManual")
-    },
-    {
-      name: "delay",
-      type: { name: "number", min: 0 },
-      defaultValue: 0,
-      description: gcli.lookup("screenshotDelayDesc"),
-      manual: gcli.lookup("screenshotDelayManual")
-    },
-    {
-      name: "fullpage",
-      type: "boolean",
-      description: gcli.lookup("screenshotFullPageDesc"),
-      manual: gcli.lookup("screenshotFullPageManual")
-    },
-    {
-      name: "node",
-      type: "node",
-      defaultValue: null,
-      description: gcli.lookup("inspectNodeDesc"),
-      manual: gcli.lookup("inspectNodeManual")
-    }
-  ],
-  exec: function Command_screenshot(args, context) {
-    var document = context.environment.contentDocument;
-    if (args.delay > 0) {
-      var promise = context.createPromise();
-      document.defaultView.setTimeout(function Command_screenshotDelay() {
-        let reply = this.grabScreen(document, args.filename);
-        promise.resolve(reply);
-      }.bind(this), args.delay * 1000);
-      return promise;
-    }
-    else {
-      return this.grabScreen(document, args.filename, args.fullpage, args.node);
-    }
-  },
-  grabScreen:
-  function Command_screenshotGrabScreen(document, filename, fullpage, node) {
-    let window = document.defaultView;
-    let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
-    let left = 0;
-    let top = 0;
-    let width;
-    let height;
-
-    if (!fullpage) {
-      if (!node) {
-        left = window.scrollX;
-        top = window.scrollY;
-        width = window.innerWidth;
-        height = window.innerHeight;
-      } else {
-        let rect = LayoutHelpers.getRect(node, window);
-        top = rect.top;
-        left = rect.left;
-        width = rect.width;
-        height = rect.height;
-      }
-    } else {
-      width = window.innerWidth + window.scrollMaxX;
-      height = window.innerHeight + window.scrollMaxY;
-    }
-    canvas.width = width;
-    canvas.height = height;
-
-    let ctx = canvas.getContext("2d");
-    ctx.drawWindow(window, left, top, width, height, "#fff");
-
-    let data = canvas.toDataURL("image/png", "");
-    let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
-
-    // Check there is a .png extension to filename
-    if (!filename.match(/.png$/i)) {
-      filename += ".png";
-    }
-
-    // If the filename is relative, tack it onto the download directory
-    if (!filename.match(/[\\\/]/)) {
-      let downloadMgr = Cc["@mozilla.org/download-manager;1"]
-        .getService(Ci.nsIDownloadManager);
-      let tempfile = downloadMgr.userDownloadsDirectory;
-      tempfile.append(filename);
-      filename = tempfile.path;
-    }
-
-    try {
-      file.initWithPath(filename);
-    } catch (ex) {
-      return "Error saving to " + filename;
-    }
-
-    let ioService = Cc["@mozilla.org/network/io-service;1"]
-      .getService(Ci.nsIIOService);
-
-    let Persist = Ci.nsIWebBrowserPersist;
-    let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
-      .createInstance(Persist);
-    persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
-                           Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
-
-    let source = ioService.newURI(data, "UTF8", null);
-    persist.saveURI(source, null, null, null, null, file);
-
-    return "Saved to " + filename;
-  }
-});
rename from browser/devtools/commandline/Commands.jsm
rename to browser/devtools/commandline/GcliCommands.jsm
--- a/browser/devtools/commandline/Commands.jsm
+++ b/browser/devtools/commandline/GcliCommands.jsm
@@ -1,25 +1,1549 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
-let EXPORTED_SYMBOLS = [ ];
+let EXPORTED_SYMBOLS = [ "GcliCommands" ];
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+const XMLHttpRequest =
+  Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
+
+Cu.import("resource:///modules/devtools/gcli.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
+                                  "resource:///modules/HUDService.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+                                  "resource://gre/modules/NetUtil.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
+                                  "resource:///modules/devtools/LayoutHelpers.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "console",
+                                  "resource://gre/modules/devtools/Console.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+                                  "resource://gre/modules/AddonManager.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "js_beautify",
+                                  "resource:///modules/devtools/Jsbeautify.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
+  let JsDebugger = {};
+  Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
+
+  let global = Components.utils.getGlobalForObject({});
+  JsDebugger.addDebuggerToGlobal(global);
+
+  return global.Debugger;
+});
+
+let prefSvc = "@mozilla.org/preferences-service;1";
+XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
+  let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
+  return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
+});
+
+Cu.import("resource:///modules/devtools/GcliTiltCommands.jsm", {});
+Cu.import("resource:///modules/devtools/GcliCookieCommands.jsm", {});
+
+/**
+ * A place to store the names of the commands that we have added as a result of
+ * calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
+ * added commands.
+ */
+let commands = [];
+
+/**
+ * Exported API
+ */
+let GcliCommands = {
+  /**
+   * Called to look in a directory pointed at by the devtools.commands.dir pref
+   * for *.mozcmd files which are then loaded.
+   * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
+   * we eval the script from the .mozcmd file. This should be a chrome window.
+   */
+  refreshAutoCommands: function GC_refreshAutoCommands(aSandboxPrincipal) {
+    // First get rid of the last set of commands
+    commands.forEach(function(name) {
+      gcli.removeCommand(name);
+    });
+
+    let dirName = prefBranch.getComplexValue("devtools.commands.dir",
+                                             Ci.nsISupportsString).data;
+    if (dirName == "") {
+      return;
+    }
+
+    let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+    dir.initWithPath(dirName);
+    if (!dir.exists() || !dir.isDirectory()) {
+      throw new Error('\'' + dirName + '\' is not a directory.');
+    }
+
+    let en = dir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
+
+    while (true) {
+      let file = en.nextFile;
+      if (!file) {
+        break;
+      }
+      if (file.leafName.match(/.*\.mozcmd$/) && file.isFile() && file.isReadable()) {
+        loadCommandFile(file, aSandboxPrincipal);
+      }
+    }
+  },
+};
+
+/**
+ * Load the commands from a single file
+ * @param nsIFile aFile The file containing the commands that we should read
+ * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
+ * we eval the script from the .mozcmd file. This should be a chrome window.
+ */
+function loadCommandFile(aFile, aSandboxPrincipal) {
+  NetUtil.asyncFetch(aFile, function refresh_fetch(aStream, aStatus) {
+    if (!Components.isSuccessCode(aStatus)) {
+      console.error("NetUtil.asyncFetch(" + aFile.path + ",..) failed. Status=" + aStatus);
+      return;
+    }
+
+    let source = NetUtil.readInputStreamToString(aStream, aStream.available());
+    aStream.close();
+
+    let sandbox = new Cu.Sandbox(aSandboxPrincipal, {
+      sandboxPrototype: aSandboxPrincipal,
+      wantXrays: false,
+      sandboxName: aFile.path
+    });
+    let data = Cu.evalInSandbox(source, sandbox, "1.8", aFile.leafName, 1);
+
+    if (!Array.isArray(data)) {
+      console.error("Command file '" + aFile.leafName + "' does not have top level array.");
+      return;
+    }
+
+    data.forEach(function(commandSpec) {
+      gcli.addCommand(commandSpec);
+      commands.push(commandSpec.name);
+    });
+  }.bind(this));
+}
+
+/**
+ * 'cmd' command
+ */
+gcli.addCommand({
+  name: "cmd",
+  description: gcli.lookup("cmdDesc"),
+  hidden: true
+});
+
+/**
+ * 'cmd refresh' command
+ */
+gcli.addCommand({
+  name: "cmd refresh",
+  description: gcli.lookup("cmdRefreshDesc"),
+  hidden: true,
+  exec: function Command_cmdRefresh(args, context) {
+    GcliCommands.refreshAutoCommands(context.environment.chromeDocument.defaultView);
+  }
+});
+
+/**
+ * 'echo' command
+ */
+gcli.addCommand({
+  name: "echo",
+  description: gcli.lookup("echoDesc"),
+  params: [
+    {
+      name: "message",
+      type: "string",
+      description: gcli.lookup("echoMessageDesc")
+    }
+  ],
+  returnType: "string",
+  hidden: true,
+  exec: function Command_echo(args, context) {
+    return args.message;
+  }
+});
+
+
+/**
+ * 'screenshot' command
+ */
+gcli.addCommand({
+  name: "screenshot",
+  description: gcli.lookup("screenshotDesc"),
+  manual: gcli.lookup("screenshotManual"),
+  returnType: "string",
+  params: [
+    {
+      name: "filename",
+      type: "string",
+      description: gcli.lookup("screenshotFilenameDesc"),
+      manual: gcli.lookup("screenshotFilenameManual")
+    },
+    {
+      name: "delay",
+      type: { name: "number", min: 0 },
+      defaultValue: 0,
+      description: gcli.lookup("screenshotDelayDesc"),
+      manual: gcli.lookup("screenshotDelayManual")
+    },
+    {
+      name: "fullpage",
+      type: "boolean",
+      defaultValue: false,
+      description: gcli.lookup("screenshotFullPageDesc"),
+      manual: gcli.lookup("screenshotFullPageManual")
+    },
+    {
+      name: "node",
+      type: "node",
+      defaultValue: null,
+      description: gcli.lookup("inspectNodeDesc"),
+      manual: gcli.lookup("inspectNodeManual")
+    }
+  ],
+  exec: function Command_screenshot(args, context) {
+    var document = context.environment.contentDocument;
+    if (args.delay > 0) {
+      var promise = context.createPromise();
+      document.defaultView.setTimeout(function Command_screenshotDelay() {
+        let reply = this.grabScreen(document, args.filename);
+        promise.resolve(reply);
+      }.bind(this), args.delay * 1000);
+      return promise;
+    }
+    else {
+      return this.grabScreen(document, args.filename, args.fullpage, args.node);
+    }
+  },
+  grabScreen:
+  function Command_screenshotGrabScreen(document, filename, fullpage, node) {
+    let window = document.defaultView;
+    let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+    let left = 0;
+    let top = 0;
+    let width;
+    let height;
+
+    if (!fullpage) {
+      if (!node) {
+        left = window.scrollX;
+        top = window.scrollY;
+        width = window.innerWidth;
+        height = window.innerHeight;
+      } else {
+        let rect = LayoutHelpers.getRect(node, window);
+        top = rect.top;
+        left = rect.left;
+        width = rect.width;
+        height = rect.height;
+      }
+    } else {
+      width = window.innerWidth + window.scrollMaxX;
+      height = window.innerHeight + window.scrollMaxY;
+    }
+    canvas.width = width;
+    canvas.height = height;
+
+    let ctx = canvas.getContext("2d");
+    ctx.drawWindow(window, left, top, width, height, "#fff");
+
+    let data = canvas.toDataURL("image/png", "");
+    let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+
+    // Check there is a .png extension to filename
+    if (!filename.match(/.png$/i)) {
+      filename += ".png";
+    }
+
+    // If the filename is relative, tack it onto the download directory
+    if (!filename.match(/[\\\/]/)) {
+      let downloadMgr = Cc["@mozilla.org/download-manager;1"]
+        .getService(Ci.nsIDownloadManager);
+      let tempfile = downloadMgr.userDownloadsDirectory;
+      tempfile.append(filename);
+      filename = tempfile.path;
+    }
+
+    try {
+      file.initWithPath(filename);
+    } catch (ex) {
+      return "Error saving to " + filename;
+    }
+
+    let ioService = Cc["@mozilla.org/network/io-service;1"]
+      .getService(Ci.nsIIOService);
+
+    let Persist = Ci.nsIWebBrowserPersist;
+    let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+      .createInstance(Persist);
+    persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
+                           Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
+
+    let source = ioService.newURI(data, "UTF8", null);
+    persist.saveURI(source, null, null, null, null, file);
+
+    return "Saved to " + filename;
+  }
+});
+
+
+let callLogDebuggers = [];
+
+/**
+ * 'calllog' command
+ */
+gcli.addCommand({
+  name: "calllog",
+  description: gcli.lookup("calllogDesc")
+})
+
+/**
+ * 'calllog start' command
+ */
+gcli.addCommand({
+  name: "calllog start",
+  description: gcli.lookup("calllogStartDesc"),
+
+  exec: function(args, context) {
+    let contentWindow = context.environment.contentDocument.defaultView;
+
+    let dbg = new Debugger(contentWindow);
+    dbg.onEnterFrame = function(frame) {
+      // BUG 773652 -  Make the output from the GCLI calllog command nicer
+      contentWindow.console.log("Method call: " + this.callDescription(frame));
+    }.bind(this);
+
+    callLogDebuggers.push(dbg);
+
+    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab;
+    HUDService.activateHUDForContext(tab);
+
+    return gcli.lookup("calllogStartReply");
+  },
+
+  callDescription: function(frame) {
+    let name = "<anonymous>";
+    if (frame.callee.name) {
+      name = frame.callee.name;
+    }
+    else {
+      let desc = frame.callee.getOwnPropertyDescriptor("displayName");
+      if (desc && desc.value && typeof desc.value == "string") {
+        name = desc.value;
+      }
+    }
+
+    let args = frame.arguments.map(this.valueToString).join(", ");
+    return name + "(" + args + ")";
+  },
+
+  valueToString: function(value) {
+    if (typeof value !== "object" || value === null) {
+      return uneval(value);
+    }
+    return "[object " + value.class + "]";
+  }
+});
 
-const Cu = Components.utils;
+/**
+ * 'calllog stop' command
+ */
+gcli.addCommand({
+  name: "calllog stop",
+  description: gcli.lookup("calllogStopDesc"),
+
+  exec: function(args, context) {
+    let numDebuggers = callLogDebuggers.length;
+    if (numDebuggers == 0) {
+      return gcli.lookup("calllogStopNoLogging");
+    }
+
+    for (let dbg of callLogDebuggers) {
+      dbg.onEnterFrame = undefined;
+    }
+    callLogDebuggers = [];
+
+    return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]);
+  }
+});
+
+
+/**
+ * 'console' command
+ */
+gcli.addCommand({
+  name: "console",
+  description: gcli.lookup("consoleDesc"),
+  manual: gcli.lookup("consoleManual")
+});
+
+/**
+ * 'console clear' command
+ */
+gcli.addCommand({
+  name: "console clear",
+  description: gcli.lookup("consoleclearDesc"),
+  exec: function Command_consoleClear(args, context) {
+    let window = context.environment.contentDocument.defaultView;
+    let hud = HUDService.getHudByWindow(window);
+    // hud will be null if the web console has not been opened for this window
+    if (hud) {
+      hud.jsterm.clearOutput();
+    }
+  }
+});
+
+/**
+ * 'console close' command
+ */
+gcli.addCommand({
+  name: "console close",
+  description: gcli.lookup("consolecloseDesc"),
+  exec: function Command_consoleClose(args, context) {
+    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
+    HUDService.deactivateHUDForContext(tab);
+  }
+});
+
+/**
+ * 'console open' command
+ */
+gcli.addCommand({
+  name: "console open",
+  description: gcli.lookup("consoleopenDesc"),
+  exec: function Command_consoleOpen(args, context) {
+    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
+    HUDService.activateHUDForContext(tab);
+  }
+});
+
+/**
+ * Restart command
+ *
+ * @param boolean nocache
+ *        Disables loading content from cache upon restart.
+ *
+ * Examples :
+ * >> restart
+ * - restarts browser immediately
+ * >> restart --nocache
+ * - restarts immediately and starts Firefox without using cache
+ */
+gcli.addCommand({
+  name: "restart",
+  description: gcli.lookup("restartFirefoxDesc"),
+  params: [
+    {
+      name: "nocache",
+      type: "boolean",
+      defaultValue: false,
+      description: gcli.lookup("restartFirefoxNocacheDesc")
+    }
+  ],
+  returnType: "string",
+  exec: function Restart(args, context) {
+    let canceled = Cc["@mozilla.org/supports-PRBool;1"]
+                     .createInstance(Ci.nsISupportsPRBool);
+    Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
+    if (canceled.data) {
+      return gcli.lookup("restartFirefoxRequestCancelled");
+    }
+
+    // disable loading content from cache.
+    if (args.nocache) {
+      Services.appinfo.invalidateCachesOnRestart();
+    }
+
+    // restart
+    Cc['@mozilla.org/toolkit/app-startup;1']
+      .getService(Ci.nsIAppStartup)
+      .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
+    return gcli.lookup("restartFirefoxRestarting");
+  }
+});
+
+/**
+ * 'inspect' command
+ */
+gcli.addCommand({
+  name: "inspect",
+  description: gcli.lookup("inspectDesc"),
+  manual: gcli.lookup("inspectManual"),
+  params: [
+    {
+      name: "node",
+      type: "node",
+      description: gcli.lookup("inspectNodeDesc"),
+      manual: gcli.lookup("inspectNodeManual")
+    }
+  ],
+  exec: function Command_inspect(args, context) {
+    let document = context.environment.chromeDocument;
+    document.defaultView.InspectorUI.openInspectorUI(args.node);
+  }
+});
+
+/**
+ * 'edit' command
+ */
+gcli.addCommand({
+  name: "edit",
+  description: gcli.lookup("editDesc"),
+  manual: gcli.lookup("editManual2"),
+  params: [
+     {
+       name: 'resource',
+       type: {
+         name: 'resource',
+         include: 'text/css'
+       },
+       description: gcli.lookup("editResourceDesc")
+     },
+     {
+       name: "line",
+       defaultValue: 1,
+       type: {
+         name: "number",
+         min: 1,
+         step: 10
+       },
+       description: gcli.lookup("editLineToJumpToDesc")
+     }
+   ],
+   exec: function(args, context) {
+     let win = HUDService.currentContext();
+     win.StyleEditor.openChrome(args.resource.element, args.line);
+   }
+});
+
+/**
+ * 'break' command
+ */
+gcli.addCommand({
+  name: "break",
+  description: gcli.lookup("breakDesc"),
+  manual: gcli.lookup("breakManual")
+});
+
+
+/**
+ * 'break list' command
+ */
+gcli.addCommand({
+  name: "break list",
+  description: gcli.lookup("breaklistDesc"),
+  returnType: "html",
+  exec: function(args, context) {
+    let win = HUDService.currentContext();
+    let dbg = win.DebuggerUI.getDebugger();
+    if (!dbg) {
+      return gcli.lookup("breakaddDebuggerStopped");
+    }
+    let breakpoints = dbg.breakpoints;
+
+    if (Object.keys(breakpoints).length === 0) {
+      return gcli.lookup("breaklistNone");
+    }
+
+    let reply = gcli.lookup("breaklistIntro");
+    reply += "<ol>";
+    for each (let breakpoint in breakpoints) {
+      let text = gcli.lookupFormat("breaklistLineEntry",
+                                   [breakpoint.location.url,
+                                    breakpoint.location.line]);
+      reply += "<li>" + text + "</li>";
+    };
+    reply += "</ol>";
+    return reply;
+  }
+});
+
+
+/**
+ * 'break add' command
+ */
+gcli.addCommand({
+  name: "break add",
+  description: gcli.lookup("breakaddDesc"),
+  manual: gcli.lookup("breakaddManual")
+});
+
+/**
+ * 'break add line' command
+ */
+gcli.addCommand({
+  name: "break add line",
+  description: gcli.lookup("breakaddlineDesc"),
+  params: [
+    {
+      name: "file",
+      type: {
+        name: "selection",
+        data: function() {
+          let win = HUDService.currentContext();
+          let dbg = win.DebuggerUI.getDebugger();
+          let files = [];
+          if (dbg) {
+            let scriptsView = dbg.contentWindow.DebuggerView.Scripts;
+            for each (let script in scriptsView.scriptLocations) {
+              files.push(script);
+            }
+          }
+          return files;
+        }
+      },
+      description: gcli.lookup("breakaddlineFileDesc")
+    },
+    {
+      name: "line",
+      type: { name: "number", min: 1, step: 10 },
+      description: gcli.lookup("breakaddlineLineDesc")
+    }
+  ],
+  returnType: "html",
+  exec: function(args, context) {
+    args.type = "line";
+    let win = HUDService.currentContext();
+    let dbg = win.DebuggerUI.getDebugger();
+    if (!dbg) {
+      return gcli.lookup("breakaddDebuggerStopped");
+    }
+    var promise = context.createPromise();
+    let position = { url: args.file, line: args.line };
+    dbg.addBreakpoint(position, function(aBreakpoint, aError) {
+      if (aError) {
+        promise.resolve(gcli.lookupFormat("breakaddFailed", [aError]));
+        return;
+      }
+      promise.resolve(gcli.lookup("breakaddAdded"));
+    });
+    return promise;
+  }
+});
+
+
+/**
+ * 'break del' command
+ */
+gcli.addCommand({
+  name: "break del",
+  description: gcli.lookup("breakdelDesc"),
+  params: [
+    {
+      name: "breakid",
+      type: {
+        name: "number",
+        min: 0,
+        max: function() {
+          let win = HUDService.currentContext();
+          let dbg = win.DebuggerUI.getDebugger();
+          if (!dbg) {
+            return gcli.lookup("breakaddDebuggerStopped");
+          }
+          return Object.keys(dbg.breakpoints).length - 1;
+        },
+      },
+      description: gcli.lookup("breakdelBreakidDesc")
+    }
+  ],
+  returnType: "html",
+  exec: function(args, context) {
+    let win = HUDService.currentContext();
+    let dbg = win.DebuggerUI.getDebugger();
+    if (!dbg) {
+      return gcli.lookup("breakaddDebuggerStopped");
+    }
+
+    let breakpoints = dbg.breakpoints;
+    let id = Object.keys(dbg.breakpoints)[args.breakid];
+    if (!id || !(id in breakpoints)) {
+      return gcli.lookup("breakNotFound");
+    }
+
+    let promise = context.createPromise();
+    try {
+      dbg.removeBreakpoint(breakpoints[id], function() {
+        promise.resolve(gcli.lookup("breakdelRemoved"));
+      });
+    } catch (ex) {
+      // If the debugger has been closed already, don't scare the user.
+      promise.resolve(gcli.lookup("breakdelRemoved"));
+    }
+    return promise;
+  }
+});
+
+/**
+ * 'export' command
+ */
+gcli.addCommand({
+  name: "export",
+  description: gcli.lookup("exportDesc"),
+});
+
+/**
+ * The 'export html' command. This command allows the user to export the page to
+ * HTML after they do DOM changes.
+ */
+gcli.addCommand({
+  name: "export html",
+  description: gcli.lookup("exportHtmlDesc"),
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let window = document.defaultView;
+    let page = document.documentElement.outerHTML;
+    window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
+  }
+});
+
+/**
+ * 'pagemod' command
+ */
+gcli.addCommand({
+  name: "pagemod",
+  description: gcli.lookup("pagemodDesc"),
+});
 
-Cu.import("resource:///modules/devtools/CmdAddon.jsm");
-Cu.import("resource:///modules/devtools/CmdBreak.jsm");
-Cu.import("resource:///modules/devtools/CmdCalllog.jsm");
-Cu.import("resource:///modules/devtools/CmdConsole.jsm");
-Cu.import("resource:///modules/devtools/CmdCookie.jsm");
-Cu.import("resource:///modules/devtools/CmdDbg.jsm");
-Cu.import("resource:///modules/devtools/CmdEcho.jsm");
-Cu.import("resource:///modules/devtools/CmdEdit.jsm");
-Cu.import("resource:///modules/devtools/CmdExport.jsm");
-Cu.import("resource:///modules/devtools/CmdInspect.jsm");
-Cu.import("resource:///modules/devtools/CmdJsb.jsm");
-Cu.import("resource:///modules/devtools/CmdPagemod.jsm");
-Cu.import("resource:///modules/devtools/CmdResize.jsm");
-Cu.import("resource:///modules/devtools/CmdRestart.jsm");
-Cu.import("resource:///modules/devtools/CmdScreenshot.jsm");
-Cu.import("resource:///modules/devtools/CmdTilt.jsm");
+/**
+ * The 'pagemod replace' command. This command allows the user to search and
+ * replace within text nodes and attributes.
+ */
+gcli.addCommand({
+  name: "pagemod replace",
+  description: gcli.lookup("pagemodReplaceDesc"),
+  params: [
+    {
+      name: "search",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceSearchDesc"),
+    },
+    {
+      name: "replace",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceReplaceDesc"),
+    },
+    {
+      name: "ignoreCase",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
+    },
+    {
+      name: "selector",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceSelectorDesc"),
+      defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodReplaceRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: "attrOnly",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
+    },
+    {
+      name: "contentOnly",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
+    },
+    {
+      name: "attributes",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceAttributesDesc"),
+      defaultValue: null,
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let searchTextNodes = !args.attrOnly;
+    let searchAttributes = !args.contentOnly;
+    let regexOptions = args.ignoreCase ? 'ig' : 'g';
+    let search = new RegExp(escapeRegex(args.search), regexOptions);
+    let attributeRegex = null;
+    if (args.attributes) {
+      attributeRegex = new RegExp(args.attributes, regexOptions);
+    }
+
+    let root = args.root || document;
+    let elements = root.querySelectorAll(args.selector);
+    elements = Array.prototype.slice.call(elements);
+
+    let replacedTextNodes = 0;
+    let replacedAttributes = 0;
+
+    function replaceAttribute() {
+      replacedAttributes++;
+      return args.replace;
+    }
+    function replaceTextNode() {
+      replacedTextNodes++;
+      return args.replace;
+    }
+
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      if (searchTextNodes) {
+        for (let y = 0; y < element.childNodes.length; y++) {
+          let node = element.childNodes[y];
+          if (node.nodeType == node.TEXT_NODE) {
+            node.textContent = node.textContent.replace(search, replaceTextNode);
+          }
+        }
+      }
+
+      if (searchAttributes) {
+        if (!element.attributes) {
+          continue;
+        }
+        for (let y = 0; y < element.attributes.length; y++) {
+          let attr = element.attributes[y];
+          if (!attributeRegex || attributeRegex.test(attr.name)) {
+            attr.value = attr.value.replace(search, replaceAttribute);
+          }
+        }
+      }
+    }
+
+    return gcli.lookupFormat("pagemodReplaceResult",
+                             [elements.length, replacedTextNodes,
+                              replacedAttributes]);
+  }
+});
+
+/**
+ * 'pagemod remove' command
+ */
+gcli.addCommand({
+  name: "pagemod remove",
+  description: gcli.lookup("pagemodRemoveDesc"),
+});
+
+
+/**
+ * The 'pagemod remove element' command.
+ */
+gcli.addCommand({
+  name: "pagemod remove element",
+  description: gcli.lookup("pagemodRemoveElementDesc"),
+  params: [
+    {
+      name: "search",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveElementSearchDesc"),
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodRemoveElementRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: 'stripOnly',
+      type: 'boolean',
+      description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
+    },
+    {
+      name: 'ifEmptyOnly',
+      type: 'boolean',
+      description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let root = args.root || document;
+    let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
+
+    let removed = 0;
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      let parentNode = element.parentNode;
+      if (!parentNode || !element.removeChild) {
+        continue;
+      }
+      if (args.stripOnly) {
+        while (element.hasChildNodes()) {
+          parentNode.insertBefore(element.childNodes[0], element);
+        }
+      }
+      if (!args.ifEmptyOnly || !element.hasChildNodes()) {
+        element.parentNode.removeChild(element);
+        removed++;
+      }
+    }
+
+    return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
+                             [elements.length, removed]);
+  }
+});
+
+/**
+ * The 'pagemod remove attribute' command.
+ */
+gcli.addCommand({
+  name: "pagemod remove attribute",
+  description: gcli.lookup("pagemodRemoveAttributeDesc"),
+  params: [
+    {
+      name: "searchAttributes",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
+    },
+    {
+      name: "searchElements",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: "ignoreCase",
+      type: "boolean",
+      description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+
+    let root = args.root || document;
+    let regexOptions = args.ignoreCase ? 'ig' : 'g';
+    let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
+    let elements = root.querySelectorAll(args.searchElements);
+    elements = Array.prototype.slice.call(elements);
+
+    let removed = 0;
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      if (!element.attributes) {
+        continue;
+      }
+
+      var attrs = Array.prototype.slice.call(element.attributes);
+      for (let y = 0; y < attrs.length; y++) {
+        let attr = attrs[y];
+        if (attributeRegex.test(attr.name)) {
+          element.removeAttribute(attr.name);
+          removed++;
+        }
+      }
+    }
+
+    return gcli.lookupFormat("pagemodRemoveAttributeResult",
+                             [elements.length, removed]);
+  }
+});
+
+
+/**
+ * Make a given string safe to use  in a regular expression.
+ *
+ * @param string aString
+ *        The string you want to use in a regex.
+ * @return string
+ *         The equivalent of |aString| but safe to use in a regex.
+ */
+function escapeRegex(aString) {
+  return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+}
+
+/**
+ * 'addon' command.
+ */
+gcli.addCommand({
+  name: "addon",
+  description: gcli.lookup("addonDesc")
+});
+
+/**
+ * 'addon list' command.
+ */
+gcli.addCommand({
+  name: "addon list",
+  description: gcli.lookup("addonListDesc"),
+  params: [{
+    name: 'type',
+    type: {
+      name: 'selection',
+      data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
+    },
+    defaultValue: 'all',
+    description: gcli.lookup("addonListTypeDesc"),
+  }],
+  exec: function(aArgs, context) {
+    function representEnabledAddon(aAddon) {
+      return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
+      getAddonStatus(aAddon) + "]]></li>";
+    }
+
+    function representDisabledAddon(aAddon) {
+      return "<li class=\"gcli-addon-disabled\">" +
+        "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
+        "]]></li>";
+    }
+
+    function getAddonStatus(aAddon) {
+      let operations = [];
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
+        operations.push("PENDING_ENABLE");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
+        operations.push("PENDING_DISABLE");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
+        operations.push("PENDING_UNINSTALL");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
+        operations.push("PENDING_INSTALL");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
+        operations.push("PENDING_UPGRADE");
+      }
+
+      if (operations.length) {
+        return " (" + operations.join(", ") + ")";
+      }
+      return "";
+    }
+
+    /**
+     * Compares two addons by their name. Used in sorting.
+     */
+    function compareAddonNames(aNameA, aNameB) {
+      return String.localeCompare(aNameA.name, aNameB.name);
+    }
+
+    /**
+     * Resolves the promise which is the scope (this) of this function, filling
+     * it with an HTML representation of the passed add-ons.
+     */
+    function list(aType, aAddons) {
+      if (!aAddons.length) {
+        this.resolve(gcli.lookup("addonNoneOfType"));
+      }
+
+      // Separate the enabled add-ons from the disabled ones.
+      let enabledAddons = [];
+      let disabledAddons = [];
+
+      aAddons.forEach(function(aAddon) {
+        if (aAddon.isActive) {
+          enabledAddons.push(aAddon);
+        } else {
+          disabledAddons.push(aAddon);
+        }
+      });
+
+      let header;
+      switch(aType) {
+        case "dictionary":
+          header = gcli.lookup("addonListDictionaryHeading");
+          break;
+        case "extension":
+          header = gcli.lookup("addonListExtensionHeading");
+          break;
+        case "locale":
+          header = gcli.lookup("addonListLocaleHeading");
+          break;
+        case "plugin":
+          header = gcli.lookup("addonListPluginHeading");
+          break;
+        case "theme":
+          header = gcli.lookup("addonListThemeHeading");
+        case "all":
+          header = gcli.lookup("addonListAllHeading");
+          break;
+        default:
+          header = gcli.lookup("addonListUnknownHeading");
+      }
+
+      // Map and sort the add-ons, and create an HTML list.
+      this.resolve(header +
+        "<ol>" +
+        enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
+        disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
+        "</ol>");
+    }
+
+    // Create the promise that will be resolved when the add-on listing has
+    // been finished.
+    let promise = context.createPromise();
+    let types = aArgs.type == "all" ? null : [aArgs.type];
+    AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
+    return promise;
+  }
+});
+
+
+/**
+ * 'dbg' command
+ */
+gcli.addCommand({
+  name: "dbg",
+  description: gcli.lookup("dbgDesc"),
+  manual: gcli.lookup("dbgManual")
+});
+
+
+/**
+ * 'dbg interrupt' command
+ */
+gcli.addCommand({
+  name: "dbg interrupt",
+  description: gcli.lookup("dbgInterrupt"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (!thread.paused) {
+        thread.interrupt();
+      }
+    }
+  }
+});
+
+/**
+ * 'dbg continue' command
+ */
+gcli.addCommand({
+  name: "dbg continue",
+  description: gcli.lookup("dbgContinue"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.resume();
+      }
+    }
+  }
+});
+
+
+/**
+ * 'dbg step' command
+ */
+gcli.addCommand({
+  name: "dbg step",
+  description: gcli.lookup("dbgStepDesc"),
+  manual: gcli.lookup("dbgStepManual")
+});
+
+
+/**
+ * 'dbg step over' command
+ */
+gcli.addCommand({
+  name: "dbg step over",
+  description: gcli.lookup("dbgStepOverDesc"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepOver();
+      }
+    }
+  }
+});
+
+/**
+ * 'dbg step in' command
+ */
+gcli.addCommand({
+  name: 'dbg step in',
+  description: gcli.lookup("dbgStepInDesc"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepIn();
+      }
+    }
+  }
+});
+
+/**
+ * 'dbg step over' command
+ */
+gcli.addCommand({
+  name: 'dbg step out',
+  description: gcli.lookup("dbgStepOutDesc"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepOut();
+      }
+    }
+  }
+});
+
+// We need a list of addon names for the enable and disable commands. Because
+// getting the name list is async we do not add the commands until we have the
+// list.
+AddonManager.getAllAddons(function addonAsync(aAddons) {
+  // We listen for installs to keep our addon list up to date. There is no need
+  // to listen for uninstalls because uninstalled addons are simply disabled
+  // until restart (to enable undo functionality).
+  AddonManager.addAddonListener({
+    onInstalled: function(aAddon) {
+      addonNameCache.push({
+        name: representAddon(aAddon).replace(/\s/g, "_"),
+        value: aAddon.name
+      });
+    },
+    onUninstalled: function(aAddon) {
+      let name = representAddon(aAddon).replace(/\s/g, "_");
+
+      for (let i = 0; i < addonNameCache.length; i++) {
+        if(addonNameCache[i].name == name) {
+          addonNameCache.splice(i, 1);
+          break;
+        }
+      }
+    },
+  });
+
+  /**
+   * Returns a string that represents the passed add-on.
+   */
+  function representAddon(aAddon) {
+    let name = aAddon.name + " " + aAddon.version;
+    return name.trim();
+  }
+
+  let addonNameCache = [];
+
+  // The name parameter, used in "addon enable" and "addon disable."
+  let nameParameter = {
+    name: "name",
+    type: {
+      name: "selection",
+      lookup: addonNameCache
+    },
+    description: gcli.lookup("addonNameDesc")
+  };
+
+  for (let addon of aAddons) {
+    addonNameCache.push({
+      name: representAddon(addon).replace(/\s/g, "_"),
+      value: addon.name
+    });
+  }
+
+  /**
+   * 'addon enable' command.
+   */
+  gcli.addCommand({
+    name: "addon enable",
+    description: gcli.lookup("addonEnableDesc"),
+    params: [nameParameter],
+    exec: function(aArgs, context) {
+      /**
+       * Enables the addon in the passed list which has a name that matches
+       * according to the passed name comparer, and resolves the promise which
+       * is the scope (this) of this function to display the result of this
+       * enable attempt.
+       */
+      function enable(aName, addons) {
+        // Find the add-on.
+        let addon = null;
+        addons.some(function(candidate) {
+          if (candidate.name == aName) {
+            addon = candidate;
+            return true;
+          } else {
+            return false;
+          }
+        });
+
+        let name = representAddon(addon);
+
+        if (!addon.userDisabled) {
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonAlreadyEnabled", [name]) + "]]>");
+        } else {
+          addon.userDisabled = false;
+          // nl-nl: {$1} is ingeschakeld.
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonEnabled", [name]) + "]]>");
+        }
+      }
+
+      let promise = context.createPromise();
+      // List the installed add-ons, enable one when done listing.
+      AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
+      return promise;
+    }
+  });
+
+  /**
+   * 'addon disable' command.
+   */
+  gcli.addCommand({
+    name: "addon disable",
+    description: gcli.lookup("addonDisableDesc"),
+    params: [nameParameter],
+    exec: function(aArgs, context) {
+      /**
+       * Like enable, but ... you know ... the exact opposite.
+       */
+      function disable(aName, addons) {
+        // Find the add-on.
+        let addon = null;
+        addons.some(function(candidate) {
+          if (candidate.name == aName) {
+            addon = candidate;
+            return true;
+          } else {
+            return false;
+          }
+        });
+
+        let name = representAddon(addon);
+
+        if (addon.userDisabled) {
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonAlreadyDisabled", [name]) + "]]>");
+        } else {
+          addon.userDisabled = true;
+          // nl-nl: {$1} is uitgeschakeld.
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonDisabled", [name]) + "]]>");
+        }
+      }
+
+      let promise = context.createPromise();
+      // List the installed add-ons, disable one when done listing.
+      AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
+      return promise;
+    }
+  });
+  Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
+});
+
+/* Responsive Mode commands */
+(function gcli_cmd_resize_container() {
+  function gcli_cmd_resize(args, context) {
+    let browserDoc = context.environment.chromeDocument;
+    let browserWindow = browserDoc.defaultView;
+    let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
+    mgr.handleGcliCommand(browserWindow,
+                          browserWindow.gBrowser.selectedTab,
+                          this.name,
+                          args);
+  }
+
+  gcli.addCommand({
+    name: 'resize',
+    description: gcli.lookup('resizeModeDesc')
+  });
+
+  gcli.addCommand({
+    name: 'resize on',
+    description: gcli.lookup('resizeModeOnDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize off',
+    description: gcli.lookup('resizeModeOffDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize toggle',
+    description: gcli.lookup('resizeModeToggleDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize to',
+    description: gcli.lookup('resizeModeToDesc'),
+    params: [
+      {
+        name: 'width',
+        type: 'number',
+        description: gcli.lookup("resizePageArgWidthDesc"),
+      },
+      {
+        name: 'height',
+        type: 'number',
+        description: gcli.lookup("resizePageArgHeightDesc"),
+      },
+    ],
+    exec: gcli_cmd_resize
+  });
+})();
+
+/**
+ * jsb command.
+ */
+gcli.addCommand({
+  name: 'jsb',
+  description: gcli.lookup('jsbDesc'),
+  returnValue:'string',
+  hidden: true,
+  params: [
+    {
+      name: 'url',
+      type: 'string',
+      description: gcli.lookup('jsbUrlDesc'),
+      manual: 'The URL of the JS to prettify'
+    },
+    {
+      name: 'indentSize',
+      type: 'number',
+      description: gcli.lookup('jsbIndentSizeDesc'),
+      manual: gcli.lookup('jsbIndentSizeManual'),
+      defaultValue: 2
+    },
+    {
+      name: 'indentChar',
+      type: {
+        name: 'selection',
+        lookup: [{name: "space", value: " "}, {name: "tab", value: "\t"}]
+      },
+      description: gcli.lookup('jsbIndentCharDesc'),
+      manual: gcli.lookup('jsbIndentCharManual'),
+      defaultValue: ' ',
+    },
+    {
+      name: 'preserveNewlines',
+      type: 'boolean',
+      description: gcli.lookup('jsbPreserveNewlinesDesc'),
+      manual: gcli.lookup('jsbPreserveNewlinesManual'),
+      defaultValue: true
+    },
+    {
+      name: 'preserveMaxNewlines',
+      type: 'number',
+      description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
+      manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
+      defaultValue: -1
+    },
+    {
+      name: 'jslintHappy',
+      type: 'boolean',
+      description: gcli.lookup('jsbJslintHappyDesc'),
+      manual: gcli.lookup('jsbJslintHappyManual'),
+      defaultValue: false
+    },
+    {
+      name: 'braceStyle',
+      type: {
+        name: 'selection',
+        data: ['collapse', 'expand', 'end-expand', 'expand-strict']
+      },
+      description: gcli.lookup('jsbBraceStyleDesc'),
+      manual: gcli.lookup('jsbBraceStyleManual'),
+      defaultValue: "collapse"
+    },
+    {
+      name: 'spaceBeforeConditional',
+      type: 'boolean',
+      description: gcli.lookup('jsbSpaceBeforeConditionalDesc'),
+      manual: gcli.lookup('jsbSpaceBeforeConditionalManual'),
+      defaultValue: true
+    },
+    {
+      name: 'unescapeStrings',
+      type: 'boolean',
+      description: gcli.lookup('jsbUnescapeStringsDesc'),
+      manual: gcli.lookup('jsbUnescapeStringsManual'),
+      defaultValue: false
+    }
+  ],
+  exec: function(args, context) {
+  let opts = {
+    indent_size: args.indentSize,
+    indent_char: args.indentChar,
+    preserve_newlines: args.preserveNewlines,
+    max_preserve_newlines: args.preserveMaxNewlines == -1 ?
+                           undefined : args.preserveMaxNewlines,
+    jslint_happy: args.jslintHappy,
+    brace_style: args.braceStyle,
+    space_before_conditional: args.spaceBeforeConditional,
+    unescape_strings: args.unescapeStrings
+  }
+
+  let xhr = new XMLHttpRequest();
+
+  try {
+    xhr.open("GET", args.url, true);
+  } catch(e) {
+    return gcli.lookup('jsbInvalidURL');
+  }
+
+  let promise = context.createPromise();
+
+  xhr.onreadystatechange = function(aEvt) {
+    if (xhr.readyState == 4) {
+      if (xhr.status == 200 || xhr.status == 0) {
+        let browserDoc = context.environment.chromeDocument;
+        let browserWindow = browserDoc.defaultView;
+        let browser = browserWindow.gBrowser;
+
+        browser.selectedTab = browser.addTab("data:text/plain;base64," +
+          browserWindow.btoa(js_beautify(xhr.responseText, opts)));
+        promise.resolve();
+      }
+      else {
+        promise.resolve("Unable to load page to beautify: " + args.url + " " +
+                        xhr.status + " " + xhr.statusText);
+      }
+    };
+  }
+  xhr.send(null);
+  return promise;
+  }
+});
rename from browser/devtools/commandline/CmdCookie.jsm
rename to browser/devtools/commandline/GcliCookieCommands.jsm
--- a/browser/devtools/commandline/CmdCookie.jsm
+++ b/browser/devtools/commandline/GcliCookieCommands.jsm
@@ -1,21 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 let EXPORTED_SYMBOLS = [ ];
 
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource:///modules/devtools/gcli.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "console",
-                                  "resource:///modules/devtools/Console.jsm");
 
 // We should really be using nsICookieManager so we can read more than just the
 // key/value of cookies. The difficulty is filtering the cookies that are
 // relevant to the current page. See
 // https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
 // For details on how this is done with Firebug
 
 /**
rename from browser/devtools/tilt/CmdTilt.jsm
rename to browser/devtools/commandline/GcliTiltCommands.jsm
rename from browser/devtools/commandline/commandline.css
rename to browser/devtools/commandline/gcli.css
--- a/browser/devtools/commandline/gcli.jsm
+++ b/browser/devtools/commandline/gcli.jsm
@@ -800,18 +800,47 @@ Conversion.prototype.toString = function
 Conversion.prototype.getPredictions = function() {
   if (typeof this.predictions === 'function') {
     return this.predictions();
   }
   return this.predictions || [];
 };
 
 /**
- * Return an index constrained by the available predictions. Basically
- * (index % predicitons.length)
+ * Accessor for a prediction by index.
+ * This is useful above <tt>getPredictions()[index]</tt> because it normalizes
+ * index to be within the bounds of the predictions, which means that the UI
+ * can maintain an index of which prediction to choose without caring how many
+ * predictions there are.
+ * @param index The index of the prediction to choose
+ */
+Conversion.prototype.getPredictionAt = function(index) {
+  if (index == null) {
+    return undefined;
+  }
+
+  var predictions = this.getPredictions();
+  if (predictions.length === 0) {
+    return undefined;
+  }
+
+  index = index % predictions.length;
+  if (index < 0) {
+    index = predictions.length + index;
+  }
+  return predictions[index];
+};
+
+/**
+ * Accessor for a prediction by index.
+ * This is useful above <tt>getPredictions()[index]</tt> because it normalizes
+ * index to be within the bounds of the predictions, which means that the UI
+ * can maintain an index of which prediction to choose without caring how many
+ * predictions there are.
+ * @param index The index of the prediction to choose
  */
 Conversion.prototype.constrainPredictionIndex = function(index) {
   if (index == null) {
     return undefined;
   }
 
   var predictions = this.getPredictions();
   if (predictions.length === 0) {
@@ -1093,16 +1122,17 @@ exports.getType = function(typeSpec) {
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 define('gcli/argument', ['require', 'exports', 'module' ], function(require, exports, module) {
+var argument = exports;
 
 
 /**
  * Thinking out loud here:
  * Arguments are an area where we could probably refactor things a bit better.
  * The split process in Requisition creates a set of Arguments, which are then
  * assigned. The assign process sometimes converts them into subtypes of
  * Argument. We might consider that what gets assigned is _always_ one of the
@@ -1146,62 +1176,34 @@ Argument.prototype.merge = function(foll
   // Is it possible that this gets called when we're merging arguments
   // for the single string?
   return new Argument(
     this.text + this.suffix + following.prefix + following.text,
     this.prefix, following.suffix);
 };
 
 /**
- * Returns a new Argument like this one but with various items changed.
- * @param options Values to use in creating a new Argument.
- * Warning: some implementations of beget make additions to the options
- * argument. You should be aware of this in the unlikely event that you want to
- * reuse 'options' arguments.
- * Properties:
- * - text: The new text value
- * - prefixSpace: Should the prefix be altered to begin with a space?
- * - prefixPostSpace: Should the prefix be altered to end with a space?
- * - suffixSpace: Should the suffix be altered to end with a space?
- * - type: Constructor to use in creating new instances. Default: Argument
- */
-Argument.prototype.beget = function(options) {
-  var text = this.text;
+ * Returns a new Argument like this one but with the text set to
+ * <tt>replText</tt> and the end adjusted to fit.
+ * @param replText Text to replace the old text value
+ */
+Argument.prototype.beget = function(replText, options) {
   var prefix = this.prefix;
   var suffix = this.suffix;
 
-  if (options.text != null) {
-    text = options.text;
-
-    // We need to add quotes when the replacement string has spaces or is empty
-    var needsQuote = text.indexOf(' ') >= 0 || text.length == 0;
-    if (needsQuote && /['"]/.test(prefix)) {
-      prefix = prefix + '\'';
-      suffix = '\'' + suffix;
-    }
-  }
-
-  if (options.prefixSpace && prefix.charAt(0) !== ' ') {
-    prefix = ' ' + prefix;
-  }
-
-  if (options.prefixPostSpace && prefix.charAt(prefix.length - 1) !== ' ') {
-    prefix = prefix + ' ';
-  }
-
-  if (options.suffixSpace && suffix.charAt(suffix.length - 1) !== ' ') {
-    suffix = suffix + ' ';
-  }
-
-  if (text === this.text && suffix === this.suffix && prefix === this.prefix) {
-    return this;
-  }
-
-  var type = options.type || Argument;
-  return new type(text, prefix, suffix);
+  // We need to add quotes when the replacement string has spaces or is empty
+  var quote = (replText.indexOf(' ') >= 0 || replText.length == 0) ?
+      '\'' : '';
+
+  if (options) {
+    prefix = (options.prefixSpace ? ' ' : '') + quote;
+    suffix = quote;
+  }
+
+  return new Argument(replText, prefix, suffix);
 };
 
 /**
  * We need to keep track of which assignment we've been assigned to
  */
 Argument.prototype.assign = function(assignment) {
   this.assignment = assignment;
 };
@@ -1275,85 +1277,81 @@ Object.defineProperty(Argument.prototype
             'null' :
             this.assignment.param.name;
     return '<' + this.prefix + ':' + this.text + ':' + this.suffix + '>' +
         ' (a=' + assignStatus + ',' + ' t=' + this.type + ')';
   },
   enumerable: true
 });
 
-exports.Argument = Argument;
+argument.Argument = Argument;
 
 
 /**
  * BlankArgument is a marker that the argument wasn't typed but is there to
  * fill a slot. Assignments begin with their arg set to a BlankArgument.
  */
 function BlankArgument() {
   this.text = '';
   this.prefix = '';
   this.suffix = '';
 }
 
 BlankArgument.prototype = Object.create(Argument.prototype);
 
 BlankArgument.prototype.type = 'BlankArgument';
 
-exports.BlankArgument = BlankArgument;
+argument.BlankArgument = BlankArgument;
 
 
 /**
  * ScriptArgument is a marker that the argument is designed to be Javascript.
  * It also implements the special rules that spaces after the { or before the
  * } are part of the pre/suffix rather than the content, and that they are
  * never 'blank' so they can be used by Requisition._split() and not raise an
  * ERROR status due to being blank.
  */
 function ScriptArgument(text, prefix, suffix) {
   this.text = text !== undefined ? text : '';
   this.prefix = prefix !== undefined ? prefix : '';
   this.suffix = suffix !== undefined ? suffix : '';
 
-  ScriptArgument._moveSpaces(this);
+  while (this.text.charAt(0) === ' ') {
+    this.prefix = this.prefix + ' ';
+    this.text = this.text.substring(1);
+  }
+
+  while (this.text.charAt(this.text.length - 1) === ' ') {
+    this.suffix = ' ' + this.suffix;
+    this.text = this.text.slice(0, -1);
+  }
 }
 
 ScriptArgument.prototype = Object.create(Argument.prototype);
 
 ScriptArgument.prototype.type = 'ScriptArgument';
 
 /**
- * Private/Dangerous: Alters a ScriptArgument to move the spaces at the start
- * or end of the 'text' into the prefix/suffix. With a string, " a " is 3 chars
- * long, but with a ScriptArgument, { a } is only one char long.
- * Arguments are generally supposed to be immutable, so this method should only
- * be called on a ScriptArgument that isn't exposed to the outside world yet.
- */
-ScriptArgument._moveSpaces = function(arg) {
-  while (arg.text.charAt(0) === ' ') {
-    arg.prefix = arg.prefix + ' ';
-    arg.text = arg.text.substring(1);
-  }
-
-  while (arg.text.charAt(arg.text.length - 1) === ' ') {
-    arg.suffix = ' ' + arg.suffix;
-    arg.text = arg.text.slice(0, -1);
-  }
-};
-
-/**
- * As Argument.beget that implements the space rule documented in the ctor.
- */
-ScriptArgument.prototype.beget = function(options) {
-  options.type = ScriptArgument;
-  var begotten = Argument.prototype.beget.call(this, options);
-  ScriptArgument._moveSpaces(begotten);
-  return begotten;
-};
-
-exports.ScriptArgument = ScriptArgument;
+ * Returns a new Argument like this one but with the text set to
+ * <tt>replText</tt> and the end adjusted to fit.
+ * @param replText Text to replace the old text value
+ */
+ScriptArgument.prototype.beget = function(replText, options) {
+  var prefix = this.prefix;
+  var suffix = this.suffix;
+
+  if (options && options.normalize) {
+    prefix = '{ ';
+    suffix = ' }';
+  }
+
+  return new ScriptArgument(replText, prefix, suffix);
+};
+
+argument.ScriptArgument = ScriptArgument;
 
 
 /**
  * Commands like 'echo' with a single string argument, and used with the
  * special format like: 'echo a b c' effectively have a number of arguments
  * merged together.
  */
 function MergedArgument(args, start, end) {
@@ -1403,72 +1401,63 @@ MergedArgument.prototype.equals = functi
   }
 
   // We might need to add a check that args is the same here
 
   return this.text === that.text &&
        this.prefix === that.prefix && this.suffix === that.suffix;
 };
 
-exports.MergedArgument = MergedArgument;
+argument.MergedArgument = MergedArgument;
 
 
 /**
  * TrueNamedArguments are for when we have an argument like --verbose which
  * has a boolean value, and thus the opposite of '--verbose' is ''.
  */
-function TrueNamedArgument(arg) {
+function TrueNamedArgument(name, arg) {
   this.arg = arg;
-  this.text = arg.text;
-  this.prefix = arg.prefix;
-  this.suffix = arg.suffix;
+  this.text = arg ? arg.text : '--' + name;
+  this.prefix = arg ? arg.prefix : ' ';
+  this.suffix = arg ? arg.suffix : '';
 }
 
 TrueNamedArgument.prototype = Object.create(Argument.prototype);
 
 TrueNamedArgument.prototype.type = 'TrueNamedArgument';
 
 TrueNamedArgument.prototype.assign = function(assignment) {
   if (this.arg) {
     this.arg.assign(assignment);
   }
   this.assignment = assignment;
 };
 
 TrueNamedArgument.prototype.getArgs = function() {
-  return [ this.arg ];
+  // NASTY! getArgs has a fairly specific use: in removing used arguments
+  // from a command line. Unlike other arguments which are EITHER used
+  // in assignments directly OR grouped in things like MergedArguments,
+  // TrueNamedArgument is used raw from the UI, or composed of another arg
+  // from the CLI, so we return both here so they can both be removed.
+  return this.arg ? [ this, this.arg ] : [ this ];
 };
 
 TrueNamedArgument.prototype.equals = function(that) {
   if (this === that) {
     return true;
   }
   if (that == null || !(that instanceof TrueNamedArgument)) {
     return false;
   }
 
   return this.text === that.text &&
        this.prefix === that.prefix && this.suffix === that.suffix;
 };
 
-/**
- * As Argument.beget that rebuilds nameArg and valueArg
- */
-TrueNamedArgument.prototype.beget = function(options) {
-  if (options.text) {
-    console.error('Can\'t change text of a TrueNamedArgument', this, options);
-  }
-
-  options.type = TrueNamedArgument;
-  var begotten = Argument.prototype.beget.call(this, options);
-  begotten.arg = new Argument(begotten.text, begotten.prefix, begotten.suffix);
-  return begotten;
-};
-
-exports.TrueNamedArgument = TrueNamedArgument;
+argument.TrueNamedArgument = TrueNamedArgument;
 
 
 /**
  * FalseNamedArguments are for when we don't have an argument like --verbose
  * which has a boolean value, and thus the opposite of '' is '--verbose'.
  */
 function FalseNamedArgument() {
   this.text = '';
@@ -1491,73 +1480,58 @@ FalseNamedArgument.prototype.equals = fu
   if (that == null || !(that instanceof FalseNamedArgument)) {
     return false;
   }
 
   return this.text === that.text &&
        this.prefix === that.prefix && this.suffix === that.suffix;
 };
 
-exports.FalseNamedArgument = FalseNamedArgument;
+argument.FalseNamedArgument = FalseNamedArgument;
 
 
 /**
  * A named argument is for cases where we have input in one of the following
  * formats:
  * <ul>
  * <li>--param value
  * <li>-p value
  * </ul>
  * We model this as a normal argument but with a long prefix.
- *
- * There are 2 ways to construct a NamedArgument. One using 2 Arguments which
- * are taken to be the argument for the name (e.g. '--param') and one for the
- * value to assign to that parameter.
- * Alternatively, you can pass in the text/prefix/suffix values in the same
- * way as an Argument is constructed. If you do this then you are expected to
- * assign to nameArg and valueArg before exposing the new NamedArgument.
- */
-function NamedArgument() {
-  if (typeof arguments[0] === 'string') {
-    this.nameArg = null;
-    this.valueArg = null;
-    this.text = arguments[0];
-    this.prefix = arguments[1];
-    this.suffix = arguments[2];
-  }
-  else if (arguments[1] == null) {
-    this.nameArg = arguments[0];
-    this.valueArg = null;
+ */
+function NamedArgument(nameArg, valueArg) {
+  this.nameArg = nameArg;
+  this.valueArg = valueArg;
+
+  if (valueArg == null) {
     this.text = '';
-    this.prefix = this.nameArg.toString();
+    this.prefix = nameArg.toString();
     this.suffix = '';
   }
   else {
-    this.nameArg = arguments[0];
-    this.valueArg = arguments[1];
-    this.text = this.valueArg.text;
-    this.prefix = this.nameArg.toString() + this.valueArg.prefix;
-    this.suffix = this.valueArg.suffix;
+    this.text = valueArg.text;
+    this.prefix = nameArg.toString() + valueArg.prefix;
+    this.suffix = valueArg.suffix;
   }
 }
 
 NamedArgument.prototype = Object.create(Argument.prototype);
 
 NamedArgument.prototype.type = 'NamedArgument';
 
 NamedArgument.prototype.assign = function(assignment) {
   this.nameArg.assign(assignment);
   if (this.valueArg != null) {
     this.valueArg.assign(assignment);
   }
   this.assignment = assignment;
 };
 
 NamedArgument.prototype.getArgs = function() {
-  return this.valueArg ? [ this.nameArg, this.valueArg ] : [ this.nameArg ];
+  return [ this.nameArg, this.valueArg ];
 };
 
 NamedArgument.prototype.equals = function(that) {
   if (this === that) {
     return true;
   }
   if (that == null) {
     return false;
@@ -1568,40 +1542,17 @@ NamedArgument.prototype.equals = functio
   }
 
   // We might need to add a check that nameArg and valueArg are the same
 
   return this.text === that.text &&
        this.prefix === that.prefix && this.suffix === that.suffix;
 };
 
-/**
- * As Argument.beget that rebuilds nameArg and valueArg
- */
-NamedArgument.prototype.beget = function(options) {
-  options.type = NamedArgument;
-  var begotten = Argument.prototype.beget.call(this, options);
-
-  // Cut the prefix into |whitespace|non-whitespace|whitespace| so we can
-  // rebuild nameArg and valueArg from the parts
-  var matches = /^([\s]*)([^\s]*)([\s]*)$/.exec(begotten.prefix);
-
-  if (this.valueArg == null && begotten.text === '') {
-    begotten.nameArg = new Argument(matches[2], matches[1], matches[3]);
-    begotten.valueArg = null;
-  }
-  else {
-    begotten.nameArg = new Argument(matches[2], matches[1], '');
-    begotten.valueArg = new Argument(begotten.text, matches[3], begotten.suffix);
-  }
-
-  return begotten;
-};
-
-exports.NamedArgument = NamedArgument;
+argument.NamedArgument = NamedArgument;
 
 
 /**
  * An argument the groups together a number of plain arguments together so they
  * can be jointly assigned to a single array parameter
  */
 function ArrayArgument() {
   this.args = [];
@@ -1664,17 +1615,17 @@ ArrayArgument.prototype.equals = functio
  * Helper when we're putting arguments back together
  */
 ArrayArgument.prototype.toString = function() {
   return '{' + this.args.map(function(arg) {
     return arg.toString();
   }, this).join(',') + '}';
 };
 
-exports.ArrayArgument = ArrayArgument;
+argument.ArrayArgument = ArrayArgument;
 
 
 });
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1841,40 +1792,29 @@ SelectionType.prototype._findPredictions
   // Cache lower case versions of all the option names
   for (i = 0; i < lookup.length; i++) {
     option = lookup[i];
     if (option._gcliLowerName == null) {
       option._gcliLowerName = option.name.toLowerCase();
     }
   }
 
-  // Exact hidden matches. If 'hidden: true' then we only allow exact matches
-  // All the tests after here check that !option.value.hidden
-  for (i = 0; i < lookup.length && predictions.length < maxPredictions; i++) {
-    option = lookup[i];
-    if (option.name === arg.text) {
-      this._addToPredictions(predictions, option, arg);
-    }
-  }
-
   // Start with prefix matching
   for (i = 0; i < lookup.length && predictions.length < maxPredictions; i++) {
     option = lookup[i];
-    if (option._gcliLowerName.indexOf(match) === 0 && !option.value.hidden) {
-      if (predictions.indexOf(option) === -1) {
-        this._addToPredictions(predictions, option, arg);
-      }
+    if (option._gcliLowerName.indexOf(match) === 0) {
+      this._addToPredictions(predictions, option, arg);
     }
   }
 
   // Try infix matching if we get less half max matched
   if (predictions.length < (maxPredictions / 2)) {
     for (i = 0; i < lookup.length && predictions.length < maxPredictions; i++) {
       option = lookup[i];
-      if (option._gcliLowerName.indexOf(match) !== -1 && !option.value.hidden) {
+      if (option._gcliLowerName.indexOf(match) !== -1) {
         if (predictions.indexOf(option) === -1) {
           this._addToPredictions(predictions, option, arg);
         }
       }
     }
   }
 
   // Try fuzzy matching if we don't get a prefix match
@@ -2246,16 +2186,19 @@ CommandType.prototype.lookup = function(
     return { name: command.name, value: command };
   }, this);
 };
 
 /**
  * Add an option to our list of predicted options
  */
 CommandType.prototype._addToPredictions = function(predictions, option, arg) {
+  if (option.value.hidden) {
+    return;
+  }
   // The command type needs to exclude sub-commands when the CLI
   // is blank, but include them when we're filtering. This hack
   // excludes matches when the filter text is '' and when the
   // name includes a space.
   if (arg.text.length !== 0 || option.name.indexOf(' ') === -1) {
     predictions.push(option);
   }
 };
@@ -2383,17 +2326,16 @@ function Command(commandSpec) {
 
   if (this.params == null) {
     this.params = [];
   }
   if (!Array.isArray(this.params)) {
     throw new Error('command.params must be an array in ' + this.name);
   }
 
-  this.hasNamedParameters = false;
   this.description = 'description' in this ? this.description : undefined;
   this.description = lookup(this.description, 'canonDescNone');
   this.manual = 'manual' in this ? this.manual : undefined;
   this.manual = lookup(this.manual);
 
   // At this point this.params has nested param groups. We want to flatten it
   // out and replace the param object literals with Parameter objects
   var paramSpecs = this.params;
@@ -2412,36 +2354,28 @@ function Command(commandSpec) {
 
   // In theory this could easily be made recursive, so param groups could
   // contain nested param groups. Current thinking is that the added
   // complexity for the UI probably isn't worth it, so this implementation
   // prevents nesting.
   paramSpecs.forEach(function(spec) {
     if (!spec.group) {
       if (usingGroups) {
-        throw new Error('Parameters can\'t come after param groups.' +
-                        ' Ignoring ' + this.name + '/' + spec.name);
+        console.error('Parameters can\'t come after param groups.' +
+            ' Ignoring ' + this.name + '/' + spec.name);
       }
       else {
         var param = new Parameter(spec, this, null);
         this.params.push(param);
-
-        if (!param.isPositionalAllowed) {
-          this.hasNamedParameters = true;
-        }
       }
     }
     else {
       spec.params.forEach(function(ispec) {
         var param = new Parameter(ispec, this, spec.group);
         this.params.push(param);
-
-        if (!param.isPositionalAllowed) {
-          this.hasNamedParameters = true;
-        }
       }, this);
 
       usingGroups = true;
     }
   }, this);
 }
 
 canon.Command = Command;
@@ -2456,69 +2390,69 @@ function Parameter(paramSpec, command, g
   this.paramSpec = paramSpec;
   this.name = this.paramSpec.name;
   this.type = this.paramSpec.type;
   this.groupName = groupName;
   this.defaultValue = this.paramSpec.defaultValue;
 
   if (!this.name) {
     throw new Error('In ' + this.command.name +
-                    ': all params must have a name');
+      ': all params must have a name');
   }
 
   var typeSpec = this.type;
   this.type = types.getType(typeSpec);
   if (this.type == null) {
     console.error('Known types: ' + types.getTypeNames().join(', '));
     throw new Error('In ' + this.command.name + '/' + this.name +
-                    ': can\'t find type for: ' + JSON.stringify(typeSpec));
+      ': can\'t find type for: ' + JSON.stringify(typeSpec));
   }
 
   // boolean parameters have an implicit defaultValue:false, which should
   // not be changed. See the docs.
   if (this.type instanceof BooleanType) {
     if (this.defaultValue !== undefined) {
-      throw new Error('In ' + this.command.name + '/' + this.name +
-                      ': boolean parameters can not have a defaultValue.' +
-                      ' Ignoring');
+      console.error('In ' + this.command.name + '/' + this.name +
+          ': boolean parameters can not have a defaultValue.' +
+          ' Ignoring');
     }
     this.defaultValue = false;
   }
 
   // Check the defaultValue for validity.
   // Both undefined and null get a pass on this test. undefined is used when
   // there is no defaultValue, and null is used when the parameter is
   // optional, neither are required to parse and stringify.
   if (this.defaultValue != null) {
     try {
       var defaultText = this.type.stringify(this.defaultValue);
       var defaultConversion = this.type.parseString(defaultText);
       if (defaultConversion.getStatus() !== Status.VALID) {
-        throw new Error('In ' + this.command.name + '/' + this.name +
-                        ': Error round tripping defaultValue. status = ' +
-                        defaultConversion.getStatus());
+        console.error('In ' + this.command.name + '/' + this.name +
+            ': Error round tripping defaultValue. status = ' +
+            defaultConversion.getStatus());
       }
     }
     catch (ex) {
-      throw new Error('In ' + this.command.name + '/' + this.name +
-                      ': ' + ex);
+      console.error('In ' + this.command.name + '/' + this.name +
+        ': ' + ex);
     }
   }
 
   // Some types (boolean, array) have a non 'undefined' blank value. Give the
   // type a chance to override the default defaultValue of undefined
   if (this.defaultValue === undefined) {
     this.defaultValue = this.type.getBlank().value;
   }
 
   // All parameters that can only be set via a named parameter must have a
   // non-undefined default value
   if (!this.isPositionalAllowed && this.defaultValue === undefined) {
-    throw new Error('In ' + this.command.name + '/' + this.name +
-                    ': Missing defaultValue for optional parameter.');
+    console.error('In ' + this.command.name + '/' + this.name +
+            ': Missing defaultValue for optional parameter.');
   }
 }
 
 /**
  * Does the given name uniquely identify this param (among the other params
  * in this command)
  * @param name The name to check
  */
@@ -2571,26 +2505,16 @@ Object.defineProperty(Parameter.prototyp
 Object.defineProperty(Parameter.prototype, 'isDataRequired', {
   get: function() {
     return this.defaultValue === undefined;
   },
   enumerable: true
 });
 
 /**
- * Reflect the paramSpec 'hidden' property (dynamically so it can change)
- */
-Object.defineProperty(Parameter.prototype, 'hidden', {
-  get: function() {
-    return this.paramSpec.hidden;
-  },
-  enumerable: true
-});
-
-/**
  * Are we allowed to assign data to this parameter using positional
  * parameters?
  */
 Object.defineProperty(Parameter.prototype, 'isPositionalAllowed', {
   get: function() {
     return this.groupName == null;
   },
   enumerable: true
@@ -5148,57 +5072,16 @@ Assignment.prototype.getMessage = functi
  * @return An array of objects with name and value elements. For example:
  * [ { name:'bestmatch', value:foo1 }, { name:'next', value:foo2 }, ... ]
  */
 Assignment.prototype.getPredictions = function() {
   return this.conversion.getPredictions();
 };
 
 /**
- * Accessor for a prediction by index.
- * This is useful above <tt>getPredictions()[index]</tt> because it normalizes
- * index to be within the bounds of the predictions, which means that the UI
- * can maintain an index of which prediction to choose without caring how many
- * predictions there are.
- * @param index The index of the prediction to choose
- */
-Assignment.prototype.getPredictionAt = function(index) {
-  if (index == null) {
-    index = 0;
-  }
-
-  if (this.isInName()) {
-    return undefined;
-  }
-
-  var predictions = this.getPredictions();
-  if (predictions.length === 0) {
-    return undefined;
-  }
-
-  index = index % predictions.length;
-  if (index < 0) {
-    index = predictions.length + index;
-  }
-  return predictions[index];
-};
-
-/**
- * Some places want to take special action if we are in the name part of a
- * named argument (i.e. the '--foo' bit).
- * Currently this does not take actual cursor position into account, it just
- * assumes that the cursor is at the end. In the future we will probably want
- * to take this into account.
- */
-Assignment.prototype.isInName = function() {
-  return this.conversion.arg.type === 'NamedArgument' &&
-         this.conversion.arg.prefix.slice(-1) !== ' ';
-};
-
-/**
  * Report on the status of the last parse() conversion.
  * We force mutations to happen through this method rather than have
  * setValue and setArgument functions to help maintain integrity when we
  * have ArrayArguments and don't want to get confused. This way assignments
  * are just containers for a conversion rather than things that store
  * a connection between an arg/value.
  * @see types.Conversion
  */
@@ -5235,18 +5118,17 @@ Assignment.prototype.ensureVisibleArgume
   // It should only be called when structural changes are happening in which
   // case we're going to ignore the event anyway. But on the other hand
   // perhaps this function shouldn't need to know how it is used, and should
   // do the inefficient thing.
   if (this.conversion.arg.type !== 'BlankArgument') {
     return false;
   }
 
-  var arg = this.conversion.arg.beget({
-    text: '',
+  var arg = this.conversion.arg.beget('', {
     prefixSpace: this.param instanceof CommandAssignment
   });
   this.conversion = this.param.type.parse(arg);
   this.conversion.assign(this);
 
   return true;
 };
 
@@ -5268,16 +5150,42 @@ Assignment.prototype.getStatus = functio
   if (!this.param.isDataRequired && this.arg.type === 'BlankArgument') {
     return Status.VALID;
   }
 
   return this.conversion.getStatus(arg);
 };
 
 /**
+ * Replace the current value with the lower value if such a concept exists.
+ */
+Assignment.prototype.decrement = function() {
+  var replacement = this.param.type.decrement(this.conversion.value);
+  if (replacement != null) {
+    var str = this.param.type.stringify(replacement);
+    var arg = this.conversion.arg.beget(str);
+    var conversion = new Conversion(replacement, arg);
+    this.setConversion(conversion);
+  }
+};
+
+/**
+ * Replace the current value with the higher value if such a concept exists.
+ */
+Assignment.prototype.increment = function() {
+  var replacement = this.param.type.increment(this.conversion.value);
+  if (replacement != null) {
+    var str = this.param.type.stringify(replacement);
+    var arg = this.conversion.arg.beget(str);
+    var conversion = new Conversion(replacement, arg);
+    this.setConversion(conversion);
+  }
+};
+
+/**
  * Helper when we're rebuilding command lines.
  */
 Assignment.prototype.toString = function() {
   return this.conversion.toString();
 };
 
 /**
  * For test/debug use only. The output from this function is subject to wanton
@@ -5485,16 +5393,22 @@ function Requisition(environment, doc) {
 
   this.commandOutputManager = canon.commandOutputManager;
 
   this.onAssignmentChange = util.createEvent('Requisition.onAssignmentChange');
   this.onTextChange = util.createEvent('Requisition.onTextChange');
 }
 
 /**
+ * Some number that is higher than the most args we'll ever have. Would use
+ * MAX_INTEGER if that made sense
+ */
+var MORE_THAN_THE_MOST_ARGS_POSSIBLE = 1000000;
+
+/**
  * Avoid memory leaks
  */
 Requisition.prototype.destroy = function() {
   this.commandAssignment.onAssignmentChange.remove(this._commandAssignmentChanged, this);
   this.commandAssignment.onAssignmentChange.remove(this._assignmentChanged, this);
 
   delete this.document;
   delete this.environment;
@@ -5518,16 +5432,57 @@ Requisition.prototype._assignmentChanged
   this.onAssignmentChange(ev);
 
   // Both for argument position and the onTextChange event, we only care
   // about changes to the argument.
   if (ev.conversion.argEquals(ev.oldConversion)) {
     return;
   }
 
+  this._structuralChangeInProgress = true;
+
+  // Refactor? See bug 660765
+  // Do preceding arguments need to have dummy values applied so we don't
+  // get a hole in the command line?
+  var i;
+  if (ev.assignment.param.isPositionalAllowed) {
+    for (i = 0; i < ev.assignment.paramIndex; i++) {
+      var assignment = this.getAssignment(i);
+      if (assignment.param.isPositionalAllowed) {
+        if (assignment.ensureVisibleArgument()) {
+          this._args.push(assignment.arg);
+        }
+      }
+    }
+  }
+
+  // Remember where we found the first match
+  var index = MORE_THAN_THE_MOST_ARGS_POSSIBLE;
+  for (i = 0; i < this._args.length; i++) {
+    if (this._args[i].assignment === ev.assignment) {
+      if (i < index) {
+        index = i;
+      }
+      this._args.splice(i, 1);
+      i--;
+    }
+  }
+
+  if (index === MORE_THAN_THE_MOST_ARGS_POSSIBLE) {
+    this._args.push(ev.assignment.arg);
+  }
+  else {
+    // Is there a way to do this that doesn't involve a loop?
+    var newArgs = ev.conversion.arg.getArgs();
+    for (i = 0; i < newArgs.length; i++) {
+      this._args.splice(index + i, 0, newArgs[i]);
+    }
+  }
+  this._structuralChangeInProgress = false;
+
   this.onTextChange();
 };
 
 /**
  * When the command changes, we need to keep a bunch of stuff in sync
  */
 Requisition.prototype._commandAssignmentChanged = function(ev) {
   // Assignments fire AssignmentChange events on any change, including minor
@@ -5559,38 +5514,16 @@ Requisition.prototype._commandAssignment
 Requisition.prototype.getAssignment = function(nameOrNumber) {
   var name = (typeof nameOrNumber === 'string') ?
     nameOrNumber :
     Object.keys(this._assignments)[nameOrNumber];
   return this._assignments[name] || undefined;
 };
 
 /**
- * There are a few places where we need to know what the 'next thing' is. What
- * is the user going to be filling out next (assuming they don't enter a named
- * argument). The next argument is the first in line that is both blank, and
- * that can be filled in positionally.
- * @return The next assignment to be used, or null if all the positional
- * parameters have values.
- */
-Requisition.prototype._getFirstBlankPositionalAssignment = function() {
-  var reply = null;
-  Object.keys(this._assignments).some(function(name) {
-    var assignment = this.getAssignment(name);
-    if (assignment.arg.type === 'BlankArgument' &&
-            assignment.param.isPositionalAllowed) {
-      reply = assignment;
-      return true; // i.e. break
-    }
-    return false;
-  }, this);
-  return reply;
-};
-
-/**
  * Where parameter name == assignment names - they are the same
  */
 Requisition.prototype.getParameterNames = function() {
   return Object.keys(this._assignments);
 };
 
 /**
  * A *shallow* clone of the assignments.
@@ -5666,44 +5599,29 @@ Requisition.prototype.getAssignments = f
 };
 
 /**
  * Alter the given assignment using the given arg. This function is better than
  * calling assignment.setConversion(assignment.param.type.parse(arg)) because
  * it adjusts the args in this requisition to keep things up to date
  */
 Requisition.prototype.setAssignment = function(assignment, arg) {
-  var originalArgs = assignment.arg.getArgs();
+  var originalArg = assignment.arg;
   var conversion = assignment.param.type.parse(arg);
   assignment.setConversion(conversion);
 
-  var replacementArgs = arg.getArgs();
-  var maxLen = Math.max(originalArgs.length, replacementArgs.length);
-  for (var i = 0; i < maxLen; i++) {
-    // If there are no more original args, or if the original arg was blank
-    // (i.e. not typed by the user), we'll just need to add at the end
-    if (i >= originalArgs.length || originalArgs[i].type === 'BlankArgument') {
-      this._args.push(replacementArgs[i]);
-      continue;
-    }
-
-    var index = this._args.indexOf(originalArgs[i]);
-    if (index === -1) {
-      console.error('Couldn\'t find ', originalArgs[i], ' in ', this._args);
-      throw new Error('Couldn\'t find ' + originalArgs[i]);
-    }
-
-    // If there are no more replacement args, we just remove the original args
-    // Otherwise swap original args and replacements
-    if (i >= replacementArgs.length) {
-      this._args.splice(index, 1);
-    }
-    else {
-      this._args[index] = replacementArgs[i];
-    }
+  // If this argument isn't assigned to anything (i.e. it was created by
+  // assignment.setBlank) we need to add it into the _args array so
+  // requisition.toString can make sense
+  if (originalArg.type === 'BlankArgument') {
+    this._args.push(arg);
+  }
+  else {
+    var index = this._args.indexOf(originalArg);
+    this._args[index] = conversion.arg;
   }
 };
 
 /**
  * Reset all the assignments to their default values
  */
 Requisition.prototype.setBlankArguments = function() {
   this.getAssignments().forEach(function(assignment) {
@@ -5722,124 +5640,74 @@ Requisition.prototype.setBlankArguments 
  * which should be set to start and end of the selection.
  * @param predictionChoice The index of the prediction that we should choose.
  * This number is not bounded by the size of the prediction array, we take the
  * modulus to get it within bounds
  */
 Requisition.prototype.complete = function(cursor, predictionChoice) {
   var assignment = this.getAssignmentAt(cursor.start);
 
-  this.onTextChange.holdFire();
-
-  var prediction = assignment.getPredictionAt(predictionChoice);
-  if (prediction == null) {
-    // No predictions generally means we shouldn't change anything on TAB, but
-    // TAB has the connotation of 'next thing' and when we're at the end of
-    // a thing that implies that we should add a space. i.e.
-    // 'help<TAB>' -> 'help '
-    // But we should only do this if the thing that we're 'completing' is valid
-    // and doesn't already end in a space.
-    if (assignment.arg.suffix.slice(-1) !== ' ' &&
-            assignment.getStatus() === Status.VALID) {
-      this._addSpace(assignment);
-    }
-
-    // Also add a space if we are in the name part of an assignment, however
-    // this time we don't want the 'push the space to the next assignment'
-    // logic, so we don't use addSpace
-    if (assignment.isInName()) {
-      var newArg = assignment.conversion.arg.beget({ prefixPostSpace: true });
-      this.setAssignment(assignment, newArg);
-    }
-  }
-  else {
+  var predictions = assignment.conversion.getPredictions();
+  if (predictions.length > 0) {
+    this.onTextChange.holdFire();
+
+    var prediction = assignment.conversion.getPredictionAt(predictionChoice);
+
     // Mutate this argument to hold the completion
-    var arg = assignment.arg.beget({ text: prediction.name });
+    var arg = assignment.arg.beget(prediction.name);
     this.setAssignment(assignment, arg);
 
-    if (!prediction.incomplete) {
-      // The prediction is complete, add a space to let the user move-on
-      this._addSpace(assignment);
-
-      // Bug 779443 - Remove or explain the reparse
-      if (assignment instanceof UnassignedAssignment) {
-        this.update(this.toString());
+    if (prediction.incomplete) {
+      // This is the easy case - the prediction is incomplete - no need to add
+      // any spaces
+      return;
+    }
+
+    // The prediction reported !incomplete, which means it's complete so we
+    // should add a space to delimit this argument and let the user move-on.
+    // The question is, where does the space go? The obvious thing to do is to
+    // add it to the suffix of the completed argument, but that's wrong because
+    // spaces are attached to the start of the next argument rather than the
+    // end of the previous one (and this matters to getCurrentAssignment).
+    // However there might not be a next argument (if we've at the end of the
+    // input), in which case we really do use this one.
+    // Also if there is already a space in those positions, don't add another
+
+    var nextIndex = assignment.paramIndex + 1;
+    var nextAssignment = this.getAssignment(nextIndex);
+    if (nextAssignment) {
+      // Add a space onto the next argument (if there isn't one there already)
+      var nextArg = nextAssignment.conversion.arg;
+      if (nextArg.prefix.charAt(0) !== ' ') {
+        nextArg = new Argument(nextArg.text, ' ' + nextArg.prefix, nextArg.suffix);
+        this.setAssignment(nextAssignment, nextArg);
       }
     }
-  }
-
-  this.onTextChange();
-  this.onTextChange.resumeFire();
-};
-
-/**
- * Pressing TAB sometimes requires that we add a space to denote that we're on
- * to the 'next thing'.
- * The question is, where does the space go? The obvious thing to do is to add
- * it to the suffix of the completed argument, but that's wrong because spaces
- * are attached to the start of the next argument rather than the end of the
- * previous one (and this matters to getCurrentAssignment).
- * However there might not be a 'next' argument (if we've at the end of the
- * input), in which case we really do use this one.
- * Also if there is already a space in those positions, don't add another
- * In addition to all of this, we need to know what the 'next' argument is.
- * We can't use the argument defined just after the thing that is being
- * completed, because we could be completing a named argument, so we need to
- * look for the first blank positional parameter, but if there isn't one of
- * those then we just add to the suffix of the current.
- * @param assignment The 'last' assignment to which to append the space if
- * there is no 'next' assignment to which we can prepend a space
- */
-Requisition.prototype._addSpace = function(assignment) {
-  var nextAssignment = this._getFirstBlankPositionalAssignment();
-  if (nextAssignment) {
-    // Add a space onto the next argument (if there isn't one there already)
-    var nextArg = nextAssignment.conversion.arg;
-    if (nextArg.prefix.charAt(0) !== ' ') {
-      nextArg = new Argument(nextArg.text, ' ' + nextArg.prefix, nextArg.suffix);
-      this.setAssignment(nextAssignment, nextArg);
-    }
-  }
-  else {
-    // There is no next argument, this must be the last assignment, so just
-    // add the space to the prefix of this argument
-    var newArg = assignment.conversion.arg.beget({ suffixSpace: true });
-    if (newArg !== assignment.conversion.arg) {
-      // It's tempting to think - "we're calling setAssignment twice in one
-      // call to complete, the first time to complete the text, the second
-      // to add a space, why not save the event cascade and do it once"
-      // However if we're setting up the command, the number of parameters
-      // changes as a result, so our call to getFirstBlankPositionalAssignment
-      // will produce the wrong answer
-      this.setAssignment(assignment, newArg);
-    }
-  }
-};
-
-/**
- * Replace the current value with the lower value if such a concept exists.
- */
-Requisition.prototype.decrement = function(assignment) {
-  var replacement = assignment.param.type.decrement(assignment.conversion.value);
-  if (replacement != null) {
-    var str = assignment.param.type.stringify(replacement);
-    var arg = assignment.conversion.arg.beget({ text: str });
-    this.setAssignment(assignment, arg);
-  }
-};
-
-/**
- * Replace the current value with the higher value if such a concept exists.
- */
-Requisition.prototype.increment = function(assignment) {
-  var replacement = assignment.param.type.increment(assignment.conversion.value);
-  if (replacement != null) {
-    var str = assignment.param.type.stringify(replacement);
-    var arg = assignment.conversion.arg.beget({ text: str });
-    this.setAssignment(assignment, arg);
+    else {
+      // There is no next argument, this must be the last assignment, so just
+      // add the space to the prefix of this argument
+      arg = assignment.conversion.arg;
+      if (arg.suffix.charAt(arg.suffix.length - 1) !== ' ') {
+        // It's tempting to think - "we're calling setAssignment twice in one
+        // call to complete, the first time to complete the text, the second
+        // to add a space, why not save the event cascade and do it once"
+        // However if we're setting up the command, the number of parameters
+        // changes as a result, so our call to getAssignment(nextIndex) will
+        // produce the wrong answer
+        arg = new Argument(arg.text, arg.prefix, arg.suffix + ' ');
+        this.setAssignment(assignment, arg);
+      }
+    }
+
+    if (assignment instanceof UnassignedAssignment) {
+      this.update(this.toString());
+    }
+
+    this.onTextChange();
+    this.onTextChange.resumeFire();
   }
 };
 
 /**
  * Extract a canonical version of the input
  */
 Requisition.prototype.toCanonicalString = function() {
   var line = [];
@@ -6049,22 +5917,19 @@ Requisition.prototype.getAssignmentAt = 
     // otherwise it looks forwards
     if (arg.assignment.arg.type === 'NamedArgument') {
       // leave the argument as it is
     }
     else if (this._args.length > i + 1) {
       // first to the next argument
       assignment = this._args[i + 1].assignment;
     }
-    else {
-      // then to the first blank positional parameter, leaving 'as is' if none
-      var nextAssignment = this._getFirstBlankPositionalAssignment();
-      if (nextAssignment != null) {
-        assignment = nextAssignment;
-      }
+    else if (assignment && assignment.paramIndex + 1 < this.assignmentCount) {
+      // then to the next assignment
+      assignment = this.getAssignment(assignment.paramIndex + 1);
     }
 
     for (j = 0; j < arg.suffix.length; j++) {
       assignForPos.push(assignment);
     }
   }
 
   // Possible shortcut, we don't really need to go through all the args
@@ -6565,17 +6430,17 @@ Requisition.prototype._assign = function
       if (assignment.param.isKnownAs(args[i].text)) {
         var arg = args.splice(i, 1)[0];
         unassignedParams = unassignedParams.filter(function(test) {
           return test !== assignment.param.name;
         });
 
         // boolean parameters don't have values, default to false
         if (assignment.param.type instanceof BooleanType) {
-          arg = new TrueNamedArgument(arg);
+          arg = new TrueNamedArgument(null, arg);
         }
         else {
           var valueArg = null;
           if (i + 1 <= args.length) {
             valueArg = args.splice(i, 1)[0];
           }
           arg = new NamedArgument(arg, valueArg);
         }
@@ -7330,17 +7195,17 @@ StringField.prototype.destroy = function
 StringField.prototype.setConversion = function(conversion) {
   this.arg = conversion.arg;
   this.element.value = conversion.arg.text;
   this.setMessage(conversion.message);
 };
 
 StringField.prototype.getConversion = function() {
   // This tweaks the prefix/suffix of the argument to fit
-  this.arg = this.arg.beget({ text: this.element.value, prefixSpace: true });
+  this.arg = this.arg.beget(this.element.value, { prefixSpace: true });
   return this.type.parse(this.arg);
 };
 
 StringField.claim = function(type) {
   return type instanceof StringType ? Field.MATCH : Field.BASIC;
 };
 
 
@@ -7385,17 +7250,17 @@ NumberField.prototype.destroy = function
 
 NumberField.prototype.setConversion = function(conversion) {
   this.arg = conversion.arg;
   this.element.value = conversion.arg.text;
   this.setMessage(conversion.message);
 };
 
 NumberField.prototype.getConversion = function() {
-  this.arg = this.arg.beget({ text: this.element.value, prefixSpace: true });
+  this.arg = this.arg.beget(this.element.value, { prefixSpace: true });
   return this.type.parse(this.arg);
 };
 
 
 /**
  * A field that uses a checkbox to toggle a boolean field
  */
 function BooleanField(type, options) {
@@ -7432,17 +7297,17 @@ BooleanField.prototype.setConversion = f
   this.element.checked = conversion.value;
   this.setMessage(conversion.message);
 };
 
 BooleanField.prototype.getConversion = function() {
   var arg;
   if (this.named) {
     arg = this.element.checked ?
-            new TrueNamedArgument(new Argument(' --' + this.name)) :
+            new TrueNamedArgument(this.name) :
             new FalseNamedArgument();
   }
   else {
     arg = new Argument(' ' + this.element.checked);
   }
   return this.type.parse(arg);
 };
 
@@ -7884,17 +7749,17 @@ exports.addField(BlankField);
  * limitations under the License.
  */
 
 define('gcli/ui/fields/javascript', ['require', 'exports', 'module' , 'gcli/util', 'gcli/argument', 'gcli/types/javascript', 'gcli/ui/fields/menu', 'gcli/ui/fields'], function(require, exports, module) {
 
 
 var util = require('gcli/util');
 
-var ScriptArgument = require('gcli/argument').ScriptArgument;
+var Argument = require('gcli/argument').Argument;
 var JavascriptType = require('gcli/types/javascript').JavascriptType;
 
 var Menu = require('gcli/ui/fields/menu').Menu;
 var Field = require('gcli/ui/fields').Field;
 var fields = require('gcli/ui/fields');
 
 
 /**
@@ -7911,17 +7776,17 @@ exports.shutdown = function() {
 
 /**
  * A field that allows editing of javascript
  */
 function JavascriptField(type, options) {
   Field.call(this, type, options);
 
   this.onInputChange = this.onInputChange.bind(this);
-  this.arg = new ScriptArgument('', '{ ', ' }');
+  this.arg = new Argument('', '{ ', ' }');
 
   this.element = util.createElement(this.document, 'div');
 
   this.input = util.createElement(this.document, 'input');
   this.input.type = 'text';
   this.input.addEventListener('keyup', this.onInputChange, false);
   this.input.classList.add('gcli-field');
   this.input.classList.add('gcli-field-javascript');
@@ -7929,17 +7794,17 @@ function JavascriptField(type, options) 
 
   this.menu = new Menu({
     document: this.document,
     field: true,
     type: type
   });
   this.element.appendChild(this.menu.element);
 
-  this.setConversion(this.type.parse(new ScriptArgument('')));
+  this.setConversion(this.type.parse(new Argument('')));
 
   this.onFieldChange = util.createEvent('JavascriptField.onFieldChange');
 
   // i.e. Register this.onItemClick as the default action for a menu click
   this.menu.onItemClick.add(this.itemClicked, this);
 }
 
 JavascriptField.prototype = Object.create(Field.prototype);
@@ -7999,17 +7864,17 @@ JavascriptField.prototype.onInputChange 
   this.item = ev.currentTarget.item;
   var conversion = this.getConversion();
   this.onFieldChange({ conversion: conversion });
   this.setMessage(conversion.message);
 };
 
 JavascriptField.prototype.getConversion = function() {
   // This tweaks the prefix/suffix of the argument to fit
-  this.arg = new ScriptArgument(this.input.value, '{ ', ' }');
+  this.arg = this.arg.beget(this.input.value, { normalize: true });
   return this.type.parse(this.arg);
 };
 
 JavascriptField.DEFAULT_VALUE = '__JavascriptField.DEFAULT_VALUE';
 
 
 });
 /*
@@ -8369,17 +8234,17 @@ SelectionField.prototype._addOption = fu
   var option = util.createElement(this.document, 'option');
   option.innerHTML = item.name;
   option.value = item.index;
   this.element.appendChild(option);
 };
 
 
 /**
- * A field that allows selection of one of a number of options
+ * A field that allows editing of javascript
  */
 function SelectionTooltipField(type, options) {
   Field.call(this, type, options);
 
   this.onInputChange = this.onInputChange.bind(this);
   this.arg = new Argument();
 
   this.menu = new Menu({ document: this.document, type: type });
@@ -8427,17 +8292,17 @@ SelectionTooltipField.prototype.onInputC
   this.item = ev.currentTarget.item;
   var conversion = this.getConversion();
   this.onFieldChange({ conversion: conversion });
   this.setMessage(conversion.message);
 };
 
 SelectionTooltipField.prototype.getConversion = function() {
   // This tweaks the prefix/suffix of the argument to fit
-  this.arg = this.arg.beget({ text: this.input.value });
+  this.arg = this.arg.beget('typed', { normalize: true });
   return this.type.parse(this.arg);
 };
 
 /**
  * Allow the menu to highlight the correct prediction choice
  */
 SelectionTooltipField.prototype.setChoiceIndex = function(choice) {
   this.menu.setChoiceIndex(choice);
@@ -9524,17 +9389,17 @@ Inputter.prototype.onKeyUp = function(ev
     else if (this.element.value === '' || this._scrollingThroughHistory) {
       this._scrollingThroughHistory = true;
       this.requisition.update(this.history.backward());
     }
     else {
       // If the user is on a valid value, then we increment the value, but if
       // they've typed something that's not right we page through predictions
       if (this.assignment.getStatus() === Status.VALID) {
-        this.requisition.increment(assignment);
+        this.assignment.increment();
         // See notes on focusManager.onInputChange in onKeyDown
         if (this.focusManager) {
           this.focusManager.onInputChange(ev);
         }
       }
       else {
         this.changeChoice(-1);
       }
@@ -9548,17 +9413,17 @@ Inputter.prototype.onKeyUp = function(ev
     }
     else if (this.element.value === '' || this._scrollingThroughHistory) {
       this._scrollingThroughHistory = true;
       this.requisition.update(this.history.forward());
     }
     else {
       // See notes above for the UP key
       if (this.assignment.getStatus() === Status.VALID) {
-        this.requisition.decrement(assignment);
+        this.assignment.decrement();
         // See notes on focusManager.onInputChange in onKeyDown
         if (this.focusManager) {
           this.focusManager.onInputChange(ev);
         }
       }
       else {
         this.changeChoice(+1);
       }
@@ -9885,132 +9750,101 @@ Completer.prototype.update = function(ev
 Completer.prototype._getCompleterTemplateData = function() {
   var input = this.inputter.getInputState();
 
   // directTabText is for when the current input is a prefix of the completion
   // arrowTabText is for when we need to use an -> to show what will be used
   var directTabText = '';
   var arrowTabText = '';
   var current = this.requisition.getAssignmentAt(input.cursor.start);
-  var emptyParameters = [];
 
   if (input.typed.trim().length !== 0) {
-    var cArg = current.arg;
-    var prediction = current.getPredictionAt(this.choice);
-
+    var prediction = current.conversion.getPredictionAt(this.choice);
     if (prediction) {
       var tabText = prediction.name;
-      var existing = cArg.text;
-
-      // Normally the cursor being just before whitespace means that you are
-      // 'in' the previous argument, which means that the prediction is based
-      // on that argument, however NamedArguments break this by having 2 parts
-      // so we need to prepend the tabText with a space for NamedArguments,
-      // but only when there isn't already a space at the end of the prefix
-      // (i.e. ' --name' not ' --name ')
-      if (current.isInName()) {
-        tabText = ' ' + tabText;
-      }
+      var existing = current.arg.text;
 
       if (existing !== tabText) {
         // Decide to use directTabText or arrowTabText
         // Strip any leading whitespace from the user inputted value because the
         // tabText will never have leading whitespace.
         var inputValue = existing.replace(/^\s*/, '');
         var isStrictCompletion = tabText.indexOf(inputValue) === 0;
         if (isStrictCompletion && input.cursor.start === input.typed.length) {
           // Display the suffix of the prediction as the completion
           var numLeadingSpaces = existing.match(/^(\s*)/)[0].length;
 
           directTabText = tabText.slice(existing.length - numLeadingSpaces);
         }
         else {
           // Display the '-> prediction' at the end of the completer element
-          // \u21E5 is the JS escape right arrow
-          arrowTabText = '\u21E5 ' + tabText;
+          // These JS escapes are aka &nbsp;&rarr; the right arrow
+          arrowTabText = ' \u00a0\u21E5 ' + tabText;
         }
       }
     }
-    else {
-      // There's no prediction, but if this is a named argument that needs a
-      // value (that is without any) then we need to show that one is needed
-      // For example 'git commit --message ', clearly needs some more text
-      if (cArg.type === 'NamedArgument' && cArg.text === '') {
-        emptyParameters.push('<' + current.param.type.name + '>\u00a0');
-      }
-    }
-  }
-
-  // Add a space between the typed text (+ directTabText) and the hints,
-  // making sure we don't add 2 sets of padding
-  if (directTabText !== '') {
-    directTabText += '\u00a0';
-  }
-  else if (!this.requisition.typedEndsWithSeparator()) {
-    emptyParameters.unshift('\u00a0');
   }
 
   // statusMarkup is wrapper around requisition.getInputStatusMarkup converting
   // space to &nbsp; in the string member (for HTML display) and status to an
   // appropriate class name (i.e. lower cased, prefixed with gcli-in-)
   var statusMarkup = this.requisition.getInputStatusMarkup(input.cursor.start);
   statusMarkup.forEach(function(member) {
     member.string = member.string.replace(/ /g, '\u00a0'); // i.e. &nbsp;
     member.className = 'gcli-in-' + member.status.toString().toLowerCase();
   }, this);
 
   // Calculate the list of parameters to be filled in
+  var trailingSeparator = this.requisition.typedEndsWithSeparator();
   // We generate an array of emptyParameter markers for each positional
   // parameter to the current command.
   // Generally each emptyParameter marker begins with a space to separate it
   // from whatever came before, unless what comes before ends in a space.
-
-  var command = this.requisition.commandAssignment.value;
-  var jsCommand = command && command.name === '{';
-
+  // Also if we've got a directTabText prediction or we're in a NamedParameter
+  // then we don't want any text for that parameter at all.
+  // The algorithm to add spaces needs to take this into account.
+
+  var firstBlankParam = true;
+  var emptyParameters = [];
   this.requisition.getAssignments().forEach(function(assignment) {
-    // Named arguments are handled with a group [options] marker
     if (!assignment.param.isPositionalAllowed) {
       return;
     }
-
-    // No hints if we've got content for this parameter
-    if (assignment.arg.toString().trim() !== '') {
+    if (current.arg.type === 'NamedArgument') {
       return;
     }
 
-    if (directTabText !== '' && current === assignment) {
+    if (assignment.arg.toString().trim() !== '') {
+      if (directTabText !== '') {
+        firstBlankParam = false;
+      }
+      return;
+    }
+
+    if (directTabText !== '' && firstBlankParam) {
+      firstBlankParam = false;
       return;
     }
 
     var text = (assignment.param.isDataRequired) ?
-        '<' + assignment.param.name + '>\u00a0' :
-        '[' + assignment.param.name + ']\u00a0';
-
+        '<' + assignment.param.name + '>' :
+        '[' + assignment.param.name + ']';
+
+    // Add a space if we don't have one at the end of the input or if
+    // this isn't the first param we've mentioned
+    if (!trailingSeparator || !firstBlankParam) {
+      text = '\u00a0' + text; // i.e. &nbsp;
+    }
+
+    firstBlankParam = false;
     emptyParameters.push(text);
   }.bind(this));
 
-  var addOptionsMarker = false;
-  // We add an '[options]' marker when there are named parameters that are
-  // not filled in and not hidden, and we don't have any directTabText
-  if (command && command.hasNamedParameters) {
-    command.params.forEach(function(param) {
-      var arg = this.requisition.getAssignment(param.name).arg;
-      if (!param.isPositionalAllowed && !param.hidden
-              && arg.type === "BlankArgument") {
-        addOptionsMarker = true;
-      }
-    }, this);
-  }
-
-  if (addOptionsMarker) {
-    // Add an nbsp if we don't have one at the end of the input or if
-    // this isn't the first param we've mentioned
-    emptyParameters.push('[options]\u00a0');
-  }
+  var command = this.requisition.commandAssignment.value;
+  var jsCommand = command && command.name === '{';
 
   // Is the entered command a JS command with no closing '}'?
   // TWEAK: This code should be considered for promotion to Requisition
   var unclosedJs = jsCommand &&
       this.requisition.getAssignment(0).arg.suffix.indexOf('}') === -1;
 
   // The text for the 'jump to scratchpad' feature, or '' if it is disabled
   var link = this.scratchpad && jsCommand ? this.scratchpad.linkText : '';
rename from browser/devtools/commandline/commandlineoutput.xhtml
rename to browser/devtools/commandline/gclioutput.xhtml
--- a/browser/devtools/commandline/commandlineoutput.xhtml
+++ b/browser/devtools/commandline/gclioutput.xhtml
@@ -4,15 +4,15 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   <link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
-  <link rel="stylesheet" href="chrome://browser/content/devtools/commandline.css" type="text/css"/>
-  <link rel="stylesheet" href="chrome://browser/skin/devtools/commandline.css" type="text/css"/>
+  <link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
+  <link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
 </head>
 <body class="gcli-body">
 <div id="gcli-output-root"></div>
 </body>
 </html>
rename from browser/devtools/commandline/commandlinetooltip.xhtml
rename to browser/devtools/commandline/gclitooltip.xhtml
--- a/browser/devtools/commandline/commandlinetooltip.xhtml
+++ b/browser/devtools/commandline/gclitooltip.xhtml
@@ -4,16 +4,16 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   <link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
-  <link rel="stylesheet" href="chrome://browser/content/devtools/commandline.css" type="text/css"/>
-  <link rel="stylesheet" href="chrome://browser/skin/devtools/commandline.css" type="text/css"/>
+  <link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
+  <link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
 </head>
 <body class="gcli-body">
 <div id="gcli-tooltip-root"></div>
 <div id="gcli-tooltip-connector"></div>
 </body>
 </html>
--- a/browser/devtools/commandline/test/Makefile.in
+++ b/browser/devtools/commandline/test/Makefile.in
@@ -7,33 +7,40 @@ DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES = \
-  browser_dbg_cmd_break.js \
-  browser_dbg_cmd.js \
-  browser_cmd_addon.js \
-  browser_cmd_calllog.js \
-  browser_cmd_commands.js \
-  browser_cmd_cookie.js \
-  browser_cmd_integrate.js \
-  browser_cmd_jsb.js \
-  browser_cmd_pagemod_export.js \
-  browser_cmd_pref.js \
-  browser_cmd_restart.js \
-  browser_cmd_settings.js \
+  browser_gcli_addon.js \
+  browser_gcli_break.js \
+  browser_gcli_calllog.js \
+  browser_gcli_commands.js \
+  browser_gcli_cookie.js \
+  browser_gcli_dbg.js \
+  browser_gcli_edit.js \
+  browser_gcli_inspect.js \
+  browser_gcli_integrate.js \
+  browser_gcli_jsb.js \
+  browser_gcli_pagemod_export.js \
+  browser_gcli_pref.js \
+  browser_gcli_responsivemode.js \
+  browser_gcli_restart.js \
+  browser_gcli_settings.js \
   browser_gcli_web.js \
   head.js \
-  helpers.js \
   $(NULL)
 
 MOCHITEST_BROWSER_FILES += \
-  browser_dbg_cmd_break.html \
-  browser_dbg_cmd.html \
-  browser_cmd_pagemod_export.html \
-  browser_cmd_jsb_script.jsi \
+  browser_gcli_break.html \
+  browser_gcli_inspect.html \
+  resources_dbg.html \
+  resources_inpage.js \
+  resources_inpage1.css \
+  resources_inpage2.css \
+  resources_jsb_script.js \
+  resources.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
+
rename from browser/devtools/commandline/test/browser_cmd_addon.js
rename to browser/devtools/commandline/test/browser_gcli_addon.js
--- a/browser/devtools/commandline/test/browser_cmd_addon.js
+++ b/browser/devtools/commandline/test/browser_gcli_addon.js
@@ -1,94 +1,43 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Tests that the addon commands works as they should
-
 function test() {
-  DeveloperToolbarTest.test("about:blank", [ GAT_test ]);
-}
-
-function GAT_test() {
-  var GAT_ready = DeveloperToolbarTest.checkCalled(function() {
-    Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
-
-    helpers.setInput('addon list dictionary');
-    helpers.check({
-      input:  'addon list dictionary',
-      hints:                       '',
-      markup: 'VVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID'
-    });
-
-    helpers.setInput('addon list extension');
-    helpers.check({
-      input:  'addon list extension',
-      hints:                      '',
-      markup: 'VVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID'
-    });
-
-    helpers.setInput('addon list locale');
-    helpers.check({
-      input:  'addon list locale',
-      hints:                   '',
-      markup: 'VVVVVVVVVVVVVVVVV',
-      status: 'VALID'
-    });
-
-    helpers.setInput('addon list plugin');
-    helpers.check({
-      input:  'addon list plugin',
-      hints:                   '',
-      markup: 'VVVVVVVVVVVVVVVVV',
-      status: 'VALID'
-    });
+  DeveloperToolbarTest.test("about:blank", function GAT_test() {
+    function GAT_ready() {
+      Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
 
-    helpers.setInput('addon list theme');
-    helpers.check({
-      input:  'addon list theme',
-      hints:                  '',
-      markup: 'VVVVVVVVVVVVVVVV',
-      status: 'VALID'
-    });
-
-    helpers.setInput('addon list all');
-    helpers.check({
-      input:  'addon list all',
-      hints:                '',
-      markup: 'VVVVVVVVVVVVVV',
-      status: 'VALID'
-    });
-
-    helpers.setInput('addon disable Test_Plug-in_1.0.0.0');
-    helpers.check({
-      input:  'addon disable Test_Plug-in_1.0.0.0',
-      hints:                                    '',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID'
-    });
-
-    helpers.setInput('addon disable WRONG');
-    helpers.check({
-      input:  'addon disable WRONG',
-      hints:                     '',
-      markup: 'VVVVVVVVVVVVVVEEEEE',
-      status: 'ERROR'
-    });
-
-    helpers.setInput('addon enable Test_Plug-in_1.0.0.0');
-    helpers.check({
-      input:  'addon enable Test_Plug-in_1.0.0.0',
-      hints:                                   '',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID',
-      args: {
-        command: { name: 'addon enable' },
-        name: { value: 'Test Plug-in', status: 'VALID' },
-      }
-    });
-
-    DeveloperToolbarTest.exec({ completed: false });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list dictionary",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list extension",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list locale",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list plugin",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list theme",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list all",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon disable Test_Plug-in_1.0.0.0",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon enable Test_Plug-in_1.0.0.0",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.exec({ completed: false });
+      finish();
+    }
+    Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
   });
-
-  Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
 }
rename from browser/devtools/commandline/test/browser_dbg_cmd_break.html
rename to browser/devtools/commandline/test/browser_gcli_break.html
rename from browser/devtools/commandline/test/browser_dbg_cmd_break.js
rename to browser/devtools/commandline/test/browser_gcli_break.js
--- a/browser/devtools/commandline/test/browser_dbg_cmd_break.js
+++ b/browser/devtools/commandline/test/browser_gcli_break.js
@@ -1,120 +1,82 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the break command works as it should
 
-const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
-                 "test/browser_dbg_cmd_break.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_break.html";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ testBreakCommands ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testBreakCommands();
+  });
 }
 
 function testBreakCommands() {
-  helpers.setInput('break');
-  helpers.check({
-    input:  'break',
-    hints:       '',
-    markup: 'IIIII',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "brea",
+    directTabText: "k",
+    status: "ERROR"
   });
 
-  helpers.setInput('break add');
-  helpers.check({
-    input:  'break add',
-    hints:           '',
-    markup: 'IIIIIVIII',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "break",
+    status: "ERROR"
   });
 
-  helpers.setInput('break add line');
-  helpers.check({
-    input:  'break add line',
-    hints:                ' <file> <line>',
-    markup: 'VVVVVVVVVVVVVV',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "break add",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "break add line",
+    emptyParameters: [ " <file>", " <line>" ],
+    status: "ERROR"
   });
 
   let pane = DebuggerUI.toggleDebugger();
-
-  var dbgConnected = DeveloperToolbarTest.checkCalled(function() {
+  pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
     pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
 
     // Wait for the initial resume.
     let client = pane.contentWindow.gClient;
-
-    var resumed = DeveloperToolbarTest.checkCalled(function() {
-
-      var framesAdded = DeveloperToolbarTest.checkCalled(function() {
-        helpers.setInput('break add line ' + TEST_URI + ' ' + content.wrappedJSObject.line0);
-        helpers.check({
-          hints: '',
-          status: 'VALID',
-          args: {
-            file: { value: TEST_URI },
-            line: { value: content.wrappedJSObject.line0 },
-          }
+    client.addOneTimeListener("resumed", function() {
+      client.activeThread.addOneTimeListener("framesadded", function() {
+        DeveloperToolbarTest.checkInputStatus({
+          typed: "break add line " + TEST_URI + " " + content.wrappedJSObject.line0,
+          status: "VALID"
         });
-
         DeveloperToolbarTest.exec({
           args: {
             type: 'line',
             file: TEST_URI,
             line: content.wrappedJSObject.line0
           },
           completed: false
         });
 
-        helpers.setInput('break list');
-        helpers.check({
-          input:  'break list',
-          hints:            '',
-          markup: 'VVVVVVVVVV',
-          status: 'VALID'
+        DeveloperToolbarTest.checkInputStatus({
+          typed: "break list",
+          status: "VALID"
         });
-
         DeveloperToolbarTest.exec();
 
-        var cleanup = DeveloperToolbarTest.checkCalled(function() {
-          helpers.setInput('break del 9');
-          helpers.check({
-            input:  'break del 9',
-            hints:             '',
-            markup: 'VVVVVVVVVVE',
-            status: 'ERROR',
-            args: {
-              breakid: { status: 'ERROR', message: '9 is greater than maximum allowed: 0.' },
-            }
+        client.activeThread.resume(function() {
+          DeveloperToolbarTest.checkInputStatus({
+            typed: "break del 0",
+            status: "VALID"
           });
-
-          helpers.setInput('break del 0');
-          helpers.check({
-            input:  'break del 0',
-            hints:             '',
-            markup: 'VVVVVVVVVVV',
-            status: 'VALID',
-            args: {
-              breakid: { value: 0 },
-            }
-          });
-
           DeveloperToolbarTest.exec({
             args: { breakid: 0 },
             completed: false
           });
+
+          finish();
         });
-
-        client.activeThread.resume(cleanup);
       });
 
-      client.activeThread.addOneTimeListener("framesadded", framesAdded);
-
       // Trigger newScript notifications using eval.
       content.wrappedJSObject.firstCall();
     });
-
-    client.addOneTimeListener("resumed", resumed);
-  });
-
-  pane._frame.addEventListener("Debugger:Connecting", dbgConnected, true);
+  }, true);
 }
rename from browser/devtools/commandline/test/browser_cmd_calllog.js
rename to browser/devtools/commandline/test/browser_gcli_calllog.js
--- a/browser/devtools/commandline/test/browser_cmd_calllog.js
+++ b/browser/devtools/commandline/test/browser_gcli_calllog.js
@@ -4,54 +4,51 @@
 // Tests that the calllog commands works as they should
 
 let imported = {};
 Components.utils.import("resource:///modules/HUDService.jsm", imported);
 
 const TEST_URI = "data:text/html;charset=utf-8,gcli-calllog";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ testCallLogStatus, testCallLogExec ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testCallLogStatus();
+    testCallLogExec();
+    finish();
+  });
 }
 
 function testCallLogStatus() {
-  helpers.setInput('calllog');
-  helpers.check({
-    input:  'calllog',
-    hints:         '',
-    markup: 'IIIIIII',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "calllog",
+    status: "ERROR"
   });
 
-  helpers.setInput('calllog start');
-  helpers.check({
-    input:  'calllog start',
-    hints:               '',
-    markup: 'VVVVVVVVVVVVV',
-    status: 'VALID'
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "calllog start",
+    status: "VALID",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('calllog stop');
-  helpers.check({
-    input:  'calllog stop',
-    hints:              '',
-    markup: 'VVVVVVVVVVVV',
-    status: 'VALID'
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "calllog start",
+    status: "VALID",
+    emptyParameters: [ ]
   });
 }
 
 function testCallLogExec() {
   DeveloperToolbarTest.exec({
     typed: "calllog stop",
     args: { },
     outputMatch: /No call logging/,
   });
 
   let hud = null;
-  var onWebConsoleOpen = DeveloperToolbarTest.checkCalled(function(aSubject) {
+  function onWebConsoleOpen(aSubject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     aSubject.QueryInterface(Ci.nsISupportsString);
     hud = imported.HUDService.getHudReferenceById(aSubject.data);
     ok(hud.hudId in imported.HUDService.hudReferences, "console open");
 
     DeveloperToolbarTest.exec({
       typed: "calllog stop",
@@ -68,17 +65,17 @@ function testCallLogExec() {
     let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
     is(labels.length, 0, "no output in console");
 
     DeveloperToolbarTest.exec({
       typed: "console close",
       args: {},
       blankOutput: true,
     });
-  });
+  }
 
   Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false);
 
   DeveloperToolbarTest.exec({
     typed: "calllog start",
     args: { },
     outputMatch: /Call logging started/,
   });
rename from browser/devtools/commandline/test/browser_cmd_commands.js
rename to browser/devtools/commandline/test/browser_gcli_commands.js
--- a/browser/devtools/commandline/test/browser_cmd_commands.js
+++ b/browser/devtools/commandline/test/browser_gcli_commands.js
@@ -4,28 +4,36 @@
 // Test various GCLI commands
 
 let imported = {};
 Components.utils.import("resource:///modules/HUDService.jsm", imported);
 
 const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ testEcho, testConsole ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testEcho();
+    testConsole(tab);
+
+    imported = undefined;
+    finish();
+  });
 }
 
 function testEcho() {
+  /*
   DeveloperToolbarTest.exec({
     typed: "echo message",
     args: { message: "message" },
     outputMatch: /^message$/,
   });
+  */
 }
 
-function testConsole(browser, tab) {
+function testConsole(tab) {
   let hud = null;
   function onWebConsoleOpen(aSubject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     aSubject.QueryInterface(Ci.nsISupportsString);
     hud = imported.HUDService.getHudReferenceById(aSubject.data);
     ok(hud.hudId in imported.HUDService.hudReferences, "console open");
 
@@ -57,10 +65,11 @@ function testConsole(browser, tab) {
       typed: "console close",
       args: {},
       blankOutput: true,
     });
 
     ok(!(hud.hudId in imported.HUDService.hudReferences), "console closed");
 
     imported = undefined;
+    finish();
   }
 }
rename from browser/devtools/commandline/test/browser_cmd_cookie.js
rename to browser/devtools/commandline/test/browser_gcli_cookie.js
--- a/browser/devtools/commandline/test/browser_cmd_cookie.js
+++ b/browser/devtools/commandline/test/browser_gcli_cookie.js
@@ -1,83 +1,53 @@
 /* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the cookie commands works as they should
 
 const TEST_URI = "data:text/html;charset=utf-8,gcli-cookie";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ testCookieCheck, testCookieExec ]);
-}
-
-function testCookieCheck() {
-  helpers.setInput('cookie');
-  helpers.check({
-    input:  'cookie',
-    hints:        '',
-    markup: 'IIIIII',
-    status: 'ERROR'
-  });
-
-  helpers.setInput('cookie lis');
-  helpers.check({
-    input:  'cookie lis',
-    hints:            't',
-    markup: 'IIIIIIVIII',
-    status: 'ERROR'
-  });
-
-  helpers.setInput('cookie list');
-  helpers.check({
-    input:  'cookie list',
-    hints:             '',
-    markup: 'VVVVVVVVVVV',
-    status: 'VALID'
-  });
-
-  helpers.setInput('cookie remove');
-  helpers.check({
-    input:  'cookie remove',
-    hints:               ' <key>',
-    markup: 'VVVVVVVVVVVVV',
-    status: 'ERROR'
-  });
-
-  helpers.setInput('cookie set');
-  helpers.check({
-    input:  'cookie set',
-    hints:            ' <key> <value> [options]',
-    markup: 'VVVVVVVVVV',
-    status: 'ERROR'
-  });
-
-  helpers.setInput('cookie set fruit');
-  helpers.check({
-    input:  'cookie set fruit',
-    hints:                  ' <value> [options]',
-    markup: 'VVVVVVVVVVVVVVVV',
-    status: 'ERROR'
-  });
-
-  helpers.setInput('cookie set fruit ban');
-  helpers.check({
-    input:  'cookie set fruit ban',
-    hints:                      ' [options]',
-    markup: 'VVVVVVVVVVVVVVVVVVVV',
-    status: 'VALID',
-    args: {
-      key: { value: 'fruit' },
-      value: { value: 'ban' },
-      secure: { value: false },
-    }
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testCookieCommands();
+    finish();
   });
 }
 
-function testCookieExec() {
+function testCookieCommands() {
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cook",
+    directTabText: "ie",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie l",
+    directTabText: "ist",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie list",
+    status: "VALID",
+    emptyParameters: [ ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie remove",
+    status: "ERROR",
+    emptyParameters: [ " <key>" ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie set",
+    status: "ERROR",
+    emptyParameters: [ " <key>", " <value>" ],
+  });
+
   DeveloperToolbarTest.exec({
     typed: "cookie set fruit banana",
     args: {
       key: "fruit",
       value: "banana",
       path: "/",
       domain: null,
       secure: false
rename from browser/devtools/commandline/test/browser_dbg_cmd.js
rename to browser/devtools/commandline/test/browser_gcli_dbg.js
--- a/browser/devtools/commandline/test/browser_dbg_cmd.js
+++ b/browser/devtools/commandline/test/browser_gcli_dbg.js
@@ -1,72 +1,67 @@
 function test() {
-  const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
-                   "test/browser_dbg_cmd.html";
+  const TEST_URI = TEST_BASE_HTTP + "resources_dbg.html";
 
-  DeveloperToolbarTest.test(TEST_URI, function() {
-    testDbgCmd();
-  });
-}
+  DeveloperToolbarTest.test(TEST_URI, function GAT_test() {
+    let pane = DebuggerUI.toggleDebugger();
+    ok(pane, "toggleDebugger() should return a pane.");
+    let frame = pane._frame;
 
-function testDbgCmd() {
-  let pane = DebuggerUI.toggleDebugger();
-  ok(pane, "toggleDebugger() should return a pane.");
-  let frame = pane._frame;
-
-  frame.addEventListener("Debugger:Connecting", function dbgConnected(aEvent) {
-    frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
+    frame.addEventListener("Debugger:Connecting", function dbgConnected(aEvent) {
+      frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
 
-    // Wait for the initial resume...
-    aEvent.target.ownerDocument.defaultView.gClient
-        .addOneTimeListener("resumed", function() {
+      // Wait for the initial resume...
+      aEvent.target.ownerDocument.defaultView.gClient
+          .addOneTimeListener("resumed", function() {
 
-      info("Starting tests.");
+        info("Starting tests.");
 
-      let contentDoc = content.window.document;
-      let output = contentDoc.querySelector("input[type=text]");
-      let btnDoit = contentDoc.querySelector("input[type=button]");
+        let contentDoc = content.window.document;
+        let output = contentDoc.querySelector("input[type=text]");
+        let btnDoit = contentDoc.querySelector("input[type=button]");
 
-      cmd("dbg interrupt", function() {
-        ok(true, "debugger is paused");
-        pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
-          ok(true, "debugger continued");
-          pane.contentWindow.gClient.addOneTimeListener("paused", function() {
-            cmd("dbg step in", function() {
+        cmd("dbg interrupt", function() {
+          ok(true, "debugger is paused");
+          pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
+            ok(true, "debugger continued");
+            pane.contentWindow.gClient.addOneTimeListener("paused", function() {
               cmd("dbg step in", function() {
                 cmd("dbg step in", function() {
-                  is(output.value, "step in", "debugger stepped in");
-                  cmd("dbg step over", function() {
-                    is(output.value, "step over", "debugger stepped over");
-                    cmd("dbg step out", function() {
-                      is(output.value, "step out", "debugger stepped out");
-                      cmd("dbg continue", function() {
+                  cmd("dbg step in", function() {
+                    is(output.value, "step in", "debugger stepped in");
+                    cmd("dbg step over", function() {
+                      is(output.value, "step over", "debugger stepped over");
+                      cmd("dbg step out", function() {
+                        is(output.value, "step out", "debugger stepped out");
                         cmd("dbg continue", function() {
-                          is(output.value, "dbg continue", "debugger continued");
-                          pane.contentWindow.gClient.close(function() {
-                            finish();
+                          cmd("dbg continue", function() {
+                            is(output.value, "dbg continue", "debugger continued");
+                            pane.contentWindow.gClient.close(function() {
+                              finish();
+                            });
                           });
                         });
                       });
                     });
                   });
                 });
               });
             });
+            EventUtils.sendMouseEvent({type:"click"}, btnDoit);
           });
-          EventUtils.sendMouseEvent({type:"click"}, btnDoit);
-        });
-        DeveloperToolbarTest.exec({
-          typed: "dbg continue",
-          blankOutput: true
+          DeveloperToolbarTest.exec({
+            typed: "dbg continue",
+            blankOutput: true
+          });
         });
       });
+
+      function cmd(aTyped, aCallback) {
+        pane.contentWindow.gClient.addOneTimeListener("paused", aCallback);
+        DeveloperToolbarTest.exec({
+          typed: aTyped,
+          blankOutput: true
+        });
+      }
     });
-
-    function cmd(aTyped, aCallback) {
-      pane.contentWindow.gClient.addOneTimeListener("paused", aCallback);
-      DeveloperToolbarTest.exec({
-        typed: aTyped,
-        blankOutput: true
-      });
-    }
   });
 }
rename from browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js
rename to browser/devtools/commandline/test/browser_gcli_edit.js
--- a/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js
+++ b/browser/devtools/commandline/test/browser_gcli_edit.js
@@ -1,20 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the edit command works
 
-const TEST_URI = "http://example.com/browser/browser/devtools/styleeditor/" +
-                 "test/browser_styleeditor_cmd_edit.html";
+const TEST_URI = TEST_BASE_HTTP + "resources.html";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ testEditStatus ]);
-  // Bug 759853
-  // testEditExec
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testEditStatus(browser, tab);
+    // Bug 759853
+    // testEditExec(browser, tab); // calls finish()
+    finish();
+  });
 }
 
 function testEditStatus(browser, tab) {
   DeveloperToolbarTest.checkInputStatus({
     typed:  "edit",
     markup: "VVVV",
     status: "ERROR",
     emptyParameters: [ " <resource>", " [line]" ],
@@ -35,36 +37,36 @@ function testEditStatus(browser, tab) {
     directTabText: "ss#style2",
     emptyParameters: [ " [line]" ],
   });
 
   DeveloperToolbarTest.checkInputStatus({
     typed:  "edit http",
     markup: "VVVVVIIII",
     status: "ERROR",
-    directTabText: "://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css",
+    directTabText: "://example.com/browser/browser/devtools/commandline/test/resources_inpage1.css",
     arrowTabText: "",
     emptyParameters: [ " [line]" ],
   });
 
   DeveloperToolbarTest.checkInputStatus({
     typed:  "edit page1",
     markup: "VVVVVIIIII",
     status: "ERROR",
     directTabText: "",
-    arrowTabText: "http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css",
+    arrowTabText: "http://example.com/browser/browser/devtools/commandline/test/resources_inpage1.css",
     emptyParameters: [ " [line]" ],
   });
 
   DeveloperToolbarTest.checkInputStatus({
     typed:  "edit page2",
     markup: "VVVVVIIIII",
     status: "ERROR",
     directTabText: "",
-    arrowTabText: "http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage2.css",
+    arrowTabText: "http://example.com/browser/browser/devtools/commandline/test/resources_inpage2.css",
     emptyParameters: [ " [line]" ],
   });
 
   DeveloperToolbarTest.checkInputStatus({
     typed:  "edit stylez",
     markup: "VVVVVEEEEEE",
     status: "ERROR",
     directTabText: "",
rename from browser/devtools/commandline/test/browser_cmd_pagemod_export.html
rename to browser/devtools/commandline/test/browser_gcli_inspect.html
rename from browser/devtools/highlighter/test/browser_inspector_cmd_inspect.js
rename to browser/devtools/commandline/test/browser_gcli_inspect.js
--- a/browser/devtools/highlighter/test/browser_inspector_cmd_inspect.js
+++ b/browser/devtools/commandline/test/browser_gcli_inspect.js
@@ -1,117 +1,68 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the inspect command works as it should
 
-const TEST_URI = "http://example.com/browser/browser/devtools/highlighter/" +
-                 "test/browser_inspector_cmd_inspect.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_inspect.html";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ testInspect ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testInspect();
+
+    finish();
+  });
 }
 
 function testInspect() {
-  helpers.setInput('inspect');
-  helpers.check({
-    input:  'inspect',
-    hints:         ' <node>',
-    markup: 'VVVVVVV',
-    status: 'ERROR'
-  });
-
-  helpers.setInput('inspect h1');
-  helpers.check({
-    input:  'inspect h1',
-    hints:            '',
-    markup: 'VVVVVVVVII',
-    status: 'ERROR',
-    args: {
-      node: { message: 'No matches' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspec",
+    directTabText: "t",
+    status: "ERROR"
   });
 
-  helpers.setInput('inspect span');
-  helpers.check({
-    input:  'inspect span',
-    hints:              '',
-    markup: 'VVVVVVVVEEEE',
-    status: 'ERROR',
-    args: {
-      node: { message: 'Too many matches (2)' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect",
+    emptyParameters: [ " <node>" ],
+    status: "ERROR"
   });
 
-  helpers.setInput('inspect div');
-  helpers.check({
-    input:  'inspect div',
-    hints:             '',
-    markup: 'VVVVVVVVEEE',
-    status: 'ERROR',
-    args: {
-      node: { message: 'Too many matches (10)' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect h1",
+    status: "ERROR"
   });
 
-  helpers.setInput('inspect .someclas');
-  helpers.check({
-    input:  'inspect .someclas',
-    hints:                   '',
-    markup: 'VVVVVVVVIIIIIIIII',
-    status: 'ERROR',
-    args: {
-      node: { message: 'No matches' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect span",
+    status: "ERROR"
   });
 
-  helpers.setInput('inspect .someclass');
-  helpers.check({
-    input:  'inspect .someclass',
-    hints:                    '',
-    markup: 'VVVVVVVVIIIIIIIIII',
-    status: 'ERROR',
-    args: {
-      node: { message: 'No matches' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect div",
+    status: "VALID"
   });
 
-  helpers.setInput('inspect #someid');
-  helpers.check({
-    input:  'inspect #someid',
-    hints:                 '',
-    markup: 'VVVVVVVVEEEEEEE',
-    status: 'ERROR',
-    args: {
-      node: { message: 'No matches' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect .someclass",
+    status: "VALID"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect #someid",
+    status: "VALID"
   });
 
-  helpers.setInput('inspect button[disabled]');
-  helpers.check({
-    input:  'inspect button[disabled]',
-    hints:                          '',
-    markup: 'VVVVVVVVIIIIIIIIIIIIIIII',
-    status: 'ERROR',
-    args: {
-      node: { message: 'No matches' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect button[disabled]",
+    status: "VALID"
   });
 
-  helpers.setInput('inspect p>strong');
-  helpers.check({
-    input:  'inspect p>strong',
-    hints:                  '',
-    markup: 'VVVVVVVVEEEEEEEE',
-    status: 'ERROR',
-    args: {
-      node: { message: 'No matches' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect p>strong",
+    status: "VALID"
   });
 
-  helpers.setInput('inspect :root');
-  helpers.check({
-    input:  'inspect :root',
-    hints:               '',
-    markup: 'VVVVVVVVVVVVV',
-    status: 'VALID'
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "inspect :root",
+    status: "VALID"
   });
 }
rename from browser/devtools/commandline/test/browser_cmd_integrate.js
rename to browser/devtools/commandline/test/browser_gcli_integrate.js
rename from browser/devtools/commandline/test/browser_cmd_jsb.js
rename to browser/devtools/commandline/test/browser_gcli_jsb.js
--- a/browser/devtools/commandline/test/browser_cmd_jsb.js
+++ b/browser/devtools/commandline/test/browser_gcli_jsb.js
@@ -1,57 +1,48 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Tests that the jsb command works as it should
+function test() {
+  const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
+                   "test/resources_jsb_script.js";
 
-const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
-                 "test/browser_cmd_jsb_script.jsi";
+  DeveloperToolbarTest.test("about:blank", function GJT_test() {
+    /* Commented out by bug 774057, re-enable with un-hidden jsb command
+    DeveloperToolbarTest.exec({
+      typed: "jsb AAA",
+      outputMatch: /valid/
+    });
 
-function test() {
-  DeveloperToolbarTest.test("about:blank", [ /*GJT_test*/ ]);
-}
+    gBrowser.addTabsProgressListener({
+      onProgressChange: function GJT_onProgressChange(aBrowser) {
+        gBrowser.removeTabsProgressListener(this);
 
-function GJT_test() {
-  helpers.setInput('jsb');
-  helpers.check({
-    input:  'jsb',
-    hints:     ' <url> [indentSize] [indentChar] [preserveNewlines] [preserveMaxNewlines] [jslintHappy] [braceStyle] [spaceBeforeConditional] [unescapeStrings]',
-    markup: 'VVV',
-    status: 'ERROR'
-  });
+        let win = aBrowser._contentWindow;
+        let uri = win.document.location.href;
+        let result = win.atob(uri.replace(/.*,/, ""));
+
+        result = result.replace(/[\r\n]]/g, "\n");
 
-  gBrowser.addTabsProgressListener({
-    onProgressChange: DeveloperToolbarTest.checkCalled(function GJT_onProgressChange(aBrowser) {
-      gBrowser.removeTabsProgressListener(this);
+        checkResult(result);
+        finish();
+      }
+    });
 
-      let win = aBrowser._contentWindow;
-      let uri = win.document.location.href;
-      let result = win.atob(uri.replace(/.*,/, ""));
+    info("Checking beautification");
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "jsb " + TEST_URI + " 4 space true -1 false collapse true false",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec({ completed: false });
 
-      result = result.replace(/[\r\n]]/g, "\n");
-
+    function checkResult(aResult) {
       let correct = "function somefunc() {\n" +
                     "    for (let n = 0; n < 500; n++) {\n" +
                     "        if (n % 2 == 1) {\n" +
                     "            console.log(n);\n" +
                     "            console.log(n + 1);\n" +
                     "        }\n" +
                     "    }\n" +
                     "}";
-      is(result, correct, "JS has been correctly prettified");
-    })
+      is(aResult, correct, "JS has been correctly prettified");
+    }
+    */
+    finish();
   });
-
-  info("Checking beautification");
-
-  helpers.setInput('jsb ' + TEST_URI);
-  /*
-  helpers.check({
-    input:  'jsb',
-    hints:     ' [options]',
-    markup: 'VVV',
-    status: 'VALID'
-  });
-  */
-
-  DeveloperToolbarTest.exec({ completed: false });
 }
rename from browser/devtools/commandline/test/browser_cmd_pagemod_export.js
rename to browser/devtools/commandline/test/browser_gcli_pagemod_export.js
--- a/browser/devtools/commandline/test/browser_cmd_pagemod_export.js
+++ b/browser/devtools/commandline/test/browser_gcli_pagemod_export.js
@@ -1,38 +1,32 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the inspect command works as it should
 
-const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+
-                 "test/browser_cmd_pagemod_export.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_inspect.html";
 
 function test() {
   let initialHtml = "";
 
-  DeveloperToolbarTest.test(TEST_URI, [
-    init,
-    testExportHtml,
-    testPageModReplace,
-    testPageModRemoveElement,
-    testPageModRemoveAttribute
-  ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    initialHtml = content.document.documentElement.innerHTML;
 
-  function init() {
-    initialHtml = content.document.documentElement.innerHTML;
-  }
+    testExportHtml();
+    testPageModReplace();
+    testPageModRemoveElement();
+    testPageModRemoveAttribute();
+    finish();
+  });
 
   function testExportHtml() {
-    helpers.setInput('export html');
-    helpers.check({
-      input:  'export html',
-      hints:             '',
-      markup: 'VVVVVVVVVVV',
-      status: 'VALID'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "export html",
+      status: "VALID"
     });
 
     let oldOpen = content.open;
     let openURL = "";
     content.open = function(aUrl) {
       openURL = aUrl;
     };
 
@@ -51,46 +45,43 @@ function test() {
     return content.document.documentElement.innerHTML;
   }
 
   function resetContent() {
     content.document.documentElement.innerHTML = initialHtml;
   }
 
   function testPageModReplace() {
-    helpers.setInput('pagemod replace');
-    helpers.check({
-      input:  'pagemod replace',
-      hints:                 ' <search> <replace> [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]',
-      markup: 'VVVVVVVVVVVVVVV',
-      status: 'ERROR'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace",
+      emptyParameters: [" <search>", " <replace>", " [ignoreCase]",
+                        " [selector]", " [root]", " [attrOnly]",
+                        " [contentOnly]", " [attributes]"],
+      status: "ERROR"
     });
 
-    helpers.setInput('pagemod replace some foo');
-    helpers.check({
-      input:  'pagemod replace some foo',
-      hints:                          ' [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo",
+      emptyParameters: [" [ignoreCase]", " [selector]", " [root]",
+                        " [attrOnly]", " [contentOnly]", " [attributes]"],
+      status: "VALID"
     });
 
-    helpers.setInput('pagemod replace some foo true');
-    helpers.check({
-      input:  'pagemod replace some foo true',
-      hints:                               ' [selector] [root] [attrOnly] [contentOnly] [attributes]',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo true",
+      emptyParameters: [" [selector]", " [root]", " [attrOnly]",
+                        " [contentOnly]", " [attributes]"],
+      status: "VALID"
     });
 
-    helpers.setInput('pagemod replace some foo true --attrOnly');
-    helpers.check({
-      input:  'pagemod replace some foo true --attrOnly',
-      hints:                                          ' [selector] [root] [contentOnly] [attributes]',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo true --attrOnly",
+      emptyParameters: [" [selector]", " [root]", " [contentOnly]",
+                        " [attributes]"],
+      status: "VALID"
     });
 
     DeveloperToolbarTest.exec({
       typed: "pagemod replace sOme foOBar",
       outputMatch: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 0\.\s*$/
     });
 
     is(getContent(), initialHtml, "no change in the page");
@@ -147,38 +138,31 @@ function test() {
           ".someclass changed to .foobarclass");
     isnot(getContent().indexOf('<p id="someid">#someid'), -1,
           "#someid did not change");
 
     resetContent();
   }
 
   function testPageModRemoveElement() {
-    helpers.setInput('pagemod remove');
-    helpers.check({
-      input:  'pagemod remove',
-      hints:                '',
-      markup: 'IIIIIIIVIIIIII',
-      status: 'ERROR'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove",
+      status: "ERROR"
     });
 
-    helpers.setInput('pagemod remove element');
-    helpers.check({
-      input:  'pagemod remove element',
-      hints:                        ' <search> [root] [stripOnly] [ifEmptyOnly]',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVV',
-      status: 'ERROR'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove element",
+      emptyParameters: [" <search>", " [root]", " [stripOnly]", " [ifEmptyOnly]"],
+      status: "ERROR"
     });
 
-    helpers.setInput('pagemod remove element foo');
-    helpers.check({
-      input:  'pagemod remove element foo',
-      hints:                            ' [root] [stripOnly] [ifEmptyOnly]',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove element foo",
+      emptyParameters: [" [root]", " [stripOnly]", " [ifEmptyOnly]"],
+      status: "VALID"
     });
 
     DeveloperToolbarTest.exec({
       typed: "pagemod remove element p",
       outputMatch: /^[^:]+: 3\. [^:]+: 3\.\s*$/
     });
 
     is(getContent().indexOf('<p class="someclass">'), -1, "p.someclass removed");
@@ -223,42 +207,26 @@ function test() {
     isnot(getContent().indexOf(".someclass"), -1, ".someclass still exists");
     isnot(getContent().indexOf("#someid"), -1, "#someid still exists");
     isnot(getContent().indexOf("<strong>p"), -1, "<strong> still exists");
 
     resetContent();
   }
 
   function testPageModRemoveAttribute() {
-    helpers.setInput('pagemod remove attribute ');
-    helpers.check({
-      input:  'pagemod remove attribute ',
-      hints:                           '<searchAttributes> <searchElements> [root] [ignoreCase]',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'ERROR',
-      args: {
-        searchAttributes: { value: undefined, status: 'INCOMPLETE' },
-        searchElements: { value: undefined, status: 'INCOMPLETE' },
-        root: { value: undefined },
-        ignoreCase: { value: false },
-      }
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove attribute",
+      emptyParameters: [" <searchAttributes>", " <searchElements>", " [root]", " [ignoreCase]"],
+      status: "ERROR"
     });
 
-    helpers.setInput('pagemod remove attribute foo bar');
-    helpers.check({
-      input:  'pagemod remove attribute foo bar',
-      hints:                                  ' [root] [ignoreCase]',
-      markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-      status: 'VALID',
-      args: {
-        searchAttributes: { value: 'foo' },
-        searchElements: { value: 'bar' },
-        root: { value: undefined },
-        ignoreCase: { value: false },
-      }
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove attribute foo bar",
+      emptyParameters: [" [root]", " [ignoreCase]"],
+      status: "VALID"
     });
 
     DeveloperToolbarTest.exec({
       typed: "pagemod remove attribute foo bar",
       outputMatch: /^[^:]+: 0\. [^:]+: 0\.\s*$/
     });
 
     is(getContent(), initialHtml, "nothing changed in the page");
rename from browser/devtools/commandline/test/browser_cmd_pref.js
rename to browser/devtools/commandline/test/browser_gcli_pref.js
--- a/browser/devtools/commandline/test/browser_cmd_pref.js
+++ b/browser/devtools/commandline/test/browser_gcli_pref.js
@@ -17,26 +17,29 @@ imports.XPCOMUtils.defineLazyGetter(impo
 imports.XPCOMUtils.defineLazyGetter(imports, "supportsString", function() {
   return Components.classes["@mozilla.org/supports-string;1"]
           .createInstance(Components.interfaces.nsISupportsString);
 });
 
 const TEST_URI = "data:text/html;charset=utf-8,gcli-pref";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [
-    setup,
-    testPrefSetEnable,
-    testPrefStatus,
-    testPrefBoolExec,
-    testPrefNumberExec,
-    testPrefStringExec,
-    testPrefSetDisable,
-    shutdown
-  ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    setup();
+
+    testPrefSetEnable();
+    testPrefStatus();
+    testPrefBoolExec();
+    testPrefNumberExec();
+    testPrefStringExec();
+    testPrefSetDisable();
+
+    shutdown();
+    finish();
+  });
 }
 
 let tiltEnabledOrig = undefined;
 let tabSizeOrig = undefined;
 let remoteHostOrig = undefined;
 
 function setup() {
   Components.utils.import("resource://gre/modules/devtools/Require.jsm", imports);
@@ -64,113 +67,102 @@ function shutdown() {
   tiltEnabledOrig = undefined;
   tabSizeOrig = undefined;
   remoteHostOrig = undefined;
 
   imports = undefined;
 }
 
 function testPrefStatus() {
-  helpers.setInput('pref');
-  helpers.check({
-    input:  'pref',
-    hints:      '',
-    markup: 'IIII',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref s",
+    markup: "IIIIVI",
+    status: "ERROR",
+    directTabText: "et"
   });
 
-  helpers.setInput('pref s');
-  helpers.check({
-    input:  'pref s',
-    hints:        'et',
-    markup: 'IIIIVI',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref show",
+    markup: "VVVVVVVVV",
+    status: "ERROR",
+    emptyParameters: [ " <setting>" ]
   });
 
-  helpers.setInput('pref sh');
-  helpers.check({
-    input:  'pref sh',
-    hints:         'ow',
-    markup: 'IIIIVII',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref show tempTBo",
+    markup: "VVVVVVVVVVEEEEEEE",
+    status: "ERROR",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref show ');
-  helpers.check({
-    input:  'pref show ',
-    markup: 'VVVVVVVVVV',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref show devtools.toolbar.ena",
+    markup: "VVVVVVVVVVIIIIIIIIIIIIIIIIIIII",
+    directTabText: "bled",
+    status: "ERROR",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref show usetexttospeech');
-  helpers.check({
-    input:  'pref show usetexttospeech',
-    hints:                           ' -> accessibility.usetexttospeech',
-    markup: 'VVVVVVVVVVIIIIIIIIIIIIIII',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref show hideIntro",
+    markup: "VVVVVVVVVVIIIIIIIII",
+    directTabText: "",
+    arrowTabText: "devtools.gcli.hideIntro",
+    status: "ERROR",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref show devtools.til');
-  helpers.check({
-    input:  'pref show devtools.til',
-    hints:                        't.enabled',
-    markup: 'VVVVVVVVVVIIIIIIIIIIII',
-    status: 'ERROR',
-    tooltipState: 'true:importantFieldFlag',
-    args: {
-      setting: { value: undefined, status: 'INCOMPLETE' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref show devtools.toolbar.enabled",
+    markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
+    status: "VALID",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref reset devtools.tilt.enabled');
-  helpers.check({
-    input:  'pref reset devtools.tilt.enabled',
-    hints:                                  '',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-    status: 'VALID'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref show devtools.tilt.enabled 4",
+    markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE",
+    directTabText: "",
+    status: "ERROR",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref show devtools.tilt.enabled 4');
-  helpers.check({
-    input:  'pref show devtools.tilt.enabled 4',
-    hints:                                   '',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref show devtools.tilt.enabled",
+    markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
+    status: "VALID",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref set devtools.tilt.enabled 4');
-  helpers.check({
-    input:  'pref set devtools.tilt.enabled 4',
-    hints:                                  '',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
-    status: 'ERROR',
-    args: {
-      setting: { arg: ' devtools.tilt.enabled' },
-      value: { status: 'ERROR', message: 'Can\'t use \'4\'.' },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref reset devtools.tilt.enabled",
+    markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
+    status: "VALID",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref set devtools.editor.tabsize 4');
-  helpers.check({
-    input:  'pref set devtools.editor.tabsize 4',
-    hints:                                    '',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-    status: 'VALID',
-    args: {
-      setting: { arg: ' devtools.editor.tabsize' },
-      value: { value: 4 },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref set devtools.tilt.enabled 4",
+    markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE",
+    status: "ERROR",
+    emptyParameters: [ ]
   });
 
-  helpers.setInput('pref list');
-  helpers.check({
-    input:  'pref list',
-    hints:           '',
-    markup: 'EEEEVEEEE',
-    status: 'ERROR'
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref set devtools.editor.tabsize 4",
+    markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
+    status: "VALID",
+    emptyParameters: [ ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "pref list",
+    markup: "EEEEVEEEE",
+    status: "ERROR",
+    emptyParameters: [ ]
   });
 }
 
 function testPrefSetEnable() {
   DeveloperToolbarTest.exec({
     typed: "pref set devtools.editor.tabsize 9",
     args: {
       setting: imports.settings.getSetting("devtools.editor.tabsize"),
rename from browser/devtools/responsivedesign/test/browser_responsive_cmd.js
rename to browser/devtools/commandline/test/browser_gcli_responsivemode.js
--- a/browser/devtools/responsivedesign/test/browser_responsive_cmd.js
+++ b/browser/devtools/commandline/test/browser_gcli_responsivemode.js
@@ -1,86 +1,58 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
-  DeveloperToolbarTest.test("about:blank", [ GAT_test ]);
-}
+  DeveloperToolbarTest.test("about:blank", function GAT_test() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize toggle",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
 
-function isOpen() {
-  return !!gBrowser.selectedTab.__responsiveUI;
-}
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize toggle",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
 
-function isClosed() {
-  return !isOpen();
-}
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize on",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
 
-function GAT_test() {
-  helpers.setInput('resize toggle');
-  helpers.check({
-    input:  'resize toggle',
-    hints:               '',
-    markup: 'VVVVVVVVVVVVV',
-    status: 'VALID'
-  });
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize off",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
 
-  DeveloperToolbarTest.exec();
-  ok(isOpen(), "responsive mode is open");
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize to 400 400",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
 
-  helpers.setInput('resize toggle');
-  helpers.check({
-    input:  'resize toggle',
-    hints:               '',
-    markup: 'VVVVVVVVVVVVV',
-    status: 'VALID'
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize off",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
+
+    executeSoon(finish);
   });
 
-  DeveloperToolbarTest.exec();
-  ok(isClosed(), "responsive mode is closed");
-
-  helpers.setInput('resize on');
-  helpers.check({
-    input:  'resize on',
-    hints:           '',
-    markup: 'VVVVVVVVV',
-    status: 'VALID'
-  });
-
-  DeveloperToolbarTest.exec();
-  ok(isOpen(), "responsive mode is open");
-
-  helpers.setInput('resize off');
-  helpers.check({
-    input:  'resize off',
-    hints:            '',
-    markup: 'VVVVVVVVVV',
-    status: 'VALID'
-  });
-
-  DeveloperToolbarTest.exec();
-  ok(isClosed(), "responsive mode is closed");
+  function isOpen() {
+    return !!gBrowser.selectedTab.__responsiveUI;
+  }
 
-  helpers.setInput('resize to 400 400');
-  helpers.check({
-    input:  'resize to 400 400',
-    hints:                   '',
-    markup: 'VVVVVVVVVVVVVVVVV',
-    status: 'VALID',
-    args: {
-      width: { value: 400 },
-      height: { value: 400 },
-    }
-  });
-
-  DeveloperToolbarTest.exec();
-  ok(isOpen(), "responsive mode is open");
-
-  helpers.setInput('resize off');
-  helpers.check({
-    input:  'resize off',
-    hints:            '',
-    markup: 'VVVVVVVVVV',
-    status: 'VALID'
-  });
-
-  DeveloperToolbarTest.exec();
-  ok(isClosed(), "responsive mode is closed");
+  function isClosed() {
+    return !isOpen();
+  }
 }
rename from browser/devtools/commandline/test/browser_cmd_restart.js
rename to browser/devtools/commandline/test/browser_gcli_restart.js
--- a/browser/devtools/commandline/test/browser_cmd_restart.js
+++ b/browser/devtools/commandline/test/browser_gcli_restart.js
@@ -1,32 +1,48 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that restart command works properly (input wise)
 
 const TEST_URI = "data:text/html;charset=utf-8,gcli-command-restart";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ testRestart ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testRestart();
+    finish();
+  });
 }
 
 function testRestart() {
-  helpers.setInput('restart');
-  helpers.check({
-    input:  'restart',
-    markup: 'VVVVVVV',
-    status: 'VALID',
-    args: {
-      nocache: { value: false },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart",
+    markup: "VVVVVVV",
+    status: "VALID",
+    emptyParameters: [ " [nocache]" ],
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart ",
+    markup: "VVVVVVVV",
+    status: "VALID",
+    directTabText: "false"
   });
 
-  helpers.setInput('restart --nocache');
-  helpers.check({
-    input:  'restart --nocache',
-    markup: 'VVVVVVVVVVVVVVVVV',
-    status: 'VALID',
-    args: {
-      nocache: { value: true },
-    }
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart t",
+    markup: "VVVVVVVVI",
+    status: "ERROR",
+    directTabText: "rue"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart --nocache",
+    markup: "VVVVVVVVVVVVVVVVV",
+    status: "VALID"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart --noca",
+    markup: "VVVVVVVVEEEEEE",
+    status: "ERROR",
   });
 }
rename from browser/devtools/commandline/test/browser_cmd_settings.js
rename to browser/devtools/commandline/test/browser_gcli_settings.js
--- a/browser/devtools/commandline/test/browser_cmd_settings.js
+++ b/browser/devtools/commandline/test/browser_gcli_settings.js
@@ -17,17 +17,24 @@ imports.XPCOMUtils.defineLazyGetter(impo
 imports.XPCOMUtils.defineLazyGetter(imports, "supportsString", function() {
   return Components.classes["@mozilla.org/supports-string;1"]
           .createInstance(Components.interfaces.nsISupportsString);
 });
 
 const TEST_URI = "data:text/html;charset=utf-8,gcli-settings";
 
 function test() {
-  DeveloperToolbarTest.test(TEST_URI, [ setup, testSettings, shutdown ]);
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    setup();
+
+    testSettings();
+
+    shutdown();
+    finish();
+  });
 }
 
 let tiltEnabled = undefined;
 let tabSize = undefined;
 let remoteHost = undefined;
 
 let tiltEnabledOrig = undefined;
 let tabSizeOrig = undefined;
--- a/browser/devtools/commandline/test/browser_gcli_web.js
+++ b/browser/devtools/commandline/test/browser_gcli_web.js
@@ -148,31 +148,28 @@ define('gclitest/index', ['require', 'ex
     options = options || {};
     if (options.settings != null) {
       settings.setDefaults(options.settings);
     }
 
     window.display = new Display(options);
     var requisition = window.display.requisition;
 
-    // setTimeout keeps stack traces clear of RequireJS frames
-    window.setTimeout(function() {
-      exports.run({
-        window: window,
-        display: window.display,
-        hideExec: true
+    exports.run({
+      window: window,
+      display: window.display,
+      hideExec: true
+    });
+
+    window.testCommands = function() {
+      require([ 'gclitest/mockCommands' ], function(mockCommands) {
+        mockCommands.setup();
       });
-
-      window.testCommands = function() {
-        require([ 'gclitest/mockCommands' ], function(mockCommands) {
-          mockCommands.setup();
-        });
-      };
-      window.testCommands();
-    }, 10);
+    };
+    window.testCommands();
 
     return {
       /**
        * The exact shape of the object returned by exec is likely to change in
        * the near future. If you do use it, please expect your code to break.
        */
       exec: requisition.exec.bind(requisition),
       update: requisition.update.bind(requisition),
@@ -192,17 +189,17 @@ define('gclitest/index', ['require', 'ex
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testCanon', 'gclitest/testCli', 'gclitest/testCompletion', 'gclitest/testExec', 'gclitest/testHelp', 'gclitest/testHistory', 'gclitest/testInputter', 'gclitest/testIncomplete', 'gclitest/testIntro', 'gclitest/testJs', 'gclitest/testKeyboard', 'gclitest/testMenu', 'gclitest/testPref', 'gclitest/testRequire', 'gclitest/testResource', 'gclitest/testScratchpad', 'gclitest/testSettings', 'gclitest/testSpell', 'gclitest/testSplit', 'gclitest/testTokenize', 'gclitest/testTooltip', 'gclitest/testTypes', 'gclitest/testUtil'], function(require, exports, module) {
+define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testCanon', 'gclitest/testCli', 'gclitest/testCompletion', 'gclitest/testExec', 'gclitest/testHelp', 'gclitest/testHistory', 'gclitest/testInputter', 'gclitest/testIncomplete', 'gclitest/testIntro', 'gclitest/testJs', 'gclitest/testKeyboard', 'gclitest/testPref', 'gclitest/testRequire', 'gclitest/testResource', 'gclitest/testScratchpad', 'gclitest/testSettings', 'gclitest/testSpell', 'gclitest/testSplit', 'gclitest/testTokenize', 'gclitest/testTooltip', 'gclitest/testTypes', 'gclitest/testUtil'], function(require, exports, module) {
 
   // We need to make sure GCLI is initialized before we begin testing it
   require('gcli/index');
 
   var examiner = require('test/examiner');
 
   // It's tempting to want to unify these strings and make addSuite() do the
   // call to require(), however that breaks the build system which looks for
@@ -213,17 +210,16 @@ define('gclitest/suite', ['require', 'ex
   examiner.addSuite('gclitest/testExec', require('gclitest/testExec'));
   examiner.addSuite('gclitest/testHelp', require('gclitest/testHelp'));
   examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory'));
   examiner.addSuite('gclitest/testInputter', require('gclitest/testInputter'));
   examiner.addSuite('gclitest/testIncomplete', require('gclitest/testIncomplete'));
   examiner.addSuite('gclitest/testIntro', require('gclitest/testIntro'));
   examiner.addSuite('gclitest/testJs', require('gclitest/testJs'));
   examiner.addSuite('gclitest/testKeyboard', require('gclitest/testKeyboard'));
-  examiner.addSuite('gclitest/testMenu', require('gclitest/testMenu'));
   examiner.addSuite('gclitest/testPref', require('gclitest/testPref'));
   examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire'));
   examiner.addSuite('gclitest/testResource', require('gclitest/testResource'));
   examiner.addSuite('gclitest/testScratchpad', require('gclitest/testScratchpad'));
   examiner.addSuite('gclitest/testSettings', require('gclitest/testSettings'));
   examiner.addSuite('gclitest/testSpell', require('gclitest/testSpell'));
   examiner.addSuite('gclitest/testSplit', require('gclitest/testSplit'));
   examiner.addSuite('gclitest/testTokenize', require('gclitest/testTokenize'));
@@ -869,71 +865,84 @@ exports.shutdown = function(opts) {
  *
  * helpers.status({
  *   // Test inputs
  *   typed: "ech",           // Required
  *   cursor: 3,              // Optional cursor position
  *
  *   // Thing to check
  *   status: "INCOMPLETE",   // One of "VALID", "ERROR", "INCOMPLETE"
- *   hints: The hint text, i.e. a concatenation of the directTabText, the
- *     emptyParameters and the arrowTabText. The text as inserted into the UI
- *     will include NBSP and Unicode RARR characters, these should be
- *     represented using normal space and '->' for the arrow
+ *   emptyParameters: [ "<message>" ], // Still to type
+ *   directTabText: "o",     // Simple completion text
+ *   arrowTabText: "",       // When the completion is not an extension
  *   markup: "VVVIIIEEE",    // What state should the error markup be in
  * });
  */
 exports.status = function(options, checks) {
   var requisition = options.display.requisition;
   var inputter = options.display.inputter;
   var completer = options.display.completer;
 
-  if (checks.typed != null) {
+  if (checks.typed) {
     inputter.setInput(checks.typed);
   }
   else {
     test.ok(false, "Missing typed for " + JSON.stringify(checks));
     return;
   }
 
-  if (checks.cursor != null) {
+  if (checks.cursor) {
     inputter.setCursor(checks.cursor);
   }
 
-  if (checks.status != null) {
+  if (checks.status) {
     test.is(requisition.getStatus().toString(),
             checks.status,
             "status for " + checks.typed);
   }
 
-  var actual = completer._getCompleterTemplateData();
-
-  if (checks.hints != null) {
-    var actualHints = actual.directTabText +
-                      actual.emptyParameters.join('') +
-                      actual.arrowTabText;
-    actualHints = actualHints.replace(/\u00a0/g, ' ')
-                             .replace(/\u21E5/, '->')
-                             .replace(/ $/, '');
-    test.is(actualHints,
-            checks.hints,
-            'hints');
+  var data = completer._getCompleterTemplateData();
+  if (checks.emptyParameters != null) {
+    var realParams = data.emptyParameters;
+    test.is(realParams.length,
+            checks.emptyParameters.length,
+            'emptyParameters.length for \'' + checks.typed + '\'');
+
+    if (realParams.length === checks.emptyParameters.length) {
+      for (var i = 0; i < realParams.length; i++) {
+        test.is(realParams[i].replace(/\u00a0/g, ' '),
+                checks.emptyParameters[i],
+                'emptyParameters[' + i + '] for \'' + checks.typed + '\'');
+      }
+    }
   }
 
-  if (checks.markup != null) {
+  if (checks.markup) {
     var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
     var statusMarkup = requisition.getInputStatusMarkup(cursor);
     var actualMarkup = statusMarkup.map(function(s) {
       return Array(s.string.length + 1).join(s.status.toString()[0]);
     }).join('');
 
     test.is(checks.markup,
             actualMarkup,
             'markup for ' + checks.typed);
   }
+
+  if (checks.directTabText) {
+    test.is(data.directTabText,
+            checks.directTabText,
+            'directTabText for \'' + checks.typed + '\'');
+  }
+
+  if (checks.arrowTabText) {
+    test.is(' \u00a0\u21E5 ' + checks.arrowTabText,
+            data.arrowTabText,
+            'arrowTabText for \'' + checks.typed + '\'');
+  }
 };
 
 /**
  * We're splitting status into setup() which alters the state of the system
  * and check() which ensures that things are in the right place afterwards.
  */
 exports.setInput = function(typed, cursor) {
   cachedOptions.display.inputter.setInput(typed);
@@ -960,126 +969,140 @@ exports.pressTab = function() {
 
 /**
  * check() is the new status. Similar API except that it doesn't attempt to
  * alter the display/requisition at all, and it makes extra checks.
  * Available checks:
  *   input: The text displayed in the input field
  *   cursor: The position of the start of the cursor
  *   status: One of "VALID", "ERROR", "INCOMPLETE"
- *   hints: The hint text, i.e. a concatenation of the directTabText, the
- *     emptyParameters and the arrowTabText. The text as inserted into the UI
- *     will include NBSP and Unicode RARR characters, these should be
- *     represented using normal space and '->' for the arrow
+ *   emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
+ *   directTabText: Simple completion text
+ *   arrowTabText: When the completion is not an extension (without arrow)
  *   markup: What state should the error markup be in. e.g. "VVVIIIEEE"
  *   args: Maps of checks to make against the arguments:
  *     value: i.e. assignment.value (which ignores defaultValue)
  *     type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
  *           Care should be taken with this since it's something of an
  *           implementation detail
  *     arg: The toString value of the argument
  *     status: i.e. assignment.getStatus
  *     message: i.e. assignment.getMessage
  *     name: For commands - checks assignment.value.name
  */
 exports.check = function(checks) {
   var requisition = cachedOptions.display.requisition;
   var completer = cachedOptions.display.completer;
   var actual = completer._getCompleterTemplateData();
 
-  if (checks.input != null) {
+  if (checks.input) {
     test.is(cachedOptions.display.inputter.element.value,
             checks.input,
             'input');
   }
 
-  if (checks.cursor != null) {
+  if (checks.cursor) {
     test.is(cachedOptions.display.inputter.element.selectionStart,
             checks.cursor,
             'cursor');
   }
 
-  if (checks.status != null) {
+  if (checks.status) {
     test.is(requisition.getStatus().toString(),
             checks.status,
             'status');
   }
 
-  if (checks.markup != null) {
+  if (checks.markup) {
     var cursor = cachedOptions.display.inputter.element.selectionStart;
     var statusMarkup = requisition.getInputStatusMarkup(cursor);
     var actualMarkup = statusMarkup.map(function(s) {
       return Array(s.string.length + 1).join(s.status.toString()[0]);
     }).join('');
 
     test.is(checks.markup,
             actualMarkup,
             'markup');
   }
 
-  if (checks.hints != null) {
-    var actualHints = actual.directTabText +
-                      actual.emptyParameters.join('') +
-                      actual.arrowTabText;
-    actualHints = actualHints.replace(/\u00a0/g, ' ')
-                             .replace(/\u21E5/, '->')
-                             .replace(/ $/, '');
-    test.is(actualHints,
-            checks.hints,
-            'hints');
+  if (checks.emptyParameters) {
+    var actualParams = actual.emptyParameters;
+    test.is(actualParams.length,
+            checks.emptyParameters.length,
+            'emptyParameters.length');
+
+    if (actualParams.length === checks.emptyParameters.length) {
+      for (var i = 0; i < actualParams.length; i++) {
+        test.is(actualParams[i].replace(/\u00a0/g, ' '),
+                checks.emptyParameters[i],
+                'emptyParameters[' + i + ']');
+      }
+    }
   }
 
-  if (checks.args != null) {
+  if (checks.directTabText) {
+    test.is(actual.directTabText,
+            checks.directTabText,
+            'directTabText');
+  }
+
+  if (checks.arrowTabText) {
+    test.is(actual.arrowTabText,
+            ' \u00a0\u21E5 ' + checks.arrowTabText,
+            'arrowTabText');
+  }
+
+  if (checks.args) {
     Object.keys(checks.args).forEach(function(paramName) {
       var check = checks.args[paramName];
 
       var assignment;
       if (paramName === 'command') {
         assignment = requisition.commandAssignment;
       }
       else {
         assignment = requisition.getAssignment(paramName);
       }
 
       if (assignment == null) {
         test.ok(false, 'Unknown arg: ' + paramName);
         return;
       }
 
-      if (check.value != null) {
+      if (check.value) {
         test.is(assignment.value,
                 check.value,
                 'arg[\'' + paramName + '\'].value');
       }
 
-      if (check.name != null) {
+      if (check.name) {
         test.is(assignment.value.name,
                 check.name,
                 'arg[\'' + paramName + '\'].name');
       }
 
-      if (check.type != null) {
+      if (check.type) {
         test.is(assignment.arg.type,
                 check.type,
                 'arg[\'' + paramName + '\'].type');
       }
 
-      if (check.arg != null) {
+      if (check.arg) {
         test.is(assignment.arg.toString(),
                 check.arg,
                 'arg[\'' + paramName + '\'].arg');
       }
 
-      if (check.status != null) {
+      if (check.status) {
         test.is(assignment.getStatus().toString(),
                 check.status,
                 'arg[\'' + paramName + '\'].status');
       }
 
-      if (check.message != null) {
+      if (check.message) {
         test.is(assignment.getMessage(),
                 check.message,
                 'arg[\'' + paramName + '\'].message');
       }
     });
   }
 };
 
@@ -1705,19 +1728,17 @@ exports.setup = function() {
   canon.addCommand(exports.tsnExtend);
   canon.addCommand(exports.tsnDeep);
   canon.addCommand(exports.tsnDeepDown);
   canon.addCommand(exports.tsnDeepDownNested);
   canon.addCommand(exports.tsnDeepDownNestedCmd);
   canon.addCommand(exports.tselarr);
   canon.addCommand(exports.tsm);
   canon.addCommand(exports.tsg);
-  canon.addCommand(exports.tshidden);
   canon.addCommand(exports.tscook);
-  canon.addCommand(exports.tslong);
 };
 
 exports.shutdown = function() {
   canon.removeCommand(exports.tsv);
   canon.removeCommand(exports.tsr);
   canon.removeCommand(exports.tse);
   canon.removeCommand(exports.tsj);
   canon.removeCommand(exports.tsb);
@@ -1731,19 +1752,17 @@ exports.shutdown = function() {
   canon.removeCommand(exports.tsnExtend);
   canon.removeCommand(exports.tsnDeep);
   canon.removeCommand(exports.tsnDeepDown);
   canon.removeCommand(exports.tsnDeepDownNested);
   canon.removeCommand(exports.tsnDeepDownNestedCmd);
   canon.removeCommand(exports.tselarr);
   canon.removeCommand(exports.tsm);
   canon.removeCommand(exports.tsg);
-  canon.removeCommand(exports.tshidden);
   canon.removeCommand(exports.tscook);
-  canon.removeCommand(exports.tslong);
 
   types.deregisterType(exports.optionType);
   types.deregisterType(exports.optionValue);
 };
 
 
 exports.option1 = { type: types.getType('string') };
 exports.option2 = { type: types.getType('number') };
@@ -1887,48 +1906,16 @@ exports.tsnDeepDownNested = {
   name: 'tsn deep down nested',
 };
 
 exports.tsnDeepDownNestedCmd = {
   name: 'tsn deep down nested cmd',
   exec: createExec('tsnDeepDownNestedCmd')
 };
 
-exports.tshidden = {
-  name: 'tshidden',
-  hidden: true,
-  params: [
-    {
-      group: 'Options',
-      params: [
-        {
-          name: 'visible',
-          type: 'string',
-          defaultValue: null,
-          description: 'visible'
-        },
-        {
-          name: 'invisiblestring',
-          type: 'string',
-          description: 'invisiblestring',
-          defaultValue: null,
-          hidden: true
-        },
-        {
-          name: 'invisibleboolean',
-          type: 'boolean',
-          description: 'invisibleboolean',
-          hidden: true
-        }
-      ]
-    }
-  ],
-  exec: createExec('tshidden')
-};
-
 exports.tselarr = {
   name: 'tselarr',
   params: [
     { name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } },
     { name: 'arr', type: { name: 'array', subtype: 'string' } },
   ],
   exec: createExec('tselarr')
 };
@@ -2025,78 +2012,16 @@ exports.tscook = {
           description: 'tscookSecureDesc'
         }
       ]
     }
   ],
   exec: createExec('tscook')
 };
 
-exports.tslong = {
-  name: 'tslong',
-  description: 'long param tests to catch problems with the jsb command',
-  returnValue:'string',
-  params: [
-    {
-      name: 'msg',
-      type: 'string',
-      description: 'msg Desc'
-    },
-    {
-      group: "Options Desc",
-      params: [
-        {
-          name: 'num',
-          type: 'number',
-          description: 'num Desc',
-          defaultValue: 2
-        },
-        {
-          name: 'sel',
-          type: {
-            name: 'selection',
-            lookup: [
-              { name: "space", value: " " },
-              { name: "tab", value: "\t" }
-            ]
-          },
-          description: 'sel Desc',
-          defaultValue: ' ',
-        },
-        {
-          name: 'bool',
-          type: 'boolean',
-          description: 'bool Desc'
-        },
-        {
-          name: 'num2',
-          type: 'number',
-          description: 'num2 Desc',
-          defaultValue: -1
-        },
-        {
-          name: 'bool2',
-          type: 'boolean',
-          description: 'bool2 Desc'
-        },
-        {
-          name: 'sel2',
-          type: {
-            name: 'selection',
-            data: ['collapse', 'expand', 'end-expand', 'expand-strict']
-          },
-          description: 'sel2 Desc',
-          defaultValue: "collapse"
-        }
-      ]
-    }
-  ],
-  exec: createExec('tslong')
-};
-
 
 });
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -2131,338 +2056,288 @@ exports.shutdown = function(options) {
 exports.testActivate = function(options) {
   if (!options.display) {
     test.log('No display. Skipping activate tests');
     return;
   }
 
   helpers.setInput('');
   helpers.check({
-    hints: ''
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput(' ');
   helpers.check({
-    hints: ''
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsr');
   helpers.check({
-    hints: ' <text>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <text>' ]
   });
 
   helpers.setInput('tsr ');
   helpers.check({
-    hints: '<text>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ '<text>' ]
   });
 
   helpers.setInput('tsr b');
   helpers.check({
-    hints: ''
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsb');
   helpers.check({
-    hints: ' [toggle]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' [toggle]' ]
   });
 
   helpers.setInput('tsm');
   helpers.check({
-    hints: ' <abc> <txt> <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <abc>', ' <txt>', ' <num>' ]
   });
 
   helpers.setInput('tsm ');
   helpers.check({
-    hints: 'a <txt> <num>'
+    emptyParameters: [ ' <txt>', ' <num>' ],
+    arrowTabText: '',
+    directTabText: 'a'
   });
 
   helpers.setInput('tsm a');
   helpers.check({
-    hints: ' <txt> <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <txt>', ' <num>' ]
   });
 
   helpers.setInput('tsm a ');
   helpers.check({
-    hints: '<txt> <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ '<txt>', ' <num>' ]
   });
 
   helpers.setInput('tsm a  ');
   helpers.check({
-    hints: '<txt> <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ '<txt>', ' <num>' ]
   });
 
   helpers.setInput('tsm a  d');
   helpers.check({
-    hints: ' <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <num>' ]
   });
 
   helpers.setInput('tsm a "d d"');
   helpers.check({
-    hints: ' <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <num>' ]
   });
 
   helpers.setInput('tsm a "d ');
   helpers.check({
-    hints: ' <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <num>' ]
   });
 
   helpers.setInput('tsm a "d d" ');
   helpers.check({
-    hints: '<num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ '<num>' ]
   });
 
   helpers.setInput('tsm a "d d ');
   helpers.check({
-    hints: ' <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <num>' ]
   });
 
   helpers.setInput('tsm d r');
   helpers.check({
-    hints: ' <num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <num>' ]
   });
 
   helpers.setInput('tsm a d ');
   helpers.check({
-    hints: '<num>'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ '<num>' ]
   });
 
   helpers.setInput('tsm a d 4');
   helpers.check({
-    hints: ''
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg');
   helpers.check({
-    hints: ' <solo> [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: [ ' <solo>' ]
   });
 
   helpers.setInput('tsg ');
   helpers.check({
-    hints: 'aaa [options]'
+    emptyParameters: [],
+    arrowTabText: '',
+    directTabText: 'aaa'
   });
 
   helpers.setInput('tsg a');
   helpers.check({
-    hints: 'aa [options]'
+    emptyParameters: [],
+    arrowTabText: '',
+    directTabText: 'aa'
   });
 
   helpers.setInput('tsg b');
   helpers.check({
-    hints: 'bb [options]'
+    emptyParameters: [],
+    arrowTabText: '',
+    directTabText: 'bb'
   });
 
   helpers.setInput('tsg d');
   helpers.check({
-    hints: ' [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aa');
   helpers.check({
-    hints: 'a [options]'
+    emptyParameters: [],
+    arrowTabText: '',
+    directTabText: 'a'
   });
 
   helpers.setInput('tsg aaa');
   helpers.check({
-    hints: ' [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aaa ');
   helpers.check({
-    hints: '[options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aaa d');
   helpers.check({
-    hints: ' [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aaa dddddd');
   helpers.check({
-    hints: ' [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aaa dddddd ');
   helpers.check({
-    hints: '[options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aaa "d');
   helpers.check({
-    hints: ' [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aaa "d d');
   helpers.check({
-    hints: ' [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsg aaa "d d"');
   helpers.check({
-    hints: ' [options]'
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tsn ex ');
   helpers.check({
-    hints: ''
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('selarr');
   helpers.check({
-    hints: ' -> tselarr'
+    directTabText: '',
+    emptyParameters: [],
+    arrowTabText: 'tselarr'
   });
 
   helpers.setInput('tselar 1');
   helpers.check({
-    hints: ''
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tselar 1', 7);
   helpers.check({
-    hints: ''
+    directTabText: '',
+    arrowTabText: '',
+    emptyParameters: []
   });
 
   helpers.setInput('tselar 1', 6);
   helpers.check({
-    hints: ' -> tselarr'
+    directTabText: '',
+    emptyParameters: [],
+    arrowTabText: 'tselarr'
   });
 
   helpers.setInput('tselar 1', 5);
   helpers.check({
-    hints: ' -> tselarr'
+    directTabText: '',
+    emptyParameters: [],
+    arrowTabText: 'tselarr'
   });
 };
 
-exports.testLong = function(options) {
-  helpers.setInput('tslong --sel');
-  helpers.check({
-    input:  'tslong --sel',
-    hints:              ' <selection> <msg> [options]',
-    markup: 'VVVVVVVIIIII'
-  });
-
-  helpers.pressTab();
-  helpers.check({
-    input:  'tslong --sel ',
-    hints:               'space <msg> [options]',
-    markup: 'VVVVVVVIIIIIV'
-  });
-
-  helpers.setInput('tslong --sel ');
-  helpers.check({
-    input:  'tslong --sel ',
-    hints:               'space <msg> [options]',
-    markup: 'VVVVVVVIIIIIV'
-  });
-
-  helpers.setInput('tslong --sel s');
-  helpers.check({
-    input:  'tslong --sel s',
-    hints:                'pace <msg> [options]',
-    markup: 'VVVVVVVIIIIIVI'
-  });
-
-  helpers.setInput('tslong --num ');
-  helpers.check({
-    input:  'tslong --num ',
-    hints:               '<number> <msg> [options]',
-    markup: 'VVVVVVVIIIIIV'
-  });
-
-  helpers.setInput('tslong --num 42');
-  helpers.check({
-    input:  'tslong --num 42',
-    hints:                 ' <msg> [options]',
-    markup: 'VVVVVVVVVVVVVVV'
-  });
-
-  helpers.setInput('tslong --num 42 ');
-  helpers.check({
-    input:  'tslong --num 42 ',
-    hints:                  '<msg> [options]',
-    markup: 'VVVVVVVVVVVVVVVV'
-  });
-
-  helpers.setInput('tslong --num 42 --se');
-  helpers.check({
-    input:  'tslong --num 42 --se',
-    hints:                      'l <msg> [options]',
-    markup: 'VVVVVVVVVVVVVVVVIIII'
-  });
-
-  helpers.pressTab();
-  helpers.check({
-    input:  'tslong --num 42 --sel ',
-    hints:                        'space <msg> [options]',
-    markup: 'VVVVVVVVVVVVVVVVIIIIIV'
-  });
-
-  helpers.pressTab();
-  helpers.check({
-    input:  'tslong --num 42 --sel space ',
-    hints:                              '<msg> [options]',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV'
-  });
-
-  helpers.setInput('tslong --num 42 --sel ');
-  helpers.check({
-    input:  'tslong --num 42 --sel ',
-    hints:                        'space <msg> [options]',
-    markup: 'VVVVVVVVVVVVVVVVIIIIIV'
-  });
-
-  helpers.setInput('tslong --num 42 --sel space ');
-  helpers.check({
-    input:  'tslong --num 42 --sel space ',
-    hints:                              '<msg> [options]',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV'
-  });
-};
-
-exports.testNoTab = function(options) {
-  helpers.setInput('tss');
-  helpers.pressTab();
-  helpers.check({
-    input:  'tss ',
-    markup: 'VVVV',
-    hints: ''
-  });
-
-  helpers.pressTab();
-  helpers.check({
-    input:  'tss ',
-    markup: 'VVVV',
-    hints: ''
-  });
-
-  helpers.setInput('xxxx');
-  helpers.check({
-    input:  'xxxx',
-    markup: 'EEEE',
-    hints: ''
-  });
-
-  helpers.pressTab();
-  helpers.check({
-    input:  'xxxx',
-    markup: 'EEEE',
-    hints: ''
-  });
-};
-
-exports.testOutstanding = function(options) {
-  // See bug 779800
-  /*
-  helpers.setInput('tsg --txt1 ddd ');
-  helpers.check({
-    input:  'tsg --txt1 ddd ',
-    hints:                 'aaa [options]',
-    markup: 'VVVVVVVVVVVVVVV'
-  });
-  */
-};
 
 });
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -2646,33 +2521,33 @@ var mockDoc = {
 
 define('gclitest/testHelp', ['require', 'exports', 'module' , 'gclitest/helpers'], function(require, exports, module) {
 
   var helpers = require('gclitest/helpers');
 
   exports.testHelpStatus = function(options) {
     helpers.status(options, {
       typed:  'help',
-      hints:      ' [search]',
       markup: 'VVVV',
-      status: 'VALID'
+      status: 'VALID',
+      emptyParameters: [ " [search]" ]
     });
 
     helpers.status(options, {
       typed:  'help foo',
       markup: 'VVVVVVVV',
       status: 'VALID',
-      hints:  ''
+      emptyParameters: [ ]
     });
 
     helpers.status(options, {
       typed:  'help foo bar',
       markup: 'VVVVVVVVVVVV',
       status: 'VALID',
-      hints:  ''
+      emptyParameters: [ ]
     });
   };
 
   exports.testHelpExec = function(options) {
     if (options.isFirefox) {
       helpers.exec(options, {
         typed: 'help',
         args: { search: null },
@@ -2963,128 +2838,144 @@ exports.testCompleted = function(options
       num: { type: 'Argument' },
       arr: { type: 'ArrayArgument' },
     }
   });
 
   helpers.setInput('tsn dif ');
   helpers.check({
     input:  'tsn dif ',
-    hints:          '<text>',
     markup: 'VVVVVVVV',
     cursor: 8,
+    directTabText: '',
+    arrowTabText: '',
     status: 'ERROR',
+    emptyParameters: [ '<text>' ],
     args: {
       command: { name: 'tsn dif', type: 'MergedArgument' },
       text: { type: 'BlankArgument', status: 'INCOMPLETE' }
     }
   });
 
   helpers.setInput('tsn di');
   helpers.pressTab();
   helpers.check({
     input:  'tsn dif ',
-    hints:          '<text>',
     markup: 'VVVVVVVV',
     cursor: 8,
+    directTabText: '',
+    arrowTabText: '',
     status: 'ERROR',
+    emptyParameters: [ '<text>' ],
     args: {
       command: { name: 'tsn dif', type: 'Argument' },
       text: { type: 'Argument', status: 'INCOMPLETE' }
     }
   });
 
   // The above 2 tests take different routes to 'tsn dif '. The results should
   // be similar. The difference is in args.command.type.
 
   helpers.setInput('tsg -');
   helpers.check({
     input:  'tsg -',
-    hints:       '-txt1 <solo> [options]',
     markup: 'VVVVI',
     cursor: 5,
+    directTabText: '-txt1',
+    arrowTabText: '',
     status: 'ERROR',
+    emptyParameters: [ ],
     args: {
       solo: { value: undefined, status: 'INCOMPLETE' },
       txt1: { value: undefined, status: 'VALID' },
       bool: { value: undefined, status: 'VALID' },
       txt2: { value: undefined, status: 'VALID' },
       num: { value: undefined, status: 'VALID' }
     }
   });
 
   helpers.pressTab();
   helpers.check({
     input:  'tsg --txt1 ',
-    hints:             '<string> <solo> [options]',
     markup: 'VVVVIIIIIIV',
     cursor: 11,
+    directTabText: '',
+    arrowTabText: '',
     status: 'ERROR',
+    emptyParameters: [ ], // Bug 770830: '<txt1>', ' <solo>'
     args: {
       solo: { value: undefined, status: 'INCOMPLETE' },
       txt1: { value: undefined, status: 'INCOMPLETE' },
       bool: { value: undefined, status: 'VALID' },
       txt2: { value: undefined, status: 'VALID' },
       num: { value: undefined, status: 'VALID' }
     }
   });
 
   helpers.setInput('tsg --txt1 fred');
   helpers.check({
     input:  'tsg --txt1 fred',
-    hints:                 ' <solo> [options]',
     markup: 'VVVVVVVVVVVVVVV',
+    directTabText: '',
+    arrowTabText: '',
     status: 'ERROR',
+    emptyParameters: [ ], // Bug 770830: ' <solo>'
     args: {
       solo: { value: undefined, status: 'INCOMPLETE' },
       txt1: { value: 'fred', status: 'VALID' },
       bool: { value: undefined, status: 'VALID' },
       txt2: { value: undefined, status: 'VALID' },
       num: { value: undefined, status: 'VALID' }
     }
   });
 
   helpers.setInput('tscook key value --path path --');
   helpers.check({
     input:  'tscook key value --path path --',
-    hints:                                 'domain [options]',
     markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+    directTabText: 'domain',
+    arrowTabText: '',
     status: 'ERROR',
+    emptyParameters: [ ],
     args: {
       key: { value: 'key', status: 'VALID' },
       value: { value: 'value', status: 'VALID' },
       path: { value: 'path', status: 'VALID' },
       domain: { value: undefined, status: 'VALID' },
       secure: { value: false, status: 'VALID' }
     }
   });
 
   helpers.setInput('tscook key value --path path --domain domain --');
   helpers.check({
     input:  'tscook key value --path path --domain domain --',
-    hints:                                                 'secure [options]',
     markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+    directTabText: 'secure',
+    arrowTabText: '',
     status: 'ERROR',
+    emptyParameters: [ ],
     args: {
       key: { value: 'key', status: 'VALID' },
       value: { value: 'value', status: 'VALID' },
       path: { value: 'path', status: 'VALID' },
       domain: { value: 'domain', status: 'VALID' },
       secure: { value: false, status: 'VALID' }
     }
   });
 };
 
 exports.testCase = function(options) {
   helpers.setInput('tsg AA');
   helpers.check({
     input:  'tsg AA',
-    hints:        ' [options] -> aaa',
     markup: 'VVVVII',
+    directTabText: '',
+    arrowTabText: 'aaa',
     status: 'ERROR',
+    emptyParameters: [ ],
     args: {
       solo: { value: undefined, text: 'AA', status: 'INCOMPLETE' },
       txt1: { value: undefined, status: 'VALID' },
       bool: { value: undefined, status: 'VALID' },
       txt2: { value: undefined, status: 'VALID' },
       num: { value: undefined, status: 'VALID' }
     }
   });
@@ -3114,129 +3005,16 @@ exports.testIncomplete = function(option
   });
   test.is(requisition._unassigned[0], requisition.getAssignmentAt(5),
           'unassigned -');
   test.is(requisition._unassigned.length, 1, 'single unassigned - tsg -');
   test.is(requisition._unassigned[0].param.type.isIncompleteName, true,
           'unassigned.isIncompleteName: tsg -');
 };
 
-exports.testHidden = function(options) {
-  helpers.setInput('tshidde');
-  helpers.check({
-    input:  'tshidde',
-    markup: 'EEEEEEE',
-    status: 'ERROR',
-    hints:  '',
-  });
-
-  helpers.setInput('tshidden');
-  helpers.check({
-    input:  'tshidden',
-    hints:          ' [options]',
-    markup: 'VVVVVVVV',
-    status: 'VALID',
-    args: {
-      visible: { value: undefined, status: 'VALID' },
-      invisiblestring: { value: undefined, status: 'VALID' },
-      invisibleboolean: { value: undefined, status: 'VALID' }
-    }
-  });
-
-  helpers.setInput('tshidden --vis');
-  helpers.check({
-    input:  'tshidden --vis',
-    hints:                'ible [options]',
-    markup: 'VVVVVVVVVIIIII',
-    status: 'ERROR',
-    args: {
-      visible: { value: undefined, status: 'VALID' },
-      invisiblestring: { value: undefined, status: 'VALID' },
-      invisibleboolean: { value: undefined, status: 'VALID' }
-    }
-  });
-
-  helpers.setInput('tshidden --invisiblestrin');
-  helpers.check({
-    input:  'tshidden --invisiblestrin',
-    hints:                           ' [options]',
-    markup: 'VVVVVVVVVEEEEEEEEEEEEEEEE',
-    status: 'ERROR',
-    args: {
-      visible: { value: undefined, status: 'VALID' },
-      invisiblestring: { value: undefined, status: 'VALID' },
-      invisibleboolean: { value: undefined, status: 'VALID' }
-    }
-  });
-
-  helpers.setInput('tshidden --invisiblestring');
-  helpers.check({
-    input:  'tshidden --invisiblestring',
-    hints:                            ' <string> [options]',
-    markup: 'VVVVVVVVVIIIIIIIIIIIIIIIII',
-    status: 'ERROR',
-    args: {
-      visible: { value: undefined, status: 'VALID' },
-      invisiblestring: { value: undefined, status: 'INCOMPLETE' },
-      invisibleboolean: { value: undefined, status: 'VALID' }
-    }
-  });
-
-  helpers.setInput('tshidden --invisiblestring x');
-  helpers.check({
-    input:  'tshidden --invisiblestring x',
-    hints:                              ' [options]',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV',
-    status: 'VALID',
-    args: {
-      visible: { value: undefined, status: 'VALID' },
-      invisiblestring: { value: 'x', status: 'VALID' },
-      invisibleboolean: { value: undefined, status: 'VALID' }
-    }
-  });
-
-  helpers.setInput('tshidden --invisibleboolea');
-  helpers.check({
-    input:  'tshidden --invisibleboolea',
-    hints:                            ' [options]',
-    markup: 'VVVVVVVVVEEEEEEEEEEEEEEEEE',
-    status: 'ERROR',
-    args: {
-      visible: { value: undefined, status: 'VALID' },
-      invisiblestring: { value: undefined, status: 'VALID' },
-      invisibleboolean: { value: undefined, status: 'VALID' }
-    }
-  });
-
-  helpers.setInput('tshidden --invisibleboolean');
-  helpers.check({
-    input:  'tshidden --invisibleboolean',
-    hints:                             ' [options]',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV',
-    status: 'VALID',
-    args: {
-      visible: { value: undefined, status: 'VALID' },
-      invisiblestring: { value: undefined, status: 'VALID' },
-      invisibleboolean: { value: true, status: 'VALID' }
-    }
-  });
-
-  helpers.setInput('tshidden --visible xxx');
-  helpers.check({
-    input:  'tshidden --visible xxx',
-    markup: 'VVVVVVVVVVVVVVVVVVVVVV',
-    status: 'VALID',
-    hints:  '',
-    args: {
-      visible: { value: 'xxx', status: 'VALID' },
-      invisiblestring: { value: undefined, status: 'VALID' },
-      invisibleboolean: { value: undefined, status: 'VALID' }
-    }
-  });
-};
 
 });
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -3260,24 +3038,24 @@ define('gclitest/testIntro', ['require',
       test.log('Skipping testIntroStatus in Firefox.');
       return;
     }
 
     helpers.status(options, {
       typed:  'intro',
       markup: 'VVVVV',
       status: 'VALID',
-      hints: ''
+      emptyParameters: [ ]
     });
 
     helpers.status(options, {
       typed:  'intro foo',
       markup: 'VVVVVVEEE',
       status: 'ERROR',
-      hints: ''
+      emptyParameters: [ ]
     });
   };
 
   exports.testIntroExec = function(options) {
     if (options.isFirefox) {
       test.log('Skipping testIntroExec in Firefox.');
       return;
     }
@@ -3547,21 +3325,21 @@ function check(initial, action, after, c
   }
   var assignment = requisition.getAssignmentAt(cursor);
   switch (action) {
     case COMPLETES_TO:
       requisition.complete({ start: cursor, end: cursor }, choice);
       break;
 
     case KEY_UPS_TO:
-      requisition.increment(assignment);
+      assignment.increment();
       break;
 
     case KEY_DOWNS_TO:
-      requisition.decrement(assignment);
+      assignment.decrement();
       break;
   }
 
   test.is(after, requisition.toString(),
           initial + ' + ' + action + ' -> ' + after);
 
   if (expectedCursor != null) {
     if (inputter) {
@@ -3666,62 +3444,16 @@ exports.testIncrDecr = function() {
   check('tselarr 2', KEY_DOWNS_TO, 'tselarr 3');
   check('tselarr 3', KEY_DOWNS_TO, 'tselarr 1');
 
   check('tselarr 3', KEY_UPS_TO, 'tselarr 2');
 };
 
 });
 /*
- * Copyright 2009-2011 Mozilla Foundation and contributors
- * Licensed under the New BSD license. See LICENSE.txt or:
- * http://opensource.org/licenses/BSD-3-Clause
- */
-
-define('gclitest/testMenu', ['require', 'exports', 'module' , 'test/assert', 'gclitest/helpers', 'gclitest/mockCommands'], function(require, exports, module) {
-
-
-var test = require('test/assert');
-var helpers = require('gclitest/helpers');
-var mockCommands = require('gclitest/mockCommands');
-
-
-exports.setup = function(options) {
-  mockCommands.setup();
-  helpers.setup(options);
-};
-
-exports.shutdown = function(options) {
-  mockCommands.shutdown();
-  helpers.shutdown(options);
-};
-
-exports.testOptions = function(options) {
-  helpers.setInput('tslong');
-  helpers.check({
-    input:  'tslong',
-    markup: 'VVVVVV',
-    status: 'ERROR',
-    hints: ' <msg> [options]',
-    args: {
-      msg: { value: undefined, status: 'INCOMPLETE' },
-      num: { value: undefined, status: 'VALID' },
-      sel: { value: undefined, status: 'VALID' },
-      bool: { value: undefined, status: 'VALID' },
-      bool2: { value: undefined, status: 'VALID' },
-      sel2: { value: undefined, status: 'VALID' },
-      num2: { value: undefined, status: 'VALID' }
-    }
-  });
-};
-
-
-});
-
-/*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
@@ -3759,116 +3491,123 @@ exports.shutdown = function(options) {
 exports.testPrefShowStatus = function(options) {
   if (options.isFirefox) {
     test.log('Skipping testPrefShowStatus in Firefox.');
     return;
   }
 
   helpers.status(options, {
     typed:  'pref s',
-    hints:        'et',
     markup: 'IIIIVI',
-    status: 'ERROR'
+    status: 'ERROR',
+    directTabText: 'et'
   });
 
   helpers.status(options, {
     typed:  'pref show',
-    hints:           ' <setting>',
     markup: 'VVVVVVVVV',
-    status: 'ERROR'
+    status: 'ERROR',
+    emptyParameters: [ ' <setting>' ]
   });
 
   helpers.status(options, {
     typed:  'pref show ',
-    hints:            'allowSet',
     markup: 'VVVVVVVVVV',
-    status: 'ERROR'
+    status: 'ERROR',
+    emptyParameters: [ ]
   });
 
   helpers.status(options, {
     typed:  'pref show tempTBo',
-    hints:                   'ol',
     markup: 'VVVVVVVVVVIIIIIII',
-    status: 'ERROR'
+    directTabText: 'ol',
+    status: 'ERROR',
+    emptyParameters: [ ]
   });
 
   helpers.status(options, {
     typed:  'pref show tempTBool',
     markup: 'VVVVVVVVVVVVVVVVVVV',
+    directTabText: '',
     status: 'VALID',
-    hints:  ''
+    emptyParameters: [ ]
   });
 
   helpers.status(options, {
     typed:  'pref show tempTBool 4',
     markup: 'VVVVVVVVVVVVVVVVVVVVE',
+    directTabText: '',
     status: 'ERROR',
-    hints:  ''
+    emptyParameters: [ ]
   });
 
   helpers.status(options, {
     typed:  'pref show tempNumber 4',
     markup: 'VVVVVVVVVVVVVVVVVVVVVE',
+    directTabText: '',
     status: 'ERROR',
-    hints:  ''
+    emptyParameters: [ ]
   });
 };
 
 exports.testPrefSetStatus = function(options) {
   if (options.isFirefox) {
     test.log('Skipping testPrefSetStatus in Firefox.');
     return;
   }
 
   helpers.status(options, {
     typed:  'pref s',
-    hints:        'et',
     markup: 'IIIIVI',
     status: 'ERROR',
+    directTabText: 'et'
   });
 
   helpers.status(options, {
     typed:  'pref set',
-    hints:          ' <setting> <value>',
     markup: 'VVVVVVVV',
-    status: 'ERROR'
+    status: 'ERROR',
+    emptyParameters: [ ' <setting>', ' <value>' ]
   });
 
   helpers.status(options, {
     typed:  'pref xxx',
     markup: 'EEEEVEEE',
     status: 'ERROR'
   });
 
   helpers.status(options, {
     typed:  'pref set ',
-    hints:           'allowSet <value>',
     markup: 'VVVVVVVVV',
-    status: 'ERROR'
+    status: 'ERROR',
+    emptyParameters: [ ' <value>' ]
   });
 
   helpers.status(options, {
     typed:  'pref set tempTBo',
-    hints:                  'ol <value>',
     markup: 'VVVVVVVVVIIIIIII',
-    status: 'ERROR'
+    directTabText: 'ol',
+    status: 'ERROR',
+    emptyParameters: [ ' <value>' ]
   });
 
   helpers.status(options, {
     typed:  'pref set tempTBool 4',
     markup: 'VVVVVVVVVVVVVVVVVVVE',
+    directTabText: '',
     status: 'ERROR',
-    hints: ''
+    emptyParameters: [ ]
   });
 
   helpers.status(options, {
     typed:  'pref set tempNumber 4',
     markup: 'VVVVVVVVVVVVVVVVVVVVV',
+    directTabText: '',
     status: 'VALID',
-    hints: ''
+    emptyParameters: [ ]
   });
 };
 
 exports.testPrefExec = function(options) {
   if (options.isFirefox) {
     test.log('Skipping testPrefExec in Firefox.');
     return;
   }
@@ -5822,17 +5561,16 @@ let testModuleNames = [
   'gclitest/testExec',
   'gclitest/testHelp',
   'gclitest/testHistory',
   'gclitest/testInputter',
   'gclitest/testIncomplete',
   'gclitest/testIntro',
   'gclitest/testJs',
   'gclitest/testKeyboard',
-  'gclitest/testMenu',
   'gclitest/testPref',
   'gclitest/mockSettings',
   'gclitest/testRequire',
   'gclitest/requirable',
   'gclitest/testResource',
   'gclitest/testScratchpad',
   'gclitest/testSettings',
   'gclitest/testSpell',
--- a/browser/devtools/commandline/test/head.js
+++ b/browser/devtools/commandline/test/head.js
@@ -6,20 +6,16 @@ const TEST_BASE_HTTP = "http://example.c
 const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/commandline/test/";
 
 let console = (function() {
   let tempScope = {};
   Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
   return tempScope.console;
 })();
 
-// Import the GCLI test helper
-let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
-
 /**
  * Open a new tab at a URL and call a callback on load
  */
 function addTab(aURL, aCallback)
 {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
@@ -38,8 +34,523 @@ function addTab(aURL, aCallback)
 
 registerCleanupFunction(function tearDown() {
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 
   console = undefined;
 });
+
+/**
+ * Various functions for testing DeveloperToolbar.
+ * Parts of this code exist in:
+ * - browser/devtools/commandline/test/head.js
+ * - browser/devtools/shared/test/head.js
+ */
+let DeveloperToolbarTest = { };
+
+/**
+ * Paranoid DeveloperToolbar.show();
+ */
+DeveloperToolbarTest.show = function DTT_show(aCallback) {
+  if (DeveloperToolbar.visible) {
+    ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
+  }
+  else {
+    DeveloperToolbar.show(true, aCallback);
+  }
+};
+
+/**
+ * Paranoid DeveloperToolbar.hide();
+ */
+DeveloperToolbarTest.hide = function DTT_hide() {
+  if (!DeveloperToolbar.visible) {
+    ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
+  }
+  else {
+    DeveloperToolbar.display.inputter.setInput("");
+    DeveloperToolbar.hide();
+  }
+};
+
+/**
+ * check() is the new status. Similar API except that it doesn't attempt to
+ * alter the display/requisition at all, and it makes extra checks.
+ * Test inputs
+ *   typed: The text to type at the input
+ * Available checks:
+ *   input: The text displayed in the input field
+ *   cursor: The position of the start of the cursor
+ *   status: One of "VALID", "ERROR", "INCOMPLETE"
+ *   emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
+ *   directTabText: Simple completion text
+ *   arrowTabText: When the completion is not an extension (without arrow)
+ *   markup: What state should the error markup be in. e.g. "VVVIIIEEE"
+ *   args: Maps of checks to make against the arguments:
+ *     value: i.e. assignment.value (which ignores defaultValue)
+ *     type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
+ *           Care should be taken with this since it's something of an
+ *           implementation detail
+ *     arg: The toString value of the argument
+ *     status: i.e. assignment.getStatus
+ *     message: i.e. assignment.getMessage
+ *     name: For commands - checks assignment.value.name
+ */
+DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
+  if (!checks.emptyParameters) {
+    checks.emptyParameters = [];
+  }
+  if (!checks.directTabText) {
+    checks.directTabText = '';
+  }
+  if (!checks.arrowTabText) {
+    checks.arrowTabText = '';
+  }
+
+  var display = DeveloperToolbar.display;
+
+  if (checks.typed) {
+    display.inputter.setInput(checks.typed);
+  }
+  else {
+    ok(false, "Missing typed for " + JSON.stringify(checks));
+    return;
+  }
+
+  if (checks.cursor) {
+    display.inputter.setCursor(checks.cursor)
+  }
+
+  var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
+
+  var requisition = display.requisition;
+  var completer = display.completer;
+  var actual = completer._getCompleterTemplateData();
+
+  /*
+  if (checks.input) {
+    is(display.inputter.element.value,
+            checks.input,
+            'input');
+  }
+
+  if (checks.cursor) {
+    is(display.inputter.element.selectionStart,
+            checks.cursor,
+            'cursor');
+  }
+  */
+
+  if (checks.status) {
+    is(requisition.getStatus().toString(),
+            checks.status,
+            'status');
+  }
+
+  if (checks.markup) {
+    var statusMarkup = requisition.getInputStatusMarkup(cursor);
+    var actualMarkup = statusMarkup.map(function(s) {
+      return Array(s.string.length + 1).join(s.status.toString()[0]);
+    }).join('');
+
+    is(checks.markup,
+            actualMarkup,
+            'markup');
+  }
+
+  if (checks.emptyParameters) {
+    var actualParams = actual.emptyParameters;
+    is(actualParams.length,
+            checks.emptyParameters.length,
+            'emptyParameters.length');
+
+    if (actualParams.length === checks.emptyParameters.length) {
+      for (var i = 0; i < actualParams.length; i++) {
+        is(actualParams[i].replace(/\u00a0/g, ' '),
+                checks.emptyParameters[i],
+                'emptyParameters[' + i + ']');
+      }
+    }
+  }
+
+  if (checks.directTabText) {
+    is(actual.directTabText,
+            checks.directTabText,
+            'directTabText');
+  }
+
+  if (checks.arrowTabText) {
+    is(actual.arrowTabText,
+            ' \u00a0\u21E5 ' + checks.arrowTabText,
+            'arrowTabText');
+  }
+
+  if (checks.args) {
+    Object.keys(checks.args).forEach(function(paramName) {
+      var check = checks.args[paramName];
+
+      var assignment;
+      if (paramName === 'command') {
+        assignment = requisition.commandAssignment;
+      }
+      else {
+        assignment = requisition.getAssignment(paramName);
+      }
+
+      if (assignment == null) {
+        ok(false, 'Unknown parameter: ' + paramName);
+        return;
+      }
+
+      if (check.value) {
+        is(assignment.value,
+                check.value,
+                'checkStatus value for ' + paramName);
+      }
+
+      if (check.name) {
+        is(assignment.value.name,
+                check.name,
+                'checkStatus name for ' + paramName);
+      }
+
+      if (check.type) {
+        is(assignment.arg.type,
+                check.type,
+                'checkStatus type for ' + paramName);
+      }
+
+      if (check.arg) {
+        is(assignment.arg.toString(),
+                check.arg,
+                'checkStatus arg for ' + paramName);
+      }
+
+      if (check.status) {
+        is(assignment.getStatus().toString(),
+                check.status,
+                'checkStatus status for ' + paramName);
+      }
+
+      if (check.message) {
+        is(assignment.getMessage(),
+                check.message,
+                'checkStatus message for ' + paramName);
+      }
+    });
+  }
+};
+
+/**
+ * Execute a command:
+ *
+ * DeveloperToolbarTest.exec({
+ *   // Test inputs
+ *   typed: "echo hi",        // Optional, uses existing if undefined
+ *
+ *   // Thing to check
+ *   args: { message: "hi" }, // Check that the args were understood properly
+ *   outputMatch: /^hi$/,     // RegExp to test against textContent of output
+ *                            // (can also be array of RegExps)
+ *   blankOutput: true,       // Special checks when there is no output
+ * });
+ */
+DeveloperToolbarTest.exec = function DTT_exec(tests) {
+  tests = tests || {};
+
+  if (tests.typed) {
+    DeveloperToolbar.display.inputter.setInput(tests.typed);
+  }
+
+  let typed = DeveloperToolbar.display.inputter.getInputState().typed;
+  let output = DeveloperToolbar.display.requisition.exec();
+
+  is(typed, output.typed, 'output.command for: ' + typed);
+
+  if (tests.completed !== false) {
+    ok(output.completed, 'output.completed false for: ' + typed);
+  }
+  else {
+    // It is actually an error if we say something is async and it turns
+    // out not to be? For now we're saying 'no'
+    // ok(!output.completed, 'output.completed true for: ' + typed);
+  }
+
+  if (tests.args != null) {
+    is(Object.keys(tests.args).length, Object.keys(output.args).length,
+       'arg count for ' + typed);
+
+    Object.keys(output.args).forEach(function(arg) {
+      let expectedArg = tests.args[arg];
+      let actualArg = output.args[arg];
+
+      if (typeof expectedArg === 'function') {
+        ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
+      }
+      else {
+        if (Array.isArray(expectedArg)) {
+          if (!Array.isArray(actualArg)) {
+            ok(false, 'actual is not an array. ' + typed + '/' + arg);
+            return;
+          }
+
+          is(expectedArg.length, actualArg.length,
+                  'array length: ' + typed + '/' + arg);
+          for (let i = 0; i < expectedArg.length; i++) {
+            is(expectedArg[i], actualArg[i],
+                    'member: "' + typed + '/' + arg + '/' + i);
+          }
+        }
+        else {
+          is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
+        }
+      }
+    });
+  }
+
+  let displayed = DeveloperToolbar.outputPanel._div.textContent;
+
+  if (tests.outputMatch) {
+    function doTest(match, against) {
+      if (!match.test(against)) {
+        ok(false, "html output for " + typed + " against " + match.source +
+                " (textContent sent to info)");
+        info("Actual textContent");
+        info(against);
+      }
+    }
+    if (Array.isArray(tests.outputMatch)) {
+      tests.outputMatch.forEach(function(match) {
+        doTest(match, displayed);
+      });
+    }
+    else {
+      doTest(tests.outputMatch, displayed);
+    }
+  }
+
+  if (tests.blankOutput != null) {
+    if (!/^$/.test(displayed)) {
+      ok(false, "html output for " + typed + " (textContent sent to info)");
+      info("Actual textContent");
+      info(displayed);
+    }
+  }
+};
+
+/**
+ * Quick wrapper around the things you need to do to run DeveloperToolbar
+ * command tests:
+ * - Set the pref 'devtools.toolbar.enabled' to true
+ * - Add a tab pointing at |uri|
+ * - Open the DeveloperToolbar
+ * - Register a cleanup function to undo the above
+ * - Run the tests
+ *
+ * @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
+ * @param testFunc A function containing the tests to run. This should
+ * arrange for 'finish()' to be called on completion.
+ */
+DeveloperToolbarTest.test = function DTT_test(uri, testFunc) {
+  let menuItem = document.getElementById("menu_devToolbar");
+  let command = document.getElementById("Tools:DevToolbar");
+  let appMenuItem = document.getElementById("appmenu_devToolbar");
+
+  registerCleanupFunction(function() {
+    DeveloperToolbarTest.hide();
+
+    // a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
+    if (menuItem) {
+      menuItem.hidden = true;
+    }
+    if (command) {
+      command.setAttribute("disabled", "true");
+    }
+    if (appMenuItem) {
+      appMenuItem.hidden = true;
+    }
+
+    // leakHunt({ DeveloperToolbar: DeveloperToolbar });
+  });
+
+  // a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
+  if (menuItem) {
+    menuItem.hidden = false;
+  }
+  if (command) {
+    command.removeAttribute("disabled");
+  }
+  if (appMenuItem) {
+    appMenuItem.hidden = false;
+  }
+
+  addTab(uri, function(browser, tab) {
+    DeveloperToolbarTest.show(function() {
+
+      try {
+        testFunc(browser, tab);
+      }
+      catch (ex) {
+        ok(false, "" + ex);
+        console.error(ex);
+        finish();
+        throw ex;
+      }
+    });
+  });
+};
+
+
+/**
+ * Memory leak hunter. Walks a tree of objects looking for DOM nodes.
+ * Usage:
+ * leakHunt({
+ *   thing: thing,
+ *   otherthing: otherthing
+ * });
+ */
+
+var noRecurse = [
+  /^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/,
+  /^Window$/, /^Document$/,
+  /^XULDocument$/, /^XULElement$/,
+  /^DOMWindow$/, /^HTMLDocument$/, /^HTML.*Element$/
+];
+
+var hide = [ /^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/ ];
+
+function leakHunt(root, path, seen) {
+  path = path || [];
+  seen = seen || [];
+
+  try {
+    var output = leakHuntInner(root, path, seen);
+    output.forEach(function(line) {
+      dump(line + '\n');
+    });
+  }
+  catch (ex) {
+    dump(ex + '\n');
+  }
+}
+
+function leakHuntInner(root, path, seen) {
+  var prefix = new Array(path.length).join('  ');
+
+  var reply = [];
+  function log(msg) {
+    reply.push(msg);
+  }
+
+  var direct
+  try {
+    direct = Object.keys(root);
+  }
+  catch (ex) {
+    log(prefix + '  Error enumerating: ' + ex);
+    return reply;
+  }
+
+  for (var prop in root) {
+    var newPath = path.slice();
+    newPath.push(prop);
+    prefix = new Array(newPath.length).join('  ');
+
+    var data;
+    try {
+      data = root[prop];
+    }
+    catch (ex) {
+      log(prefix + prop + '  Error reading: ' + ex);
+      continue;
+    }
+
+    var recurse = true;
+    var message = getType(data);
+
+    if (matchesAnyPattern(message, hide)) {
+      continue;
+    }
+
+    if (message === 'function' && direct.indexOf(prop) == -1) {
+      continue;
+    }
+
+    if (message === 'string') {
+      var extra = data.length > 10 ? data.substring(0, 9) + '_' : data;
+      message += ' "' + extra.replace(/\n/g, "|") + '"';
+      recurse = false;
+    }
+    else if (matchesAnyPattern(message, noRecurse)) {
+      message += ' (no recurse)'
+      recurse = false;
+    }
+    else if (seen.indexOf(data) !== -1) {
+      message += ' (already seen)';
+      recurse = false;
+    }
+
+    if (recurse) {
+      seen.push(data);
+      var lines = leakHuntInner(data, newPath, seen);
+      if (lines.length == 0) {
+        if (message !== 'function') {
+          log(prefix + prop + ' = ' + message + ' { }');
+        }
+      }
+      else {
+        log(prefix + prop + ' = ' + message + ' {');
+        lines.forEach(function(line) {
+          reply.push(line);
+        });
+        log(prefix + '}');
+      }
+    }
+    else {
+      log(prefix + prop + ' = ' + message);
+    }
+  }
+
+  return reply;
+}
+
+function matchesAnyPattern(str, patterns) {
+  var match = false;
+  patterns.forEach(function(pattern) {
+    if (str.match(pattern)) {
+      match = true;
+    }
+  });
+  return match;
+}
+
+function getType(data) {
+  if (data === null) {
+    return 'null';
+  }
+  if (data === undefined) {
+    return 'undefined';
+  }
+
+  var type = typeof data;
+  if (type === 'object' || type === 'Object') {
+    type = getCtorName(data);
+  }
+
+  return type;
+}
+
+function getCtorName(aObj) {
+  try {
+    if (aObj.constructor && aObj.constructor.name) {
+      return aObj.constructor.name;
+    }
+  }
+  catch (ex) {
+    return 'UnknownObject';
+  }
+
+  // If that fails, use Objects toString which sometimes gives something
+  // better than 'Object', and at least defaults to Object if nothing better
+  return Object.prototype.toString.call(aObj).slice(8, -1);
+}
deleted file mode 100644
--- a/browser/devtools/commandline/test/helpers.js
+++ /dev/null
@@ -1,881 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-
-/*
- *
- *  DO NOT ALTER THIS FILE WITHOUT KEEPING IT IN SYNC WITH THE OTHER COPIES
- *  OF THIS FILE.
- *
- *  UNAUTHORIZED ALTERATION WILL RESULT IN THE ALTEREE BEING SENT TO SIT ON
- *  THE NAUGHTY STEP.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *  FOR A LONG TIME.
- *
- */
-
-
-/*
- * Use as a JSM
- * ------------
- * helpers._createDebugCheck() and maybe other functions in this file can be
- * useful at runtime, so it is possible to use helpers.js as a JSM.
- * Copy commandline/test/helpers.js to shared/helpers.jsm, and then add to
- * DeveloperToolbar.jsm the following:
- *
- * XPCOMUtils.defineLazyModuleGetter(this, "helpers",
- *                                 "resource:///modules/devtools/helpers.jsm");
- *
- * At the bottom of DeveloperToolbar.prototype._onload add this:
- *
- * var options = { display: this.display };
- * this._input.onkeypress = function(ev) {
- *   helpers.setup(options);
- *   dump(helpers._createDebugCheck() + '\n\n');
- * };
- *
- * Now GCLI will emit output on every keypress that both explains the state
- * of GCLI and can be run as a test case.
- */
-
-var EXPORTED_SYMBOLS = [ 'helpers' ];
-
-var test = { };
-
-/**
- * Various functions for testing DeveloperToolbar.
- * Parts of this code exist in:
- * - browser/devtools/commandline/test/head.js
- * - browser/devtools/shared/test/head.js
- */
-let DeveloperToolbarTest = { };
-
-/**
- * Paranoid DeveloperToolbar.show();
- */
-DeveloperToolbarTest.show = function DTT_show(aCallback) {
-  if (DeveloperToolbar.visible) {
-    ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
-  }
-  else {
-    DeveloperToolbar.show(true, aCallback);
-  }
-};
-
-/**
- * Paranoid DeveloperToolbar.hide();
- */
-DeveloperToolbarTest.hide = function DTT_hide() {
-  if (!DeveloperToolbar.visible) {
-    ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
-  }
-  else {
-    DeveloperToolbar.display.inputter.setInput("");
-    DeveloperToolbar.hide();
-  }
-};
-
-/**
- * check() is the new status. Similar API except that it doesn't attempt to
- * alter the display/requisition at all, and it makes extra checks.
- * Test inputs
- *   typed: The text to type at the input
- * Available checks:
- *   input: The text displayed in the input field
- *   cursor: The position of the start of the cursor
- *   status: One of "VALID", "ERROR", "INCOMPLETE"
- *   emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
- *   directTabText: Simple completion text
- *   arrowTabText: When the completion is not an extension (without arrow)
- *   markup: What state should the error markup be in. e.g. "VVVIIIEEE"
- *   args: Maps of checks to make against the arguments:
- *     value: i.e. assignment.value (which ignores defaultValue)
- *     type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
- *           Care should be taken with this since it's something of an
- *           implementation detail
- *     arg: The toString value of the argument
- *     status: i.e. assignment.getStatus
- *     message: i.e. assignment.getMessage
- *     name: For commands - checks assignment.value.name
- */
-DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
-  if (!checks.emptyParameters) {
-    checks.emptyParameters = [];
-  }
-  if (!checks.directTabText) {
-    checks.directTabText = '';
-  }
-  if (!checks.arrowTabText) {
-    checks.arrowTabText = '';
-  }
-
-  var display = DeveloperToolbar.display;
-
-  if (checks.typed) {
-    info('Starting tests for ' + checks.typed);
-    display.inputter.setInput(checks.typed);
-  }
-  else {
-    ok(false, "Missing typed for " + JSON.stringify(checks));
-    return;
-  }
-
-  if (checks.cursor) {
-    display.inputter.setCursor(checks.cursor)
-  }
-
-  var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
-
-  var requisition = display.requisition;
-  var completer = display.completer;
-  var actual = completer._getCompleterTemplateData();
-
-  /*
-  if (checks.input) {
-    is(display.inputter.element.value,
-            checks.input,
-            'input');
-  }
-
-  if (checks.cursor) {
-    is(display.inputter.element.selectionStart,
-            checks.cursor,
-            'cursor');
-  }
-  */
-
-  if (checks.status) {
-    is(requisition.getStatus().toString(),
-            checks.status,
-            'status');
-  }
-
-  if (checks.markup) {
-    var statusMarkup = requisition.getInputStatusMarkup(cursor);
-    var actualMarkup = statusMarkup.map(function(s) {
-      return Array(s.string.length + 1).join(s.status.toString()[0]);
-    }).join('');
-
-    is(checks.markup,
-            actualMarkup,
-            'markup');
-  }
-
-  if (checks.emptyParameters) {
-    var actualParams = actual.emptyParameters;
-    is(actualParams.length,
-            checks.emptyParameters.length,
-            'emptyParameters.length');
-
-    if (actualParams.length === checks.emptyParameters.length) {
-      for (var i = 0; i < actualParams.length; i++) {
-        is(actualParams[i].replace(/\u00a0/g, ' '),
-                checks.emptyParameters[i],
-                'emptyParameters[' + i + ']');
-      }
-    }
-    else {
-      info('Expected: [ \"' + actualParams.join('", "') + '" ]');
-    }
-  }
-
-  if (checks.directTabText) {
-    is(actual.directTabText,
-            checks.directTabText,
-            'directTabText');
-  }
-
-  if (checks.arrowTabText) {
-    is(actual.arrowTabText,
-            ' \u00a0\u21E5 ' + checks.arrowTabText,
-            'arrowTabText');
-  }
-
-  if (checks.args) {
-    Object.keys(checks.args).forEach(function(paramName) {
-      var check = checks.args[paramName];
-
-      var assignment;
-      if (paramName === 'command') {
-        assignment = requisition.commandAssignment;
-      }
-      else {
-        assignment = requisition.getAssignment(paramName);
-      }
-
-      if (assignment == null) {
-        ok(false, 'Unknown parameter: ' + paramName);
-        return;
-      }
-
-      if (check.value) {
-        is(assignment.value,
-                check.value,
-                'checkStatus value for ' + paramName);
-      }
-
-      if (check.name) {
-        is(assignment.value.name,
-                check.name,
-                'checkStatus name for ' + paramName);
-      }
-
-      if (check.type) {
-        is(assignment.arg.type,
-                check.type,
-                'checkStatus type for ' + paramName);
-      }
-
-      if (check.arg) {
-        is(assignment.arg.toString(),
-                check.arg,
-                'checkStatus arg for ' + paramName);
-      }
-
-      if (check.status) {
-        is(assignment.getStatus().toString(),
-                check.status,
-                'checkStatus status for ' + paramName);
-      }
-
-      if (check.message) {
-        is(assignment.getMessage(),
-                check.message,
-                'checkStatus message for ' + paramName);
-      }
-    });
-  }
-};
-
-/**
- * Execute a command:
- *
- * DeveloperToolbarTest.exec({
- *   // Test inputs
- *   typed: "echo hi",        // Optional, uses existing if undefined
- *
- *   // Thing to check
- *   args: { message: "hi" }, // Check that the args were understood properly
- *   outputMatch: /^hi$/,     // RegExp to test against textContent of output
- *                            // (can also be array of RegExps)
- *   blankOutput: true,       // Special checks when there is no output
- * });
- */
-DeveloperToolbarTest.exec = function DTT_exec(tests) {
-  tests = tests || {};
-
-  if (tests.typed) {
-    DeveloperToolbar.display.inputter.setInput(tests.typed);
-  }
-
-  let typed = DeveloperToolbar.display.inputter.getInputState().typed;
-  let output = DeveloperToolbar.display.requisition.exec();
-
-  is(typed, output.typed, 'output.command for: ' + typed);
-
-  if (tests.completed !== false) {
-    ok(output.completed, 'output.completed false for: ' + typed);
-  }
-  else {
-    // It is actually an error if we say something is async and it turns
-    // out not to be? For now we're saying 'no'
-    // ok(!output.completed, 'output.completed true for: ' + typed);
-  }
-
-  if (tests.args != null) {
-    is(Object.keys(tests.args).length, Object.keys(output.args).length,
-       'arg count for ' + typed);
-
-    Object.keys(output.args).forEach(function(arg) {
-      let expectedArg = tests.args[arg];
-      let actualArg = output.args[arg];
-
-      if (typeof expectedArg === 'function') {
-        ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
-      }
-      else {
-        if (Array.isArray(expectedArg)) {
-          if (!Array.isArray(actualArg)) {
-            ok(false, 'actual is not an array. ' + typed + '/' + arg);
-            return;
-          }
-
-          is(expectedArg.length, actualArg.length,
-                  'array length: ' + typed + '/' + arg);
-          for (let i = 0; i < expectedArg.length; i++) {
-            is(expectedArg[i], actualArg[i],
-                    'member: "' + typed + '/' + arg + '/' + i);
-          }
-        }
-        else {
-          is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
-        }
-      }
-    });
-  }
-
-  let displayed = DeveloperToolbar.outputPanel._div.textContent;
-
-  if (tests.outputMatch) {
-    var doTest = function(match, against) {
-      if (!match.test(against)) {
-        ok(false, "html output for " + typed + " against " + match.source +
-                " (textContent sent to info)");
-        info("Actual textContent");
-        info(against);
-      }
-    }
-    if (Array.isArray(tests.outputMatch)) {
-      tests.outputMatch.forEach(function(match) {
-        doTest(match, displayed);
-      });
-    }
-    else {
-      doTest(tests.outputMatch, displayed);
-    }
-  }
-
-  if (tests.blankOutput != null) {
-    if (!/^$/.test(displayed)) {
-      ok(false, "html output for " + typed + " (textContent sent to info)");
-      info("Actual textContent");
-      info(displayed);
-    }
-  }
-};
-
-/**
- * Quick wrapper around the things you need to do to run DeveloperToolbar
- * command tests:
- * - Set the pref 'devtools.toolbar.enabled' to true
- * - Add a tab pointing at |uri|
- * - Open the DeveloperToolbar
- * - Register a cleanup function to undo the above
- * - Run the tests
- *
- * @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
- * @param target Either a function or array of functions containing the tests
- * to run. If an array of test function is passed then we will clear up after
- * the tests have completed. If a single test function is passed then this
- * function should arrange for 'finish()' to be called on completion.
- */
-DeveloperToolbarTest.test = function DTT_test(uri, target) {
-  let menuItem = document.getElementById("menu_devToolbar");
-  let command = document.getElementById("Tools:DevToolbar");
-  let appMenuItem = document.getElementById("appmenu_devToolbar");
-
-  registerCleanupFunction(function() {
-    DeveloperToolbarTest.hide();
-
-    // a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
-    if (menuItem) {
-      menuItem.hidden = true;
-    }
-    if (command) {
-      command.setAttribute("disabled", "true");
-    }
-    if (appMenuItem) {
-      appMenuItem.hidden = true;
-    }
-
-    // leakHunt({ DeveloperToolbar: DeveloperToolbar });
-  });
-
-  // a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
-  if (menuItem) {
-    menuItem.hidden = false;
-  }
-  if (command) {
-    command.removeAttribute("disabled");
-  }
-  if (appMenuItem) {
-    appMenuItem.hidden = false;
-  }
-
-  waitForExplicitFinish();
-
-  gBrowser.selectedTab = gBrowser.addTab();
-  content.location = uri;
-
-  let tab = gBrowser.selectedTab;
-  let browser = gBrowser.getBrowserForTab(tab);
-
-  var onTabLoad = function() {
-    browser.removeEventListener("load", onTabLoad, true);
-
-    DeveloperToolbarTest.show(function() {
-      if (helpers) {
-        helpers.setup({ display: DeveloperToolbar.display });
-      }
-
-      if (Array.isArray(target)) {
-        try {
-          target.forEach(function(func) {
-            func(browser, tab);
-          })
-        }
-        finally {
-          DeveloperToolbarTest._checkFinish();
-        }
-      }
-      else {
-        try {
-          target(browser, tab);
-        }
-        catch (ex) {
-          ok(false, "" + ex);
-          DeveloperToolbarTest._finish();
-          throw ex;
-        }
-      }
-    });
-  }
-
-  browser.addEventListener("load", onTabLoad, true);
-};
-
-DeveloperToolbarTest._outstanding = [];
-
-DeveloperToolbarTest._checkFinish = function() {
-  info('_checkFinish. ' + DeveloperToolbarTest._outstanding.length + ' outstanding');
-  if (DeveloperToolbarTest._outstanding.length == 0) {
-    DeveloperToolbarTest._finish();
-  }
-}
-
-DeveloperToolbarTest._finish = function() {
-  info('Finish');
-  DeveloperToolbarTest.closeAllTabs();
-  finish();
-}
-
-DeveloperToolbarTest.checkCalled = function(aFunc, aScope) {
-  var todo = function() {
-    var reply = aFunc.apply(aScope, arguments);
-    DeveloperToolbarTest._outstanding = DeveloperToolbarTest._outstanding.filter(function(aJob) {
-      return aJob != todo;
-    });
-    DeveloperToolbarTest._checkFinish();
-    return reply;
-  }
-  DeveloperToolbarTest._outstanding.push(todo);
-  return todo;
-};
-
-DeveloperToolbarTest.checkNotCalled = function(aMsg, aFunc, aScope) {
-  return function() {
-    ok(false, aMsg);
-    return aFunc.apply(aScope, arguments);
-  }
-};
-
-/**
- *
- */
-DeveloperToolbarTest.closeAllTabs = function() {
-  while (gBrowser.tabs.length > 1) {
-    gBrowser.removeCurrentTab();
-  }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-var helpers = {};
-
-helpers._display = undefined;
-
-helpers.setup = function(options) {
-  helpers._display = options.display;
-  if (typeof ok !== 'undefined') {
-    test.ok = ok;
-    test.is = is;
-    test.log = info;
-  }
-};
-
-helpers.shutdown = function(options) {
-  helpers._display = undefined;
-};
-
-/**
- * Various functions to return the actual state of the command line
- */
-helpers._actual = {
-  input: function() {
-    return helpers._display.inputter.element.value;
-  },
-
-  hints: function() {
-    var templateData = helpers._display.completer._getCompleterTemplateData();
-    var actualHints = templateData.directTabText +
-                      templateData.emptyParameters.join('') +
-                      templateData.arrowTabText;
-    return actualHints.replace(/\u00a0/g, ' ')
-                      .replace(/\u21E5/, '->')
-                      .replace(/ $/, '');
-  },
-
-  markup: function() {
-    var cursor = helpers._display.inputter.element.selectionStart;
-    var statusMarkup = helpers._display.requisition.getInputStatusMarkup(cursor);
-    return statusMarkup.map(function(s) {
-      return Array(s.string.length + 1).join(s.status.toString()[0]);
-    }).join('');
-  },
-
-  cursor: function() {
-    return helpers._display.inputter.element.selectionStart;
-  },
-
-  current: function() {
-    return helpers._display.requisition.getAssignmentAt(helpers._actual.cursor()).param.name;
-  },
-
-  status: function() {
-    return helpers._display.requisition.getStatus().toString();
-  },
-
-  outputState: function() {
-    var outputData = helpers._display.focusManager._shouldShowOutput();
-    return outputData.visible + ':' + outputData.reason;
-  },
-
-  tooltipState: function() {
-    var tooltipData = helpers._display.focusManager._shouldShowTooltip();
-    return tooltipData.visible + ':' + tooltipData.reason;
-  }
-};
-
-helpers._directToString = [ 'boolean', 'undefined', 'number' ];
-
-helpers._createDebugCheck = function() {
-  var requisition = helpers._display.requisition;
-  var command = requisition.commandAssignment.value;
-  var input = helpers._actual.input();
-  var padding = Array(input.length + 1).join(' ');
-
-  var output = '';
-  output += 'helpers.setInput(\'' + input + '\');\n';
-  output += 'helpers.check({\n';
-  output += '  input:  \'' + input + '\',\n';
-  output += '  hints:  ' + padding + '\'' + helpers._actual.hints() + '\',\n';
-  output += '  markup: \'' + helpers._actual.markup() + '\',\n';
-  output += '  cursor: ' + helpers._actual.cursor() + ',\n';
-  output += '  current: \'' + helpers._actual.current() + '\',\n';
-  output += '  status: \'' + helpers._actual.status() + '\',\n';
-  output += '  outputState: \'' + helpers._actual.outputState() + '\',\n';
-
-  if (command) {
-    output += '  tooltipState: \'' + helpers._actual.tooltipState() + '\',\n';
-    output += '  args: {\n';
-    output += '    command: { name: \'' + command.name + '\' },\n';
-
-    requisition.getAssignments().forEach(function(assignment) {
-      output += '    ' + assignment.param.name + ': { ';
-
-      if (typeof assignment.value === 'string') {
-        output += 'value: \'' + assignment.value + '\', ';
-      }
-      else if (helpers._directToString.indexOf(typeof assignment.value) !== -1) {
-        output += 'value: ' + assignment.value + ', ';
-      }
-      else if (assignment.value === null) {
-        output += 'value: ' + assignment.value + ', ';
-      }
-      else {
-        output += '/*value:' + assignment.value + ',*/ ';
-      }
-
-      output += 'arg: \'' + assignment.arg + '\', ';
-      output += 'status: \'' + assignment.getStatus().toString() + '\', ';
-      output += 'message: \'' + assignment.getMessage() + '\'';
-      output += ' },\n';
-    });
-
-    output += '  }\n';
-  }
-  else {
-    output += '  tooltipState: \'' + helpers._actual.tooltipState() + '\'\n';
-  }
-  output += '});';
-
-  return output;
-};
-
-/**
- * We're splitting status into setup() which alters the state of the system
- * and check() which ensures that things are in the right place afterwards.
- */
-helpers.setInput = function(typed, cursor) {
-  helpers._display.inputter.setInput(typed);
-
-  if (cursor) {
-    helpers._display.inputter.setCursor({ start: cursor, end: cursor });
-  }
-
-  helpers._display.focusManager.onInputChange();
-
-  test.log('setInput("' + typed + '"' + (cursor == null ? '' : ', ' + cursor) + ')');
-};
-
-/**
- * Simulate focusing the input field
- */
-helpers.focusInput = function() {
-  helpers._display.inputter.focus();
-};
-
-/**
- * Simulate pressing TAB in the input field
- */
-helpers.pressTab = function() {
-  helpers.pressKey(9 /*KeyEvent.DOM_VK_TAB*/);
-};
-
-/**
- * Simulate pressing RETURN in the input field
- */
-helpers.pressReturn = function() {
-  helpers.pressKey(13 /*KeyEvent.DOM_VK_RETURN*/);
-};
-
-/**
- * Simulate pressing a key by keyCode in the input field
- */
-helpers.pressKey = function(keyCode) {
-  var fakeEvent = {
-    keyCode: keyCode,
-    preventDefault: function() { },
-    timeStamp: new Date().getTime()
-  };
-  helpers._display.inputter.onKeyDown(fakeEvent);
-  helpers._display.inputter.onKeyUp(fakeEvent);
-};
-
-/**
- * check() is the new status. Similar API except that it doesn't attempt to
- * alter the display/requisition at all, and it makes extra checks.
- * Available checks:
- *   input: The text displayed in the input field
- *   cursor: The position of the start of the cursor
- *   status: One of "VALID", "ERROR", "INCOMPLETE"
- *   hints: The hint text, i.e. a concatenation of the directTabText, the
- *     emptyParameters and the arrowTabText. The text as inserted into the UI
- *     will include NBSP and Unicode RARR characters, these should be
- *     represented using normal space and '->' for the arrow
- *   markup: What state should the error markup be in. e.g. "VVVIIIEEE"
- *   args: Maps of checks to make against the arguments:
- *     value: i.e. assignment.value (which ignores defaultValue)
- *     type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
- *           Care should be taken with this since it's something of an
- *           implementation detail
- *     arg: The toString value of the argument
- *     status: i.e. assignment.getStatus
- *     message: i.e. assignment.getMessage
- *     name: For commands - checks assignment.value.name
- */
-helpers.check = function(checks) {
-  if ('input' in checks) {
-    test.is(helpers._actual.input(), checks.input, 'input');
-  }
-
-  if ('cursor' in checks) {
-    test.is(helpers._actual.cursor(), checks.cursor, 'cursor');
-  }
-
-  if ('current' in checks) {
-    test.is(helpers._actual.current(), checks.current, 'current');
-  }
-
-  if ('status' in checks) {
-    test.is(helpers._actual.status(), checks.status, 'status');
-  }
-
-  if ('markup' in checks) {
-    test.is(helpers._actual.markup(), checks.markup, 'markup');
-  }
-
-  if ('hints' in checks) {
-    test.is(helpers._actual.hints(), checks.hints, 'hints');
-  }
-
-  if ('tooltipState' in checks) {
-    test.is(helpers._actual.tooltipState(), checks.tooltipState, 'tooltipState');
-  }
-
-  if ('outputState' in checks) {
-    test.is(helpers._actual.outputState(), checks.outputState, 'outputState');
-  }
-
-  if (checks.args != null) {
-    var requisition = helpers._display.requisition;
-    Object.keys(checks.args).forEach(function(paramName) {
-      var check = checks.args[paramName];
-
-      var assignment;
-      if (paramName === 'command') {
-        assignment = requisition.commandAssignment;
-      }
-      else {
-        assignment = requisition.getAssignment(paramName);
-      }
-
-      if (assignment == null) {
-        test.ok(false, 'Unknown arg: ' + paramName);
-        return;
-      }
-
-      if ('value' in check) {
-        test.is(assignment.value,
-                check.value,
-                'arg.' + paramName + '.value');
-      }
-
-      if ('name' in check) {
-        test.is(assignment.value.name,
-                check.name,
-                'arg.' + paramName + '.name');
-      }
-
-      if ('type' in check) {
-        test.is(assignment.arg.type,
-                check.type,
-                'arg.' + paramName + '.type');
-      }
-
-      if ('arg' in check) {
-        test.is(assignment.arg.toString(),
-                check.arg,
-                'arg.' + paramName + '.arg');
-      }
-
-      if ('status' in check) {
-        test.is(assignment.getStatus().toString(),
-                check.status,
-                'arg.' + paramName + '.status');
-      }
-
-      if ('message' in check) {
-        test.is(assignment.getMessage(),
-                check.message,
-                'arg.' + paramName + '.message');
-      }
-    });
-  }
-};
-
-/**
- * Execute a command:
- *
- * helpers.exec({
- *   // Test inputs
- *   typed: "echo hi",        // Optional, uses existing if undefined
- *
- *   // Thing to check
- *   args: { message: "hi" }, // Check that the args were understood properly
- *   outputMatch: /^hi$/,     // Regex to test against textContent of output
- *   blankOutput: true,       // Special checks when there is no output
- * });
- */
-helpers.exec = function(tests) {
-  var requisition = helpers._display.requisition;
-  var inputter = helpers._display.inputter;
-
-  tests = tests || {};
-
-  if (tests.typed) {
-    inputter.setInput(tests.typed);
-  }
-
-  var typed = inputter.getInputState().typed;
-  var output = requisition.exec({ hidden: true });
-
-  test.is(typed, output.typed, 'output.command for: ' + typed);
-
-  if (tests.completed !== false) {
-    test.ok(output.completed, 'output.completed false for: ' + typed);
-  }
-  else {
-    // It is actually an error if we say something is async and it turns
-    // out not to be? For now we're saying 'no'
-    // test.ok(!output.completed, 'output.completed true for: ' + typed);
-  }
-
-  if (tests.args != null) {
-    test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
-            'arg count for ' + typed);
-
-    Object.keys(output.args).forEach(function(arg) {
-      var expectedArg = tests.args[arg];
-      var actualArg = output.args[arg];
-
-      if (Array.isArray(expectedArg)) {
-        if (!Array.isArray(actualArg)) {
-          test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
-          return;
-        }
-
-        test.is(expectedArg.length, actualArg.length,
-                'array length: ' + typed + '/' + arg);
-        for (var i = 0; i < expectedArg.length; i++) {
-          test.is(expectedArg[i], actualArg[i],
-                  'member: "' + typed + '/' + arg + '/' + i);
-        }
-      }
-      else {
-        test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
-      }
-    });
-  }
-
-  if (!options.window.document.createElement) {
-    test.log('skipping output tests (missing doc.createElement) for ' + typed);
-    return;
-  }
-
-  var div = options.window.document.createElement('div');
-  output.toDom(div);
-  var displayed = div.textContent.trim();
-
-  if (tests.outputMatch) {
-    var doTest = function(match, against) {
-      if (!match.test(against)) {
-        test.ok(false, "html output for " + typed + " against " + match.source);
-        console.log("Actual textContent");
-        console.log(against);
-      }
-    }
-    if (Array.isArray(tests.outputMatch)) {
-      tests.outputMatch.forEach(function(match) {
-        doTest(match, displayed);
-      });
-    }
-    else {
-      doTest(tests.outputMatch, displayed);
-    }
-  }
-
-  if (tests.blankOutput != null) {
-    if (!/^$/.test(displayed)) {
-      test.ok(false, "html for " + typed + " (textContent sent to info)");
-      console.log("Actual textContent");
-      console.log(displayed);
-    }
-  }
-};
rename from browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.html
rename to browser/devtools/commandline/test/resources.html
--- a/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.html
+++ b/browser/devtools/commandline/test/resources.html
@@ -11,17 +11,17 @@
       var div = document.createElement('div');
       div.id = 'divid';
       div.classList.add('divclass');
       div.appendChild(document.createTextNode('div'));
       div.setAttribute('data-a1', 'div');
       pid.parentNode.appendChild(div);
     });
   </script>
-  <script src="resources_inpage.jsi"></script>
+  <script src="resources_inpage.js"></script>
   <link rel="stylesheet" type="text/css" href="resources_inpage1.css"/>
   <link rel="stylesheet" type="text/css" href="resources_inpage2.css"/>
   <style type="text/css">
     p { color: #800; }
     div { color: #008; }
     h4 { color: #080; }
     h3 { color: #880; }
   </style>
rename from browser/devtools/commandline/test/browser_dbg_cmd.html
rename to browser/devtools/commandline/test/resources_dbg.html
rename from browser/devtools/styleeditor/test/resources_inpage.jsi
rename to browser/devtools/commandline/test/resources_inpage.js
--- a/browser/devtools/styleeditor/test/resources_inpage.jsi
+++ b/browser/devtools/commandline/test/resources_inpage.js
@@ -1,10 +1,10 @@
 
-// This script is used from within browser_styleeditor_cmd_edit.html
+// This script is used from within browser_gcli_edit.html
 
 window.addEventListener('load', function() {
   var pid = document.getElementById('pid');
   var h3 = document.createElement('h3');
   h3.id = 'h3id';
   h3.classList.add('h3class');
   h3.appendChild(document.createTextNode('h3'));
   h3.setAttribute('data-a1', 'h3');
rename from browser/devtools/styleeditor/test/resources_inpage1.css
rename to browser/devtools/commandline/test/resources_inpage1.css
rename from browser/devtools/styleeditor/test/resources_inpage2.css
rename to browser/devtools/commandline/test/resources_inpage2.css
rename from browser/devtools/commandline/test/browser_cmd_jsb_script.jsi
rename to browser/devtools/commandline/test/resources_jsb_script.js
deleted file mode 100644
--- a/browser/devtools/highlighter/CmdInspect.jsm
+++ /dev/null
@@ -1,29 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-let EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'inspect' command
- */
-gcli.addCommand({
-  name: "inspect",
-  description: gcli.lookup("inspectDesc"),
-  manual: gcli.lookup("inspectManual"),
-  params: [
-    {
-      name: "node",
-      type: "node",
-      description: gcli.lookup("inspectNodeDesc"),
-      manual: gcli.lookup("inspectNodeManual")
-    }
-  ],