diff --git a/content/docs/reference/templates/functions.md b/content/docs/reference/templates/functions.md index 4c0fd40..a8a2896 100644 --- a/content/docs/reference/templates/functions.md +++ b/content/docs/reference/templates/functions.md @@ -8,490 +8,2212 @@ values you can send in your response or use as arguments for other functions. -> Functions are underappreciated. In general, not just in templates. // Rob Pike +## Channel -{{< callout context="note" title="Note" icon="outline/info-circle" >}} +These functions relate to channels and threads. + +{{< callout context="tip" title="Tip: Current Channel or Thread" icon="outline/rocket" >}} + +Unless specified otherwise, these functions accept an ID, name, or `nil` for their thread or channel argument. + +{{< /callout >}} + +### addThreadMember + +```yag +{{ addThreadMember }} +``` + +Adds a member to an existing thread. Does nothing if either argument is invalid. + +### closeThread + +```yag +{{ closeThread }} +``` + +Closes the given thread. + +- `lock`: whether to also lock the thread. Default `false`. + +### createForumPost + +```yag +{{ $post := createForumPost [values] }} +``` + +Creates a new forum post. Returns a channel object on success. + +- `channel`: the forum channel to post to. +- `name`: The post title. May not be empty. Must be a string. +- `content`: the initial message's content; may be a string, an embed, or a complex message. May not be empty. +- `values` (optional): Additional options for the post. May include: + - `"slowmode"`: The thread's slowmode in seconds. + - `"tags"`: One or more forum tag name or ID. Duplicate and invalid tags are ignored. + + +### createThread + +```yag +{{ $thread := createThread [private] [auto_archive_duration] [invitable] }} +``` + +Creates a new thread in the specified channel. Returns a channel object on success. + +- `channel`: the parent channel to create the thread in. +- `message`: either `nil` to create a channel thread, or a message ID to create a message thread. +- `private`: whether the thread is private. Default `false`. +- `auto_archive_duration`: how long the thread will show in the channel list after inactivity.
+ Valid values are 60, 1440, 4320, and 10080 minutes. Defaults to 10080 (7 days). +- `invitable`: whether non-moderators can add other members to the thread. (true/false) + +Note: There is no functional difference between a channel thread and a message thread. + +Because the optional arguments are positional, you must provide the preceding ones if you wish to override a later +option. Consider the following example to create a public thread in the current channel with no message reference that +is archived after an hour and allows non-moderators to add others: + +```yag +{{ createThread nil nil "new thread" false 60 true }} +``` + +### deleteForumPost + +```yag +{{ deleteForumPost }} +``` + +Deletes the given forum post. + +This function is functionally the same to [deleteThread](#deletethread). +Use whichever function is semantically more meaningful in the context of your custom command. + +### deleteThread + +```yag +{{ deleteThread }} +``` + +Deletes the given thread. + +This function is functionally the same to [deleteForumPost](#deleteforumpost). +Use whichever function is semantically more meaningful in the context of your custom command. + +### editChannelName + +```yag +{{ editChannelName }} +``` + +Edits the name of the given channel. + +- `newName`: the new name for the channel. Must be a string. + +This function is, together with [editChannelTopic](#editchanneltopic), limited to 10 calls per custom command execution. +In addition to this, Discord limits the number of channel modifications to 2 per 10 minutes. + +### editChannelTopic + +```yag +{{ editChannelTopic }} +``` + +Edits the topic of the given channel. + +- `newTopic`: the channel's new topic. Must be a string. Discord markdown is supported. + +This function is, together with [editChannelName](#editchannelname), limited to 10 calls per custom command execution. +In addition to this, Discord limits the number of channel modifications to 2 per 10 minutes. + +### editThread + +```yag +{{ editThread }} +``` + +Edits the specified thread. + +- `opts`: a sdict containing the thread parameters to edit, supporting the following keys (all optional): + - `slowmode`: the thread's slowmode in seconds. + - `tags`: one or more forum tag name or ID. Duplicate and invalid tags are ignored. + - `auto_archive_duration`: how long the thread will show in the channel list after inactivity. + - `invitable`: whether non-moderators can add other members to the thread. Defaults to false. + +### getChannelOrThread + +```yag +{{ $channel := getChannelOrThread }} +``` + +Returns the full channel or thread object for the given channel. + +### getChannelPins + +```yag +{{ $pins := getChannelPins }} +``` + +Returns a slice of message objects pinned to the given channel or thread. + +Rate-limited to 2 (premium: 4) calls per custom command execution. + +### getChannel + +```yag +{{ $channel := getChannel }} +``` + +Returns the full channel object for the given channel. Will not work for threads. + +### getPinCount + +```yag +{{ $numPins := getPinCount }} +``` + +Returns the number of pinned messages in given channel. + +### getThread + +```yag +{{ $thread := getThread }} +``` + +Returns the full thread object for the given thread. Will not work for channels. + +### openThread + +```yag +{{ openThread }} +``` + +Reopens the given thread. + +### pinForumPost + +```yag +{{ pinForumPost }} +``` + +Pins the given forum post, which may be specified by its ID or name. + +### removeThreadMember + +```yag +{{ removeThreadMember }} +``` + +Removes the given member from the given thread. + +### unpinForumPost + +```yag +{{ unpinForumPost }} +``` + +Unpins the given forum post, which may be specified by its ID or name. + +## Database + +These functions help you interact with the [custom command database](/learn/intermediate/database). + +### dbBottomEntries + +```yag +{{ $entries := dbBottomEntries }} +``` + +Returns up to `amount` entries from the database, sorted in ascending order by the numeric value, then by entry ID. + +- `amount`: the maximum number of entries to return, capped at 100. +- `pattern`: the PostgreSQL pattern to match entries against. +- `nSkip`: the number of entries to skip before returning results. + +### dbCount + +```yag +{{ $count := dbCount }} +``` + +Returns the count of all matching database entries that are not expired. + +The argument must be one of the following: +- `userID`: count entries for the given user ID. +- `pattern`: count only entries with keys matching the given pattern. +- `query`: an sdict with the following (all optional) keys: + - `userID`: only count entries with a matching UserID field. Defaults to all UserIDs. + - `pattern`: only counts entries with keys matching the given pattern. Defaults to all keys. + +### dbDelByID + +```yag +{{ dbDelByID }} +``` + +Deletes a database entry under the given `userID` by its `ID`. + +### dbDelMultiple + +```yag +{{ $numDeleted := dbDelMultiple }} +``` + +Deletes up to `amount` entries from the database matching the given criteria. Returns the number of deleted entries. + +- `query`: an sdict with the following (all optional) keys: + - `userID`: only delete entries with a matching UserID field. Defaults to all UserIDs. + - `pattern`: only delete entries with keys matching the given pattern. Defaults to all keys. + - `reverse`: whether to delete entries with the lowest value first. Default is `false` (highest value first). +- `amount`: the maximum number of entries to delete, capped at 100. +- `nSkip`: the number of entries to skip before deleting. + +### dbDel + +```yag +{{ dbDel }} +``` + +Deletes the specified entry from the database. + +### dbGetPatternReverse + +```yag +{{ $entries := dbGetPatternReverse }} +``` + +Retrieves up to `amount` entries from the database in descending order as a slice. + +- `userID`: the user ID to retrieve entries for. +- `pattern`: the PostgreSQL pattern to match entries against. +- `amount`: the maximum number of entries to return, capped at 100. +- `nSkip`: the number of entries to skip before returning results. + +See [dbGetPattern](#dbgetpattern) for a function that retrieves entries in ascending order. + +### dbGetPattern + +```yag +{{ $entries := dbGetPattern }} +``` + +Returns up to `amount` entries from the database in ascending order as a slice. + +- `userID`: the user ID to retrieve entries for. +- `pattern`: the PostgreSQL pattern to match entries against. +- `amount`: the maximum number of entries to return, capped at 100. +- `nSkip`: the number of entries to skip before returning results. + +See [dbGetPatternReverse](#dbgetpatternreverse) for a function that retrieves entries in descending order. + +### dbGet + +```yag +{{ $entry := dbGet }} +``` + +Returns the specified database entry. + +### dbIncr + +```yag +{{ $newValue := dbIncr }} +``` + +Increments the value of the specified database entry by `incrBy`. Returns the new value as a floating-point number. + +- `incrBy`: the amount to increment the value by. Must be a valid number. + +### dbRank + +```yag +{{ $rank := dbRank }} +``` + +Returns the rank of the specified entry in the set of entries as defined by `query`. + +- `query`: an sdict with the following (all optional) keys: + - `userID`: only include entries with the given user ID. + - `pattern`: only include entries with keys matching the given pattern. + - `reverse`: if `true`, entries with lower values have higher ranks. Default is `false`. + +### dbSetExpire + +```yag +{{ dbSetExpire }} +``` + +Same as [dbSet](#dbset) but with an additional expiration `ttl` in seconds. + +### dbSet + +```yag +{{ dbSet }} +``` + +Sets the value for the specified `key` and `userID` to `value`. + +- `value`: an arbitrary value to set. + +### dbTopEntries + +```yag +{{ $entries := dbTopEntries }} +``` + +Returns up to `amount` entries from the database, sorted in descending order by the numeric value, then by entry ID. + +- `pattern`: the PostgreSQL pattern to match entries against. +- `amount`: the maximum number of entries to return, capped at 100. +- `nSkip`: the number of entries to skip before returning results. + +{{< callout context="caution" title="Caution: Storing Numerical Values" icon="outline/alert-triangle" >}} + +Numerical values are stored as floating-point numbers in the database; large numbers such as user IDs will lose +precision. To avoid this, convert them to a string before writing to the database. + +Numerical `dict` keys are retrieved as an `int64`, therefore you'd have to write
+`{{ $dict.Get (toInt64 N)}}` to retrieve the value associated with the numerical key `N`. + +{{< /callout >}} + +## Encoding and Decoding + +### decodeBase64 + +```yag +{{ $decoded := decodeBase64 }} +``` + +Undoes the transformation performed by [`encodeBase64`](#encodebase64), converting the base64-encoded `string` back to +its original form. + + +### encodeBase64 + +```yag +{{ $encoded := encodeBase64 }} +``` + +Encodes the input `string` to base64. + +### hash + +```yag +{{ $hash := hash }} +``` + +Generates the SHA256 hash of the input string. + +### json + +```yag +{{ $json := json [indent] }} +``` + +Encodes `value` as JSON. If the `indent` flag is `true`, the output is pretty-printed with appropriate indentation. + +### jsonToSdict + +```yag +{{ $sdict := jsonToSdict }} +``` + +Parses the JSON-encoded data into a string-dictionary, returning an error if the input was invalid JSON. + +### urlescape + +```yag +{{ $result := urlescape }} +``` + +Escapes the input `string` such that it can be safely placed inside a URL path segment, replacing special characters +(including `/`) with `%XX` sequences as needed. + +### urlunescape + +```yag +{{ $result := urlunescape }} +``` + +Undos the transformation performed by [`urlescape`](#urlescape), converting encoded substrings of the form `%AB` to the +byte `0xAB`. + +### urlquery + +```yag +{{ $result := urlquery }} +``` + +Returns the escaped value of the textual representation of the arguments in a form suitable for embedding in a URL +query. + +## Executing Custom Commands + +These functions enable you to execute a custom command within an already running custom command. + +### cancelScheduledUniqueCC + +```yag +{{ cancelScheduledUniqueCC }} +``` + +Cancels a previously scheduled custom command execution using [scheduleUniqueCC](#scheduleuniquecc). + +### execCC + +```yag +{{ execCC }} +``` + +Executes another custom command specified by `ccID`. + +- `ccID`: the ID of the custom command to execute. +- `channel`: the channel to execute the custom command in. May be `nil`, a channel ID, or a channel name. +- `delay`: the delay in seconds before executing the custom command. +- `data`: some arbitrary data to pass to the executed custom command. + +#### Example + +The following example showcases a custom command executing itself. + +```yag +{{ if .ExecData }} + {{ sendMessage nil (print "Executing custom command... Got data: " .ExecData) }} + {{ return }} +{{ end }} + +{{ sendMessage nil "Starting up..." }} +{{ execCC .CCID nil 5 "Hello, world!" }} +``` + +### scheduleUniqueCC + +```yag +{{ scheduleUniqueCC }} +``` + +Schedules a custom command execution to occur in the future, identified by `key`. + +- `ccID`: the ID of the custom command to execute. +- `channel`: the channel to execute the custom command in. May be `nil`, a channel ID, or a channel name. +- `delay`: the delay in seconds before executing the custom command. +- `key`: a unique key to identify the scheduled custom command. +- `data`: some arbitrary data to pass to the executed custom command. + +To cancel such a scheduled custom command before it runs, use [cancelScheduledUniqueCC](#cancelscheduleduniquecc). + +## Interactions + +{{< callout context="tip" title="Tip" icon="outline/rocket" >}} + +Use of interactions within YAGPDB is an advanced topic; the documentation should be used only as reference. To learn +about using interactions, [see here](/docs/reference/custom-interactions). + +{{< /callout >}} + +### Interaction Responses + +- Only one interaction response may be sent to each interaction. +- If you do not send an interaction response, members will see "This application did not respond" on Discord. +- You may only send an interaction response to the interaction which triggered the command. +- Text output directly to the response is automatically sent as an interaction response if the interaction hasn't + already been responded to. +- A CC executed with `execCC` by the triggered CC will be able to send initial responses to the triggering interaction. +- A response is not the same thing as a followup. + +### sendModal + +```yag +{{ sendModal }} +``` + +Sends a modal to the member who triggered the interaction. + +- `modal`: an sdict with the following keys: + - `title`: the title of the modal. + - `custom_id`: a unique identifier for the modal. + - `fields`: a slice of sdicts with the following keys: + - `label`: the label for the field. + - `placeholder`: the placeholder text for the field. + - `value`: the default value for the field. + - `required`: whether the field is required. + - `style`: the style of the field (1 for short, 2 for long). + - `min_length`: the minimum length of the field. + - `max_length`: the maximum length of the field. + +#### Example + +```yag +{{ $modal := sdict + "title" "My Custom Modal" + "custom_id" "modals-my_first_modal" + "fields" (cslice + (sdict "label" "Name" "placeholder" "Duck" "required" true) + (sdict "label" "Do you like ducks?" "value" "Heck no") + (sdict "label" "Duck hate essay" "min_length" 100 "style")) }} +{{ sendModal $modal }} +``` + +### updateMessage + +```yag +{{ updateMessage }} +``` + +Edits the message on which the button, select menu, or modal was triggered on. + +- `newMessage`: the new message content. May be a string, an embed, or a complex message. + +#### Example + +The following example must be triggered by a component or modal submission. + +```yag +{{ $button := cbutton "label" "I won!" "custom_id" "i_won" }} +{{ $content := printf "Press this button when you win! The last person who won was %s! They wanted to say they are a %s %s." .User.Mention adjective noun }} + +{{ $message := complexMessageEdit "content" $content "buttons" $button }} +{{ updateMessage $message }} +``` + + +### updateMessageNoEscape + +```yag +{{ updateMessageNoEscape }} +``` + +Same as [updateMessage](#updatemessage), plus it does not escape mentions. + +### Interaction Followups + +- Interaction followups may be sent up to 15 minutes after an interaction. +- To send a followup, you must have the interaction token of the interaction you are following up. +- You can send as many followups as you'd like. +- Text output directly to the response is automatically sent as an interaction followup if the interaction has + already been responded to. +- A followup is not the same thing as a response. + +### editResponse + +```yag +{{ editResponse }} +``` + +Edits a response to an interaction. + +- `interactionToken`: the token of the interaction to edit. `nil` for the triggering interaction. +- `messageID`: the ID of a follow-up message. `nil` for the original interaction response. +- `newContent`: the new content for the message. + +#### Example + +The following example must be triggered by a component trigger or modal submission. + +```yag +{{ $token := .Interaction.Token }} + +{{ sendResponse nil "Here's the first message!" }} +{{ $id := sendResponseRetID $token (complexMessage "content" "Here's a sneaky one!" "ephemeral" true) }} + +{{ sleep 2 }} + +{{ editResponse $token $id (print "I've edited this message to say " noun) }} +{{ $editedResponse := getResponse $token $id }} +{{ editResponse $token nil $editedResponse.Content }} +``` + +### editResponseNoEscape + +```yag +{{ editResponseNoEscape }} +``` + +Same as [editResponse](#editresponse), plus it does not escape mentions. + +### Interaction Response/Followup Hybrids + +Hybrid functions will send an interaction response if the interaction has not already been responded to, otherwise +they will send the equivalent followup function. See [editResponse](#editresponse) for an example using +`sendResponse*` functions. + +### sendResponse + +```yag +{{ sendResponse }} +``` + +Sends a message in response to an interaction. Supports the `ephemeral` flag in `complexMessage`. + +### sendResponseNoEscape + +```yag +{{ sendResponseNoEscape }} +``` + +Same as [sendResponse](#sendresponse), plus it does not escape mentions. + +### sendResponseNoEscapeRetID + +```yag +{{ sendResponseNoEscapeRetID }} +``` + +Same as [sendResponseNoEscape](#sendresponsenoescape), but also returns the message ID. + +### sendResponseRetID + +```yag +{{ sendResponseRetID }} +``` + +Same as [sendResponse](#sendresponse), but also returns the message ID. + +### Interaction Miscellaneous + +### cbutton + +```yag +{{ $button := cbutton "list of button values" }} +``` + +Creates a [button object](https://discord.com/developers/docs/interactions/message-components#button-object) for use in +interactions. + +A link style button *must* have a URL and may not have a Custom ID. All other styles *must* have a Custom ID and cannot +have a URL. All buttons must have either a label or an emoji. + +#### Example + +```yag +{{ $button := cbutton "label" "Button" "custom_id" "buttons-duck" }} +{{ $message := complexMessage "buttons" $button }} +{{ sendMessage nil $message }} +``` + +### cmenu + +```yag +{{ $menu := cmenu "list of select menu values" }} +``` + +Creates a [select menu object](https://discord.com/developers/docs/interactions/message-components#select-menu-object) +for use in interactions. + +The type should be provided as a string: `"text"`, `"user"`, `"role"`, `"mentionable"`, or `"channel"`. Text type menus +*must* have `options`, while all other types cannot. + +#### Example + +```yag +{{ $menu := cmenu + "type" "text" + "placeholder" "Choose a terrible thing" + "custom_id" "menus-duck" + "options" (cslice + (sdict "label" "Two Ducks" "value" "opt-1" "default" true) + (sdict "label" "A Duck" "value" "duck-option" "emoji" (sdict "name" "🦆")) + (sdict "label" "Half a Duck" "value" "third-option" "description" "Don't let the smaller amount fool you.")) + "max_values" 3 }} + +{{ sendMessage nil (complexMessage "menus" $menu) }} +``` + +### ephemeralResponse + +```yag +{{ ephemeralResponse }} +``` + +Tells the bot to send the response text as an ephemeral message. Only works when triggered by an interaction. Works on +responses and follow-ups. + +#### Example + +```yag +{{ ephemeralResponse }} + +This text is invisible to others! +``` + +### getResponse + +```yag +{{ $response := getResponse }} +``` + +Returns the response or follow-up with the specified message ID belonging to the given interaction as a [message +object](/docs/reference/templates/syntax-and-data#message). Is also valid for ephemeral messages. + +## Math + +### add + +```yag +{{ $sum := add x y [...] }} +``` + +Returns the sum of the provided numbers. Detects the first number's type and performs the operation accordingly. + +### bitwiseAnd + +```yag +{{ $result := bitwiseAnd x y }} +``` + +Performs a bitwise AND operation on the two provided numbers and returns the result. + +### bitwiseAndNot + +```yag +{{ $result := bitwiseAndNot x y }} +``` + +Performs a bitwise AND NOT operation on the two provided numbers and returns the result. + +### bitwiseNot + +```yag +{{ $result := bitwiseNot x }} +``` + +Performs a bitwise NOT operation on the provided number and returns the result. + +### bitwiseOr + +```yag +{{ $result := bitwiseOr x y [...] }} +``` + +Performs a bitwise OR operation on the provided numbers and returns the result. + +### bitwiseXor + +```yag +{{ $result := bitwiseXor x y }} +``` + +Performs a bitwise XOR operation on the two provided numbers and returns the result. + +### bitwiseLeftShift + +```yag +{{ $result := bitwiseLeftShift x y }} +``` + +Shifts X left by Y bits and returns the result. + +### bitwiseRightShift + +```yag +{{ $result := bitwiseRightShift x y }} +``` + +Shifts X right by Y bits and returns the result. + +### cbrt + +```yag +{{ $result := cbrt x }} +``` + +Returns the cube root of the provided number. + +### div + +```yag +{{ $result := div x y [...] }} +``` + +Performs division on the provided numbers. Detects the first number's type and performs the operation accordingly. +If you need a floating-point number as a result of integer division, use [fdiv](#fdiv). + +### fdiv + +```yag +{{ $result := fdiv x y [...] }} +``` + +Special case of [div](#div); always returns a floating-point number as result. + +### log + +```yag +{{ $result := log x [base] }} +``` + +Returns the logarithm of X with the given base. If no base is provided, the natural logarithm is used. + +### mathConst + +```yag +{{ $result := mathConst "constant" }} +``` + +Returns the value of the specified math constant. See the [math constants list](https://pkg.go.dev/math#pkg-constants). + +### max + +```yag +{{ $result := max x y }} +``` + +Returns the larger of the two provided numbers. + +### min + +```yag +{{ $result := min x y }} +``` + +Returns the smaller of the two provided numbers. + +### mod + +```yag +{{ $result := mod x y }} +``` + +Returns the floating-point remainder of the division of X by Y. + +Takes the sign of X, so `mod -5 3` results in `-2`, not `1`. To ensure a non-negative result, use `mod` twice: +`{{ mod (add (mod x y) y) y }}`. + +### mult + +```yag +{{ $result := mult x y [...] }} +``` + +Performs multiplication on the provided numbers. Detects the first number's type and returns the result accordingly. + +### pow + +```yag +{{ $result := pow x y }} +``` + +Returns X raised to the power of Y as a floating-point number. + +### randInt + +```yag +{{ $result := randInt [start] stop }} +``` + +Returns a random integer in the right-closed interval of `[0, stop)` or `[start, stop)` if two arguments are provided. +That is, the result is always greater than or equal to `start` and strictly less than `stop`. + +### round + +```yag +{{ $result := round x }} +``` + +Returns the nearest integer to X as float. Normal rounding rules apply. + +### roundCeil + +```yag +{{ $result := roundCeil x }} +``` + +Returns the smallest integer greater than or equal to X. Put simply, always round up. + +### roundEven + +```yag +{{ $result := roundEven x }} +``` + +Returns the nearest integer to X, rounding ties (x.5) to the nearest even integer. + +### roundFloor + +```yag +{{ $result := roundFloor x }} +``` + +Returns the largest integer less than or equal to X. Put simply, always round down. + +### sqrt + +```yag +{{ $result := sqrt x }} +``` + +Returns the square root of X as a floating-point number. + +### sub + +```yag +{{ $result := sub x y [...] }} +``` + +Subtracts the provided numbers from each other. Detects the first number's type and returns the result accordingly. + +## Member + +### editNickname + +```yag +{{ editNickname "newNick" }} +``` + +Edits the nickname of the member who triggered the command. The bot must have the `MANAGE_NICKNAMES` permission and be +higher in the role hierarchy than the member. The bot cannot change the nickname of the server owner. + +### getMember + +```yag +{{ $member := getMember }} +``` + +Returns the [member object](/docs/reference/templates/syntax-and-data#member) for the given mention or user ID. + +### getMemberVoiceState + +```yag +{{$state := getMemberVoiceState }} +``` + +Returns the voice state for the member specified by ID or mention, or `nil` if the member is not in a voice channel. + +### getTargetPermissionsIn + +```yag +{{ $perms := getTargetPermissionsIn }} +``` + +Returns the permissions of the specified member in the given channel as a [permissions bitfield][perms]. + +[perms]: https://discord.com/developers/docs/topics/permissions#permissions + +#### Example + +To calculate the permission in a channel other than the current channel, for which we could just use the +[hasPermissions](#haspermissions) or [targetHasPermissions](#targethaspermissions) function, we will have to use bitwise +operations: + +```yag +{{ $perms := getTargetPermissionsIn .User.ID $someChannel }} +{{ $mask := bitwiseAnd .Permissions.ManageRoles $perms }} +{{ if eq $mask .Permissions.ManageRoles }} + You have the permissions to manage roles! +{{ else }} + You do not have the permissions to manage roles! +{{ end }} +``` + +### hasPermissions + +```yag +{{ $hasPerms := hasPermissions }} +``` + +Returns whether the member who triggered the command has the specified permission bit. +See [`.Permissions`](/docs/reference/templates/syntax-and-data/#context-data) for more information. + +#### Example + +```yag +{{ if hasPermissions .Permissions.Administrator }} + You have the Administrator permission! +{{ else }} + You do not have the Administrator permission. +{{ end }} +``` + +### onlineCount + +```yag +{{ $count := onlineCount }} +``` + +Returns the count of online members on the current server, including bots. + +### targetHasPermissions + +```yag +{{ $hasPerms := targetHasPermissions }} +``` + +Returns whether the specified member has the specified permission bit. + +## Mentions + +Certain mentions are escaped by default, such that they don't ping. These functions help you actually *pinging* these +special mentions. + +### mentionEveryone + +```yag +{{ mentionEveryone }} +``` + +Mentions `@everyone` without escaping it. + +### mentionHere + +```yag +{{ mentionHere }} +``` + +Mentions `@here` without escaping it. + +### mentionRole + +```yag +{{ mentionRole }} +``` + +Mentions `role`, which may be specified by ID, mention, name, or role object, without escaping it. + +### mentionRoleID + +```yag +{{ mentionRoleID }} +``` + +Mentions the given role without escaping it. + +### mentionRoleName + +```yag +{{ mentionRoleName }} +``` + +Mentions the role with the given name without escaping it. Searches for first case-insensitive match. + +Prefer [mentionRoleID](#mentionroleid), as IDs are guaranteed to be unique and do not change with role edits. + +## Message + +### addMessageReactions + +```yag +{{ addMessageReactions }} +``` + +Adds reactions to a message with the given ID. + +- `emojis...`: a list of emojis to add as reactions. May also be a slice of emojis. + +Default emojis are best used in the Unicode format for these purposes. Custom emojis follow a specific format in these +functions. Please see the example below. + +#### Example + +```yag +{{ addMessageReactions nil .Message.ID "👍" "👎" "yagpdb:505114640032858114" }} +``` + +### addReactions + +```yag +{{ addReactions }} +``` + +Adds reactions to the message that triggered the command. + +- `emojis...`: a list of emojis to add as reactions. May also be a slice of emojis. + +### addResponseReactions + +```yag +{{ addResponseReactions }} +``` + +Adds reactions to the response message. + +- `emojis...`: a list of emojis to add as reactions. May also be a slice of emojis. + +Note that a message sent via [sendMessage](#sendmessage) is not the response---use +[addMessageReactions](#addmessagereactions) for that. + +### complexMessageEdit + +```yag +{{ $message := complexMessageEdit [allowed_mentions] [content] [embed] [silent] }} +``` + +Creates a complex message object for use in [editMessage](#editmessage) or [editMessageNoEscape](#editmessagenoescape). + +- `allowed_mentions`: an sdict with the following keys: + - `parse`: a slice of accepted values for mentions. May include `users`, `roles`, and `everyone`. + - `users`: a slice of user IDs to mention. + - `roles`: a slice of role IDs to mention. + - `replied_user`: whether to mention the replied user. +- `content`: the new content for the message. +- `embed`: an embed object or a slice of up to 10 embed objects. +- `silent`: whether to suppress push and desktop notifications. + +All of these keys are optional, but providing none of them will have no effect. See [complexMessage](#complexmessage) +for an example. + +### complexMessage + +```yag +{{ $message := complexMessage [allowed_mentions] [content] [embed] [file] [filename] [reply] [silent] }} +``` + +Creates a complex message object for use in [sendMessage](#sendmessage) functions. + +- `allowed_mentions`: an sdict with the following keys: + - `parse`: a slice of accepted values for mentions. May include `users`, `roles`, and `everyone`. + - `users`: a slice of user IDs to mention. + - `roles`: a slice of role IDs to mention. + - `replied_user`: whether to mention the replied user. +- `content`: the message content. +- `embed`: an embed object or a slice of up to 10 embed objects. +- `file`: the content to print as a file. +- `filename`: the name of the file. +- `reply`: the ID of the message to reply to. +- `silent`: whether to suppress push and desktop notifications. + +All of these keys are optional, but providing an empty content, file, or no embeds will result in no message being sent. + +#### Example + +The following example will output a message with an embed, some content, and a file attachment. It will also reply to +the triggering message and ping the author of that message, but suppress the resulting notification. + +```yag +{{ $message := complexMessage + "allowed_mentions" (sdict + "replied_user" true + ) + "content" "Hello, world!" + "embed" (cembed + "title" "Embed Title" + "description" "Embed Description" + "color" 0xff0000 + ) + "file" "This is a file." + "filename" "example.txt" + "reply" .Message.ID + "silent" true +}} +{{ sendMessage nil $message }} +``` + +### deleteAllMessageReactions + +```yag +{{ deleteAllMessageReactions [emojis...] }} +``` + +Deletes all reactions from a message, optionally constrained to specific emojis. + +- `emojis`: the emojis to delete. May also be a slice. Not providing this argument will delete any and all reactions. + +### deleteMessageReaction + +```yag +{{ deleteMessageReaction }} +``` + +Deletes a specific user's reaction from a message. + +- `userID`: the ID of the user whose reaction to delete. +- `emojis...`: the emojis to delete. May also be a slice. + +### deleteMessage + +```yag +{{ deleteMessage [delay] }} +``` + +Deletes the specified message. + +- `delay`: an optional delay in seconds to delete the message after. Defaults to 10 seconds. Max 86400 seconds (1 day). + +### deleteResponse + +```yag +{{ deleteResponse [delay] }} +``` + +Deletes the response message. + +- `delay`: an optional delay in seconds to delete after. Defaults to 10 seconds. Max 86400 seconds (1 day). + +### deleteTrigger + +```yag +{{ deleteTrigger [delay] }} +``` + +Deletes the triggering message. + +- `delay`: an optional delay in seconds to delete after. Defaults to 10 seconds. Max 86400 seconds (1 day). + +### editMessageNoEscape + +```yag +{{ editMessageNoEscape }} +``` + +Edits the given message without escaping mentions. + +- `newMessageContent`: the new content for the message. May also be the result from + [complexMessageEdit](#complexmessageedit). + +### editMessage + +```yag +{{ editMessage }} +``` + +Edits the given message with escaping mentions. + +- `newMessageContent`: the new content for the message. May also be the result from + [complexMessageEdit](#complexmessageedit). + +### getMessage + +```yag +{{ $message := getMessage }} +``` + +Returns the [message object](/docs/reference/templates/syntax-and-data#message) for the given message ID in the +specified channel. + +### pinMessage + +```yag +{{ pinMessage }} +``` + +Pins the specified message. + +### publishMessage + +```yag +{{ publishMessage }} +``` + +Publishes the specified message. + +### publishResponse + +```yag +{{ publishResponse }} +``` + +Publishes the response message. + +For this to work, the custom command must be running in such an announcement channel. + +### sendDM + +```yag +{{ sendDM }} +``` + +Sends a direct message to the triggering user. + +- `message`: the message to send. May also be the result from a [complexMessage](#complexmessage) call. + +### sendMessageNoEscapeRetID + +```yag +{{ $messageID := sendMessageNoEscapeRetID }} +``` + +Same as [sendMessageNoEscape](#sendmessagenoescape), but also returns the message ID. + +### sendMessageNoEscape + +```yag +{{ sendMessageNoEscape }} +``` + +Same as [sendMessage](#sendmessage), but does not escape mentions. + +### sendMessageRetID + +```yag +{{ $messageID := sendMessageRetID }} +``` + +Same as [sendMessage](#sendmessage), but also returns the message ID. + +### sendMessage + +```yag +{{ sendMessage }} +``` + +Sends a message in the specified channel. + +- `message`: the message to send. May also be the result from a [complexMessage](#complexmessage) call. + +### unpinMessage + +```yag +{{ unpinMessage }} +``` + +Unpins the specified message. + +## Miscellaneous + +### adjective + +```yag +{{ $adj := adjective }} +``` + +Returns a random adjective. + +### cembed + +```yag +{{ $embed := cembed [title] [url] [description] [color] [fields] [author] [thumbnail] [image] [footer] }} +``` + +Returns an embed object to send with [sendMessage](#sendmessage)-related functions. + +All keys are optional, but the Discord API will reject completey empty embeds, so *some* content is required. + +- `title`: the title of the embed +- `url`: the URL to hyperlink the title with +- `description`: the main text +- `color`: which color to display on the left side of the embed +- `fields`: a slice of sdicts with the following keys: + - `name`: the name of the field + - `value`: which text to have inside this field + - `inline`: an optional boolean whether this field should be displayed in-line with other fields +- `author`: Shows some details at the very top of the embed. Is an sdict with the following keys: + - `name`: The name of the author + - `url`: the URL to hyperlink the name with + - `icon_url`: the author's icon +- `thumbnail`: a small image in the top-right corner. Is an sdict with the following keys: + - `url`: the image's URL +- `image`: an image to display at full width at the bottom of the embed. Is an sdict with the following keys: + - `url`: the image's URL +- `footer`: Shows some details at the very bottom of the embed. Is an sdict with the following keys: + - `text`: the footer's text + - `icon_url`: a small icon to display to the left of the footer's text + - `timestamp`: a (static) timestamp to display to the right of the footer's text + +{{< callout context="tip" title="Tip" icon="outline/rocket" >}} + +To help you get used to the embed structure in custom commands, check out , a +community-made embed visualizer for YAGPDB's custom command system. + +{{< /callout >}} + +### createTicket + +```yag +{{ $ticket := createTicket }} +``` + +Creates a new ticket associated to the specified author with given topic. + +- `author`: the member to associate this ticket with. +- `topic`: the topic of this ticket. Must be a string. + +{{< callout context="caution" title="Warning" icon="outline/alert-triangle" >}} + + +For this function to work correctly, the ticketing system must be enabled. + +{{< /callout >}} + +### cslice + +```yag +{{ $slice := cslice }} +``` + +Creates a slice of the provided values. + +### dict + +```yag +{{ $dict := dict [values...] }} +``` + +Creates a dictionary from the provided key-value pairs. The number of parameters must be even. + +### execAdmin + +```yag +{{ execAdmin "command" [args...] }} +``` + +Runs the given command with the provided (optional) arguments as the bot. + +### execTemplate + +```yag +{{ execTemplate "template" [data...] }} +``` + +Executes the associated `"template"` template, optionally with data. Please see +[Associated Templates](/docs/reference/templates/syntax-and-data#associated-templates). + +### exec + +```yag +{{ exec "command" [args...] }} +``` + +Executes the given command with the provided (optional) arguments as the triggering user. + +This will not work for commands with paginated embed results, e.g. `warnings`. + +### getWarnings + +```yag +{{ $warnings := getWarnings }} +``` + +Returns a slice of warnings imposed on the specified user. + +- `user`: the user to get the warnings for. Can be either a user ID or a user object. + +### humanizeThousands + +```yag +{{ $formatted := humanizeThousands }} +``` + +Places commas to separate groups of thousands in a number. + +- `number`: the number to format. Must be an int or a string. Must be a whole number. + +### inFold + +```yag +{{ $result := inFold }} +``` + +Same as [in](#in), but is case-insensitive. + +### in + +```yag +{{ $result := in }} +``` + +Returns whether the case-sensitive `value` is in the provided list. + +### index + +```yag +{{ $item := index }} +``` + +Returns the item at the specified index in `list`. + +`list` is zero-indexed, so the first item is at index 0. `list` can be a slice, map, or string. + +If you are indexing a map (that is, `dict` or `sdict`), `index` must be matching the key (as maps are unordered). +Indexing a string type returns the character at that position as a rune. + +You may optionally add additional indices in case you have nested structures, like `index $x 0 1`. This is equivalent to +chaining `index` calls, e.g. `index (index $x 0) 1`. + +### kindOf + +``` +{{ $kind := kindOf [indirect] }} +``` + +Returns the [kind](https://pkg.go.dev/reflect#Kind) of the provided value. + +If `value` is behind an `interface{}` or pointer, set `indirect` to true to read the inner value. Most users of this +function will want to do this. + +### len + +```yag +{{ $length := len }} +``` + +Returns the length of the provided list. `list` can be a slice, map, or string. + +### noun + +```yag +{{ $noun := noun }} +``` + +Returns a random noun. + +### parseArgs + +```yag +{{ $args := parseArgs [...cargs] }} +``` + +Parses arguments passed to the custom command. Ensures that at least `requiredArgs` are passed and checks that these +arguments match as specified by `carg...`, emits `errorMessage` otherwise. + +Passing an empty string as `errorMessage` will generate one for you based on the provided argument definitions. + +The result has the `.Get N` and `.IsSet N` methods available, returning the value or reporting whether the argument is +present, respectively, at position `N` (starting from 0). + +- `...cargs`: a list of argument definitions. Must have at least `requiredArgs` elements. Has the following arguments: + - `"type"`: the type of this argument as a quoted string. + - `"name"`: the name of this argument. Must be a string. + +An argument's `"type"` must be one of the following: + +- `int` (whole number) +- `float` (decimal number) +- `string` (text) +- `user` (user mentions, resolves to the [user](https://docs.yagpdb.xyz/reference/templates#user) structure) +- `userid` (mentions or user IDs, resolves to the ID itself) +- `member` (mentions or user IDs, resolves to the [member](https://docs.yagpdb.xyz/reference/templates#member) + structure) +- `channel` (channel mention or ID, resolves to the channel structure) +- `role` (role name or ID, resolves as type \*discordgo.Role) +- `duration` (duration that is human-readable, i.e `10h5m` or `10 hour 5 minutes` would both resolve to the same + duration) + +Additionally, the `int`, `float`, and `duration` type support validation ranges in the interval `(min, max)`, where for +`duration` it is in seconds. + +#### Example + +```yag +{{ $args := parseArgs 1 "" (carg "int" "coolness level" 0 100) (carg "member" "target member") }} +Coolness: {{ $args.Get 0 }} +{{- if $args.IsSet 1 }} +Target: {{ ($args.Get 1).User }} +{{- else }} +Target: {{ .User }} +{{ end }} +``` + +Please see our [in-depth guide] in the learning resources for a full breakdown of this function and how to make good use +of it. + +[in-depth guide]: /learn/beginner/inputs-1 + +### sendTemplateDM + +```yag +{{ $messageID := sendTemplateDM "template" [data] }} +``` + +Same as [sendTemplate](#sendtemplate), but sends it to the triggering user's direct messages instead and returns the +*response* message's ID. + +### sendTemplate + +```yag +{{ $messageID := sendTemplate "template" [data] }} +``` + +Sends an [Associated Template](/docs/reference/templates/syntax-and-data#associated-templates) to `channel`, with +optional `data`, returning the *response* message's ID. + +### seq + +```yag +{{ $sequence := seq }} +``` + +Creates a new slice with integer-type elements, starting from `start` and ending at `stop-1`. `start` and `stop` must be +whole numbers. Limited to 10,000 elements. + +### shuffle + +```yag +{{ $shuffled := shuffle }} +``` + +Returns a shuffled (randomized) version of the provided list. + +### sleep + +```yag +{{ sleep }} +``` + +Pauses the execution of the custom command for the specified number of seconds. The maximum duration is 60 seconds, +combined across all `sleep` calls within the custom command and its associated templates. + +### slice + +```yag +{{ $result := slice [end] }} +``` + +Returns a subslice of the input `item` (which may be an array, slice, or string) containing the elements starting at +index `start` (inclusive), and ending at index `end`, exclusive. If only `start` is provided, it is interpreted as the +start index and the subslice extends to the end of `item`. + +### sort + +```yag +{{ $sorted := [options] }} +``` + +Returns the given list in a sorted order. The list's items must all be of the same type. The optional `options` argument +is an sdict with the following (optional) keys: +- `key`: if sorting a list of maps, the key's value to sort by. This key must be present on all maps in the slice. +- `reverse`: whether to sort in reverse (descending) order. Default: `false`. + +Limited to 1 call on regular servers and 3 calls on premium servers. + +### verb + +```yag +{{ $verb := verb }} +``` + +Returns a random verb. + +## Role functions + +### addRole + +```yag +{{ $role := addRole [delay] }} +``` + +Adds the specified role to the triggering member. + +- `role`: a role ID, mention, name, or role object. +- `delay`: an optional delay in seconds. + +### addRoleID + +```yag +{{ addRoleID [delay] }} +``` + +Adds the specified role ID to the triggering member. + +- `delay`: an optional delay in seconds. + +### addRoleName + +```yag +{{ addRoleName [delay] }} +``` + +Adds the first case-insensitive matching role name to the triggering member. + +- `delay`: an optional delay in seconds. + + +### getRole + +```yag +{{ $role := getRole }} +``` + +Returns a [role object](https://discord.com/developers/docs/topics/permissions#role-object). +`role` may either be an ID or a name to match against (ignoring case). + +### getRoleID + +```yag +{{ $role := getRoleID }} +``` + +Returns a [role object](https://discord.com/developers/docs/topics/permissions#role-object) by its ID. + +### getRoleName + +```yag +{{ $role := getRoleName }} +``` + +Returns a [role object](https://discord.com/developers/docs/topics/permissions#role-object) by its name +(case-insensitive). + +### giveRole + +```yag +{{ giveRole [delay] }} +``` + +Gives the specified role to the target member. + +- `role`: a role ID, mention, name, or role object. +- `delay`: an optional delay in seconds. + +### giveRoleID + +```yag +{{ giveRoleID [delay] ]}} +``` + +Gives the role specified by its ID to the target member. + +- `member`: the member to target. Either an ID, mention, or user object, but must be part of the server. +- `delay`: an optional delay in seconds. + +### giveRoleName + +```yag +{{ giveRoleName [delay] }} +``` + +Gives the first case-insensitive matching role name to the target member. + +- `delay`: an optional delay in seconds. + +### hasRole + +```yag +{{ $result := hasRole }} +``` + +Reports whether the triggering member has the specified role. + +- `role`: a role ID, mention, name, or role object. + +### hasRoleID + +```yag +{{ $result := hasRoleID }} +``` + +Reports whether the triggering member has the specified role ID. + +### hasRoleName + +```yag +{{ $result := hasRoleName }} +``` + +Reports whether the triggering member has the specified role name (case-insensitive). + +### removeRole + +```yag +{{ removeRole [delay] }} +``` + +Removes the specified role from the triggering member. + +- `role`: a role ID, mention, name, or role object. +- `delay`: an optional delay in seconds. -Every function having both cases possible for an argument - ID/name, then this name is handled case insensitive, for -example `getRole "yagpdb"` and `getRole "yAgPdB"` would have same responses even if server has both of these roles, so -using IDs is better. +### removeRoleID + +```yag +{{ removeRoleID [delay] }} +``` + +Removes the role with the specified ID from the triggering member with an optional delay in seconds. + +### removeRoleName + +```yag +{{ removeRoleName [delay] }} +``` + +Removes the first case-insensitive matching role name from the triggering member with an optional delay in seconds. + +### roleAbove + +```yag +{{ $result := roleAbove }} +``` + +Reports whether `role1` is above `role2` in the role hierarchy. Both arguments must be a +[role object](https://discord.com/developers/docs/topics/permissions#role-object). + +### setRoles + +```yag +{{ setRoles }} +``` + +Sets the roles of the specified user to the provided list of role IDs. The roles are overwritten, so any existing roles +are removed if not included in the new list. `newRoles` must be a slice. `target` may be a user ID, mention, or user +object, but must be a member of the server. + +### takeRole + +```yag +{{ takeRole [delay] }} +``` + +Removes the specified role from the target member. + +- `target`: a user ID, mention, or user object. The target must be part of the server. +- `role`: a role ID, mention, name or role object. +- `delay`: an optional delay in seconds. + +### takeRoleID + +```yag +{{ takeRoleID [delay] }} +``` + +Removes the specified role from `target`. `target` may be a user ID, mention, or user object, but must be a member of +the server. + +- `delay`: an optional delay in seconds. -{{< /callout >}} -### Channel +### takeRoleName + +```yag +{{ takeRoleName [delay] }} +``` + +Removes the first case-insensitive matching role name from `target` with an optional delay in seconds. +`target` may be a user ID, mention, or user object, but must be a member of the server. + +### targetHasRole + +```yag +{{ $result := targetHasRole }} +``` + +Reports whether the target member has the specified role. + +- `role`: a role ID, mention, name or role object. + +### targetHasRoleID + +```yag +{{ $result := targetHasRoleID }} +``` + +Reports whether the specified target has the specified role ID. +`target` may be a user ID, mention, or user object, but must be a member of the server. + +### targetHasRoleName + +```yag +{{ $result := targetHasRoleName }} +``` + +Reports whether the specified target has the specified role name (case-insensitive). +`target` may be a user ID, mention, or user object, but must be a member of the server. + +## String manipulation {{< callout context="note" title="Note" icon="outline/info-circle" >}} -The ratelimit for editing a channel is 2 requests per 10 minutes per channel. +All regexp functions are limited to 10 different pattern calls per CC. {{< /callout >}} -| **Function** | **Description** | -| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `addThreadMember` thread member | Adds a member to an existing thread. Does nothing if either thread or member arguments are invalid. Argument `thread` can be either ID, "name" or even `nil` for current thread, and `member` can either be ID or @ mention. | -| `createForumPost` channel name content (values) | Creates a new forum post in forum `channel`. Argument `name` represents the title of the post, `content` can be a string, an embed or a complex message. The optional `"values"` argument consists of key-value pairs:`"slowmode" value` allows the user to specify the thread's slowmode in seconds. `"tags" value` allows the user to specify one or more forum tags. Duplicate and invalid tags are ignored, and its `value` can be either a string or cslice for multiple tags. Returns \*templates.CtxChannel upon success.

Example: `{{createForumPost <forumChannelID> "Post Title" "content as a string" "slowmode" 60}}`. | -| `createThread` channel messageID name (values) | Creates a new thread in `channel`. `messageID` can point to a valid message (creates a message thread) or nil. `name` is the title of the thread. Optional `values` determine how thread is created and come in following order - `private` of type _bool_ determines whether the thread is private; `auto_archive_duration` must be an integer between 60 and 10080 and it determines when the thread will stop showing in the channel list after given minutes of inactivity, can be set to: 60, 1440, 4320, 10080 ; `invitable` of type _bool_, whether non-moderators can add other non-moderators to a thread, it is only available on private threads. Returns \*templates.CtxChannel upon success.
Example: `{{createThread nil nil "YAGPDB is cool" true 60 true}}` will create a thread named "YAGPDB is cool" under current channel without any message reference, thread is private, it will get archived in an hour and non-moderators can add others to thread. | -| `deleteForumPost` post | Deletes existing post in the forum - `post` can be either its ID, post’s name or even `nil` if done inside that post. If supplied argument is not a valid active post then it is ignored. Is an alias of `deleteThread` function. | -| `deleteThread` thread | Deletes existing thread - `thread` can be either its ID, thread’s name or even `nil` if done inside that thread. If supplied argument is not a valid active thread then it is ignored. | -| `editChannelName`
channel "newName" | Function edits channel's name. `channel` can be either ID, "name" or even `nil` if triggered in that channel name change is intended to happen. `"newName"` has to be of type _string_. For example >`{{editChannelName nil (print "YAG - " (randInt 1000))}}` | -| `editChannelTopic` channel "newTopic" | Function edits channel's topic/description. `channel` can be either ID, "name" or `nil` if triggered in that channel where name change is intended to happen. `"newTopic"` has to be of type _string_. For example >`{{editChannelTopic nil "YAG is cool"}}` | -| `getChannel` channel | Function returns full channel object of given `channel` argument which can be either its ID, name or `nil` for triggering channel, and is of type _\*templates.CtxChannel_. For example > `{{(getChannel nil).Name}}` returns the name of the channel command was triggered in. | -| `getChannelOrThread` channel | Returns type _\*templates.CtxChannel_ corresponding to [Channel](/docs/reference/templates/syntax-and-data#channel) object. | -| `getChannelPins` channel | Returns a slice of all pinned message objects in targeted channel. | -| `getPinCount` channel | Returns the count of pinned messages in given channel which can be either its ID, name or `nil` for triggering channel. Can be called 2 times for regular and 4 for premium servers. | -| `getThread` channel | Returns type _\*templates.CtxChannel_ corresponding to [Channel](/docs/reference/templates/syntax-and-data#channel) object. | -| `removeThreadMember` thread member | Removes a member from an existing thread. Does nothing if either thread or user are invalid. Argument `thread` can be either ID, "name" or even `nil` for current thread, and `member` can either be ID or @ mention. | - -### Database - -| **Function** | **Description** | -| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `dbBottomEntries` pattern amount nSkip | Returns `amount (max 100)`top entries of keys determined by the `pattern` from the database, sorted by the numeric value in a ascending order, next by entry ID. | -| `dbCount` (userID\|pattern\|query) | Returns the count of all database entries which are not expired. Optional arguments: if `userID` is given, counts entries for that userID; if `pattern`, only those keys are counted that match the given pattern; and if `query` is provided, it should be an sdict with the following keys:
  • `userID` - only counts entries with that userID, defaults to counting entries with any userID.
  • `pattern` - only counts dbEntry keys with names matching the pattern given, defaults to counting entries with any name.
| -| `dbDel` userID key | Deletes the specified key for the specified value from the database. | -| `dbDelByID` userID ID | Deletes database entry by its ID. | -| `dbDelMultiple` query amount skip | Deletes `amount (max 100)` entries from the database matching the criteria provided. `query` should be an _sdict_ with the following options:
  • `userID` - only deletes entries with the dbEntry field .UserID provided, defaults to deleting entries with any ID.
  • `pattern` - only deletes entry keys with a name matching the pattern given.
  • `reverse` - if true, starts deleting entries with the lowest values first; otherwise starts deleting entries with the highest values first. Default is `false`.
Returns the number of rows that got deleted or an error. | -| `dbGet` userID key | Retrieves a value from the database for the specified user, this returns DBEntry object. Does not fetch member data as user object for .User like `dbGetPattern`, `dbBottom/TopEntries` do. | -| `dbGetPattern` userID pattern amount nSkip | Retrieves up to`amount (max 100)`entries from the database in ascending order. | -| `dbGetPatternReverse` userID pattern amount nSkip | Retrieves`amount (max 100)`entries from the database in descending order. | -| `dbIncr` userID key incrBy | Increments the value for specified key for the specified user, if there was no value then it will be set to `incrBy`. Also returns the entry's current, increased value. | -| `dbRank` query userID key | Returns the rank of the entry specified by the user ID and key provided in the set of entries matching the criteria provided. `query` specifies the set of entries that should be considered, and should be a sdict with the following options:
  • `userID` - only includes entries with that user ID, defaults to including entries with any user ID
  • `pattern` - only includes database's `key` entries with names matching the pattern given, defaults to counting entries with any name
  • `reverse` - if true, entries with lower value have higher rank; otherwise entries with higher value have higher rank. Default is `false`.
| -| `dbSet` userID key value | Sets the value for the specified `key` for the specific `userID` to the specified `value`. `userID` can be any number of type _int64_.

Values are stored either as of type _float64_ (for numbers, oct or hex) or as varying type in bytes (for _slices_, _maps_, _strings_ etc) depending on input argument. | -| `dbSetExpire` userID key value ttl | Same as `dbSet` but with an expiration `ttl` which is an _int_ and represents seconds. | -| `dbTopEntries` pattern amount nSkip | Returns `amount (max 100)`top entries of keys determined by the `pattern` from the database, sorted by the numeric value in a descending order, next by entry ID. | - -Patterns are basic PostgreSQL patterns, not Regexp: An underscore `(_)` matches any single character; a percent sign -`(%)` matches any sequence of zero or more characters. +### hasPrefix -{{< callout context="note" title="Note" icon="outline/info-circle" >}} +```yag +{{ $result := hasPrefix }} +``` -**Note about saving numbers into database:** As stated above, database stores numbers as type _float64_. If you save a -large number into database like an _int64_ (which IDs are), the value will be truncated. To avoid this behavior, you can -convert the number to type _string_ before saving and later back to its original type when retrieving it. Example: `{{$v -:= .User.ID}} {{dbSet 0 "userid" (str $v)}} {{$fromDB := toInt (dbGet 0 "user_id").Value}}` +Reports whether the given `string` begins with `prefix`. -`dict` key values are also retrieved as _int64,_ so to use them for indexing one has to e.g. `index $x (toInt64 0)` +### hasSuffix -{{< /callout >}} +```yag +{{ $result := hasSuffix }} +``` -### ExecCC +Reports whether the given `string` ends with `suffix`. -{{< callout context="danger" title="Danger" icon="outline/alert-octagon" >}} +### joinStr -`execCC` calls are limited to 1 / CC for non-premium users and 10 / CC for premium users. +```yag +{{ $result := joinStr }} +``` -{{< /callout >}} +Concatenates `args...` in order, inserting the given `separator` between consecutive arguments and returns the result. +As a special case, slices of strings are formatted as if each element was provided separately, so + +```yag +{{ joinStr " " (cslice "cat" "dog") }} +``` -| **Function** | **Description** | -| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `cancelScheduledUniqueCC` ccID key | Cancels a previously scheduled custom command execution using `scheduleUniqueCC`. | -| `execCC` ccID channel delay data | Function that executes another custom command specified by `ccID`. With delay 0 the max recursion depth is 2 (using `.StackDepth` shows the current depth). `execCC` is rate-limited strictly at max 10 delayed custom commands executed per channel per minute, if you go over that it will be simply thrown away. Argument `channel` can be `nil`, channel's ID or name. The`delay` argument is execution delay of another CC is in seconds. The `data` argument is content that you pass to the other executed custom command. To retrieve that `data` you use `.ExecData`. This example is important > [execCC example](/docs/reference/custom-command-examples#countdown-example-exec-cc) also next snippet which shows you same thing run using the same custom command > [Snippets](#execcc-sections-snippets). `execCC` is also thoroughly covered in this [GitHub gist](https://gist.github.com/l-zeuch/9f10d128184509ad531778f26550ed6d). | -| `scheduleUniqueCC` ccID channel delay key data | Same as `execCC`except there can only be 1 scheduled cc execution per server per key (unique name for the scheduler), if key already exists then it is overwritten with the new data and delay (as above, in seconds).An example would be a mute command that schedules the unmute action sometime in the future. However, let's say you use the unmute command again on the same user, you would want to override the last scheduled unmute to the new one. This can be used for that. | +yields `cat dog`. -#### ExecCC section's snippets +See also [printf](#printf) if you just want to concatenate arguments without a separator. -- To demonstrate execCC and .ExecData using the same CC. +### lower ```yag -{{ $yag := "YAGPDB rules! " }} -{{ $ctr := 0 }} {{ $yourCCID := .CCID }} -{{ if .ExecData }} - {{ $ctr = add .ExecData.number 1 }} - {{ $yag = print $yag $ctr }} {{ .ExecData.YAGPDB }} -{{ else }} - So, someone rules. - {{ $ctr = add $ctr 1 }} {{ $yag = print $yag 1 }} -{{ end }} -{{ if lt $ctr 5 }} - {{ execCC $yourCCID nil 3 (sdict "YAGPDB" $yag "number" $ctr) }} -{{ else }} FUN'S OVER! {{ end }} +{{ $result := lower }} ``` -### Interactions +Converts `string` to all lowercase and returns the result. -{{< callout context="tip" title="Tip" icon="outline/rocket" >}} +### print -Use of interactions within YAGPDB is an advanced topic; the documentation should be used only as reference. To learn -about using interactions, [see here](/docs/reference/custom-interactions). +```yag +{{ $result := print }} +``` -{{< /callout >}} +Concatenates the arguments in order, adding spaces between arguments when neither is a string. -#### Interaction Responses +### println -- Only one interaction response may be sent to each interaction. -- If you do not send an interaction response, members will see "This application did not respond" on Discord. -- You may only send an interaction response to the interaction which triggered the command. -- Text output directly to the response is automatically sent as an interaction response if the interaction hasn't - already been responded to. -- A CC executed with `execCC` by the triggered CC will be able to send initial responses to the triggering interaction. -- A response is not the same thing as a followup. +```yag +{{ $result := println }} +``` -| **Function** | **Description** | -| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sendModal` modal | Responds to an interaction by showing the member a modal. `modal` must be an `sdict` with the following keys: `title`, `custom_id`, and `fields`. The `fields` argument should be a slice of sdicts with the following keys: `label`, `placeholder`, `value` (default value if they don't enter anything), `required`, `style` (1 for short, 2 for long), `min_length`, and `max_length`, however only the `label` argument is required for each field. You cannot send a modal in response to a user submitting another modal. Example in section's [Snippets](#interactions-sections-snippets). | -| `updateMessage` newMessage | Edits the message on which the button, select menu, or modal was triggered on. | -| `updateMessageNoEscape` newMessage | Edits the message triggered on and has same logic in escaping characters as `sendMessageNoEscape`. | +Concatenates the arguments in order, adding spaces between arguments when neither is a string and inserting a newline at +the end. -#### Interaction Followups +### printf -- Interaction followups may be sent up to 15 minutes after an interaction. -- To send a followup, you must have the interaction token of the interaction you are following up. -- You can send as many followups as you'd like. -- Text output directly to the response is automatically sent as an interaction followup if the interaction has - already been responded to. -- A followup is not the same thing as a response. +```yag +{{ $result := }} +``` -| **Function** | **Description** | -| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `editResponse` interactionToken messageID newMessageContent | Edits one of the bot's responses to an interaction. `interactionToken` must be a valid token or `nil` to target the triggering interaction. `messageID` must be a valid message ID of a followup message, or `nil` to target the original interaction response. Example in section's [Snippets](#interactions-sections-snippets). | -| `editResponseNoEscape` interactionToken messageID newMessageContent | Edits the response and has same logic in escaping characters as `sendMessageNoEscape`. | +Interpolates `args...` according to `format`. See the [Go `fmt` package documentation](https://pkg.go.dev/fmt). -#### Interaction Response/Followup Hybrids +### reFind -- Hybrid functions will send an interaction response if the interaction has not already been responded to, otherwise they will send the equivalent followup function. +```yag +{{ $result := reFind }} +``` -| **Function** | **Description** | -| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sendResponse` interactionToken message | Sends a message (string, embed, or complexMessage) in response to an interaction. Supports the `ephemeral` flag in `complexMessage`. `interactionToken` must be a valid token or `nil` to target the triggering interaction. Example in section's [Snippets](#interactions-sections-snippets). | -| `sendResponseNoEscape` interactionToken message | Sends a message as a response, and doesn't escape mentions (e.g. role mentions, reply mentions or @here/@everyone). | -| `sendResponseNoEscapeRetID` interactionToken message | Same as `sendResponseNoEscape`, but also returns messageID to assigned variable for later use. | -| `sendResponseRetID` interactionToken message | Same as `sendResponse`, but also returns messageID to assigned variable for later use. Example in section's [Snippets](#interactions-sections-snippets). | +Returns the first match of the regular expression `regex` in `text`, or the empty string if the pattern did not match +anywhere. -#### Interaction Miscellaneous +### reFindAll -| **Function** | **Description** | -| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `cbutton` "list of button values" | Functions similarly to `cembed`. [Available values](https://discord.com/developers/docs/interactions/message-components#button-object) A Link style button must have a URL and cannot have a Custom ID. All other styles must have a Custom ID and cannot have a URL. All buttons must have either a label or an emoji. Example in section's [Snippets](#interactions-sections-snippets). | -| `cmenu` "list of select menu values" | Functions similarly to `cembed`. [Available values](https://discord.com/developers/docs/interactions/message-components#select-menu-object) Type should be provided as a string, either `"text"`, `"user"`, `"role"`, `"mentionable"`, or `"channel"`. Text type menus must have `options`, all other types cannot. Example in section's [Snippets](#interactions-sections-snippets). | -| `ephemeralResponse` | Send the response text ephemerally. Only works when triggered by an interaction. Works on responses and followups. | -| `getResponse` interactionToken messageID | Can be used to get the bot's responses or followup messages, including ephemeral messages. Returns a [Message](/docs/reference/templates/syntax-and-data#message) object. `interactionToken` must be a valid token or `nil` to target the triggering interaction. `messageID` must be a valid message ID of a followup message, or `nil` to target the original interaction response. Example in section's [Snippets](#interactions-sections-snippets). | +```yag +{{ $result := reFindAll [count] }} +``` -#### Interactions section's snippets +Returns a slice of successive matches of `regex` in `text`. If `count` is provided, the number of matches is limited to +that amount; otherwise, all matches are returned. -- To demonstrate creating buttons and menus +### reFindAllSubmatches ```yag -{{ $funButton := cbutton - "label" "My Custom Button" - "custom_id" "duck-button" - "style" "success" }} -{{ $badButton := cbutton - "label" "My Useless Button" - "style" "secondary" - "disabled" true }} -{{ $emojiButton := cbutton - "emoji" ( sdict "name" "🦆" ) - "style" "link" - "url" "https://yagpdb.xyz" }} -{{ $menu := cmenu - "type" "text" - "placeholder" "Choose a terrible thing" - "custom_id" "duck-menus-my_first_menu" - "options" (cslice - (sdict "label" "Ducks" "value" "opt-1" "default" true) - (sdict "label" "Duck" "value" "opt-2" "emoji" (sdict "name" "🦆")) - (sdict "label" "Half a Duck" "value" "opt-3" "description" "Don't let the smaller amount fool you.")) - "max_values" 3 }} -{{ $message := complexMessage "buttons" (cslice $funButton $badButton $emojiButton) "menus" $menu }} -{{ sendMessage nil $message }} +{{ $result := reFindAllSubmatches [count] }} ``` -- To demonstrate responding with a modal (this must be triggered by a component or modal submission) +Returns a slice of successive submatches of `regex` in `text`. Each submatch is itself a slice containing the match of +the entire expression, followed by any matches of capturing groups. If `count` is provided, the number of submatches is +limited to that amount; otherwise, all submatches are returned. + +### reQuoteMeta ```yag -{{ $modal := sdict - "title" "My Custom Modal" - "custom_id" "modals-my_first_modal" - "fields" (cslice - (sdict "label" "Name" "placeholder" "Duck" "required" true) - (sdict "label" "Do you like ducks?" "value" "Heck no") - (sdict "label" "Duck hate essay" "min_length" 100)) }} -{{ sendModal $modal }} +{{ $result := reQuoteMeta }} ``` -- To demonstrate sending, getting, and editing responses (this must be triggered by a component or modal submission) +Escapes all regular expression metacharacters in the input `string`; the result is a regular expression matching the +literal input string. + +### reReplace ```yag -{{ $interactionToken := .Interaction.Token }} -{{ sendResponse nil "Here's the first message!" }} -{{ $followupID := sendResponseRetID $interactionToken (complexMessage "content" "Here's a sneaky one!" "ephemeral" true) }} -{{ sleep 2 }} -{{ editResponse $interactionToken $followupID (print "I've edited this message to say " noun) }} -{{ $editedResponse := getResponse $interactionToken $followupID }} -{{ editResponse $interactionToken nil $editedResponse.Content }} +{{ $result := reReplace }} ``` -- To demonstrate updating the triggering message (this must be triggered by a component or modal submission) +Replaces all matches of `regex` in `text` with `replacement`. + +### reSplit ```yag -{{ $button := cbutton "label" "I won!" "custom_id" "i_won" }} -{{ $content := printf "Press this button when you win! The last person who won was %s! They wanted to say they are a %s %s." .User.Mention adjective noun }} +{{ $result := reSplit [count] }} +``` -{{ $message := complexMessageEdit "content" $content "buttons" $button }} -{{ updateMessage $message }} +Splits the `text` around each match of `regex`, returning a slice of delimited substrings. + +if the `count` parameter is specified, it limits the number of substrings to return: + +- `count > 0`: at most `count` substrings; the last substring will be the unsplit remainder; +- `count == 0`: the result is `nil` (zero substrings); +- `count < 0`: all substrings. + +### sanitizeText + +```yag +{{ $result := sanitizeText }} ``` -### Math +Replaces accented and confusable characters in `string` with their normal, ISO-Latin variants. -{{< callout context="note" title="Note" icon="outline/info-circle" >}} +### split -Boolean logic (and, not, or) and comparison operators (eq, gt, lt, etc.) are covered in [conditional -branching](/docs/reference/templates/syntax-and-data#if-conditional-branching). +```yag +{{ $result := split }} +``` -{{< /callout >}} +Splits `string` around each instance of `separator`, returning a slice of delimited substrings. -| **Function** | **Description** | -| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `add` x y z ... | Returns x + y + z + ..., detects first number's type - is it _int_ or _float_ and based on that adds. (use `toFloat` on the first argument to force floating point math.)`{{add 5 4 3 2 -1}}` sums all these numbers and returns `13`. | -| `bitwiseAnd` x y | The output of bitwise AND is 1 if the corresponding bits of two operands is 1. If either bit of an operand is 0, the result of corresponding bit is evaluated to 0. Example: `{{bitwiseAnd 12 25}}` returns `8`, that in binary 00001100 AND 00011001 is 00001000. | -| `bitwiseAndNot` x y | This function is called bit clear because of AND NOT. For example in the expression z = x AND NOT y, each bit of z is 0 if the corresponding bit of y is 1; otherwise it equals to the corresponding bit of x. `{{bitwiseAndNot 7 12}}` returns `3`, that is 0111 AND NOT 1100 is 11. | -| `bitwiseNot` x | The bitwise NOT operator inverts the bits of the argument. Example: `{{bitwiseNot 7}}` returns `-8`. that in binary 0111 to 1000 | -| `bitwiseOr` x y z... | The output of bitwise OR is 1 if at least one corresponding bit of two operands is 1. Example: `{{bitwiseOr 12 25}}` returns `29`, that in binary 00001100 OR 00011001 is 00011101. | -| `bitwiseXor` x y | The result of bitwise XOR operator is 1 if the corresponding bits of two operands are opposite. Example: `{{bitwiseXor 12 25}}` returns `21`, that in binary 00001100 OR 00011001 is 00010101. | -| `bitwiseLeftShift` x y | Left shift operator shifts all bits towards left by a certain number of specified bits. The bit positions that have been vacated by the left shift operator are filled with 0. Example: `{{range seq 0 3}} {{bitwiseLeftShift 212 .}} {{end}}` returns `212 424 848` | -| `bitwiseRightShift` x y | Right shift operator shifts all bits towards right by certain number of specified bits. Example: `{{range seq 0 3}} {{bitwiseRightShift 212 .}} {{end}}` returns `212 106 53`. | -| `cbrt` x | Returns the cube root of given argument in type _float64_ e.g. `{{cbrt 64}}` returns `4`. | -| `div` x y z ... | Division, like `add` or `mult`, detects first number's type first. `{{div 11 3}}` returns `3` whereas `{{div 11.1 3}}` returns `3.6999999999999997` | -| `fdiv` x y z ... | Meant specifically for floating point numbers division. | -| `log` x (base) | Log is a logarithm function using (log base of x). Arguments can be any type of numbers, as long as they follow logarithm logic. Return value is of type _float64_. If base argument is not given It is using natural logarithm (base e - The Euler's constant) as default.`{{ log "123" 2 }}` will return `6.94251450533924`. | -| `mathConst` "arg" | Function returns all constants available in go's math package as _float64_. `"arg"` has to be a case-insensitive _string_ from [math constants list](https://pkg.go.dev/math@go1.18.2#pkg-constants). For example `{{mathConst "sqrtphi"}}` would return `1.272019649514069`. | -| `max` x y | Returns the larger of x or y as type _float64_. | -| `min` x y | Returns the smaller of x or y as type _float64_. | -| `mod` x y | Mod returns the floating-point remainder of the division of x by y. For example, `mod 17 3` returns `2` as type _float64_.

Note that like Go's `[math.Mod](https://pkg.go.dev/math#Mod)` function, `mod` takes the sign of `x`, so `mod -5 3` results in `-2`, not `1`. To ensure a non-negative result, use `mod` twice, like such: `mod (add (mod x y) y) y`. | -| `mult` x y z ... | Multiplication, like `add` or `div`, detects first number's type. `{{mult 3.14 2}}` returns `6.28` | -| `pow` x y | Pow returns x\*\*y, the base-x exponential of y which have to be both numbers. Type is returned as _float64_. `{{ pow 2 3 }}` returns `8`. | -| `randInt` (stop, or start stop) | Returns a random integer between 0 and stop, or start - stop if two args are provided.Result will be `start <= random number < stop`. Without arguments, range is 0..10. Example in section's [Snippets](#math-sections-snippets). | -| `round` x | Returns the nearest integer, rounding half away from zero. Regular rounding > 10.4 is `10` and 10.5 is `11`. All round functions return type _float64_, so use conversion functions to get integers. For more complex rounding, example in section's [Snippets](#math-sections-snippets). | -| `roundCeil` x | Returns the least integer value greater than or equal to input or rounds up. `{{roundCeil 1.1}}` returns `2`. | -| `roundEven` x | Returns the nearest integer, rounding ties to even.
`{{roundEven 10.5}}` returns `10 {{roundEven 11.5}}` returns `12`. | -| `roundFloor` x | Returns the greatest integer value less than or equal to input or rounds down. `{{roundFloor 1.9}}` returns `1`. | -| `sqrt` x | Returns the square root of a number as type _float64_.
`{{sqrt 49}}` returns `7, {{sqrt 12.34 \|printf "%.4f"}} returns 3.5128` | -| `sub` x y z ... | Returns x - y -z - ... Works like add, just subtracts. | - -#### Math section's snippets - -- `{{$d := randInt 10}}` Stores random _int_ into variable `$d` (a random number from 0-9). -- To demonstrate rounding float to 2 decimal places.\ - `{{div (round (mult 12.3456 100)) 100}}` returns 12.35\ - `{{div (roundFloor (mult 12.3456 100)) 100}}` returns 12.34 - -### Member - -| **Function** | **Description** | -| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `getTargetPermissionsIn` memberID channelID | Returns target’s permissions in the given channel. | -| `editNickname` "newNick" | Edits triggering user's nickname, argument has to be of type _string_. YAGPDB's highest role has to be above the highest role of the member and bot can't edit owner's nickname. | -| `hasPermissions` arg | Returns true/false on whether triggering user has the permission bit _int64_ that is also set in .Permissions*.* | -| `getMember` mention/userID | Function returns [Member object](/docs/reference/templates/syntax-and-data#member) having above methods. `{{(getMember .User.ID).JoinedAt}}`
is the same as `{{.Member.JoinedAt}}` | -| `onlineCount` | Returns the count of online users/members on current server. | -| `targetHasPermissions` memberID arg | Returns true/false on whether targeted member has the permission bit _int64_. | - -Permissions are covered on -[Discord permissions documentation](https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags). For example to get -permission bit for "use application commands" `{{bitwiseLeftShift 1 32}}` would return _int64_ `4294967296`. - -### Mentions - -| **Function** | **Description** | -| ---------------------------- | ------------------------------------------------------------------------ | -| `mentionEveryone` | Mentions `@everyone`. | -| `mentionHere` | Mentions `@here`. | -| `mentionRoleID` roleID | Mentions the role found with the provided ID. | -| `mentionRoleName` "rolename" | Mentions the first role found with the provided name (case-insensitive). | - -There is also .Mention method available for channel, role, user structs/objects. - -#### Mentions section's snippets - -- `<@{{.User.ID}}>` Outputs a mention to the user that called the command and is the same as `{{.User.Mention}}` -- `<@###########>` Mentions the user that has the ID ###### (See [How to get IDs](/docs/reference/how-to-get-ids) to get ID). -- `<#&&&&&&&&&&&>` Mentions the channel that has ID &&&&&& (See [How to get IDs](/docs/reference/how-to-get-ids) to get ID). - -* `<@&##########>` Mentions the role with ID ######## ([listroles](/docs/core/all-commands#listroles) command - gives roleIDs). This is usable for example with `{{sendMessageNoEscape nil "Welcome to role <@&11111111...>"}}`. - Mentioning that role has to be enabled server- side in Discord. - -- `` Mentions a slash command, and makes it clickable and interactive with proper arguments e.g. - ``. - -### Message - -| **Function** | **Description** | -| -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `addMessageReactions` channel messageID emojis... | Same as `addReactions` or `addResponseReactions`, but can be used on any messages using its ID. `channel` can be either `nil`, channel's ID or its name.Emojis can be presented as a _cslice_. Example in section's [Snippets](#message-sections-snippets). | -| `addReactions` "👍" "👎" ... | Adds each emoji as a reaction to the message that triggered the command (recognizes Unicode emojis and `emojiName:emojiID`). Emojis can be presented as a _cslice_. | -| `addResponseReactions` "👍" "👎" ... | Adds each emoji as a reaction to the response message (recognizes Unicode emojis and `emojiName:emojiID`). Emojis can be presented as a _cslice_. | -| `complexMessage` "allowed_mentions" arg "content" arg "embed" arg "file" arg "filename" arg "reply" arg "silent" arg | `complexMessage` creates a _so-called_ bundle of different message fields for `sendMessage...` functions to send them out all together. Its arguments need to be preceded by predefined keys:
`"allowed_mentions"` sends out very specific mentions where `arg` is an _sdict_ having keys: `"parse"` that takes a _cslice_ with accepted values for a type to mention - "users", "roles", "everyone"; _sdict_ keys`"users"`, `"roles"` take a _cslice_ of IDs either for users or roles and `"replied_user"` is a _bool_ true/false for mentioning replied user.`"content"` for regular text; `"embed"` for embed arguments created by `cembed` or `sdict`. With `cslice` you can use up to 10 embeds as arguments for `"embed"`. `"file"` for printing out content as a file with default name `attachment_YYYY-MM-DD_HH-MM-SS.txt` (max size 100 000 characters ca 100kB). `"filename"` lets you define custom file name if `"file"` is used with max length of 64 characters, extension name remains `txt`. `"reply"`replies to a message, where `arg`is messageID. If replied message is in another channel, `sendMessage`channel must be also that channel. To "reply-ping", use `sendMessageNoEscape`.`"silent"` suppresses message's push and desktop notifications, `arg` is _bool_ true/false.Example in this section's [Snippets](#message-sections-snippets). | -| `complexMessageEdit` "allowed_mentions" arg "content" arg "embed" arg "silent" arg | Special case for `editMessage` function - either if `complexMessage` is involved or works even with regular message. Has parameters "allowed_mentions",`"content", "embed"` and `"silent"` that edit the message and work the same way as for `complexMessage`. Example in this section's [Snippets](#message-sections-snippets). | -| `deleteAllMessageReactions` channel messageID (emojis...) | Deletes all reactions pointed message has. `channel` can be ID, "name" or `nil`. `emojis` argument is optional and works like it's described for the function `deleteMessageReaction`. | -| `deleteMessage` channel messageID (delay) | Deletes message with given `messageID` from `channel`. Channel can be either `nil`, channel's ID or its name. `(delay)` is optional and like following two delete functions, it defaults to 10 seconds, max being 1 day or 86400 seconds. Example in section's [Snippets](functions#message-sections-snippets). | -| `deleteMessageReaction` channel messageID userID emojis... | Deletes reaction(s) from a message. `channel` can be ID, "name" or `nil`.
`emojis` argument can be up to 10 emojis, syntax is `emojiName` for Unicode/Discord's default emojis and `emojiName:emojiID` for custom emotes.
Example: `{{deleteMessageReaction nil (index .Args 1) .User.ID "👍" "👎"}}` will delete current user's reactions with thumbsUp/Down emotes from current running channel's message which ID is given to command as first argument `(index .Args 1)`.
Also usable with [Reaction trigger](/docs/reference/templates/syntax-and-data#reaction). | -| `deleteResponse` (delay) | Deletes the response after a certain time from optional `delay` argument (max 86400 seconds = 1 day). Defaults to 10 seconds. | -| `deleteTrigger` (delay) | Deletes the trigger after a certain time from optional `delay` argument (max 86400 seconds = 1 day). Defaults to 10 seconds. | -| `editMessage` channel messageID newMessageContent | Edits the message in channel, channel can be either `nil`, channel's ID or "name". Light example in section's [Snippets](#message-sections-snippets). | -| `editMessageNoEscape` channel messageID newMessageContent | Edits the message in channel and has same logic in escaping characters as `sendMessageNoEscape`. | -| `getMessage` channel messageID | Returns a [Message](/docs/reference/templates/syntax-and-data#message) object. `channel` can be either its ID, name or nil for triggering channel. | -| `pinMessage` channel messageID | Pins a message by its ID in given channel. `channel` can be either its ID, name or nil for triggering channel. Can be called 5 times. | -| `publishMessage` channel messageID | Publishes a message by its ID in given announcement channel. `channel` can be either its ID, name or nil for triggering channel. Can be called once. This function will not work for leave or join messages. | -| `publishResponse` | Publishes the response when executed in an announcement channel. This function will not work for leave or join messages. | -| `sendDM` "message here" | Sends the user a direct message, only one DM can be sent per custom command (accepts embed objects). YAG will only DM triggering user. This function will not work for leave messages. | -| `sendMessage` channel message | Sends `message (string or embed)` in `channel`, channel can be either `nil`, the channel ID or the channel's "name". | -| `sendMessageNoEscape` channel message | Sends `message (string or embed)` in `channel`, channel can be either `nil`, the channel ID or the channel "name". Doesn't escape mentions (e.g. role mentions, reply mentions or @here/@everyone). | -| `sendMessageNoEscapeRetID` channel message | Same as `sendMessageNoEscape`, but also returns messageID to assigned variable for later use. | -| `sendMessageRetID` channel message | Same as `sendMessage`, but also returns messageID to assigned variable for later use. Example in section's [Snippets](#message-sections-snippets). | -| `unpinMessage` channel messageID | Unpins the message by its ID in given channel. `channel` can be either its ID, name or nil for triggering channel. Can be called 5 times. | - -#### Message section's snippets - -- Sends message to current channel `nil` and gets messageID to variable `$x`. Also adds reactions to this message. After - 5 seconds, deletes that message. > - - `{{$x := sendMessageRetID nil "Hello there!"}} {{addMessageReactions nil $x (cslice "👍" "👎") "❤️" }} -{{deleteMessage nil $x 5}}` - -- To demonstrate `sleep` and slightly also `editMessage` functions. >\ - `{{$x := sendMessageRetID nil "Hello"}} {{sleep 3}} {{editMessage nil $x "There"}} {{sleep 3}} {{sendMessage nil "We -all know, that"}} {{sleep 3}} YAGPDB rules!` -- To demonstrate usage of `complexMessage` with `sendMessage`. `{{sendMessage nil (complexMessage "reply" .Message.ID -"content" "Who rules?" "embed" (cembed "description" "YAGPDB of course!" "color" 0x89aa00) "file" "Here we print -something nice - you all are doing awesome!" "filename" currentTime.Weekday)}}` -- To demonstrate usage of `complexMessageEdit` with `editMessage`.\ - `{{$mID := sendMessageRetID nil (complexMessage "content" "You know what is..." "silent" true "embed" (cembed "title" -"FUN!?" "color" 0xaa8900))}} {{sleep 3}} {{editMessage nil $mID (complexMessageEdit "embed" (cembed "title" "YAGPDB!" -"color" 0x89aa00) "content" "Yes, it's always working with...")}}{{sleep 3}}{{editMessage nil $mID (complexMessageEdit -"embed" nil "content" "Will delete this message in a sec, goodbye YAG!")}}{{deleteMessage nil $mID 3}}` - -### Miscellaneous +### title -{{< callout context="note" title="Note" icon="outline/info-circle" >}} +```yag +{{ $result := title }} +``` -`if`, `range`, `try-catch`, `while`, `with` actions are all covered on the [actions template documentation](/docs/reference/templates/syntax-and-data#actions). +Returns the string with the first letter of each word capitalized. (Title Case) -{{< /callout >}} +### trimSpace -| **Function** | **Description** | -| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `adjective` | Returns a random adjective. | -| `cembed` "list of embed values" | Function to generate embed inside custom command. [In-depth custom embeds reference](/docs/reference/custom-embeds). | -| `createTicket` author topic | Creates a new ticket with the author and topic provided. [Ticket object documentation](/docs/reference/templates/syntax-and-data#tickets). | -| `cslice`, `sdict` | Please see [custom type documentation](/docs/reference/templates/syntax-and-data#custom-types). | -| `dict` key1 value1 key2 value2 ... | Creates an unordered collection of key-value pairs, a dictionary so to say. The number of parameters to form key-value pairs must be even. [Dictionary example script](/docs/reference/custom-command-examples#dictionary-example). Keys and values can be of any type. Key is not restricted to _string_ only as in case with `sdict`. `dict` also has helper methods .Del, .Get, .HasKey and .Set and they function the same way as `sdict` ones discussed in [templates.Sdict documentation](/docs/reference/templates/syntax-and-data#templates-sdict). | -| `exec` "command" "args" "args" "args" ... | Executes a YAGPDB command (e.g. roll, kick etc) in a custom command. Exec can be run max 5 times per CC. If real command returns an embed - `exec` will return raw data of type embed, so you can use embed fields for better formatting - e.g. `{{$resp := exec "whois"}} {{$resp.Title}} Joined at > {{(index $resp.Fields 4).Value}}` will return the title (username#discriminator) and "Joined at" field's value from `whois` command.
**NB!** This will not work for commands with paginated embed returns, like `un/nn` commands!exec syntax is `exec "command" arguments` - this means you format it the same way as you would type the command regularly, just without the prefix, e.g. if you want to clear 2 messages and avoiding the pinned message > `{{exec "clear 2 -nopin"}}`, where `"command"` part is whole `"clear 2 -nopin"`. If you change that number inside CC somewhere then you have to use `arguments` part of exec formatting > `{{$x := 2}} {{exec "clear" $x "-nopin"}}` Here `"clear"` is the `"command"` and it is followed by `arguments`, one variable `$x` and one string `"-nopin"`. Last example is the same as `{{exec (joinStr " " "clear" $x "-nopin")}}`(also notice the space in `joinStr` separator). | -| `execAdmin` "command" "args" "args" "args" ... | Functions same way as `exec` but effectively runs the command as the bot user (YAGPDB). This has essentially the same effect as if a user with the same permissions and roles as YAGPDB ran the command: for example, if YAGPDB had ban members permission but the user which ran the command did not, `{{exec "ban" 12345}}` would error due to insufficient permissions but `{{execAdmin "ban" 12345}}` would succeed. | -| `execTemplate` "template" data | Executes the associated template, optionally with data. A more detailed treatment of this function can be found in the [Associated Templates](/docs/reference/templates/syntax-and-data#associated-templates) section. | -| `getWarnings` user | Returns a _slice_ of warnings of type _[[]\*moderation.WarningModel](https://github.com/botlabs-gg/yagpdb/blob/master/moderation/models.go#L121)_ given to user argument which can be its ID or user object. | -| `hasPrefix` string prefix | `hasPrefix` tests whether the given `string` begins with `prefix` and returns _bool_. Example > `{{hasPrefix "YAGPDB" "YAG"}}` returns `true`. | -| `hasSuffix` string suffix | hasSuffix tests whether the given `string` ends with `suffix` and returns _bool_. Example > `{{hasSuffix "YAGPDB" "YAG"}}` returns `false`. | -| `humanizeThousands` arg | This function places comma to separate groups of thousands of a number. `arg` can be _int_ or _string_, has to be a whole number, e.g. `{{humanizeThousands "1234567890"}}` will return `1,234,567,890`. | -| `in` list value | Returns _bool_ true/false whether case-sensitive value is in list/_slice_. `{{ in (cslice "YAGPDB" "is cool") "yagpdb" }}` returns `false`. | -| `index` arg ...keys | Returns the result by indexing its first argument with following arguments. Each indexed item must be a _map_, _slice_ or _array._ Indexed _string_ returns value in _uint8_. Example: `{{index .Args 1}}` returns first argument after trigger which is always at position 0. More than one positional keys can be used, in pseudo-code: `index X 0 1` is equivalent to calling `index (index X 0) 1` | -| `inFold` list value | Same as `in`, but is case-insensitive. `{{inFold (cslice "YAGPDB" "is cool") "yagpdb"}}` returns `true`. | -| `kindOf` value (flag) | This function helps to determine what kind of data type we are dealing with. `flag` part is a _bool_ and if set as **true** (**false** is optional) returns the value where given `value` points to. Example: `{{kindOf cembed false}} {{kindOf cembed true}}` will return `ptr` and `struct`. | -| `len` arg | Returns the integer length of its argument. arg can be an _array_, _slice_, _map_, or _string._`{{ len (cslice 1 2 3) }}` returns `3`. | -| `noun` | Returns a random noun. | -| `parseArgs` required_args error_message `...carg` | Checks the arguments for a specific type. Has methods `.Get` and `.IsSet`.
`carg "type" "name"` is required by `parseArgs` and it defines the type of argument for `parseArgs`. An example in [Custom Command Examples.](/docs/reference/custom-command-examples.md#parseargs-example) | -| `sendTemplate` channel templateName (data) | Function sends a formulated template to another channel and returns sent response's messageID.
Channel is like always either name, number or nil; and returns messageID. `data` is optional and is meant for additional data for the template. Example: `{{define "logsTemplate"}}This text will output on different channel, you can also use functions like {{currentTime}}. {{.TemplateArgs}} would be additional data sent out. {{end}}`Now we call that "logs" in the same custom command.`{{sendTemplate "logs" "logsTemplate" "YAG rules!"}}.`

[Template definition documentation](https://pkg.go.dev/text/template#hdr-Nested_template_definitions). | -| `sendTemplateDM` templateName (data) | Works the same way as function above. Only channel's name is not in the arguments. YAGPDB **will only** DM the triggering user. This function will not work for leave messages. | -| `seq` start stop | Creates a new _slice_ of type _int_, beginning from start number, increasing in sequence and ending at stop (not included). `{{seq -4 2}}` returns a _slice_ `[ -4 -3 -2 -1 0 1 ]`. Sequence's max length is 10 000. | -| `shuffle` list | Returns a shuffled, randomized version of a list/_slice_. | -| `sleep` seconds | Pauses execution of template's action-structure inside custom command for max 60 seconds combined. Argument `seconds` is an integer (whole number). Example in [snippets](#message-sections-snippets). | -| `sort` slice (...args) | Sorts a slice of same type values with optional arguments. These arguments are presented in an `sdict` as keys: `"reverse"` true/false and `"key"` with dictionary/map's key name as value. Example > `{{sort (cslice (sdict "name" "bob") (sdict "name" "alice") (sdict "name" "yagpdb")) (sdict "key" "name" "reverse" true)}}` would return `[map[name:yagpdb] map[name:bob] map[name:alice]]`. Sorting mixed types is not supported. Previous sorting options `"subslices"` and `"emptyslices"` have been removed.
Sort function is limited to 1/3 CC calls regular/premium. | -| `verb` | Returns a random verb. | - -### Role functions +```yag +{{ $result := trimSpace }} +``` -{{< callout context="note" title="Note" icon="outline/info-circle" >}} +Returns the string with all leading and trailing white space removed. -In all role functions where userID is required as argument to target a user, it can also be full user object. +### upper -{{< /callout >}} +```yag +{{ $result := upper }} +``` -| **Function** | **Description** | -| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `addRoleID` roleID | Adds the role with the given ID to the user that triggered the command (use the `listroles` command for a list of roles). | -| `addRoleName` roleName | Adds the role with given name to the user that triggered the command (use the `listroles` command for a list of roles). | -| `getRole` role | Returns a [role object](https://discord.com/developers/docs/topics/permissions#role-object) of type _\*discordgo.Role._ `role` can be either role's ID or role's name. | -| `giveRoleID` userID roleID | Gives a role by ID to the target. | -| `giveRoleName` userID "roleName" | Gives a role by name to the target. | -| `hasRoleID` roleID | Returns true if the triggering user has the role with the specified ID (use the listroles command for a list of roles). | -| `hasRoleName` "rolename" | Returns true if the triggering user has the role with the specified name (case-insensitive). | -| `removeRoleID` roleID (delay) | Removes the role with the given ID from the user that triggered the command (use the listroles command for a list of roles). `Delay` is optional argument in seconds. | -| `removeRoleName` roleName (delay) | Removes the role with given name from the user that triggered the command (use the listroles command for a list of roles). `Delay` is optional argument in seconds. | -| `roleAbove` role1 role2 | `roleAbove` compares two role objects e.g. `getRole`return and gives`true/false` value is `role1` positioned higher than `role2` or not. | -| `setRoles` userID roles | Overwrites the roles of the given user using the slice of roles provided, which should be a slice of role IDs. IDs can be ints or strings. Example: `{{setRoles .User.ID cslice}}` would clear the roles of the triggering user. | -| `takeRoleID` userID roleID (delay) | Takes away a role by ID from the target. `Delay` is optional argument in seconds. | -| `takeRoleName` userID "roleName" (delay) | Takes away a role by name from the target. `Delay` is optional argument in seconds. | -| `targetHasRoleID` userID roleID | Returns true if the given/targeted user has the role with the specified ID (use the listroles command for a list of roles). Example in section's Snippets. | -| `targetHasRoleName` userID "roleName" | Returns true if the given/targeted user has the role with the specified name (case-insensitive). | - -### String manipulation +Converts `string` to all uppercase and returns the result. -{{< callout context="note" title="Note" icon="outline/info-circle" >}} +## Time -All regexp functions are limited to 10 different pattern calls per CC. +### currentTime -{{< /callout >}} +```yag +{{ $time := currentTime }} +``` -| **Function** | **Description** | -| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `joinStr` "separator" "str1" (arg1)(arg2) "str2" ... | Joins several strings into one, separated by the first argument`"separator"`, example:`{{joinStr "" "1" "2" "3"}}` returns `123`. Also if functions have _string, \[]string_ or easily convertible return, they can be used inside `joinStr` e.g. `{{joinStr ""` `"Let's calculate " (add (mult 13 3) 1 2) ", was returned at "` `(currentTime.Format "15:04") "."}}` | -| `lower` "string" | Converts the string to lowercase. | -| `print`, `printf`, `println` | These are GO template package's predefined functions and are aliases for [fmt.Sprint](https://golang.org/pkg/fmt/#Sprint), [fmt.Sprintf](https://golang.org/pkg/fmt/#Sprintf) and [fmt.Sprintln](https://golang.org/pkg/fmt/#Sprintln). Formatting is also discussed in [Go formatting documentation](https://golang.org/pkg/fmt/#hdr-Printing). [`printf` cheat sheet](https://yourbasic.org/golang/fmt-printf-reference-cheat-sheet/).

`printf` is usable for example to determine the type of the value > `{{printf "%T" currentTime}}` outputs `currentTime` functions output value type of `time.Time`. In many cases, `printf` is a great alternative to `joinStr` for concatenate strings. | -| `reFind` "regex" "string" | Compares "string" to regex pattern and returns first match. `{{reFind "AG" "YAGPDB is cool!"}}`returns `AG` (regex pattern is case sensitive). | -| `reFindAll` "regex" "string" (count) | Adds all regex matches from the "string" to a _slice_. Example in section's [Snippets](functions.md#string-manipulation-sections-snippets). Optional `count` determines how many matches are made. **Example:** `{{reFindAll "a*" "abaabaccadaaae" 4}}` would return `[a aa a ].` | -| `reFindAllSubmatches` "regex" "string" (count) | Returns whole-pattern matches and also the sub-matches within those matches as _slices_ inside a _slice_. `{{reFindAllSubmatches "(?i)y([a-z]+)g" "youngish YAGPDB"}}` returns `[[young oun] [YAG A]]` (regex pattern here is case insensitive). Optional `count` works the same way as for `reFindAll`. So example above with `count` set to 1 would return `[[young oun]]`. | -| `reQuoteMeta` "string" | `reQuoteMeta` returns a string that escapes all regular expression metacharacters inside the argument text; the returned string is a regular expression matching the literal text. Example in [package documentation](https://pkg.go.dev/regexp#QuoteMeta). | -| `reReplace` "regex" "string1" "string2" | Replaces "string1" contents with "string2" at regex match point. `{{reReplace "I am" "I am cool!" "YAGPDB is"}}` returns `YAGPDB is cool!` (regex pattern here is case sensitive).
Inside "string2" dollar-sign, $ with numeric name like $1 or ${1} are interpreted as referrals to the submatches in "regex" pattern, so for instance $1 represents the text of the first submatch. To insert a literal $ in the output, use $$. | -| `reSplit` "regex" "string" (count) | `reSplit` slices `string` into substrings separated by the `regex` expression and returns a _slice_ of the substrings between those expression matches. The optional `count` determines the number of substrings to return. If `count` is negative number the function returns all substrings, if 0 then none. If `count` is bigger than 0 it returns at most n substrings, the last substring being the unsplit remainder.**Example:** ` {{ $x := reSplit "a" "yagpdb has a lot of fame" 5}}``{{$x}} {{index $x 3}} ` would return `[y gpdb h s lot of f me]` and `lot of f.` | -| `sanitizeText` "string" | Detects accented and confusable characters in input and turns these characters to normal, ISO-Latin ones. `{{ sanitizeText "𝔭𝒶ỿ𝕡𝕒ℓ" }}`would return `paypal`. | -| `slice` arg integer (integer2) | Function's first argument must be of type _string_ or _slice_.Outputs the `arg` after cutting/slicing off integer (numeric) value of symbols (actually starting the string's index from integer through integer2) - e.g. `{{slice "Fox runs" 2}}`outputs `x runs`. When using also integer2 - e.g. `{{slice "Fox runs" 1 7}}`, it outputs `ox run`. For slicing whole arguments, let's say words, see example in section's [Snippets](#string-manipulation-sections-snippets). This `slice` function is not the same as basic dynamically-sized _slice_ data type discussed in this reference doc. Also it's custom, not having 3-indices as the default one from [text/template](https://golang.org/pkg/text/template/#hdr-Functions) package. | -| `split` "string" "sepr" | Splits given `"string"` to substrings separated by `"sepr"`arg and returns new _slice_ of the substrings between given separator e.g. `{{split "YAG, is cool!" ","}}` returns `[YAG is cool!]` _slice_ where `YAG` is at `index` position 0 and `is cool!` at `index` position 1. Example also in section's [Snippets](functions.md#string-manipulation-sections-snippets). | -| `title` "string" | Returns the string with the first letter of each word capitalized. | -| `trimSpace` "string" | Returns the string with all leading and trailing white space removed. | -| `upper` "string" | Converts the string to uppercase. | -| `urlescape` "string" | Escapes the _string_ so it can be safely placed inside a URL path segment - e.g. "Hello, YAGPDB!" becomes "Hello%2C%20YAGPDB%21"
There's also predefined template package function `urlquery` which is covered in [Go text/template documentation](https://pkg.go.dev/text/template#hdr-Functions). | +Returns the current time in UTC. -{{< callout context="note" title="Note" icon="outline/info-circle" >}} +### formatTime -Special information we can include in the string is _escape sequences_. Escape sequences are two (or more) characters, -the first of which is a backslash `\`, which gives the remaining characters special meaning - let's call them -metacharacters. The most common escape sequence you will encounter is `\n`, which means "newline". +```yag +{{ $formatted := formatTime