Creating a Command

In this tutorial we're going to make a /slap command, that will cause the user to appear to slap the user specified. Make sure you've read the Introduction to Scripting in ChatZilla before you continue.

How to Define Commands

The basis for plug-in-based commands is the following line:

   client.commandManager.defineCommands(plugin.cmdlist);

This will add the commands defined in plugin.cmdlist to the available commands. This is how you should add any commands to ChatZilla (for the simplicity and elegance, if nothing else).

The variable plugin.cmdlist is an array of arrays, where the outer array of the list of commands, and each item in the inner arrays defines one part of an individual command.

The inner array items are as follows:

  1. [string] The command name.
  2. [function or string] Either the function to handle the command, or a semicolon (;) separated list of commands to run ("command1 params; command2 params").
  3. [number or null] A combination of various flags, defined below, or null to use the defaults.
  4. [optional string] The usage of the command, which is explained in detail later.

In other words, plugin.cmllist is an array of items of this form:

   [command, handler, flags, usage]

Command Flags

A combination of any of the following may be used (separate them with a pipe (|) character to combine them).

CMD_CONSOLE The command may be run from the 'console' (i.e. the input box in ChatZilla). Commands without this flag may be run from scripts, but wont show up in the list of commands available to the user. Included in default
CMD_NO_HELP The command has no localisable help. Included in default
CMD_NEED_NET Command needs a network, and is guaranteed to have a valid e.network object when called.
CMD_NEED_SRV Command needs a connected server, and will get a valid e.server object when called.
CMD_NEED_CHAN Command needs a channel view, but not nessessarily a joined channel (i.e. the view may still be there, but the user may not actually be a member of it any more). e.channel will be a valid object when called.
CMD_NEED_USER Command needs a user (i.e. in a /query view), and will get a valid e.user object when called.

Usage 101

The usage system for the Command Manager is more sophisticated than one might imagine, so here's a basic run-down on how to use it:

  • Parameters go inside angle brackets (for example, <nickname>).
  • Parameter by default only match a single 'word' of the input.
    • Apart from those parameter names listed below, a parameter will match a single word of the input, and pass the string value to the function using the parameter's name.

      Thus, <nickname> will match one word only, and pass the value to the handler function as the property nickname (see "Coding the Command Handler" below for more details).

      Note: this is not strictly true. There are some other parameter names that are handled differently. For example, currently <reason>, <action>, <text>, <message>, <params>, <expression>, <ircCommand>, <prefValue>, <newTopic> and <commandList> are all synonyms for the <rest> type.

    • A parameter <state> matches "yes", "on", "true", "1", "0", "false", "off", "no", and passes the value as a boolean (using the obvious mapping, e.g. "yes" is passed as true, etc.).
    • A parameter <toggle> matches those of <state>, but also allows the value "toggle".

      If this parameter is a valid <state> value, it's passed as a boolean exactly as with <state>. Otherwise, it will pass the string "toggle" (which is the only other value that matches).

    • A final parameter <rest> matches the remaining input.
    • A final parameter <...> causes the parameter before it to be a list, and any unmatched items are also matched according to the penultimate item.

      The items are returned in an array (where 'param' is the name for the penultimate parameter) called paramList. paramList[0] is the value of the penultimate item (and all subsequent array indices are for the extra items allowed by <...>). For example, the usage <nick> <...> will pass the list of 'nick's as an array called nickList.

  • Sections in square brackets ([]) are optional. The contents of an optional block must either be there in their entirety, or not at all.

    For example, the usage [<p1> <p2> [<p3> <p4>]] will only match when there are 0, 2 or 4 parameters. With 1 or 3 parameters, <p2> or <p4> (respectively) would be required.

OK, so that was more than a quick explanation, the basic points to get from this are that you put your parameters in <> and any optional bits in [].

Our Command's Definition

This should be fairly self-explanatory now - the command "slap" will use the handler cmdSlap, it can be used directly by the user, doesn't have any help, and must be done within a channel. The command has a single required parameter, nick. The item in plugin.cmdlist will therefore be:

   ["slap", cmdSlap, CMD_CONSOLE | CMD_NO_HELP | CMD_NEED_CHAN, "<nick>"]

We will be coding cmdSlap in a minute, first we must write the full command defining code.

   plugin.cmdlist = [
                      ["slap", cmdSlap, CMD_CONSOLE | CMD_NO_HELP | CMD_NEED_CHAN, "<nick>"]
                    ];
   client.commandManager.defineCommands(plugin.cmdlist);

This code needs to go inside the initPlugin routine, as defined in the Introduction to Scripting in ChatZilla tutorial.

Coding the Command Handler

Command handling functions, like many other event handling functions, take a single parameter, which has all the details of the event and data being passed in (this is where parameters and other useful information will come from). Convention dictates that this parameter is called e. We now have the following template for the command handler:

   function cmdSlap(e) {
       // Code here!
   }

There are a number of properties that might be on the object e:

  • e.network
  • e.server
  • e.channel
  • e.user

Which of these are set will depend on the current view when the command is run, for example, from a channel view (as our command will be used from) e.network, e.server and e.channel will be set. The flags passed to the Command Manager define which of these items the command requires, in our case we only required a channel object.

The object e also contains the parameters passed to the command, using the names in the usage definition. Thus our only required parameter will be stored in e.nick.

Note: multi-word parameters should be defined in the usage with a hyphen between words (e.g. <my-param>) but will be stored without the hyphen, and the following letter upper-cased (e.g. e.myParam).

Since the Command Manager will have made sure we're in a channel, and have the e.nick data, the code is really simple:

   dispatch("me slaps " + e.nick + " about a bit with a small fish");

The dispatch call is exactly the same as entering / followed by the text into ChatZilla. All we do, is make the user execute the command /me slaps <nick> about a bit with a small fish where <nick> is the nickname passed to the command.

Thus, the entire cmdSlap code is:

   function cmdSlap(e) {
       dispatch("me slaps " + e.nick + " about a bit with a small fish");
   }

And that's it! Your first command.

If you aren't sure about any of the code, have a look at the final script in the source code directory.

Extension

You may have wondered if there are any requirements for the parameter <nick> - does anything check this?

The answer is no - you can specify anything for the parameter, the Command Manager only checks that it's there, not what it is. For example, you can do /slap himself (or equally /slap herself) to make it look like you're slapping yourself.

Why not check that the parameter is a valid nickname? Firstly, it makes the example shorter and easier to follow, and secondly, it's actually non-trivial to check if a given string is an existing nickname.

Feel free to experiment and try and code this yourself - if you want the command to fail, just return from the function before calling dispatch.

Hint

The best way to check if a user exists is to use the e.channel.getUser function (see the first item here). This function will return the object for the user specified, if they exist - or undefined otherwise.

Powered by the Content Parser System, copyright 2002 - 2010 James G. Ross.