WoW:Creating a slash command: Difference between revisions

From AddOn Studio
Jump to navigation Jump to search
m (→‎Simple Example: Unfinished sentence)
m (Move page script moved page Creating a slash command to Creating a slash command without leaving a redirect)
 
(11 intermediate revisions by 10 users not shown)
Line 1: Line 1:
This HOWTO teaches the basics of creating [[slash command|slash commands]] for your [[AddOn]].
{{wow/uihowto}}
'''Slash commands''' allow the player to type commands into the chat window to interact with add-ons. This tutorial describes the necessary steps to add slash commands to your addon.


== Simple Example ==
A fast example:


Suppose you have:
SLASH_TEST1 = "/test1"
SLASH_TEST2 = "/addontest1"
SlashCmdList["TEST"] = function(msg)
    print("Hello World!")
end


function MyScript_Command(cmd)
This assigns a handler function to 'SlashCmdList["TEST"]', and creates 'SLASH_TEST1' and 'SLASH_TEST2' global variables, with the actual slash commands of '/test1' and '/addontest1'. WoW processes the 'SlashCmdList' and uses the key of "TEST" to find the global variable 'SLASH_TEST1', so those names must match and not conflict with another add-on or WoW UI slash key name.
  DEFAULT_CHAT_FRAME:AddMessage("Command: " .. cmd);
 
end
WoW will then use the SlashCmdList 'TEST' key to find consecutive 'SLASH_TESTx' globals by iterating 'SLASH_TEST1', 'SLASH_TEST2', an so on until the next numbered global is not found. So the appended numbers must be consecutive and not have a gap. All of the 'SLASH_TESTx' slash commands will now execute the same handler.  
 
In the '''OnLoad function''' of your script, ''or'' in the .lua '''any place after the function is defined''', put in the following:
When a user types a command starting with "/test1" or "/addontest1", WoW will run the Lua function assigned to SlashCmdList["TEST"], passing the command string without "/test1 " to the function as 'msg'.
 
== Background ==
Slash command handlers are typically invoked by Blizzard's FrameXML code handling the player's chat input; therefore, an addon offering a slash command must register the command by placing certain values in a location where the chat input handling code looks for them.


SLASH_MYSCRIPT1 = "/myscript";
An addon must create a function that would handle the slash command (possibly parsing the argument string passed to it), and place it into the SlashCmdList table. Additionally, an addon must declare which slash commands it wishes to bind to its handler function.
SLASH_MYSCRIPT2 = "/mys"; -- A shortcut or alias
SlashCmdList["MYSCRIPT"] = MyScript_Command;


'''Note''': The slash command(s) must be defined in an OnLoad Function or after the function has been defined. If the slash command is defined when the function it "points to" (which is <tt>MyScript_Command</tt> in the above script) has not been defined yet, the slash command '''will not work'''.
== Strategy ==
# Pick a unique identifier for the slash command: i.e. MYADDON
#: A common convention is ADDONNAME if you only have one slash command, or ADDONNAME_COMMANDNAME if you have multiple (where ADDONNAME is the name of your addon).
# Decide which slash commands you want to respond to: i.e. /myadd.
#: You can select multiple alternatives for the same command -- allowing shorter or longer command names to be used in case of conflicts.
# Assign your selected slash commands to SLASH_MYADDON1, SLASH_MYADDON2, etc global variables.
# Write a slash command handler function (taking (msg, editbox) as arguments), and place assign it to SlashCmdList["MYADDON"].


== Further Examples ==
Here is a simple example that can be placed anywhere in a Lua file:
-- 1. Pick HELLOWORLD as the unique identifier.
-- 2. Pick /hiw and /hellow as slash commands (/hi and /hello are actual emotes)
SLASH_HELLOWORLD1, SLASH_HELLOWORLD2 = '/hiw', '/hellow'; -- 3.
function SlashCmdList.HELLOWORLD(msg, editbox) -- 4.
  print("Hello, World!");
end


'''OnLoad Function:'''
== Parsing Arguments ==
If the user types '/yourcmd someargs' into chat, the function handling '/yourcmd' is passed 'someargs' as the first argument we have been naming 'msg', with the second argument as the chat edit box widget. Your handler function can then choose to act on that argument string. For simple slash commands, comparisons to pre-determined strings may be sufficient. Suppose we wanted to modify the "Hello, World!" example above to display a different string if the command was passed an argument, say "/hiw bye".


  function AddonName_OnLoad()
  local function MyAddonCommands(msg, editbox)
  SlashCmdList["ADDONNAME"] = FunctionToCall;
  if msg == 'bye' then
  SLASH_ADDONNAME1 = "/slash1";
    print('Goodbye, World!')
  SLASH_ADDONNAME2 = "/slash2";
  else
    print("Hello, World!")
  end
  end
  end
   
   
  function AddonName_SlashCmdHandler()
  SLASH_HELLOWORLD1, SLASH_HELLOWORLD2 = '/hiw', '/hellow'
  -- do stuff
end
   
   
And in your XML file:
SlashCmdList["HELLOWORLD"] = MyAddonCommands  -- add /hiw and /hellow to command list


<OnLoad>
Here is a more complex slash command example that is able to process arguments for commands that uses Lua [[Pattern matching]] to parse the arguments string:
  AddonName_OnLoad();
</OnLoad>


The above example will work as long as <tt>AddonName_OnLoad</tt> is called.
local function MyAddonCommands(msg, editbox)
 
  -- pattern matching that skips leading whitespace and whitespace between cmd and args
'''After the function has been defined:'''
  -- any whitespace at end of args is retained
 
  local _, _, cmd, args = string.find(msg, "%s?(%w+)%s?(.*)")
function MySlashCmdFunction()
   
-- Some stuff here
  if cmd == "add" and args ~= "" then
    print("adding " .. args)
    -- Handle adding of the contents of rest... to something.
  elseif cmd == "remove" and args ~= "" then
    print("removing " .. args)
    -- Handle removing of the contents of rest... to something. 
  else
    -- If not handled above, display some sort of help message
    print("Syntax: /hellow (add|remove) someIdentifier");
  end
  end
  end
  SlashCmdList["ADDONNAME"] = MySlashCmdFunction;
   SLASH_ADDONNAME1 = "/slash1";
SLASH_HELLOWORLD1, SLASH_HELLOWORLD2 = '/hiw', '/hellow'
  SLASH_ADDONNAME2 = "/slash2";
SlashCmdList["HELLOWORLD"] = MyAddonCommands   -- add /hiw and /hellow to command list


== The Details ==
== Notes ==
 
* Default UI commands often have precedence over addon-created slash commands. There is no defined precedence order for addon-created commands, so conflicts caused by multiple addons attempting to use the same slash command will resolve non-deterministically.
<pre>SLASH_<CommandId><num>
** If the unique command identifier (the key in SlashCmdList) conflicts between multiple addons, the addon that executes the assignment last will own the slash command.
SlashCmdList["<CommandId>"] = <CodeToExecute></pre>
* Command identifiers are generally all caps, with underscores if necessary. These can also contain lowercase characters.
 
** The actual 'SLASH_&lt;CommandId&gt;&lt;Number&gt;' values should be localizable if you plan on your addon being translated, but the command ID will remain the same.
Slash command parsing is done by the chat frame, and it works as follows.
 
* The key of each entry is the <CommandId>. It should be the unique name of your Addon.
* The parser then examines '''SLASH_''&lt;CommandId&gt;''1''', '''SLASH_''&lt;CommandId&gt;''2''', ... and so on, until it either finds a match, or gets a nil value (undefined) on the next '''SLASH_''&lt;CommandId&gt;''''&lt;Number&gt;'''''.
* If there was a hit, then the function value of '''SlashCmdList["''&lt;CommandId&gt;''"]''' is invoked, with the rest of the command line as its single parameter
 
* Special 'built in' slash commands for chat are handled first.
* The chat handler then iterates over the contents of the global table '''SlashCmdList'''
* Otherwise, the next command is searched until a match is found or the list is exhausted.
 
== Conventions ==
 
* Command ID's are generally all caps, with underscores if necessary. These can also contain lowercase characters.
* Pick a command ID that's going to be unique to your addon, a common convention is ADDONNAME_COMMANDNAME, or if you just have one, then ADDONNAME (Where ADDONNAME is the name of your addon).
* The actual '''SLASH_''&lt;CommandId&gt;''''&lt;Number&gt;''''' values should be localizable if you plan on your addon being translated, but the command ID will remain the same.
* Be prudent about how many aliases you make for your command, and try and pick something that's unlikely to collide with someone else's (including Blizzard's!)
* Be prudent about how many aliases you make for your command, and try and pick something that's unlikely to collide with someone else's (including Blizzard's!)
* There's a second parameter passed to the slash command handler functions that is rarely used. It is the chat frame edit box frame that the slash command originated from.
SLASH_BLAH1 = "/blah"
SlashCmdList["BLAH"] = function(msg, editBox)
    -- change the text on the editBox.
    editBox:Show()
    editBox:SetText("Blah blah blah!")
end
* If you want to set your slash command handler function to a method of an object, you will need to encapsulate the call to it inside a dummy function.


[[Category:AddOns|Create a Slash Command]]
function SomeObject:SlashHandler(message, editbox)
[[Category:HOWTOs|Create a Slash Command]]
  -- do stuff
end
SLASH_BLAH1 = "/blah"
SlashCmdList["BLAH"] = function(message, editbox) SomeObject:SlashHandler(message, editbox) end
[[Category:AddOns]]
[[Category:HOWTOs]]

Latest revision as of 04:47, 15 August 2023

HOWTOs

Slash commands allow the player to type commands into the chat window to interact with add-ons. This tutorial describes the necessary steps to add slash commands to your addon.

A fast example:

SLASH_TEST1 = "/test1"
SLASH_TEST2 = "/addontest1"
SlashCmdList["TEST"] = function(msg)
   print("Hello World!")
end 

This assigns a handler function to 'SlashCmdList["TEST"]', and creates 'SLASH_TEST1' and 'SLASH_TEST2' global variables, with the actual slash commands of '/test1' and '/addontest1'. WoW processes the 'SlashCmdList' and uses the key of "TEST" to find the global variable 'SLASH_TEST1', so those names must match and not conflict with another add-on or WoW UI slash key name.

WoW will then use the SlashCmdList 'TEST' key to find consecutive 'SLASH_TESTx' globals by iterating 'SLASH_TEST1', 'SLASH_TEST2', an so on until the next numbered global is not found. So the appended numbers must be consecutive and not have a gap. All of the 'SLASH_TESTx' slash commands will now execute the same handler.

When a user types a command starting with "/test1" or "/addontest1", WoW will run the Lua function assigned to SlashCmdList["TEST"], passing the command string without "/test1 " to the function as 'msg'.

Background[edit]

Slash command handlers are typically invoked by Blizzard's FrameXML code handling the player's chat input; therefore, an addon offering a slash command must register the command by placing certain values in a location where the chat input handling code looks for them.

An addon must create a function that would handle the slash command (possibly parsing the argument string passed to it), and place it into the SlashCmdList table. Additionally, an addon must declare which slash commands it wishes to bind to its handler function.

Strategy[edit]

  1. Pick a unique identifier for the slash command: i.e. MYADDON
    A common convention is ADDONNAME if you only have one slash command, or ADDONNAME_COMMANDNAME if you have multiple (where ADDONNAME is the name of your addon).
  2. Decide which slash commands you want to respond to: i.e. /myadd.
    You can select multiple alternatives for the same command -- allowing shorter or longer command names to be used in case of conflicts.
  3. Assign your selected slash commands to SLASH_MYADDON1, SLASH_MYADDON2, etc global variables.
  4. Write a slash command handler function (taking (msg, editbox) as arguments), and place assign it to SlashCmdList["MYADDON"].

Here is a simple example that can be placed anywhere in a Lua file:

-- 1. Pick HELLOWORLD as the unique identifier.
-- 2. Pick /hiw and /hellow as slash commands (/hi and /hello are actual emotes)
SLASH_HELLOWORLD1, SLASH_HELLOWORLD2 = '/hiw', '/hellow'; -- 3.
function SlashCmdList.HELLOWORLD(msg, editbox) -- 4.
 print("Hello, World!");
end

Parsing Arguments[edit]

If the user types '/yourcmd someargs' into chat, the function handling '/yourcmd' is passed 'someargs' as the first argument we have been naming 'msg', with the second argument as the chat edit box widget. Your handler function can then choose to act on that argument string. For simple slash commands, comparisons to pre-determined strings may be sufficient. Suppose we wanted to modify the "Hello, World!" example above to display a different string if the command was passed an argument, say "/hiw bye".

local function MyAddonCommands(msg, editbox)
  if msg == 'bye' then
    print('Goodbye, World!')
  else
    print("Hello, World!")
  end
end

SLASH_HELLOWORLD1, SLASH_HELLOWORLD2 = '/hiw', '/hellow'

SlashCmdList["HELLOWORLD"] = MyAddonCommands   -- add /hiw and /hellow to command list

Here is a more complex slash command example that is able to process arguments for commands that uses Lua Pattern matching to parse the arguments string:

local function MyAddonCommands(msg, editbox)
  -- pattern matching that skips leading whitespace and whitespace between cmd and args
  -- any whitespace at end of args is retained
  local _, _, cmd, args = string.find(msg, "%s?(%w+)%s?(.*)")
   
  if cmd == "add" and args ~= "" then
    print("adding " .. args)
    -- Handle adding of the contents of rest... to something.
  elseif cmd == "remove" and args ~= "" then
    print("removing " .. args)
    -- Handle removing of the contents of rest... to something.   
  else
    -- If not handled above, display some sort of help message
    print("Syntax: /hellow (add|remove) someIdentifier");
  end
end

SLASH_HELLOWORLD1, SLASH_HELLOWORLD2 = '/hiw', '/hellow'

SlashCmdList["HELLOWORLD"] = MyAddonCommands   -- add /hiw and /hellow to command list

Notes[edit]

  • Default UI commands often have precedence over addon-created slash commands. There is no defined precedence order for addon-created commands, so conflicts caused by multiple addons attempting to use the same slash command will resolve non-deterministically.
    • If the unique command identifier (the key in SlashCmdList) conflicts between multiple addons, the addon that executes the assignment last will own the slash command.
  • Command identifiers are generally all caps, with underscores if necessary. These can also contain lowercase characters.
    • The actual 'SLASH_<CommandId><Number>' values should be localizable if you plan on your addon being translated, but the command ID will remain the same.
  • Be prudent about how many aliases you make for your command, and try and pick something that's unlikely to collide with someone else's (including Blizzard's!)
  • There's a second parameter passed to the slash command handler functions that is rarely used. It is the chat frame edit box frame that the slash command originated from.
SLASH_BLAH1 = "/blah"
SlashCmdList["BLAH"] = function(msg, editBox)
    -- change the text on the editBox.
    editBox:Show()
    editBox:SetText("Blah blah blah!")
end
  • If you want to set your slash command handler function to a method of an object, you will need to encapsulate the call to it inside a dummy function.
function SomeObject:SlashHandler(message, editbox)
  -- do stuff
end
SLASH_BLAH1 = "/blah"
SlashCmdList["BLAH"] = function(message, editbox) SomeObject:SlashHandler(message, editbox) end