printf, index, len,
etc > https://golang.org/pkg/text/template/ . This section is meant to be a concise and to the point reference document for all available templates/functions. Functions are covered here. For detailed explanations and syntax guide refer to the learning resource.code block
should refer to a function, parts of a template's action-structure or output returned by YAGPDB; single word/literal-structure in italics refers to type. Methods and fields (e.g. .Append, .User) are usually kept in standard formatting. If argument for a function is optional, it's enclosed in parenthesis ( )
. If there are many optional arguments possible, it's usually denoted by 3-dot ...
ellipsis.
If functions or methods are denoted with an accent, tilde ~, they are not yet deployed in actual YAGPDB bot but are already in master code branch.{{.User.Username}}
{{ ... }}
syntax of having two curly brackets aka braces around context is necessary to form a template's control structure also known as an action with methods and functions stated below."
for straight double quotes, 0x27 > '
for apostrophes and 0x60 `
for backticks;
so make sure no "smart-quotes" are being used.{{ . }}
encompasses all active data available for use in the templating system, in other words it always refers to current context.
For example .User is a Discord User object/structure of current context, meaning the triggering user. To get user object for other users, functions getMember
, userArg
would help. Same meaning of object/struct applies to other Fields with dot prefix. If it is mentioned as a Method (for example, .Append for type cslice) or as a field on a struct (for example, .User.Bot) then it can not be used alone in template context and always belongs on a parent value. That is, {{.Bot}}
would return <no value>
whereas {{.User.Bot}}
returns bool true/false. Another good example is .Reaction.Emoji.MessageFormat, here you can use .MessageFormat every time you get emoji structure of type discordgo.Emoji, either using reaction triggers or for example .Guild.Emojis.
From official docs > "Execution of the template walks the structure and sets the cursor, represented by a period .
and called "dot", to the value at the current location in the structure as execution proceeds." All following fields/methods/objects like User/Guild/Member/Channel etc are all part of that dot-structure and there are some more in tables below.{{/* this is a comment */}}
. May contain newlines. Comments do not nest and they start and end at the delimiters.{{- /* this is a multi-line
comment with whitespace trimmed from preceding and following text */ -}}
Using{{- ... -}}
is also handy insiderange
actions, because whitespaces and newlines are rendered there as output.
$
has a special significance in templates, it is set to the starting value of a dot. This means you have access to the global context from anywhere - e.g., inside range
/with
actions. $
for global context would cease to work if you redefine it inside template, to recover it {{ $ := . }}
.
$
also denotes the beginning of a variable, which maybe be initialized inside a template action. So data passed around template pipeline can be initialized using syntax > $variable := value
. Previously declared variable can also be assigned with new data > $variable = value
, it has to have a white-space before it or control panel will error out. Variable scope extends to the end
action of the control structure (if
, with
, range
, etc.
) in which it is declared, or to the end of custom command if there are no control structures - call it global scope. |
. Borrowed from Unix pipes, the concept is simple: each pipeline’s output becomes the input of the following pipe. One limitation of the pipes is that they can only work with a single value and that value becomes the last parameter of the next pipeline.
Example: {{randInt 41 | add 2}}
would pipelinerandInt
function's return to addition add
as second parameter and it would be added to 2; this more simplified would be like {{40 | add 2}}
with return 42. If written normally, it would be {{ add 2 (randInt 41) }}
. Same pipeline but using a variable is also useful one -{{$x:=40 | add 2}}
would not return anything as printout, 40 still goes through pipeline to addition and 42 is stored to variable $x
whereas {{($x:=40) | add 2}}
would return 42 and store 40 to $x
.{{ . }}
. The accessible data ranges from useful constants to information regarding the environment in which the custom command was executed, such as the user that ran it, the channel it was ran in, and so on. .User
, are usable on all values that share the same type. That is, given a user $user
, $user.ID
is a valid construction that yields the ID of the user. Similarly, provided a channel $channel
, $channel.Name
gives the name of the channel.regex
and trigger is set to \A
, it would print \A
.{{len .Guild.Roles}}
gives you how many roles are there in that guild. Role struct has following fields..Guild.GetChannel id
.Guild.GetEmoji id
.Guild.GetMemberPermissions channelID memberID memberRoles
{{.Guild.GetMemberPermissions .Channel.ID .Member.User.ID .Member.Roles}}
would retrieve the permissions integer the triggering member has in the context/triggering channel..Guild.GetRole id
.Guild.GetVoiceState userID
{{if .Guild.GetVoiceState .User.ID}} user is in voice channel {{else}} user is not in voice channel {{end}}
.Parse
will convert this to of type time.Time.{{index .Args 0}}
. .Cmd
(.Cmd
is the actual trigger) .CmdArgs
is a slice of type string. For example {{$allArgs := (joinStr " " .CmdArgs)}}
saves all the arguments after trigger to a variable $allArgs
. "day"
and input message is "Have a nice day my dear YAG!"
output will be "my dear YAG!"
- rest is cut off.getMessage
function.UserID
, MessageID
,
Emoji.(ID/Name/...)
, ChannelID
, GuildID
. The Emoji.ID is the ID of the emoji for custom emojis, and Emoji.Name will hold the Unicode emoji if its a default one. (otherwise the name of the custom emoji).emojiname:ID
.<:.Reaction.Emoji.APIName>
and <a:.Reaction.Emoji.APIName>
for animated emojis.{{range .ReactionMessage.Reactions}}
{{.Count}} - {{.Emoji.Name}}
{{end}}
.Message
and it works the same way.true
.{{ }}
, are what makes templates dynamic. Without them, templates would be no more than static text. In this section, we introduce several special kinds of actions which affect the control flow of the program. For example, iteration actions like range
and while
permit statements to be executed multiple times, while conditional actions like if
and with
allow for alteration of what statements are ran or are not ran.if
action's pipeline and comparison operators - these operators don't need to be inside if
branch. if
statements always need to have an enclosing end
.
Learning resources covers conditional branching more in depth.
eq
, though often used with 2 arguments (eq x y
) can actually be used with more than 2. If there are more than 2 arguments, it checks whether the first argument is equal to any one of the following arguments. This behaviour is unique to eq
.1.23
and 1
would throw incompatible types for comparison
error as they are not the same type (one is float, the other int). To fix this, you should convert both to the same type -> for example, toFloat 1
.{{if (condition)}} output {{end}}
if
statement with conditional statement, limiting the initialized scope to that if
statement.
{{$x := 24}}
{{if eq ($x := 42) 42}} Inside: {{$x}} {{end}}
Outside: {{$x}}
{{if (condition)}} output1 {{else if (condition)}} output2 {{end}}
else if
statements as many different conditionals you have.{{if (condition)}} output1 {{else}} output2 {{end}}
{{if and (cond1) (cond2) (cond3)}} output {{end}}
{{if not (condition)}} output {{end}}
{{if or (cond1) (cond2) (cond3)}} output {{end}}
eq
{{if eq .Channel.ID ########}} output {{end}}
ne
{{$x := 7}} {{$y := 8}} {{ne $x $y}}
returns true
lt
{{if lt (len .Args) 5}} output {{end}}
le
{{$x := 7}} {{$y := 8}} {{le $x $y}}
returns true
gt
{{if gt (len .Args) 1}} output {{end}}
ge
{{$x := 7}} {{$y := 8}} {{ge $x $y}}
returns false
range
iterates over element values in variety of data structures in pipeline - slices/arrays, maps or channels. The dot .
is set to successive elements of those data structures and output will follow execution. If the value of pipeline has zero length, nothing is output or if an {{else}}
action is used, that section will be executed.continue
action may be used. Likewise, if one wishes to skip all remaining iterations, the break
action may be used.range
is important because methods mentioned above in this documentation:.Server.ID
, .Message.Content
etc are all already using the dot on the pipeline and if they are not carried over to the range
control structure directly, these fields do not exists and template will error out. Getting those values inside range
and also with
action would need $.User.ID
for example.
range
on slices/arrays provides both the index and element for each entry; range
on map iterates over key/element pairs. If a range
action initializes a variable, that variable is set to the successive elements of the iteration. range
can also declare two variables, separated by a comma and set by index and element or key and element pair. In case of only one variable, it is assigned the element.
Like if
, range
is concluded with{{end}}
action and declared variable scope inside range
extends to that point.
dbSet
can return a short write error if the size of the database entry exceeds some threshold. try
-catch
construct enables this possibility.if
action with an associated else
branch, the try
-catch
construct is composed of two blocks: the try
branch and the catch
branch. First, the code in the try
branch is ran, and if an error is raised by a function during execution, the catch
branch is executed instead with the context (.
) set to the offending error.Error
method with a predetermined message. (For context, all errors have a method Error
which is specified to return a message describing the reason that the error was thrown.) For example, the following example has different behavior depending on whether "Reaction blocked" is in the message of the error caught.while
iterates as long as the specified condition is true, or more generally evaluates to a non-empty value. The dot (.
) is not affected, unlike with the range
action. Analogous to range
, while
introduces a new scope which is concluded by the end
action. Within the body of a while
action, the break
and continue
actions can be used to appropriate effect, like in a range
action.with
lets you assign and carry pipeline value with its type as a dot (.
) inside that control structure, it's like a shorthand. If the value of the pipeline is empty, dot is unaffected and when an else
or else if
action is used, execution moves on to those branches instead, similar to the if
action.
Affected dot inside with
is important because methods mentioned above in this documentation:.Server.ID
, .Message.Content
etc are all already using the dot on the pipeline and if they are not carried over to the with
control structure directly, these fields do not exists and template will error out. Getting those values inside with
and also range
action would need $.User.ID
for example.if
and range
actions, with
is concluded using {{end}}
and variable scope extends to that point.define
action. It has the following syntax:$name
) defined in an outer scope:$name
is desired, then it needs to be passed as part of the context when executing the associated template. $
and the context dot (.
) both initially refer to the data passed as context during execution. Consequently, any data on the original context that needs to be accessed must be explicitly provided as part of the context data. For example, if one wishes to access .User.Username
in an associated template body, it is necessary to pass .User.Username
as part of the context data when executing said template.return
action. Encountering a return
action will cause execution of the associated template to end immediately and control to be returned to the caller. For example, below is an associated template that always returns 1
:{{ return }}
by itself is completely valid.return
action at the top level is perfectly valid, and will result in execution of the custom command being stopped at the point the return
is encountered.template
, block
, or execTemplate
.template
is a function-like action that executes the associated template with the name provided, ignoring its return value. Note that the name of the template to execute must be a string constant; similar to define
actions, a variable referencing a value of string type is invalid. Data to use as the context may optionally be provided following the name.template
is function-like, it is not an actual function, leading to certain quirks; notably, it must be used alone, not part of another action (like a variable declaration), and the data argument need not be parenthesized. Due to this, it is recommended that execTemplate
, which has much more intuitive behavior, be used instead of the template
action if at possible.template
action in action:{{- ... -}}
.block
has a structure similar to that of a define
action. It is equivalent to a define
action followed by a template
action:execTemplate
is essentially the same as the template
action, but provides access to the return value of the template and may be used as part of another action. Below is an example using execTemplate
:$x
that holds a slice/dictionary, writing $y := $x
and then mutating $y
via Append
/Set
/Del
/etc. will modify $x
as well. For example:cslice.AppendSlice
or a range
+ Set
call .templates.Slice
- This is a custom composite data type defined using an underlying data type []interface{} . It is of kind slice (similar to array) having interface{} type as its value and can be initialized using cslice
function. Retrieving specific element inside templates.Slice is by indexing its position number.cslice value1 value2 ...
cembed
and sdict
for example).
cslice 1 "2" (dict "three" 3) 4.5
returns [1 2 map[three:3] 4.5]
, having length of 4 and index positions from 0 to 3. Notice that thanks to type interface{} value, templates.Slice elements' inherent type does not change.false
. Under these circumstances if the element is a string then those elements will be included as a part of the []string slice and rest simply ignored. Also time.Time elements - their default string notation will be included. If none are string an empty []string slice is returned.true
it will return []string only if all elements are pure string, else <no value>
is returned.{{(cslice currentTime.Month 42 "YAPGDB").StringSlice}}
will return a slice [February YAGPDB]
. If the flag would have been set to true - {{...).StringSlice true}}, all elements in that slice were not strings and <no value>
is returned.templates.SDict
- This is a custom composite data type defined on an underlying data type map[string]interface{}. This is of kind map having string type as its key and interface{} type as that key's value and can be initialized using sdict
function. A map is key-value store. This means you store value and you access that value by a key. Map is an unordered list and the number of parameters to form key-value pairs must be even, difference to regular map is that templates.SDict
is ordered by its key. Retrieving specific element inside templates.Sdict is by indexing its key.sdict "key1" value1 "key2" value2 ...
dict
function, creating a templates.SDict type map, key must be of type string. Can be used for example in cembed
. If only one argument is passed to sdict
function having type map[string]interface{}; for example .ExecData and data retrieved from database can be of such type if sdict
was used, it is converted to a new sdict.sdict "one" 1 "two" 2 "three" (cslice 3 4) "five" 5.5
returns unordered map[five:5.5 one:1 three:[3 4] two:2]
, having length of four and index positions are its keys. Notice that thanks to type interface{} value, templates.SDict elements' inherent type does not change.{{(sdict "YAGPDB" "is cool").HasKey "YAGPDB"}}
would return true
.{{cslice.AppendSlice $dbSlice}}
or {{sdict $dbDict}}
. Recent changes to YAG have changed this: values with custom types are now serialized properly, making manual conversion unnecessary.(_)
matches any single character; a percent sign (%)
matches any sequence of zero or more characters.userID
of 0 to make it global (or any other number, but 0 is safe).
There can be 10 database interactions per CC, out of which dbTop/BottomEntries, dbCount, dbGetPattern, and dbDelMultiple may only be run twice. (50,10 for premium users).userID
argument or ID of the user if for example .User.ID
was used for dbSet
..ID
field, .Mention is still usable with correct userID field entry.createTicket author topic
nil
(to use the triggering member); user ID in form of a string or an integer; a user struct; or a member struct. The topic must be a string. Returns a template ticket struct on success.username#discrim
.{{.DiscordEpoch.Unix}}
would return in seconds > 1420070400.1h0m0s
.1m0s
.1s
.