summaryrefslogtreecommitdiffstats
path: root/comm/suite/chatzilla/js/lib/command-manager.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/suite/chatzilla/js/lib/command-manager.js')
-rw-r--r--comm/suite/chatzilla/js/lib/command-manager.js952
1 files changed, 952 insertions, 0 deletions
diff --git a/comm/suite/chatzilla/js/lib/command-manager.js b/comm/suite/chatzilla/js/lib/command-manager.js
new file mode 100644
index 0000000000..76d2818c3c
--- /dev/null
+++ b/comm/suite/chatzilla/js/lib/command-manager.js
@@ -0,0 +1,952 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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/. */
+
+// @internal
+function getAccessKey(str)
+{
+ var i = str.indexOf("&");
+ if (i == -1)
+ return "";
+ return str[i + 1];
+}
+
+// @internal
+function CommandRecord(name, func, usage, help, label, accesskey, flags,
+ keystr, tip, format, helpUsage)
+{
+ this.name = name;
+ this.func = func;
+ this._usage = usage;
+ this.scanUsage();
+ this.help = help;
+ this.label = label ? label : name;
+ this.accesskey = accesskey ? accesskey : "";
+ this.format = format;
+ this.helpUsage = helpUsage;
+ this.labelstr = label.replace ("&", "");
+ this.tip = tip;
+ this.flags = flags;
+ this._enabled = true;
+ this.keyNodes = new Array();
+ this.keystr = keystr;
+ this.uiElements = new Array();
+}
+
+CommandRecord.prototype.__defineGetter__ ("enabled", cr_getenable);
+function cr_getenable ()
+{
+ return this._enabled;
+}
+
+CommandRecord.prototype.__defineSetter__ ("enabled", cr_setenable);
+function cr_setenable (state)
+{
+ for (var i = 0; i < this.uiElements.length; ++i)
+ {
+ if (state)
+ this.uiElements[i].removeAttribute ("disabled");
+ else
+ this.uiElements[i].setAttribute ("disabled", "true");
+ }
+ return (this._enabled = state);
+}
+
+CommandRecord.prototype.__defineSetter__ ("usage", cr_setusage);
+function cr_setusage (usage)
+{
+ this._usage = usage;
+ this.scanUsage();
+}
+
+CommandRecord.prototype.__defineGetter__ ("usage", cr_getusage);
+function cr_getusage()
+{
+ return this._usage;
+}
+
+/**
+ * @internal
+ *
+ * Scans the argument spec, in the format "<a1> <a2> [<o1> <o2>]", into an
+ * array of strings.
+ */
+CommandRecord.prototype.scanUsage =
+function cr_scanusage()
+{
+ var spec = this._usage;
+ var currentName = "";
+ var inName = false;
+ var len = spec.length;
+ var capNext = false;
+
+ this._usage = spec;
+ this.argNames = new Array();
+
+ for (var i = 0; i < len; ++i)
+ {
+ switch (spec[i])
+ {
+ case '[':
+ this.argNames.push (":");
+ break;
+
+ case '<':
+ inName = true;
+ break;
+
+ case '-':
+ capNext = true;
+ break;
+
+ case '>':
+ inName = false;
+ this.argNames.push (currentName);
+ currentName = "";
+ capNext = false;
+ break;
+
+ default:
+ if (inName)
+ currentName += capNext ? spec[i].toUpperCase() : spec[i];
+ capNext = false;
+ break;
+ }
+ }
+}
+
+/**
+ * Manages commands, with accelerator keys, help text and argument processing.
+ *
+ * You should never need to create an instance of this prototype; access the
+ * command manager through |client.commandManager|.
+ *
+ * @param defaultBundle An |nsIStringBundle| object to load command parameters,
+ * labels a help text from.
+ */
+function CommandManager(defaultBundle)
+{
+ this.commands = new Object();
+ this.commandHistory = new Object();
+ this.defaultBundle = defaultBundle;
+ this.currentDispatchDepth = 0;
+ this.maxDispatchDepth = 10;
+ this.dispatchUnwinding = false;
+}
+
+// @undocumented
+CommandManager.prototype.defaultFlags = 0;
+
+/**
+ * Adds multiple commands in a single call.
+ *
+ * @param cmdary |Array| containing commands to define; each item in the |Array|
+ * is also an |Array|, with either 3 or 4 items - corresponding to
+ * the first three or four arguments of |defineCommand|. An extra
+ * property, |stringBundle|, may be set on the |cmdary| |Array|
+ * to override the |defaultBundle| for all the commands.
+ */
+CommandManager.prototype.defineCommands =
+function cmgr_defcmds(cmdary)
+{
+ var len = cmdary.length;
+ var commands = new Object();
+ var bundle = "stringBundle" in cmdary ? cmdary.stringBundle : null;
+
+ for (var i = 0; i < len; ++i)
+ {
+ let name = cmdary[i][0];
+ let func = cmdary[i][1];
+ let flags = cmdary[i][2];
+ let usage = (3 in cmdary[i]) ? cmdary[i][3] : "";
+ commands[name] = this.defineCommand(name, func, flags, usage, bundle);
+ }
+
+ return commands;
+}
+
+/**
+ * Adds a single command.
+ *
+ * @param name The |String| name of the command to define.
+ * @param func A |Function| to call to handle dispatch of the new command.
+ * @param flags Optional. A |Number| indicating any special requirements for the
+ * command.
+ * @param usage Optional. A |String| specifying the arguments to the command. If
+ * not specified, then it is assumed there are none.
+ * @param bundle Optional. An |nsIStringBundle| to fetch parameters, labels,
+ * accelerator keys and help from. If not specified, the
+ * |defaultBundle| is used.
+ */
+CommandManager.prototype.defineCommand =
+function cmdmgr_defcmd(name, func, flags, usage, bundle)
+{
+ if (!bundle)
+ bundle = this.defaultBundle;
+
+ var helpDefault = MSG_NO_HELP;
+ var labelDefault = name;
+ var aliasFor;
+
+ if (typeof flags != "number")
+ flags = this.defaultFlags;
+
+ if (typeof usage != "string")
+ usage = "";
+
+ if (typeof func == "string")
+ {
+ var ary = func.match(/(\S+)/);
+ if (ary)
+ aliasFor = ary[1];
+ else
+ aliasFor = null;
+ helpDefault = getMsg (MSG_DEFAULT_ALIAS_HELP, func);
+ if (aliasFor)
+ labelDefault = getMsgFrom (bundle, "cmd." + aliasFor + ".label",
+ null, name);
+ }
+
+ var label = getMsgFrom(bundle, "cmd." + name + ".label", null,
+ labelDefault);
+ var accesskey = getMsgFrom(bundle, "cmd." + name + ".accesskey", null,
+ getAccessKey(label));
+ var help = helpDefault;
+ var helpUsage = "";
+ // Help is only shown for commands that available from the console.
+ if (flags & CMD_CONSOLE)
+ {
+ help = getMsgFrom(bundle, "cmd." + name + ".help", null, helpDefault);
+ // Only need to lookup localized helpUsage for commands that have them.
+ if (usage)
+ {
+ helpUsage = getMsgFrom(bundle, "cmd." + name + ".helpUsage", null,
+ "");
+ }
+ }
+ var keystr = getMsgFrom (bundle, "cmd." + name + ".key", null, "");
+ var format = getMsgFrom (bundle, "cmd." + name + ".format", null, null);
+ var tip = getMsgFrom (bundle, "cmd." + name + ".tip", null, "");
+ var command = new CommandRecord(name, func, usage, help, label, accesskey,
+ flags, keystr, tip, format, helpUsage);
+ this.addCommand(command);
+ if (aliasFor)
+ command.aliasFor = aliasFor;
+
+ return command;
+}
+
+/**
+ * Installs accelerator keys for commands into an existing document.
+ *
+ * @internal
+ * @param document An |XULDocument| within which to install the accelerator
+ * keys. Each command's key is installed by |installKey|.
+ * @param commands Optional. An |Array| or |Object| continaing |CommandRecord|
+ * objects. If not specified, all commands in the
+ * |CommandManager| are installed.
+ */
+CommandManager.prototype.installKeys =
+function cmgr_instkeys(document, commands)
+{
+ var parentElem = document.getElementById("dynamic-keys");
+ if (!parentElem)
+ {
+ parentElem = document.createElement("keyset");
+ parentElem.setAttribute("id", "dynamic-keys");
+ document.documentElement.appendChild(parentElem);
+ }
+
+ if (!commands)
+ commands = this.commands;
+
+ for (var c in commands)
+ this.installKey (parentElem, commands[c]);
+}
+
+/**
+ * Installs the accelerator key for a single command.
+ *
+ * This creates a <key> XUL element inside |parentElem|. It should usually be
+ * called once per command, per document, so that accelerator keys work in all
+ * application windows.
+ *
+ * @internal
+ * @param parentElem An |XULElement| to add the <key> too.
+ * @param command The |CommandRecord| to install.
+ */
+CommandManager.prototype.installKey =
+function cmgr_instkey(parentElem, command)
+{
+ if (!command.keystr)
+ return;
+
+ var ary = command.keystr.match (/(.*\s)?([\S]+)$/);
+ if (!ASSERT(ary, "couldn't parse key string ``" + command.keystr +
+ "'' for command ``" + command.name + "''"))
+ {
+ return;
+ }
+
+ var key = document.createElement ("key");
+ key.setAttribute ("id", "key:" + command.name);
+ key.setAttribute ("oncommand", "dispatch('" + command.name +
+ "', {isInteractive: true, source: 'keyboard'});");
+
+ if (ary[1])
+ key.setAttribute ("modifiers", ary[1]);
+
+ if (ary[2].indexOf("VK_") == 0)
+ key.setAttribute ("keycode", ary[2]);
+ else
+ key.setAttribute ("key", ary[2]);
+
+ parentElem.appendChild(key);
+ command.keyNodes.push(key);
+}
+
+/**
+ * Uninstalls accelerator keys for commands from a document.
+ *
+ * @internal
+ * @param commands Optional. An |Array| or |Object| continaing |CommandRecord|
+ * objects. If not specified, all commands in the
+ * |CommandManager| are uninstalled.
+ */
+CommandManager.prototype.uninstallKeys =
+function cmgr_uninstkeys(commands)
+{
+ if (!commands)
+ commands = this.commands;
+
+ for (var c in commands)
+ this.uninstallKey (commands[c]);
+}
+
+/**
+ * Uninstalls the accelerator key for a single command.
+ *
+ * @internal
+ * @param command The |CommandRecord| to uninstall.
+ */
+CommandManager.prototype.uninstallKey =
+function cmgr_uninstkey(command)
+{
+ for (var i in command.keyNodes)
+ {
+ try
+ {
+ /* document may no longer exist in a useful state. */
+ command.keyNodes[i].parentNode.removeChild(command.keyNodes[i]);
+ }
+ catch (ex)
+ {
+ dd ("*** caught exception uninstalling key node: " + ex);
+ }
+ }
+}
+
+/**
+ * Use |defineCommand|.
+ *
+ * @internal
+ * @param command The |CommandRecord| to add to the |CommandManager|.
+ */
+CommandManager.prototype.addCommand =
+function cmgr_add(command)
+{
+ if (objectContains(this.commands, command.name))
+ {
+ /* We've already got a command with this name - invoke the history
+ * storage so that we can undo this back to its original state.
+ */
+ if (!objectContains(this.commandHistory, command.name))
+ this.commandHistory[command.name] = new Array();
+ this.commandHistory[command.name].push(this.commands[command.name]);
+ }
+ this.commands[command.name] = command;
+}
+
+/**
+ * Removes multiple commands in a single call.
+ *
+ * @param cmdary An |Array| or |Object| containing |CommandRecord| objects.
+ * Ideally use the value returned from |defineCommands|.
+ */
+CommandManager.prototype.removeCommands =
+function cmgr_removes(cmdary)
+{
+ for (var i in cmdary)
+ {
+ var command = isinstance(cmdary[i], Array) ?
+ {name: cmdary[i][0]} : cmdary[i];
+ this.removeCommand(command);
+ }
+}
+
+/**
+ * Removes a single command.
+ *
+ * @param command The |CommandRecord| to remove from the |CommandManager|.
+ * Ideally use the value returned from |defineCommand|.
+ */
+CommandManager.prototype.removeCommand =
+function cmgr_remove(command)
+{
+ delete this.commands[command.name];
+ if (objectContains(this.commandHistory, command.name))
+ {
+ /* There was a previous command with this name - restore the most
+ * recent from the history, returning the command to its former glory.
+ */
+ this.commands[command.name] = this.commandHistory[command.name].pop();
+ if (this.commandHistory[command.name].length == 0)
+ delete this.commandHistory[command.name];
+ }
+}
+
+/**
+ * Registers a hook for a particular command.
+ *
+ * A command hook is uniquely identified by the pair |id|, |before|; only a
+ * single hook may exist for a given pair of |id| and |before| values. It is
+ * wise to use a unique |id|; plugins should construct an |id| using
+ * |plugin.id|, e.g. |plugin.id + "-my-hook-1"|.
+ *
+ * @param commandName A |String| command name to hook. The command named must
+ * already exist in the |CommandManager|; if it does not, no
+ * hook is added.
+ * @param func A |Function| to handle the hook.
+ * @param id A |String| identifier for the hook.
+ * @param before A |Boolean| indicating whether the hook wishes to be
+ * called before or after the command executes.
+ */
+CommandManager.prototype.addHook =
+function cmgr_hook (commandName, func, id, before)
+{
+ if (!ASSERT(objectContains(this.commands, commandName),
+ "Unknown command '" + commandName + "'"))
+ {
+ return;
+ }
+
+ var command = this.commands[commandName];
+
+ if (before)
+ {
+ if (!("beforeHooks" in command))
+ command.beforeHooks = new Object();
+ command.beforeHooks[id] = func;
+ }
+ else
+ {
+ if (!("afterHooks" in command))
+ command.afterHooks = new Object();
+ command.afterHooks[id] = func;
+ }
+}
+
+/**
+ * Registers multiple hooks for commands.
+ *
+ * @param hooks An |Object| containing |Function| objects to call for each
+ * hook; the key of each item is the name of the command it
+ * wishes to hook. Optionally, the |_before| property can be
+ * added to a |function| to override the default |before| value
+ * of |false|.
+ * @param prefix Optional. A |String| prefix to apply to each hook's command
+ * name to compute an |id| for it.
+ */
+CommandManager.prototype.addHooks =
+function cmgr_hooks (hooks, prefix)
+{
+ if (!prefix)
+ prefix = "";
+
+ for (var h in hooks)
+ {
+ this.addHook(h, hooks[h], prefix + ":" + h,
+ ("_before" in hooks[h]) ? hooks[h]._before : false);
+ }
+}
+
+/**
+ * Unregisters multiple hooks for commands.
+ *
+ * @param hooks An |Object| identical to the one passed to |addHooks|.
+ * @param prefix Optional. A |String| identical to the one passed to |addHooks|.
+ */
+CommandManager.prototype.removeHooks =
+function cmgr_remhooks (hooks, prefix)
+{
+ if (!prefix)
+ prefix = "";
+
+ for (var h in hooks)
+ {
+ this.removeHook(h, prefix + ":" + h,
+ ("before" in hooks[h]) ? hooks[h].before : false);
+ }
+}
+
+/**
+ * Unregisters a hook for a particular command.
+ *
+ * The arguments to |removeHook| are the same as |addHook|, but without the
+ * hook function itself.
+ *
+ * @param commandName The |String| command name to unhook.
+ * @param id The |String| identifier for the hook.
+ * @param before A |Boolean| indicating whether the hook was to be
+ * called before or after the command executed.
+ */
+CommandManager.prototype.removeHook =
+function cmgr_unhook (commandName, id, before)
+{
+ var command = this.commands[commandName];
+
+ if (before)
+ delete command.beforeHooks[id];
+ else
+ delete command.afterHooks[id];
+}
+
+/**
+ * Gets a sorted |Array| of |CommandRecord| objects which match.
+ *
+ * After filtering by |flags| (if specified), if an exact match for
+ * |partialName| is found, only that is returned; otherwise, all commands
+ * starting with |partialName| are returned in alphabetical order by |label|.
+ *
+ * @param partialName Optional. A |String| prefix to search for.
+ * @param flags Optional. Flags to logically AND with commands.
+ */
+CommandManager.prototype.list =
+function cmgr_list(partialName, flags, exact)
+{
+ /* returns array of command objects which look like |partialName|, or
+ * all commands if |partialName| is not specified */
+ function compare (a, b)
+ {
+ a = a.labelstr.toLowerCase();
+ b = b.labelstr.toLowerCase();
+
+ if (a == b)
+ return 0;
+
+ if (a > b)
+ return 1;
+
+ return -1;
+ }
+
+ var ary = new Array();
+ var commandNames = keys(this.commands);
+
+ for (var name of commandNames)
+ {
+ let command = this.commands[name];
+ if ((!flags || (command.flags & flags)) &&
+ (!partialName || command.name.startsWith(partialName)))
+ {
+ if (exact && partialName &&
+ partialName.length == command.name.length)
+ {
+ /* exact match */
+ return [command];
+ }
+ ary.push(command);
+ }
+ }
+
+ ary.sort(compare);
+ return ary;
+}
+
+/**
+ * Gets a sorted |Array| of command names which match.
+ *
+ * |listNames| operates identically to |list|, except that only command names
+ * are returned, not |CommandRecord| objects.
+ */
+CommandManager.prototype.listNames =
+function cmgr_listnames (partialName, flags)
+{
+ var cmds = this.list(partialName, flags, false);
+ var cmdNames = new Array();
+
+ for (var c in cmds)
+ cmdNames.push (cmds[c].name);
+
+ cmdNames.sort();
+ return cmdNames;
+}
+
+/**
+ * Internal use only.
+ *
+ * Called to parse the arguments stored in |e.inputData|, as properties of |e|,
+ * for the CommandRecord stored on |e.command|.
+ *
+ * @params e Event object to be processed.
+ */
+// @undocumented
+CommandManager.prototype.parseArguments =
+function cmgr_parseargs (e)
+{
+ var rv = this.parseArgumentsRaw(e);
+ //dd("parseArguments '" + e.command.usage + "' " +
+ // (rv ? "passed" : "failed") + "\n" + dumpObjectTree(e));
+ delete e.currentArgIndex;
+ return rv;
+}
+
+/**
+ * Internal use only.
+ *
+ * Don't call parseArgumentsRaw directly, use parseArguments instead.
+ *
+ * Parses the arguments stored in the |inputData| property of the event object,
+ * according to the format specified by the |command| property.
+ *
+ * On success this method returns true, and propery names corresponding to the
+ * argument names used in the format spec will be created on the event object.
+ * All optional parameters will be initialized to |null| if not already present
+ * on the event.
+ *
+ * On failure this method returns false and a description of the problem
+ * will be stored in the |parseError| property of the event.
+ *
+ * For example...
+ * Given the argument spec "<int> <word> [ <word2> <word3> ]", and given the
+ * input string "411 foo", stored as |e.command.usage| and |e.inputData|
+ * respectively, this method would add the following propertys to the event
+ * object...
+ * -name---value--notes-
+ * e.int 411 Parsed as an integer
+ * e.word foo Parsed as a string
+ * e.word2 null Optional parameters not specified will be set to null.
+ * e.word3 null If word2 had been provided, word3 would be required too.
+ *
+ * Each parameter is parsed by calling the function with the same name, located
+ * in this.argTypes. The first parameter is parsed by calling the function
+ * this.argTypes["int"], for example. This function is expected to act on
+ * e.unparsedData, taking it's chunk, and leaving the rest of the string.
+ * The default parse functions are...
+ * <word> parses contiguous non-space characters.
+ * <int> parses as an int.
+ * <rest> parses to the end of input data.
+ * <state> parses yes, on, true, 1, 0, false, off, no as a boolean.
+ * <toggle> parses like a <state>, except allows "toggle" as well.
+ * <...> parses according to the parameter type before it, until the end
+ * of the input data. Results are stored in an array named
+ * paramnameList, where paramname is the name of the parameter
+ * before <...>. The value of the parameter before this will be
+ * paramnameList[0].
+ *
+ * If there is no parse function for an argument type, "word" will be used by
+ * default. You can alias argument types with code like...
+ * commandManager.argTypes["my-integer-name"] = commandManager.argTypes["int"];
+ */
+// @undocumented
+CommandManager.prototype.parseArgumentsRaw =
+function parse_parseargsraw (e)
+{
+ var argc = e.command.argNames.length;
+
+ function initOptionals()
+ {
+ for (var i = 0; i < argc; ++i)
+ {
+ if (e.command.argNames[i] != ":" &&
+ e.command.argNames[i] != "..." &&
+ !(e.command.argNames[i] in e))
+ {
+ e[e.command.argNames[i]] = null;
+ }
+
+ if (e.command.argNames[i] == "...")
+ {
+ var paramName = e.command.argNames[i - 1];
+ if (paramName == ":")
+ paramName = e.command.argNames[i - 2];
+ var listName = paramName + "List";
+ if (!(listName in e))
+ e[listName] = [ e[paramName] ];
+ }
+ }
+ }
+
+ if ("inputData" in e && e.inputData)
+ {
+ /* if data has been provided, parse it */
+ e.unparsedData = e.inputData;
+ var parseResult;
+ var currentArg;
+ e.currentArgIndex = 0;
+
+ if (argc)
+ {
+ currentArg = e.command.argNames[e.currentArgIndex];
+
+ while (e.unparsedData)
+ {
+ if (currentArg != ":")
+ {
+ if (!this.parseArgument (e, currentArg))
+ return false;
+ }
+ if (++e.currentArgIndex < argc)
+ currentArg = e.command.argNames[e.currentArgIndex];
+ else
+ break;
+ }
+
+ if (e.currentArgIndex < argc && currentArg != ":")
+ {
+ /* parse loop completed because it ran out of data. We haven't
+ * parsed all of the declared arguments, and we're not stopped
+ * at an optional marker, so we must be missing something
+ * required... */
+ e.parseError = getMsg(MSG_ERR_REQUIRED_PARAM,
+ e.command.argNames[e.currentArgIndex]);
+ return false;
+ }
+ }
+
+ if (e.unparsedData)
+ {
+ /* parse loop completed with unparsed data, which means we've
+ * successfully parsed all arguments declared. Whine about the
+ * extra data... */
+ display (getMsg(MSG_EXTRA_PARAMS, e.unparsedData), MT_WARN);
+ }
+ }
+
+ var rv = this.isCommandSatisfied(e);
+ if (rv)
+ initOptionals();
+ return rv;
+}
+
+/**
+ * Returns true if |e| has the properties required to call the command
+ * |command|.
+ *
+ * If |command| is not provided, |e.command| is used instead.
+ *
+ * @param e Event object to test against the command.
+ * @param command Command to test.
+ */
+// @undocumented
+CommandManager.prototype.isCommandSatisfied =
+function cmgr_isok (e, command)
+{
+ if (typeof command == "undefined")
+ command = e.command;
+ else if (typeof command == "string")
+ command = this.commands[command];
+
+ if (!command.enabled)
+ return false;
+
+ for (var i = 0; i < command.argNames.length; ++i)
+ {
+ if (command.argNames[i] == ":")
+ return true;
+
+ if (!(command.argNames[i] in e))
+ {
+ e.parseError = getMsg(MSG_ERR_REQUIRED_PARAM, command.argNames[i]);
+ //dd("command '" + command.name + "' unsatisfied: " + e.parseError);
+ return false;
+ }
+ }
+
+ //dd ("command '" + command.name + "' satisfied.");
+ return true;
+}
+
+/**
+ * Internal use only.
+ * See parseArguments above and the |argTypes| object below.
+ *
+ * Parses the next argument by calling an appropriate parser function, or the
+ * generic "word" parser if none other is found.
+ *
+ * @param e event object.
+ * @param name property name to use for the parse result.
+ */
+// @undocumented
+CommandManager.prototype.parseArgument =
+function cmgr_parsearg (e, name)
+{
+ var parseResult;
+
+ if (name in this.argTypes)
+ parseResult = this.argTypes[name](e, name, this);
+ else
+ parseResult = this.argTypes["word"](e, name, this);
+
+ if (!parseResult)
+ e.parseError = getMsg(MSG_ERR_INVALID_PARAM,
+ [name, e.unparsedData]);
+
+ return parseResult;
+}
+
+// @undocumented
+CommandManager.prototype.argTypes = new Object();
+
+/**
+ * Convenience function used to map a list of new types to an existing parse
+ * function.
+ */
+// @undocumented
+CommandManager.prototype.argTypes.__aliasTypes__ =
+function at_alias (list, type)
+{
+ for (var i in list)
+ {
+ this[list[i]] = this[type];
+ }
+}
+
+/**
+ * Internal use only.
+ *
+ * Parses an integer, stores result in |e[name]|.
+ */
+// @undocumented
+CommandManager.prototype.argTypes["int"] =
+function parse_int (e, name)
+{
+ var ary = e.unparsedData.match (/(\d+)(?:\s+(.*))?$/);
+ if (!ary)
+ return false;
+ e[name] = Number(ary[1]);
+ e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
+ return true;
+}
+
+/**
+ * Internal use only.
+ *
+ * Parses a word, which is defined as a list of nonspace characters.
+ *
+ * Stores result in |e[name]|.
+ */
+// @undocumented
+CommandManager.prototype.argTypes["word"] =
+function parse_word (e, name)
+{
+ var ary = e.unparsedData.match (/(\S+)(?:\s+(.*))?$/);
+ if (!ary)
+ return false;
+ e[name] = ary[1];
+ e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
+ return true;
+}
+
+/**
+ * Internal use only.
+ *
+ * Parses a "state" which can be "true", "on", "yes", or 1 to indicate |true|,
+ * or "false", "off", "no", or 0 to indicate |false|.
+ *
+ * Stores result in |e[name]|.
+ */
+// @undocumented
+CommandManager.prototype.argTypes["state"] =
+function parse_state (e, name)
+{
+ var ary =
+ e.unparsedData.match (/(true|on|yes|1|false|off|no|0)(?:\s+(.*))?$/i);
+ if (!ary)
+ return false;
+ if (ary[1].search(/true|on|yes|1/i) != -1)
+ e[name] = true;
+ else
+ e[name] = false;
+ e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
+ return true;
+}
+
+/**
+ * Internal use only.
+ *
+ * Parses a "toggle" which can be "true", "on", "yes", or 1 to indicate |true|,
+ * or "false", "off", "no", or 0 to indicate |false|. In addition, the string
+ * "toggle" is accepted, in which case |e[name]| will be the string "toggle".
+ *
+ * Stores result in |e[name]|.
+ */
+// @undocumented
+CommandManager.prototype.argTypes["toggle"] =
+function parse_toggle (e, name)
+{
+ var ary = e.unparsedData.match
+ (/(toggle|true|on|yes|1|false|off|no|0)(?:\s+(.*))?$/i);
+
+ if (!ary)
+ return false;
+ if (ary[1].search(/toggle/i) != -1)
+ e[name] = "toggle";
+ else if (ary[1].search(/true|on|yes|1/i) != -1)
+ e[name] = true;
+ else
+ e[name] = false;
+ e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
+ return true;
+}
+
+/**
+ * Internal use only.
+ *
+ * Returns all unparsed data to the end of the line.
+ *
+ * Stores result in |e[name]|.
+ */
+// @undocumented
+CommandManager.prototype.argTypes["rest"] =
+function parse_rest (e, name)
+{
+ e[name] = e.unparsedData;
+ e.unparsedData = "";
+ return true;
+}
+
+/**
+ * Internal use only.
+ *
+ * Parses the rest of the unparsed data the same way the previous argument was
+ * parsed. Can't be used as the first parameter. if |name| is "..." then the
+ * name of the previous argument, plus the suffix "List" will be used instead.
+ *
+ * Stores result in |e[name]| or |e[lastName + "List"]|.
+ */
+// @undocumented
+CommandManager.prototype.argTypes["..."] =
+function parse_repeat (e, name, cm)
+{
+ ASSERT (e.currentArgIndex > 0, "<...> can't be the first argument.");
+
+ var lastArg = e.command.argNames[e.currentArgIndex - 1];
+ if (lastArg == ":")
+ lastArg = e.command.argNames[e.currentArgIndex - 2];
+
+ var listName = lastArg + "List";
+ e[listName] = [ e[lastArg] ];
+
+ while (e.unparsedData)
+ {
+ if (!cm.parseArgument(e, lastArg))
+ return false;
+ e[listName].push(e[lastArg]);
+ }
+
+ e[lastArg] = e[listName][0];
+ return true;
+}