Custom Commands / Context Menus

Under Settings - Commands you can add Custom Commands and customize some Context Menus (and the User Info Dialog) with your own entries.

Check out YouTube for various video tutorials.

Custom Commands

Custom commands allow you to specify aliases for anything you could also enter directly into the inputbox, like chat messages or regular commands (with the exception of other custom commands, which is a limitation implemented to prevent infinite loops).

To add a Custom Command add a new entry to the list labeled "Custom Commands", in the following format:

/<commandName> <what the command should do>

Everything up to the first space is the name of the command, and everything after the first space is what the command will do or execute. For example:

/hello Hello World!

If you added that to the Custom Commands list and enter /hello in the inputbox, then it would send Hello World! to chat, just as if you would have written it yourself and pressed Enter.

Any entry in the "Custom Commands" list starting with a # will be completely ignored. For example:

# Hello World!

See Replacements for more advanced usage.

Restrict to channel

Adding a # and a channel name you can restrict the command to that channel:

/hello#joshimuz Hello Joshimuz Chat!

This /hello command would only be executed in #joshimuz, however if you still have the version without a channel in the Custom Commands list as well, it will fallback to that in other channels. This way to can add variations of commands for specific channels.

Anonymous Custom Commands

Custom Commands that aren't defined in the Custom Commands list do not have a name and can thus only be executed from the context they are defined, for example when adding Inline-Commands to the User Dialog or Context Menus.

You can also execute Anonymous Custom Commands directly from the inputbox, by prepending //, which allows you to use Replacements:

/echo Open Channels: $(chans)
Executes as a normal command (nothing replaced)
Outputs Open Channels: $(chans)
//echo Open Channels: $(chans)
Executes as an Anonymous Custom Command
Outputs Open Channels: joshimuz lotsofs cirno_tv

Chaining Commands

Executing several commands in a row is not a feature of Custom Commands, although the /chain command can be used to achieve something like that.

Foreach

The /foreach command can be used to run the same command for each entry of a space-separated list, for example a list of channels from the $1- replacement.

Run command in specific channel

The /runin command can be used to run a command in a specific open channel.

Replacements

Anything starting with $ in the <what the command should do> section is treated as some sort of replacement. Each replacement must contain an identifier which identifies what the replacement should be replaced with.

For the short notation the identifier is written directly after the dollar sign: $<identifier> . In thise case it may only consist of a number and an optional dash: $<1-9>[-] . Numeric identifiers refer to the parameters supplied to the command.

For the regular notation the identifier is written after the $ in parentheses: $(<identifier>) . This type of notation makes a more clear distinction between replacement and the rest of the (literal) text and may contain numbers (including higher than 9) and other identifiers, depending on the context.

Put $$ (the $ twice) for any required replacement (for example $$1 ), which means the whole Custom Command will only be run if that replacement turns into a non-empty value. This can be used to make sure that a parameter that is necessary for the command to make sense is actually being supplied.

Escaping / Literal Text

If you want to use a dollar sign $ literally, without it beginning a replacement, you can escape it with a backslash: \$. A backslash will always interpret the following character as a regular character without a special meaning, while the backslash itself will not show up in the result.

Example: $replace($1-,(\\w+),(\$1\),regRef)

This function (surrounds all consecutive word characters with brackets) contains some escaping:

Alternatively you can use $"<literal text>" which interprets everything inside the quotes as literal text without any special meaning. To use a quote inside the literal text, it can be doubled: $"This is a dollar sign: ""$""" turns into the plain text This is a dollar sign: "$". Instead of " you can also use ` (backquote) or ' (single quote): $`This is a dollar sign: "$"` is equivalent to the above.

The previous example could also be written like this: $replace($1-,$"(\w+)",$"($1)",regRef)

Simple Replacements

A basic use of replacements is using the short notation to put in parameters supplied when executing the command. Consider this Custom Command:

/slap /me slaps $$1 around a bit with a large trout

Then, when you enter /slap moobot in the inputbox, it will replace $$1 with the first word after the command, which in this case would be moobot, making the resulting command:

/me slaps moobot around a bit with a large trout

This is the syntax for specifying parameters (word in this context means anything separated by a space):

$1, $2, $3
First word, second word, third word etc.
$(1), $(2), $(3) is the equivalent in the regular notation
$1-
First word, and all the words after it
$2-, $3- is also possible
$(1-), $(2-), $(3-) is the equivalent in the regular notation
$$1
First word, but required, meaning the command will only be executed if this parameter is actually present
$$2, $$3- is also possible
$$(1), $$(2), $$(3-) is the equivalent in the regular notation

The short notation ( $1 ) only works for the numbers 1 to 9, which usually should be enough. For other kinds of replacements you must use the regular notation including parentheses: $(10) .

Pre-defined Parameters

Custom Commands can be used in a number of different places. Depending on the context there are different pre-defined parameters available. The following table shows which identifiers can be used in which context. To use an identifier put it in a replacement, for example $(chan) or $$join(1-,/).

Context Identifier Description
All chan The current channel context (without leading #)
stream The stream name of the current channel context (different from chan for Chatrooms)
chans All currently open regular channels (separated by spaces, without leading #)
stream... Stream Info (e.g. uptime, stream title) identifiers
User Context Menu 1 Name of the user
Various Various user-related identifiers
msg Message text of the selected message (depending on the line in chat you opened the User Contex Menu from, not available for your own messages)
msg-time Message time of the selected message (depending on the line in chat you opened the User Contex Menu from, not available for your own messages), as milliseconds since 1970-01-01 00:00:00 UTC, intended to be used with $datetime(), e.g. $datetime(datetime,,,$(msg-time))
msg-id Message id of the selected message (depending on the line in chat you opened the User Contex Menu from, not available for your own messages)
automod-msg-id Message id of the selected message filtered by AutoMod, for approving or denying the message (when opened by clicking on an appropriate message in chat)
User Dialog All from User Context Menu See above
2-, reason Ban reason (if selected)
msg Message text of the selected message (> in front of message, depending on the line in chat you opened it from, not available for your own messages)
msg-time Message time of the selected message (> in front of message, depending on the line in chat you opened it from, not available for your own messages), as milliseconds since 1970-01-01 00:00:00 UTC, intended to be used with $datetime(), e.g. $datetime(datetime,,,$(msg-time))
msg-id Message id of the selected message (> in front of message, depending on the line in chat you opened it from, not available for your own messages)
automod-msg-id Message id of the selected message filtered by AutoMod, for approving or denying the message (when opened by clicking on an appropriate message in chat)
followage / accountage How long ago (e.g. 3.2 years) the user has followed / has created the Twitch account (only if available)
followdate / accountdate The date (e.g. 2012-09-15 17:19:29 +0200) the user has followed / has created the Twitch account (only if available)
Channel Context menu 1 Name of the currently active channel (without leading #)
Streams Context menu 1- Names of selected streams
Hotkey 1 The currently selected user (if present)
Selected Text Context menu 1-, msg The selected text
Admin Context menu title The stream title currently set in the Admin Dialog
game The game (category) currently set in the Admin Dialog
tag-ids The tags currently set in the Admin Dialog (ids, comma-separated)
tag-names The tags currently set in the Admin Dialog (display names, comma-separated)

User-related Identifiers

These are available where a user is involved, such as the User Dialog and User Context Menu. In some contexts they may also be available with the my- prefix for your own user info (e.g. my-full-nick).

Stream Info Identifiers

The stream info is of the current channel context, if available.

Only available if live:

Pre-defined Parameters Example

/streaminfo /echo [Stream Status] $(streamstatus) [Uptime] $(streamuptime)
Entering /streaminfo outputs an info message (only for you) with the current stream status and uptime.

In addition, there is an implicit channel context, which means channel-aware commands like /ban are executed in the appropriate channel.

Functions

Functions are replacements, however they have a function name before the identifier (there is no short notation for functions):

$<functionName>(<identifier>,<some parameters>,[optional parameters])

Note: The <identifier> parameter means anything not starting with $ is interpreted as the identifier only. You can think of it as an extension to the regular replacement: $(1-) -> $join(1-,/)

Functions by topic (ones marked with * are not available in every context):

The following functions are always available:

$if(<identifier>,<output if exists>,[output if not])
If the value the identifier refers to exists (non-empty), it will return the first function parameter, the second otherwise.
Example: $if(1,$1,nope) with command parameters cheese cake turns into cheese, with no parameters turns into nope, the optional [output if not] function parameter.
$ifeq(<identifier>,<comparison>,<output if equal>,[output if not])
Similar to $if, but instead of just checking for the existence of a parameter it compares it to a given value (<comparison>).
Example: $ifeq(1,cheesecake,yummy) with parameters cheesecake turns into yummy, with parameters cheese cake turns into an an empty string, since the optional [output if not] has not been specified.
$switch(<identifier>,<case1>:<result1>,..,[casen]:[resultn],[default])
Similiar to a switch statement in programming, or one or several $ifeq() functions. Compares the value associated with the identifier with the case values and returns the following result if it matches. If none of the case values match, it will return the default, or an empty value.
Example: /set fontSize $switch($get(fontSize),25:50,50:18,25) when added as a Custom Command alternates between font sizes 18, 25 and 50.
$join(<identifier>,<separator>)
Joins together the arguments the identifier refers to, using the given separator.
Example: $join(1-,/) with 1- referring to flour sugar eggs turns into flour/sugar/eggs
This effectively replaces spaces in the parameters with the separator.
$lower(<identifier>)
Makes the given input lowercase.
Example: $lower(1) with 1 referring to Fremily turns into fremily.
$upper(<identifier>)
Makes the given input uppercase.
Example: $upper(1) with 1 referring to Fremily turns into FREMILY.
$trim(<input>)
Removes leading and trailing space (U+0020 and lower, using the String.trim() method).
Example: $trim( abc ) turns into abc.
$quote(<input>,[quote character])
Add quotes around the input. Any quotes in input will be doubled. A custom quote character can be specified, by default a double-quote (") is used.
Example: $quote(51° 28' 38" N) turns into "51° 28' 38"" N" and $quote(51° 28' 38" N,') turns into '51° 28'' 38" N'.
$replace(<input>,<search>,<replace>,[method])
Search and replace in text.
Especially when using Regex, remember escaping \ (\\) and $ (\$) when they should e.g. be used in regex rather than interpreted as special Custom Command characters. Instead of escaping each special character individually, you can also use Literal Text.
Methods are:
Example: $replace(A b and another B,b,bee) turns into A bee and another bee
Example: $replace(Was timed out for 30 seconds,.*?(\\d+) seconds,Number of seconds: \$1,regRef) turns into Number of seconds: 30
Example: $replace($1-,$"~([a-z]+)~",$replace($(g1),$"(\w)",$"$1+",regRef),regCustom) adds + behind every character surrounded by ~ (the inner $replace() is in the replace parameter and executed for each match)
$rand([output1],[output2],[output3],..)
Randomly chooses one of the outputs.
Example: $rand(cheesecake,strawberry cake,$1-) with 1- referring to apple pie turns into either cheesecake, strawberry cake or apple pie.
$randnum(<from>,<to>) or $randnum(<to>)
Randomly chooses a number in the given range (inclusive). If only one number is given, it the range is 0 to the given number. If the "from" is not a number, it defaults to 0, if the "to" is not a number it defaults to a really big number.
Example: $randnum(600,800) chooses a random number between 600 and 800.
Example: $randum($$1) chooses a random number between 0 and what is the first parameter.
$calc(<simple math expression>)
Limited support for performing calculations, with binary operators (* / % + -) and functions (sqrt() sin() cos() tan()).
Example: //echo $calc(2^3) $calc( (3+4\) / 2) when entered into the inputbox returns 8 3.5 (note the parentheses in the second, as well as how the closing parenthesis needs to be escaped).
Example: //echo $calc($"sqrt(81) * (1 + 4/2)") outputs 27 (this uses $" " to specify literal text instead of escaping the parenthesis with a backslash).
$round(<number>,[numDecimalPlaces],[roundingMode],[minNumDecimalPlaces])
Round a number to the given amount of decimal places, with a rounding mode of empty (half-up), ceil, floor, up, down or half-down, with the given number of minimum decimal places (fills with 0).
Example: //echo $round(1.335) outputs 1
Example: //echo $round(1.335,2) outputs 1.34
Example: //echo $round(345.5,3,floor,3) outputs 345.500 (fills up to 3 decimal places)
Example: //echo $round(2.565,2,,2) outputs 2.57 (uses default rounding mode)
$urlencode(<input>)
Uses UrlEncoder.encode() to prepare the input to be used in a URL query parameter.
Example: $urlencode($(msg)) in User Dialog encodes the currently selected message.
$sort(<input>,[type],[separator])
Sorts the given input alphabetically. The sort type can be "abc" (default) for case-insensitive sorting or "Abc" for case-sensitive sorting. The separator is what separates the parts that are sorted, by default a space.
Example: $sort(B c a) turns into a B c
Example: $sort(B c a,Abc) turns into B a c
$input([message],[intial],[type])
Requests text input from the user by showing an input dialog. Execution is paused while the dialog is open. The user may enter an empty value (the result is just empty) or cancel the dialog (the command will not be executed).
The message is shown in the input dialog, the initial text will already be in the input field when the dialog opens. The type can be set to simple to use the previously default simple input dialog.
Example: $input()
Example: $input(Enter a number please)
$datetime([format],[timezone],[locale],[unix time])
Outputs the current date/time. You can optionally give a format pattern (based on DateTimeFormatter), a timezone (based on ZoneId, although something like "New York" should also work) and a locale (a language tag such as "en"). The optional unix time parameter must be in milliseconds.
Predefined formats:
Examples:
$datetime()
Wednesday, March 13, 2019 3:11:48 PM CET
(Default format depends on the locale, in this case using the system default.)
$datetime(,,de)
Mittwoch, 13. März 2019 15:12 Uhr MEZ
(Default format depends on the locale, in this case explicitly specified.)
$datetime(time)
23:31:27
(Using one of the pre-defined formats "time".)
$datetime(datetime2,Vancouver)
2019-03-12 15:31:45 PDT GMT-0700
(Using the more verbose "datetime2" pre-defined format, with a timezone specified.)
$datetime(datetime_full,Rome,it)
mercoledì 13 marzo 2019 15.32.03 CET
(Using one of the locale-specific pre-defined formats, with timezone and locale specified.)
$datetime(,london)
Wednesday, March 13, 2019 2:16:36 PM GMT
(Empty format to be able to specify timezone.)
$datetime(HH:mm:ss zzzz,Tokyo,en)
07:50:20 Japan Standard Time
(Output is usually based on your system language, but you can also explicitely specify it.)
$datetime(eeee\, dd. MMMM yyyy,,de)
Dienstag, 12. März 2019
(Custom format, , escaped since it normally separates function parameters, empty timezone in order to be able to specify locale.)
$datetime(datetime2,Berlin,,1646937275000)
2022-03-10 19:34:35 MEZ GMT+0100
(Preset format, with timezone, no locale, with a time specified in milliseconds since 1970-01-01 00:00:00 UTC.)
$json(<input>,<output>)
Parse the JSON in <input> and use in <output>, where $j(<path>,[default],[sub],...) can be used to access specific values. The JSON input could e.g. come from the $request() function.
If the path isn't formatted correctly or the JSON is invalid the command may not work. Check out the Debug Log (e.g. Extra - Debug window) to find out what went wrong.
The <path> specifies what value to return from the $j(<path>,[default]) function, whereas the optional [default] value will be returned if the path is not valid or points to an empty value.
In the <path> you specify keys of JSON objects separated by -> (e.g. key1->key2->key3) or indices of JSON arrays in brackets [ ] (e.g. key1[0] for the first element of the array key1). Additionally the brackets [ ] can contain:
The optional [sub] values can contain additional $j() replacements, which are applied to the result of the path or previous [sub] parameter. If prefixed with each: it will be applied to each element on an array/object and the result collected into an array (for objects the $(key) replacement and for arrays the $(index) replacement is available).

Examples with the following JSON as input:
    {
        "books":[
            {"title":"book1", "author":"author1", "tags":["tag1","tag2"]},
            {"title":"book2", "author":"author2", "tags":["tag1"]},
            {"title":"book3", "author":"author2", "tags":["tag1", "tag3"]},
            {"title":"book4", "author":"author2"}
        ],
        "authors":{
            "author1":{"name":"name1", "age":24},
            "author2":{"name":"name2", "age":62}
        },
        "numBooks": 4,
        "numAuthors": 2
    }
$json($get(var,j),There are $j(numBooks) books of $j(numAuthors) authors.)
$json($get(var,j),There are $j(books[size]) books of $j(books->[collect:author][unique][size]) authors.)
There are 4 books of 2 authors.
Reading the "num" values provided in the JSON or determining the same information from the "books" array.
$json($get(var,j),The last book is called $j(books[last]->title) by $j(books[last]->author).)
The last book is called book4 by author2.
$json($get(var,j),The first book is $j(books[0]))
The first book is {"author":"author1","title":"book1","tags":["tag1","tag2"]}
If the end of the specified path is a JSONArray or JSONObject it will be returned as a JSON encoded String.
$json($get(var,j),$j(books[10]->title,Book not found))
Book not found
Since the index 10 does not exist, the default value Book not found is returned. If no default value is provided an empty string would be returned.
$json($get(var,j),Books of author2: $j(books[filter:author=author2][collect:title]))
Books of author2: ["book2","book3","book4"]
$json($get(var,j),Tags of author2: $j(books[filter:author=author2][combine:tags][unique]))
Tags of author2: ["tag1","tag3"]
$json($get(var,j),Tags of author2: $j(books[filter:author=author2][combine:tags][unique][join]))
Tags of author2: tag1, tag3
$json($get(var,j),$j(authors[collect:name][sort][join]))
name1, name2
$json($get(var,j),$j(authors,,each:$(key): $j(name) \(age $j(age)\),$j([sort][join])))
author1: name1 (age 24), author2: name2 (age 62)
The [sub] parameters of $j() are used here:
$j(
    // Path to "authors" JSON object
    authors,
    // Skip the optional "[default]" parameter
    ,
    // Apply to each entry of "authors" and collect result in an array
    each:$(key): $j(name) \(age $j(age)\),
    // Sort and join array created from previous parameter
    $j([sort][join])
)
You can test these examples yourself if you store the JSON in the variable "j" using the command /set var j copyJSONfromabove and then use the //echo $json($get(var,j),...) command in the chat inputbox to output an info message with the result in chat. Pasting the JSON directly into the $json() function would require escaping the , characters to work.

The following functions are only available in some contexts:

$is(<match input>)
Outputs true if the match succeeds, nothing otherwise. The match input is in the Highlight format, although what can actually be matched against depends on where the command is ran from, for example the user or message text is only available from the User Dialog or User Context Menu.
Example: $if($is(mystatus:bm),I'm a mod,Not a mod) will output I'm a mod in channels where you are the broadcaster or a moderator, Not a mod otherwise.
$get(<settingName>,[key])
Returns the value of a setting. Different setting types return differently formatted values. There is no comprehensive list of settings, unless you count the Chatty source.
One intended use for this is the special setting var, where you can set a string value using setting commands (/set var foo bar) and then retrieve the value with this function ($get(var,foo) returns bar).
Example: //echo $get(username) returns the name you are logged into Chatty with.
Example: $if($get(ontop),ONTOP) will return ONTOP only if "View - Always on top" is enabled.
$request(<url>,[options])
Performs a GET request on the given http/https URL and returns the body of the reponse interpreted as UTF-8 encoded text. If an error occurs the response will be empty.
Options:
Note: Normally Custom Commands are performed instantaneously, however the replacements for any Custom Command that contains the $request() function will be performed asynchronously so that it can complete the request without freezing the GUI. This means the result of the Custom Command may be run seconds or more later.
Tip: Open "Extra - Debug window" to view debug output of the requests being performed.

Tip: Enter e.g. //echo $datetime() into the chat inputbox to test a function directly, use arrow up/down keys to cycle through previous inputs. Of course you won't be able to use some context dependant parameters this way.

Examples of Custom Commands with these functions:

/slap /me slaps $$1 around a bit with a large $if(2,$2,trout)
Entering /slap Nightbot turns into /me slaps Nightbot around a bit with a large trout
Entering /slap Nightbot cheesecake turns into /me slaps Nightbot around a bit with a large cheesecake
/mt /openUrlPrompt http://multitwitch.tv/$$join(1-,/)
Entering /mt outputs an "insufficient parameters" message because the $$join is required to return something, which it can't from the identifier 1- if there are no parameters
Entering /mt joshimuz lotsofs opens the URL http://multitwitch.tv/joshimuz/lotsofs

Note: A backslash can be used to escape parenthesis in function parameters. Example: $if(streamuptime,$(streamuptime),(n/a\)). In this example only the closing one after n/a has to be escaped, because the opening one doesn't have a special meaning in this context and the ones around streamuptime have a special meaning that takes precedence (opening/closing the replacement).

Custom Replacements

You can create your own identifiers for replacements by adding an entry to the Custom Commands list starting with an underscore:

_m $ifeq(1,$(chan),,$$1: )

Instead of a command, this creates an identifier that can be used in a replacement:

/faq $(_m)FAQ: https://pastebin.com/KySx3KDu

When the /faq command is run, the $(_m) gets replaced with whatever is defined in _m, in this case it creates a mention if the first parameter isn't equal to the current channel.

The data that can be accessed via replacements is the same as in the command it is used in, so in this example the text provided after the /faq is available via the $1- replacement.

Optionally you can also provide a second parameter in a Custom Replacement that overwrites the default value of the $1- replacement:

/faq $(_m,$(custom-nick))FAQ: https://pastebin.com/KySx3KDu

This will make whatever value is contained in $(custom-nick) available in $1- instead of the default.

Note: Custom Replacement identifiers always start with an underscore.

Note: Custom Replacements don't work when placed inside eachother. So for example in _abc Abc: $(_m) the $(_m) will always be empty (whether it's defined in the Custom Commands list or not).

Custom Context Menus / User Dialog Buttons

Under Settings - Commands there are several settings that allow you to add additional entries/buttons in a few different places:

User Context Menu
Entries get appended to the menu that opens when you right-click on a user in chat or the userlist.
Channel Context Menu
Entries get appended to the menu that opens when you right-click on the chat.
Streams Context Menu
Entries get appended to any menu that contains a "Twitch Stream" submenu (for example the User Context Menu, Live Streams Dialog Context Menu).
User Dialog Buttons
Defines which buttons are visible in the dialog that opens when you click on a user in chat (or double-click in the userlist). Note the Special Commands you can use for this setting.

All those settings share the same format (with some slight differences noted separately). A setting can contain several lines, and each line can contain one of the available formats:

/Ban[B] /Unban[U] 5s[1] 2m[2] 10m[3] 30m[4]
Spoiler[S]=/timeout $$1 600 No spoilers

@b1
./Message /Report
.Warn User=$$1: Plz no spammerino

Note: Command Names/Labels may not contain the characters [ ] { } except for their special meaning of Shortcuts and Positioning.

Format 1: List Custom Command Names

You can list the name of several Custom Commands in one line, for example:

/Slap /Permit

Which means the command with the name "slap" will be added first, then "permit" after that. These must be existing commands, either pre-defined Chatty commands or Custom Commands you added yourself.

Note that you may only specify the command names, no parameters. The parameters will be supplied automatically depending on the context. For example when you have /Slap added to the User Dialog and then open the dialog on the user tailsgaming and click the "Slap" button, it's as if you entered /slap tailsgaming.

/Slap /Permit
Command names should be prepended with a forward slash / (although it may also work without).
//Slap
Prepending two forward slashes // will put the command in the special submenu More.. (for Context Menus) or in a second line of buttons (for the User Dialog).
/Set_color is displayed as Set color
Underscores in commands are replaced with a space for display in a Context menu or on a button.

In the same line, you can also specify Timeout Buttons:

5 2m 10m
Times are added just like Custom Commands, except that they must not start with a slash / and must be a number followed by an optional suffix. They are interpreted as seconds by default, unless you add a suffix: s - seconds, m - minutes, h - hours, d - days.
120s 120 is displayed as two buttons with the label 120s and 2m
Both definitions create a button with a 120 seconds timeout, however if you use a suffix, then the definition is used as button label directly, otherwise the label is automatically created based on the time.

Format 2: Inline-Commands

You can define commands directly in the setting, without having to add them as a named Custom Command first. The syntax for this is:

<label with spaces>=<what the command should do>

Note that as opposed to Custom Command names the label may contain spaces, and for that purpose the separating character is an equals sign =. The label may not contain an equals sign itself. Example:

Warn User=$$1: Plz no spammerino

As with Custom Commands, the <what the command should do> part can contain replacements using identifiers for the current context.

Format 3: Submenus

Any line starting with @ defines a custom submenu. Any following lines that start with a dot . will then be put in that menu (both command name lists and inline commands). For example:

@Rules
./No_Spam /No_Spoilers
.Spoiler=/timeout $$1 600 no spoilers

For Context Menus you can add submenus with custom names (only 1 level though), or even add entries to existing submenus by specifying the name (for example @Twitch Stream).

For User Dialog Buttons there are no named submenus, however this notation can be used to put the buttons in separate rows. Any submenu name starting with a will create a row on the top, all other ones on the bottom. The menu name a1 is the default for buttons that don't have a menu defined, and b1 is the default for the //Command notation. Example:

/Ban /Unban
@a1
.Spoiler=/timeout $$1 600 no spoilers
@a2
.5s[1] 2m[2] 10m[3] 30m[4]
@b1
./Slap

In this case the Ban and Unban commands are in the default a1 row, which means they are in the same row as the Spoiler button (these are just different ways of writing it). This also adds a second top row a2 for the timeout buttons as well as a single bottom row for the Slap command.

Separators

In Context menus you can add separators between entries. When you use a commands list, you can add a vertical bar (|) between entries.

You can also add a separator by adding a single dash (-) on it's own line.

Example (separator before Timeout menu, before Message and before Vods):

/Ban /Purge
-
@Timeout
.5s 10m
-
/Message /Report | /Vods

Shortcuts

You can add a shortcut to the end of a label or command name by enclosing it with [ ] (square brackets):

/Ban[B] or Spoiler[S]=/timeout $$1 .. (depending on the line format)

For User Dialog Buttons those can be used while the dialog is open and focused. They are interpreted by getKeyStroke() which means anything that function understands can be used. However spaces are not allowed, so a plus sign + can be used instead. Examples: alt+Q, shift+1, INSERT

Note: The lowercase/uppercase matters for it to be parsed correctly.

Adding a vertical bar | after the shortcut will use the text after it as label for the shortcut on the button (no spaces allowed). If you include the | but don't specify any text, then no label will be displayed for that shortcut:

/Slap[NUMPAD1|Np1] /Permit[NUMPAD2|]

For the User Dialog Buttons you can also include the string nokeylabels anywhere in the setting, which removes any labels for the shortcuts, unless they are explicitly defined.

For Context Menus a single character can be used as a Mnemonic, for quick access to menu entries. For this purpose, submenus may also contain the same syntax: @Rules[R] (which would allow you to open that submenu by pressing R on your keyboard when the context menu is open).

Positioning

You can define an absolute position in the menu the entry should appear at by enclosing it with { } (curly brackets) at the end of the label or command name (but before a shortcut if there is any):

Mention{1}=/insertword $$1: \

This will put the Mention menu entry at the second position in the menu (counting starts from 0).

Another example:

@Twitch Stream[s]
.Videos{2}[v]=/openUrlPrompt https://www.twitch.tv/$$1/videos/past-broadcasts
@Important{0}
.Slap=/me slaps $$1 around a bit with a large trout
@Really Important{0}
.FAQ=FAQ: https://pastebin.com/KySx3KDu

This puts the Videos entry into the pre-defined Twitch Stream submenu at the third position in the submenu (also adding the accelerator key s to the menu and v to the entry).

It also adds the Important submenu at the first position (since it hasn't been added yet) and after that adds the Really Important submenu at the first position as well, moving down Important. This demonstrates that the positioning is based on the current state of the menu, so it can matter when you add entries with absolute positioning.

Dynamic Labels using Custom Commands

Note: This feature must be enabled in the Settings under "Commands" (otherwise replacements in labels have no effect).

You can use Custom Command replacements in the label of inline commands or submenus. The label is updated:

For example if you have a counter command that increases a number, it could show the current number in the menu entry label by reading it from the settings via $get():

Increase counter ($get(var,c))=/set2 var c $calc($get(var,c) + 1)

You can also use this to hide an entry, by adding a required replacement, like $$is(mystatus:M), which will cause the entire label to be empty if you are not a mod in the channel and thus will not be added to the menu. Just adding $$is(mystatus:M) will add true if you are a mod, so you can wrap it in an $if() (in this example it's a submenu called "Mod Menu"):

@$if($$is(mystatus:M),Mod Menu)

Note: Compared to identifiers for regular commands, some information may be missing in the context of labels and restrictions.

Optional Menu Entries (Restrictions)

Note: This feature must be enabled in the Settings under "Commands" (otherwise added restrictions have no effect).

You can add restrictions to individual menu entries or a group of entries. The restriction is applied (entries added or removed):

The restriction must always be on it's own line and start and end with a square bracket, which contain a Custom Command that is surrounded by spaces. If the Custom Command returns a non-empty value the menu entries will show up, otherwise they are hidden.

[ <restriction using custom command> ]
Only affects the following menu entry. A similar effect can be achieved by using Label Commands.
[<name> <restriction using custom command> ]
Opens up a section, like an HTML tag. The <name> is used to identify where the section ends. Different restrictions can be nested inside eachother, causing them all to be applied to the affected menu entries.
[/<name>]
Ends a section that has the given name.

Example:

[mod $is(mystatus:M) ]
@Modes
.Emoteonly[E]=/emoteonly
.Emoteonly Off[O]=/emoteonlyoff
.Subsonly[S]=/subscribers
.Subsonly Off[D]=/subscribersoff
Clear[C]=/clear

[ $ifeq($datetime(M),9,true) ]
/Subtember
[/mod]

[ $is(chan:joshimuz\,botimuz) ]
/JoshFAQ /JoshSub

The "Modes" submenu, the "Clear" command and the "Subtember" command only show when you are a mod in the channel. The $is() function uses Highlight syntax and returns an empty value if it doesn't match. It's that Custom Command part that defines the actual restriction, the "mod" in [mod ... ] is arbitrarily named, it just has to match the closing [/mod].

The "Subtember" command has an additional requirement though, defined directly above it, which uses the functions $ifeq() and $datetime() to only show the menu entry when the month is September.

The "/JoshFAQ" and "/JoshSub" commands only show in the channel #joshimuz or #botimuz. Note that the \, between the channel names requires the backslash to escape the comma, meaning it tells the Custom Command parser that the comma isn't meant as a function parameter separator, but rather to separate the channels in the Highlighting syntax.

Note: Compared to identifiers for regular commands, some information may be missing in the context of labels and restrictions.

Special Commands

In the User Dialog Buttons setting you can use some special commands:

To make use of these you only need to enter the command, you don't need any parameters (Chatty will take care of that). For example simply add /Modunmod or Approve=/Automod_approve to add it to the layout (using the syntax shown on this help page). Chatty will then recognize the command names and the buttons will only show up when they are needed.