From c016edce5d4d48c3ec870ffe1bbf1ddc0aee8d9c Mon Sep 17 00:00:00 2001 From: Joe Date: Mon, 22 Jul 2024 23:24:12 -0700 Subject: [PATCH] all: use custom language definition for YAGDPB templates --- content/docs/custom-commands/commands.md | 4 +- content/docs/moderation/moderation-tools.md | 2 +- .../docs/reference/custom-command-examples.md | 36 ++--- content/docs/reference/custom-embeds.md | 10 +- content/docs/reference/custom-interactions.md | 40 +++--- content/docs/reference/templates/functions.md | 10 +- .../reference/templates/syntax-and-data.md | 46 +++---- content/learn/beginner/control-flow-1.md | 18 +-- content/learn/beginner/datatypes-1.md | 12 +- content/learn/beginner/inputs-1.md | 24 ++-- content/learn/beginner/outputs-1.md | 18 +-- content/learn/intermediate/control-flow-2.md | 28 ++-- content/learn/intermediate/data-types-2.md | 8 +- content/learn/intermediate/database.md | 38 +++--- content/learn/intermediate/outputs-2.md | 22 +-- scripts/THIRD_PARTY_LICENSES | 26 ++++ scripts/highlight.mjs | 13 +- scripts/yag.tmLanguage.json | 129 ++++++++++++++++++ 18 files changed, 321 insertions(+), 163 deletions(-) create mode 100644 scripts/THIRD_PARTY_LICENSES create mode 100644 scripts/yag.tmLanguage.json diff --git a/content/docs/custom-commands/commands.md b/content/docs/custom-commands/commands.md index 63692cc..02d3776 100644 --- a/content/docs/custom-commands/commands.md +++ b/content/docs/custom-commands/commands.md @@ -25,7 +25,7 @@ a page to edit it. A new custom command has the default response: -```go +```yag Edit this to change the output of the custom command {{.CCID}}! ``` @@ -195,7 +195,7 @@ need to write that code yourself in the response. Example: -```go +```yag {{ if eq .Reaction.Emoji.APIName "😀" "⭐️" }} This is an allowed reaction! {{ else if eq .Reaction.Emoji.APIName "🦆" }} diff --git a/content/docs/moderation/moderation-tools.md b/content/docs/moderation/moderation-tools.md index d775672..12d798e 100644 --- a/content/docs/moderation/moderation-tools.md +++ b/content/docs/moderation/moderation-tools.md @@ -284,7 +284,7 @@ based on warning count, you can take advantage of the template scripting within Example: -```go +```yag {{/* Number of warnings at which action is to be taken (eg: for action to take place at 4 warnings set threshold to 4) */}} {{ $threshold := 4 }} {{ define "punish_check" }} diff --git a/content/docs/reference/custom-command-examples.md b/content/docs/reference/custom-command-examples.md index f962084..776faf5 100644 --- a/content/docs/reference/custom-command-examples.md +++ b/content/docs/reference/custom-command-examples.md @@ -30,7 +30,7 @@ YAGPDB has a built-in random response system for custom commands, but sometimes certain responses to occur. You can do this by creating a singular response and creating a variable with randInt. Then use an if else if statement like this to print out your desired output. -```go +```yag {{$var := randInt 100}} {{if lt $var 10}} @@ -52,7 +52,7 @@ following: Trigger type: `Join message in server channel` -```go +```yag {{if .UsernameHasInvite}} {{$silent := execAdmin "ban" .User.ID "ad blocked"}} {{else}} @@ -69,7 +69,7 @@ This particular command loops over a cslice and a sdict. Trigger type: `Command` Trigger: `range` -```go +```yag {{/* range can iterate over many things, let's start with slice */}} {{ $slice := cslice "YAGPDB " "is " "cool!" }} {{/* Here, we range over with 1 argument, meaning the dot will be set to current iteration value */}} @@ -89,7 +89,7 @@ your input that you are on. Range will work on any kind of slice/array. for example. If we wanted to look for all the entries in our database we can use range and index through them all in the following. -```go +```yag {{$lb := dbTopEntries "%" 100 0}} {{range $lb}} {{.UserID}} **:** {{.Key}} **:** {{.Value}} @@ -106,7 +106,7 @@ will have to use `dict`. Trigger type: `Command` Trigger: `dict` -```go +```yag {{ $dict := dict 0 "foobar" "hello" "world" }} {{/* Retrieve value with integer key with index */}} 0 - {{ index $dict 0 -}} @@ -131,7 +131,7 @@ are: Trigger type: `Command` Trigger: `send` -```go +```yag {{$args := parseArgs 2 "Syntax is " (carg "channel" "channel to send to") (carg "string" "text to send")}} @@ -145,7 +145,7 @@ This example consists of two custom commands, and after copy/paste `REPLACE-WITH actual custom command ID's in your system. This custom command is very complex, uses very many advanced functions, all it does, constructs a 10 second countdown timer command-system for given starting time. -```go +```yag {{$args := parseArgs 2 "" (carg "duration" "countdown-duration") (carg "string" "countdown-message")}} @@ -159,7 +159,7 @@ Second part of the custom commands, here we see, how `data`-part of exeCC was ma `sdict`and now we are calling those keys with `.ExecData` - for example `.ExecData.MessageID` sets new variable the same as stated in previous code. -```go +```yag {{$timeLeft := .ExecData.T.Sub currentTime}} {{$cntDownMessageHeader := print "Countdown Timer: " .ExecData.Message}} {{$formattedTimeLeft := humanizeDurationSeconds $timeLeft}} @@ -190,7 +190,7 @@ inserted to database begins with "notes\_". #### Save note -```go +```yag {{$args := parseArgs 2 "" (carg "string" "key") (carg "string" "value")}} @@ -201,7 +201,7 @@ Saved `{{$args.Get 0}}` as `{{$args.Get 1}}` #### Get note -```go +```yag {{$key := print "notes_" .StrippedMsg}} {{$note := dbGet .User.ID $key}} {{if $note}} @@ -215,7 +215,7 @@ Note: `{{$strippedKey}}` Created {{humanizeTimeSinceDays $note.CreatedAt}} ago: #### List user's notes -```go +```yag {{$notes := dbGetPattern .User.ID "notes_%" 100 0}} {{range $notes}} {{- $strippedKey := slice .Key 6 (len .Key)}} @@ -230,7 +230,7 @@ You don't have any notes :( With YAGPDB's database system, you can now add cooldowns to you custom commands. You can either make them global cooldowns or a per user cooldown. -```go +```yag {{/* CONFIGURATION HERE CHANGE VALUES AS NEEDED */}} {{/* 0 for per user, 1 for global */}} @@ -271,7 +271,7 @@ Trigger type: `Regex` Trigger: `\A` `BE SURE TO RESTRICT THE COMMAND TO A SINGLE CHANNEL` -```go +```yag {{/* If you are not doing (no twice msg in a row) or (role assignment for latest user) you can remove counter_user and by extension everything to do with $lastUser*/}} {{/* First time running command, set up initial values*/}} @@ -339,7 +339,7 @@ command take away roles from someone instead of giving them by simply using the Trigger type: `Command` Trigger: `giveRoleName` -```go +```yag {{if eq (len .Args) 3}} {{$allowedRoles := (cslice "Patron" "Quality Patron" "Paypal Donors")}} {{$role := (index .CmdArgs 1)}} @@ -365,7 +365,7 @@ only string keys), `sendMessage`, and `cembed`in action. Trigger type: `Command` Trigger: `bc` -```go +```yag {{if eq (len .Args) 3}} {{$channel := (index .CmdArgs 0)}} {{$msg:= (joinStr " " (slice .CmdArgs 1))}} @@ -398,7 +398,7 @@ custom commands. Trigger type: `Command` Trigger: `avatar` -```go +```yag {{$ln := (len .Args)}} {{$sizes := (cslice "16" "32" "64" "128" "256" "512" "1024" "2048" "4096")}} {{$err1 := "Wrong image size input format! Possible values: 16, 32, 64, 128, 256, 512, 1024, 2048, 4096."}} @@ -456,7 +456,7 @@ This command is used to replace suggestion bots. You can adapt it to your needs. Trigger type: `Command` Trigger: `suggest` -```go +```yag {{ $channel := 476178740133494784 }} {{/* Replace this with your suggestion channel ID */}} {{if gt (len .Args) 1}} @@ -487,7 +487,7 @@ emote file directly from Discord's database. Trigger type: `Command` Trigger: `bigemote` -```go +```yag {{ $matches := reFindAllSubmatches `<(a)?:.*?:(\d+)>` .StrippedMsg }} {{ if $matches }} {{ $animated := index $matches 0 1 }} diff --git a/content/docs/reference/custom-embeds.md b/content/docs/reference/custom-embeds.md index a25896a..46ec225 100644 --- a/content/docs/reference/custom-embeds.md +++ b/content/docs/reference/custom-embeds.md @@ -92,7 +92,7 @@ Embeds in custom commands are a little more difficult. Also, there is no generat To start off, we'll take a look at this example and break it down: -```go +```yag {{ $embed := cembed "title" "This is my title" "description" "This is my description." }} {{ sendMessage nil $embed }} ``` @@ -115,7 +115,7 @@ To make your code readable, especially for large embeds, **indents** may be used {{< callout title="Custom Command \"embed\"" >}} -```go +```yag {{ $advice := execAdmin "advice" }} {{ $topic := execAdmin "topic" }} {{ $catfact := execAdmin "catfact" }} @@ -165,7 +165,7 @@ is given as integer and you can convert a hex color to it using Up next, I have added some fields. This is a bit more difficult, but doable if you have understood it once. Let's break it down in this example: -```go +```yag "fields" (cslice (sdict "name" "Title of field 1" "value" "Description of field 1" "inline" false) (sdict "name" "Title of field 2" "value" "Description of field 2" "inline" false) @@ -189,7 +189,7 @@ You can display an image by simply pasting the link to it in the response, or by Trigger type: command trigger: `imageembed` -```go +```yag {{ $embed := cembed "image" (sdict "url" "https://i.imgur.com/ttIwOmn.png") }} {{ sendMessage nil $embed }} ``` @@ -227,7 +227,7 @@ Simple embeds work with switches, here is a list of them all: The values for simple embeds need to bet placed within quotes: -```go +```yag -se -title "This is my title" -desc "This is my description" -thumbnail "https://via.placeholder.com/300/" ``` diff --git a/content/docs/reference/custom-interactions.md b/content/docs/reference/custom-interactions.md index 9f7193f..9aa5aff 100644 --- a/content/docs/reference/custom-interactions.md +++ b/content/docs/reference/custom-interactions.md @@ -106,7 +106,7 @@ _interaction_ to be sent, meaning you'll only be able to show a modal after a us Let's examine how to make a basic button. -```go +```yag {{ $button := cbutton "label" "Button" }} {{ $message := complexMessage "buttons" $button }} {{ sendMessage nil $message }} @@ -128,7 +128,7 @@ Multiple buttons and menus can not have the same custom ID in one message. {{< /callout >}} -```go +```yag {{ $button := cbutton "label" "Button" "custom_id" "buttons-duck" }} {{ $message := complexMessage "buttons" $button }} {{ sendMessage nil $message }} @@ -158,7 +158,7 @@ Select menus are available in the following types: Here is an example of a select menu with three text options defined. -```go +```yag {{ $menu := cmenu "type" "text" "placeholder" "Choose a terrible thing" @@ -191,7 +191,7 @@ because in our code defining the select menu, we defined the `"value"` args of o The other menu types are more straightforward. `options` should not be defined for any menu type except `text`. -```go +```yag {{ $menu := cmenu "type" "role" "placeholder" "Choose roles who are secretly ducks" @@ -215,7 +215,7 @@ Setting default values in these select menus is a more involved process than for `default` value on each option, you must instead provide a `default_values` argument containing a slice of [default value structures](https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure). -```go +```yag {{ $adminRoleID := "1210128415689285642" }} {{ $soggysaussagesUserID := "329826270898683904" }} @@ -246,7 +246,7 @@ it as an `int64`, which would not work. A channel type menu optionally allows you to filter which channel types are made available for selection. You can use the `channel_types` argument which accepts a slice of [channel types](https://discord.com/developers/docs/resources/channel#channel-object-channel-types). -```go +```yag {{ $issuesChannel := "1210135699135926312" }} {{ $updatesChannel := "1210135938722693151" }} @@ -279,7 +279,7 @@ Link style buttons do not trigger _interactions_. {{< /callout >}} -```go +```yag {{ $button1 := cbutton "label" "Duck One" "custom_id" "buttons-duck-alpha" "style" "success" }} {{ $button2 := cbutton "emoji" (sdict "name" "🦆") "custom_id" "buttons-duck-beta" "style" "danger" }} {{ $button3 := cbutton "label" "Duck Three" "emoji" (sdict "name" "🦆") "url" "https://yagpdb.xyz" "style" "link" }} @@ -300,7 +300,7 @@ Confirming this behavior will be left as an exercise to the reader (you). Let's add in a select menu now. -```go +```yag {{ $button1 := cbutton "label" "Duck One" "custom_id" "buttons-duck-alpha" "style" "success" }} {{ $button2 := cbutton "emoji" (sdict "name" "🦆") "custom_id" "buttons-duck-beta" "style" "danger" }} {{ $button3 := cbutton "label" "Duck Three" "emoji" (sdict "name" "🦆") "url" "https://yagpdb.xyz" "style" "link" }} @@ -334,7 +334,7 @@ A row of components can have 5 buttons, **or** 1 menu. Let's say we want to play tic tac toe. If we just add 9 buttons into the same slice in our complex message, they'll just fill the first row with 5 buttons and the second row with 4, which isn't what we're looking for. Here's a solution: -```go +```yag {{ $blankEmoji := sdict "name" "⬜" }} {{ $row1 := cslice (cbutton "emoji" $blankEmoji "custom_id" "tictactoe-button-1" "style" "secondary") (cbutton "emoji" $blankEmoji "custom_id" "tictactoe-button-2" "style" "secondary") (cbutton "emoji" $blankEmoji "custom_id" "tictactoe-button-3" "style" "secondary") }} @@ -365,7 +365,7 @@ you need a button to attack them, and a button to befriend them. You also want e If you always had three enemies, this code would look something like this: -```go +```yag {{ $message := complexMessage "content" "Dragon, Ogre, Duck, attack you!" "buttons" (cslice @@ -391,7 +391,7 @@ A quick solution to this problem is to pass all of our buttons into one `"button `"menus"`, or even `"components"` with more components than the row can take (i.e 6+ buttons or 2+ menus) results in the function automatically distributing the components to new rows. -```go +```yag {{ $msg1 := complexMessage "content" "Message 1" "buttons" (cslice (cbutton "label" "Button") (cbutton "label" "Button") (cbutton "label" "Button") (cbutton "label" "Button") (cbutton "label" "Button") (cbutton "label" "Button") (cbutton "label" "Button")) @@ -450,7 +450,7 @@ end In scripting, this manifests from the following code: -```go +```yag {{ $row1 := cslice (cbutton "label" "Button") (cbutton "label" "Button") (cbutton "label" "Button") (cbutton "label" "Button") }} {{ $row2 := cslice (cbutton "label" "Button") (cbutton "label" "Button") }} {{ $row3 := cslice (cmenu "type" "mentionable") }} @@ -469,7 +469,7 @@ Which produces this message: When applying this new skill to our turn-based combat game, the code looks something like this: -```go +```yag {{ $rows := cslice }} {{ $enemies := cslice "Dragon" "Ogre" "Duck" }} @@ -501,7 +501,7 @@ fields are required, depending on if you are using a custom emoji or not. | ID | ID of the emoji, only necessary when using Custom Emoji. | | Name | Name of the emoji, use the unicode character here. Only necessary when using builtin unicode emojis. | -```go +```yag {{ $unicodeEmojiButton := cbutton "emoji" (sdict "name" "😀") }} {{ $customEmojiButton := cbutton "emoji" (sdict "id" "733037741532643428") }} {{ $animatedEmojiButton := cbutton "emoji" (sdict "id" "786307104247775302") }} @@ -559,7 +559,7 @@ button or uses a select menu. You cannot send a modal as a response to a user su | Custom ID | The Custom ID is referenced to trigger a custom command when the modal is submitted (which you'll need to do if you care about retrieving what the user inputted). | | Fields | A slice of [discordgo.TextInputComponent](https://discord.com/developers/docs/interactions/message-components#text-input-object)s. | -```go +```yag {{ $modal := sdict "title" "My Custom Modal" "custom_id" "modals-my_first_modal" @@ -599,7 +599,7 @@ Example: An UNO custom command system where all uno buttons are parsed in the sa with the trigger field `uno-`. This can take individual action for a button with custom ID `uno-join` and one with `uno-leave`. -```go +```yag {{ if eq .StrippedID "join" }} {{ sendResponse nil "You joined the UNO game!" }} {{ else if eq .StrippedID "leave" }} @@ -614,7 +614,7 @@ chosen. A modal's values are simply the values of each field in order. Example: A user has chosen an option in a select menu whose value is `blue-7`, triggering the following command which will determine if it is a playable card. -```go +```yag {{ $selectedOptions := .Values }} {{/* ["blue-7"] */}} {{ $cardRaw := index $selectedOptions 0 }} {{/* "blue-7" */}} {{ $cardSplit := split $cardRaw "-" }} {{/* ["blue" "7"] */}} @@ -640,7 +640,7 @@ Example 2: A user is setting up a new UNO game with a modal, they've filled out ![A modal for setting up a game of UNO](uno-modal.png) -```go +```yag {{ $numberOfDecks := index .Values 0 }} {{ $minCardsForUNO := index .Values 1 }} @@ -711,7 +711,7 @@ Possible followups: Here is a basic scenario where you need to use `editResponse` and `getResponse` to work with an _ephemeral_ followup message. You cannot use the standard `editMessage` or `getMessage` for this because it is an ephemeral message. -```go +```yag {{ $interactionToken := .Interaction.Token }} {{ sendResponse nil "Here's the first message!" }} {{ $followupID := sendResponseRetID $interactionToken (complexMessage "content" "Here's a sneaky one!" "ephemeral" true) }} @@ -723,7 +723,7 @@ message. You cannot use the standard `editMessage` or `getMessage` for this beca Here's a scenario where you would want to update a message. -```go +```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 }} diff --git a/content/docs/reference/templates/functions.md b/content/docs/reference/templates/functions.md index a4a7f18..9ab1492 100644 --- a/content/docs/reference/templates/functions.md +++ b/content/docs/reference/templates/functions.md @@ -92,7 +92,7 @@ convert the number to type _string_ before saving and later back to its original - To demonstrate execCC and .ExecData using the same CC. -```go +```yag {{ $yag := "YAGPDB rules! " }} {{ $ctr := 0 }} {{ $yourCCID := .CCID }} {{ if .ExecData }} @@ -170,7 +170,7 @@ about using interactions, [see here](/docs/reference/custom-interactions). - To demonstrate creating buttons and menus -```go +```yag {{ $funButton := cbutton "label" "My Custom Button" "custom_id" "duck-button" @@ -198,7 +198,7 @@ about using interactions, [see here](/docs/reference/custom-interactions). - To demonstrate responding with a modal (this must be triggered by a component or modal submission) -```go +```yag {{ $modal := sdict "title" "My Custom Modal" "custom_id" "modals-my_first_modal" @@ -211,7 +211,7 @@ about using interactions, [see here](/docs/reference/custom-interactions). - To demonstrate sending, getting, and editing responses (this must be triggered by a component or modal submission) -```go +```yag {{ $interactionToken := .Interaction.Token }} {{ sendResponse nil "Here's the first message!" }} {{ $followupID := sendResponseRetID $interactionToken (complexMessage "content" "Here's a sneaky one!" "ephemeral" true) }} @@ -223,7 +223,7 @@ about using interactions, [see here](/docs/reference/custom-interactions). - To demonstrate updating the triggering message (this must be triggered by a component or modal submission) -```go +```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 }} diff --git a/content/docs/reference/templates/syntax-and-data.md b/content/docs/reference/templates/syntax-and-data.md index 41f0ec8..637d764 100644 --- a/content/docs/reference/templates/syntax-and-data.md +++ b/content/docs/reference/templates/syntax-and-data.md @@ -367,16 +367,16 @@ the same type -> for example, `toFloat 1`. {{< /callout >}} -| Case | Example | -|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| if | `{{if (condition)}} output {{end}}`
Initialization statement can also be inside `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}}` | -| else if | `{{if (condition)}} output1 {{else if (condition)}} output2 {{end}}`
You can have as many `else if` statements as many different conditionals you have. | -| else | `{{if (condition)}} output1 {{else}} output2 {{end}}` | +| Case | Example | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| if | `{{if (condition)}} output {{end}}`
Initialization statement can also be inside `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}}` | +| else if | `{{if (condition)}} output1 {{else if (condition)}} output2 {{end}}`
You can have as many `else if` statements as many different conditionals you have. | +| else | `{{if (condition)}} output1 {{else}} output2 {{end}}` | ### Boolean Logic | Case | Example | -|------|-----------------------------------------------------| +| ---- | --------------------------------------------------- | | and | `{{if and (cond1) (cond2) (cond3)}} output {{end}}` | | not | `{{if not (condition)}} output {{end}}` | | or | `{{if or (cond1) (cond2) (cond3)}} output {{end}}` | @@ -384,7 +384,7 @@ the same type -> for example, `toFloat 1`. ### Comparison Operators | Case | Example | -|-----------------------------|--------------------------------------------------------| +| --------------------------- | ------------------------------------------------------ | | Equal: `eq` | `{{if eq .Channel.ID ########}} output {{end}}` | | Not equal: `ne` | `{{$x := 7}} {{$y := 8}} {{ne $x $y}}` returns `true` | | Less than: `lt` | `{{if lt (len .Args) 5}} output {{end}}` | @@ -418,7 +418,7 @@ 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.\ -```go +```yag {{/* range over an integer */}} {{range 2}}{{.}}{{end}} {{range $k, $v := toInt64 2}}{{$k}}{{$v}}{{end}} @@ -468,7 +468,7 @@ context, all errors have a method `Error` which is specified to return a message was thrown.) For example, the following example has different behavior depending on whether "Reaction blocked" is in the message of the error caught. -```go +```yag {{ try }} {{ addReactions "👋" }} added reactions successfully @@ -488,7 +488,7 @@ message of the error caught. 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. -```go +```yag {{/* efficiently search for an element in a sorted slice using binary search */}} {{ $xs := cslice 1 3 5 6 6 8 10 12 }} {{ $needle := 8 }} @@ -525,7 +525,7 @@ and also `range` action would need `$.User.ID` for example. Like `if` and `range` actions, `with` is concluded using `{{end}}` and variable scope extends to that point. -```go +```yag {{/* Shows the scope and how dot is affected by object's value in pipeline */}} {{ $x := "42" }} {{ with and ($z:= seq 0 5) ($x := seq 0 10) }} len $x: `{{ len $x }}` @@ -558,7 +558,7 @@ programming languages. To define an associated template, use the `define` action. It has the following syntax: -```go +```yag {{ define "template_name" }} {{/* associated template body */}} {{ end }} @@ -569,7 +569,7 @@ To define an associated template, use the `define` action. It has the following **Warning:** Template definitions must be at the top level of the custom command program; in other words, they cannot be nested in other actions (for example, an if action.) That is, the following custom command is invalid: -```go +```yag {{ if $cond }} {{ define "hi" }} hi! {{ end }} {{ end }} @@ -583,7 +583,7 @@ valid template program. Note that the first criterion precludes using variables template; that is, the following custom command is invalid, as the body of the associated template references a variable (`$name`) defined in an outer scope: -```go +```yag {{ $name := "YAG" }} {{ define "hello" }} Hello, {{ $name }}! @@ -602,7 +602,7 @@ To return a value from an associated template, use the `return` action. Encounte 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`: -```go +```yag {{ define "getOne" }} {{ return 1 }} {{ end }} ``` @@ -613,7 +613,7 @@ Note that it is not necessary for a value to be returned; `{{ return }}` by itse **Note:** Since all custom commands are themselves templates, using a `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. -```go +```yag {{ if not .CmdArgs }} no arguments passed {{ return }} {{/* anything beyond this point is not executed */}} @@ -645,7 +645,7 @@ action if at possible. Below is an example of the `template` action in action: -```go +```yag {{ define "sayHi" }} {{- if . -}} hi there, {{ . }} @@ -665,7 +665,7 @@ template definitions (and actions in general). `block` has a structure similar to that of a `define` action. It is equivalent to a `define` action followed by a `template` action: -```go +```yag {{ $name := "YAG" }} {{ block "sayHi" $name }} hi there, {{ . }} @@ -683,7 +683,7 @@ template definitions (and actions in general). `execTemplate` is essentially the same as the `template` action, but it provides access to the return value of the template and may be used as part of another action. Below is an example using `execTemplate`: -```go +```yag {{ define "factorial" }} {{- $n := 1 }} {{- range seq 2 (add . 1) }} @@ -716,7 +716,7 @@ called an empty interface which allows a value to be of any type. So any argumen undesirable in certain situations. That is, if you have a variable `$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: -```go +```yag {{ $x := sdict "k" "v" }} {{ $y := $x }} {{ $y.Set "k" "v2" }} {{/* modify $y */}} @@ -727,7 +727,7 @@ that is, modifying $y changed $x too. */}} If this behavior is undesirable, copy the slice/dictionary via `cslice.AppendSlice` or a `range` + `Set` call . -```go +```yag {{ $x := sdict "k" "v" }} {{ $y := sdict }} {{ range $k, $v := $x }} {{- $y.Set $k $v -}} {{ end }} @@ -765,7 +765,7 @@ YAGPDB]`. If the flag would have been set to true - \{{...).StringSlice true\}}, General example: -```go +```yag Creating a new cslice: {{ $x := (cslice "red" "red") }} **{{ $x }}** Appending to current cslice data and assigning newly created cslice to same variable: @@ -800,7 +800,7 @@ an unordered list and the number of parameters to form key-value pairs must be e | .HasKey "key" | Returns _bool_ true/false regarding whether the key is set or not e.g. `{{(sdict "YAGPDB" "is cool").HasKey "YAGPDB"}}` would return `true`. | | .Set "key" value | Changes/sets given key to a new value or creates new one, if no such key exists in _sdict_. | -```go +```yag Creating sdict: {{ $x := sdict "color1" "green" "color2" "red" }} **{{ $x }}** Retrieving key "color2": **{{ $x.Get "color2" }}** Changing "color2" to "yellow": {{ $x.Set "color2" "yellow" }} **{{ $x }}** diff --git a/content/learn/beginner/control-flow-1.md b/content/learn/beginner/control-flow-1.md index 02878ec..64cc277 100644 --- a/content/learn/beginner/control-flow-1.md +++ b/content/learn/beginner/control-flow-1.md @@ -16,7 +16,7 @@ incoming cars have passed, then check again. This is a simple example of a decis The most basic form of control flow is the `if` statement. An `if` statement checks a condition and executes a block of code if the condition is true. If the condition is false, the block of code is skipped. -```go +```yag {{ if eq 5 5 }} {{/* It is conventional, though not required, to consistently indent inner blocks of code with spaces or tabs. */}} Five is equal to five! @@ -28,7 +28,7 @@ functions in a [later section](#comparison-actions) on this page. We can expand this to execute a different block of code if the condition is false by using an `else` block: -```go +```yag {{ if eq 5 3 }} Five is equal to three! {{ else }} @@ -39,7 +39,7 @@ We can expand this to execute a different block of code if the condition is fals This can be further expanded to check multiple conditions using `else if`, which are checked sequentially until one of them is true: -```go +```yag {{ if eq 5 3 }} Five is equal to three! {{ else if eq 5 5 }} @@ -58,7 +58,7 @@ For example, consider how you would check whether a string `$s` is empty. One wa the string to zero using `if gt (len $s) 0`, but since empty strings are falsy, the more idiomatic solution is to simply write `if $s`, like so: -```go +```yag {{ $s := "" }} {{ if $s }} not empty @@ -78,7 +78,7 @@ for a condition and returns early via the `{{ return }}` action. Therefore, the Rewriting the second example to use these guard clauses yields the following code: -```go +```yag {{ if ne 5 3 }} Five is not equal to three! {{ return }} @@ -128,7 +128,7 @@ in the scope in which it was defined, as well as all nested scopes within. Let u coolness value, which should be true if the user's name is "alice". We can achieve this by defining a variable in the outer scope and re-assigning, using the `=` operator, its value in the inner scope: -```go +```yag {{ $isCool := false }} {{ if eq .User.Username "alice" }} @@ -174,7 +174,7 @@ block of code. 2. Predict the output of the following code snippets. If there is an error in the snippet, what is the cause of the error, and how can it be fixed? Also note down potential improvements to the code that make it easier to follow. - ```go + ```yag {{ $num1 := 10 }} {{ if $num1 }} {{ num1 := 6 }} @@ -186,7 +186,7 @@ block of code. {{ $num1 }} ``` - ```go + ```yag {{ $name := "John" }} {{ if eq $name "John" }} {{ $familyName := "Walters" }} @@ -194,7 +194,7 @@ block of code. My name is: {{ $name }} {{ $familyName }} ``` - ```go + ```yag {{ $mood := "happy" }} {{ if gt $mood "Sad" }} Be {{ $mood }}! diff --git a/content/learn/beginner/datatypes-1.md b/content/learn/beginner/datatypes-1.md index 90aebc5..fcfb84b 100644 --- a/content/learn/beginner/datatypes-1.md +++ b/content/learn/beginner/datatypes-1.md @@ -14,7 +14,7 @@ A variable is a way to store a value and give it a name, to which you can refer In Custom Commands, you define a variable by starting with a `$`, its name, and the assignment operator `:=`. To illustrate this, consider the following example: -```go +```yag {{ $name := "Alice" }} {{ $age := 42 }} {{ $isCool := true }} @@ -30,7 +30,7 @@ When and why this becomes necessary will be discussed in a later chapter. When debugging your code, you might have to figure out the type of a certain variable. You can do this by using the [`printf` function](/docs/reference/templates/functions/#string-manipulation) with the `%T` format verb, like so: -```go +```yag {{ $name := "Alice" }} {{ printf "%T" $name }} ``` @@ -47,12 +47,11 @@ In programming, we have similar categories, such as numbers, strings, and boolea Each of these categories has its own set of operations that can be performed on them. For instance, you can add two numbers together, but you cannot add two strings together (at least not in the way you might expect). - ### Strings A string is a sequence of zero or more characters. You can generally think of it as a word or a sentence. In the bot's template actions, you can create a string by enclosing some text in double quotes (`"`). For instance, -`"Hello, world!"` is a string. We call those *double-quoted strings*. +`"Hello, world!"` is a string. We call those _double-quoted strings_. Now, here we might run into a problem quite quickly: what if we want to include a double quote in our string? We can't just write `"Peter said "Hello, world!""`, as the bot would think the string ends at the quotes before `Hello` and not @@ -74,9 +73,8 @@ Please note that not all escape sequences are supported by Discord. #### Raw String Literals It should become relatively clear that a lot of new lines and other special characters can make a quoted string quite -hard to read. To make this easier, you can use backticks (`` ` ``) to create a *raw string literal*. A raw string -literal does not attempt to interpret its contents in any way, and will simply contain the text between the opening `` -` `` and closing `` ` `` unmodified---we cannot even escape a backtick to include one in the string, but we will later +hard to read. To make this easier, you can use backticks (`` ` ``) to create a _raw string literal_. A raw string +literal does not attempt to interpret its contents in any way, and will simply contain the text between the opening `` ` `` and closing `` ` `` unmodified---we cannot even escape a backtick to include one in the string, but we will later cover functions that solve this special case. ```txt diff --git a/content/learn/beginner/inputs-1.md b/content/learn/beginner/inputs-1.md index a9b8df0..2f82972 100644 --- a/content/learn/beginner/inputs-1.md +++ b/content/learn/beginner/inputs-1.md @@ -18,7 +18,7 @@ explore a more hands-on approach to parsing arguments. The first step is to define the arguments that the command will take. This is done using the aforementioned `parseArgs` function. The syntax is as follows: -```go +```yag {{ $args := parseArgs required_args error_message ...cargs }} ``` @@ -31,7 +31,7 @@ the user about what went wrong. The `...carg` is a variadic argument, that is, it can take any number of arguments. Each `carg` is a single argument definition. The `carg` function has the following syntax: -```go +```yag {{ carg <"type"> <"description"> }} ``` @@ -43,11 +43,11 @@ Following types are supported: - `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) + 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) + duration) The `description` is a human-readable description of the argument. This is used in the error message if the argument is not valid. @@ -55,7 +55,7 @@ not valid. Combining all of this, let's create a custom command that takes two arguments: a coolness level and a user that is part of the server to apply said level to. -```go +```yag {{ $args := parseArgs 2 "" (carg "int" "coolness level") (carg "member" "target member") }} ``` @@ -64,14 +64,14 @@ of the server to apply said level to. Currently, our code doesn't do anything with the arguments. To access the arguments, we use the `.Get` method on the `$args` variable. The syntax is as follows: -```go +```yag {{ $args.Get }} ``` The `index` is the position of the argument, starting from 0. The arguments are stored in the order they are defined in the `parseArgs` function call. Let us now modify our custom command to access these arguments: -```go +```yag {{ $args := parseArgs 2 "" (carg "int" "coolness level") (carg "member" "target member") }} coolness: {{ $args.Get 0 }} @@ -84,7 +84,7 @@ member: {{ ($args.Get 1).Nick }} Now, we want to limit the coolness level to a number between 0 and 100. We can do this by adding a simple check: -```go +```yag {{ $args := parseArgs 2 "" (carg "int" "coolness level") (carg "member" "target member") }} {{ if or (gt ($args.Get 0) 100) (lt ($args.Get 0) 0) }} @@ -99,7 +99,7 @@ member: {{ ($args.Get 1).Nick }} There is one major thing to note about this code: we're starting to repeat a lot of our `$args.Get N` calls! Let's fix that first. -```go +```yag {{ $args := parseArgs 2 "" (carg "int" "coolness level") (carg "member" "target member") }} {{ $coolness := $args.Get 0 }} @@ -118,7 +118,7 @@ Now, we can make use of another great feature of `parseArgs`: Certain types supp used to validate the input. For example, the `int` type supports two additional arguments that can be used to specify a range of valid values, such that the bot will do the validation for us. -```go +```yag {{ $args := parseArgs 2 "" (carg "int" "coolness level" 0 100) (carg "member" "target member") }} {{ $coolness := $args.Get 0 }} @@ -142,13 +142,13 @@ easier to read. If you have optional arguments, you can check if they were provided by using the `.IsSet` method on the `$args` variable. The syntax is as follows: -```go +```yag {{ $args.IsSet }} ``` Let us modify our custom command to introduce a third optional argument, a message to send to the user. -```go +```yag {{ $args := parseArgs 2 "" (carg "int" "coolness level" 0 100) (carg "member" "target member") (carg "string" "message") }} diff --git a/content/learn/beginner/outputs-1.md b/content/learn/beginner/outputs-1.md index 72c5fa3..9c9e015 100644 --- a/content/learn/beginner/outputs-1.md +++ b/content/learn/beginner/outputs-1.md @@ -3,8 +3,8 @@ title = "Outputs 1" weight = 210 +++ -In this chapter, we will go over two ways to output text from a custom command: using the *response*, and later on using -*template actions*. +In this chapter, we will go over two ways to output text from a custom command: using the _response_, and later on using +_template actions_. ## Response @@ -13,7 +13,7 @@ is triggered. For instance, create a new custom command with the following response: -```go +```yag Hello World. ``` @@ -30,7 +30,7 @@ This will make the bot respond "Hello World." in a new message when the command ### Actions As Output Earlier, we just made the bot respond with some static text. However, often we want our custom command to behave -differently depending on input. This is where *template actions* come in. +differently depending on input. This is where _template actions_ come in. Template actions are a way to dynamically change the output depending on various things, such as the user who triggered the command, the arguments passed to the command, or even the current time. @@ -38,7 +38,7 @@ the command, the arguments passed to the command, or even the current time. The bot evaluates the template action and replaces it with the result of the evaluation. For instance, the following code will make the bot respond with the server name when the command is triggered: -```go +```yag {{ .Guild.Name }} ``` @@ -46,14 +46,14 @@ As you can see, we use double curly braces (`{{` and `}}`) to denote a template The braces are essential: without these, the bot would simply respond with the text verbatim. A common pitfall we often see in the support channels is something like the following: -```go +```yag Hello .User.Username! ``` If we want to bring this a step further, we can combine the plain response with some template actions to make it a bit more nicer-looking: -```go +```yag Hey there {{ .User.Username }}! Welcome to {{ .Guild.Name }}! ``` @@ -67,14 +67,14 @@ Custom command functions allow you to perform calculations, add or remove roles channel, and lots more! The syntax is a little different to what you might be used to; All arguments to a function follow the function name itself, like so: -```go +```yag {{ add 5 3 }} ``` Some functions also return the result of their operation, which can be passed as arguments to other functions. For example: -```go +```yag {{ mult 5 (add 3 2) }} ``` diff --git a/content/learn/intermediate/control-flow-2.md b/content/learn/intermediate/control-flow-2.md index ea3d321..afa709a 100644 --- a/content/learn/intermediate/control-flow-2.md +++ b/content/learn/intermediate/control-flow-2.md @@ -21,7 +21,7 @@ map. If you have worked with other programming languages, `range` is roughly equ Consider the following program, which iterates over a slice of snacks and generates a line of output for each one. -```go +```yag {{ $snacks := cslice (sdict "Name" "chips" "Calories" 540) (sdict "Name" "peanuts" "Calories" 580) @@ -59,7 +59,7 @@ Observe that this output contains some unwanted whitespace; ideally, we want eac with no leading indentation. However, the extra whitespace is to be expected with our current program: the range block is indented, and YAGPDB simply reproduces that indentation. -```go +```yag {{ range $snacks }} {{ .Name }} contain {{ .Calories }} calories. ^^^^ @@ -68,7 +68,7 @@ is indented, and YAGPDB simply reproduces that indentation. One solution, then, is to remove the whitespace in our source code, save the final newline: -```go +```yag {{ range $snacks }}{{ .Name }} contains {{ .Calories }} calories {{ end }} ``` @@ -76,7 +76,7 @@ One solution, then, is to remove the whitespace in our source code, save the fin Although this version works, we have sacrificed readability. To retain the indentation in our source code while simultaneously avoiding unwanted whitespace in our output, we can use _trim markers_. -```go +```yag {{ range $snacks }} {{- .Name }} contain {{ .Calories }} calories. {{ end }} @@ -97,7 +97,7 @@ Use trim markers `{{-` and `-}}` to remove unwanted whitespace in output while k It is also possible to range over the (key, value) pairs of a map. To do so, assign two variables to the result of the range action, corresponding to the key and value respectively: -```go +```yag {{/* key is fruit; value is price */}} {{ $fruitPrices := sdict "pineapple" 3.50 "apple" 1.50 "banana" 2.60 }} @@ -125,7 +125,7 @@ There are a few other, less common ways to invoke the range action. - **Iterating _n_ times.** To iterate a fixed number of times, provide an integer to `range`: - ```go + ```yag {{ range 5 }} {{/* executed 5 times */}} {{ end }} @@ -134,7 +134,7 @@ There are a few other, less common ways to invoke the range action. To iterate over an interval of integers (say, the integers between `5` and `10` exclusive), use the `seq` function to generate a slice of integers and then range over the result: - ```go + ```yag {{ range seq 5 10 }} {{/* executed with the dot . set to 5, 6, 7, 8, 9 in succession */}} {{ end }} @@ -143,7 +143,7 @@ There are a few other, less common ways to invoke the range action. - **Single-variable range.** Instead of using the dot `.` to access the current element or value, one can also assign it to a variable: - ```go + ```yag {{ $sports := cslice "tennis" "basketball" "soccer" }} {{ range $sport := $sports }} {{/* executed with $sport set to "tennis", "basketball", "soccer" in succession */}} @@ -155,7 +155,7 @@ There are a few other, less common ways to invoke the range action. - **Range with else branch.** Similar to an if conditional, a range action may also have an `else` block, executed if the slice or map is empty. - ```go + ```yag {{ $empty := cslice }} {{ range $empty }} {{/* ... */}} @@ -168,7 +168,7 @@ There are a few other, less common ways to invoke the range action. The following program illustrates a common error for first-time users of `range`. -```go {hl_lines=4} +```yag {{ $nums := cslice 1 2 3 }} {{ range $nums }} {{/* ... */}} @@ -182,7 +182,7 @@ counterproductive here, as `.User.Username` tries to look up the field `User` on we really want is to access the global context data as it was before the range loop. One solution is to save the original context data in a variable prior to the loop: -```go +```yag {{ $dot := . }} {{ range ... }} {{ $dot.User.Username }} @@ -197,7 +197,7 @@ context data for you. In a range block, the dot is overwritten by elements of the slice or map, so code such as `.User.Username` is likely to error. If you need to access the global context data, do so through the predefined `$` variable instead. -```go +```yag {{ range ... }} {{ $.User.Username }} {{/* instead of .User.Username */}} {{ end }} @@ -212,7 +212,7 @@ error. If you need to access the global context data, do so through the predefin For instance, the following code loops as long as `$n` is not 1. In each iteration, `$n` is updated to either `n/2` or `3n+1`. -```go +```yag {{ $n := 19 }} {{ print $n " " -}} @@ -250,7 +250,7 @@ Just like the `if` action, `with` runs a block of code if the given expression i For instance, the following program -```go +```yag {{ $msg := "I <3 the YAGPDB documentation!" }} {{ with reFind `\d+` $msg }} pattern found in text; the dot {{ printf "%q" . }} contains the match diff --git a/content/learn/intermediate/data-types-2.md b/content/learn/intermediate/data-types-2.md index 23f3d0e..2263d6c 100644 --- a/content/learn/intermediate/data-types-2.md +++ b/content/learn/intermediate/data-types-2.md @@ -12,7 +12,7 @@ In this chapter, we will explore these data types in more detail. A slice is an ordered list of items. In custom commands, we can **c**reate a **slice** by providing the items in order to the `cslice` function: -```go +```yag {{ $fruits := cslice "banana" "orange" "apple" }} ``` @@ -31,7 +31,7 @@ For available operations on slices, please refer to [our template documentation] Empty slices are _falsy_, so can be used directly in conditional statements; it is not necessary to explicitly check the length: -```go +```yag {{ $users := cslice }} {{/* imagine this data is dynamically generated */}} {{ if $users }} one or more users @@ -58,7 +58,7 @@ Custom commands offer two kinds of maps: sdicts and dicts. A sdict only supports To create a map, provide a sequence of key-value pairs to the `sdict` or the `dict` function as appropriate: -```go +```yag {{ $fruitPrices := sdict "pineapple" 3.50 "apple" 1.50 "banana" 2.60 }} {{/* For readability, it's common to put each key/value pair on a new line. */}} @@ -81,7 +81,7 @@ For available operations on maps, please refer to [our template documentation][d Consider the following code that displays the value of `$fruitPrices` as defined in the previous example: -```go +```yag {{ $fruitPrices := sdict "pineapple" 3.50 "apple" 1.50 "banana" 2.60 }} {{ $fruitPrices }} ``` diff --git a/content/learn/intermediate/database.md b/content/learn/intermediate/database.md index c657f33..150327b 100644 --- a/content/learn/intermediate/database.md +++ b/content/learn/intermediate/database.md @@ -89,7 +89,7 @@ That concludes the overview, now let's get into basic interactions! `dbSet` creates or overwrites an entry in the database. -```go +```yag {{ dbSet user_id key value }} ``` @@ -112,7 +112,7 @@ We know how to create database entries; now, how do we retrieve them? This is where `dbGet` comes in: as its name suggests, it fetches the database entry with the given user ID and key. If no such entry exists, it returns `nil`. -```go +```yag {{ dbGet user_id key }} ``` @@ -120,7 +120,7 @@ If no such entry exists, it returns `nil`. `dbGet` returns the database entry object, not the value. To access the value, read the `Value` field: -```go +```yag {{ (dbGet user_id key).Value }} ``` @@ -131,7 +131,7 @@ If no such entry exists, it returns `nil`. Now we know how to create and fetch entries from the database. But a good program also frees unused storage, and custom commands are no exception. Use `dbDel` to delete a database entry: -```go +```yag {{ dbDel user_id key }} ``` @@ -147,7 +147,7 @@ otherwise be quite hard to achieve, or at least not very efficient. allowing you to further use the value. Said increment can be any valid number, that is, integers and float. Do note, however, that the return type of `dbIncr` is always a float, even if you use an integer for the increment argument. -```go +```yag {{dbIncr }} ``` @@ -155,7 +155,7 @@ however, that the return type of `dbIncr` is always a float, even if you use an not already exist. Try thinking about how you would implement a custom command that increases a given entry by a set amount, gets the value, but also sets a new entry if it doesn't already exist. -```go +```yag {{$db := dbGet .User.ID "someKey"}} {{$add := add (toFloat $db.Value) $x}} {{dbSet .User.ID "someKey" (str $add)}} @@ -173,7 +173,7 @@ Now you might want to set entries which get deleted after a while. To do so, you As we recall from the beginning, database entries have an `.ExpiresAt` field of type `time.Time`. The `dbSetExpire` function adds a timestamp to this field, telling the bot that we only want to use the DB entry until then. -```go +```yag {{dbSetExpire }} ``` @@ -181,7 +181,7 @@ The `Expires in` is given in seconds. A common use case for this function is a cooldown: As long as the entry exists, the command is still on cooldown. -```go +```yag {{ if $db := dbGet 2000 "cooldown" }} Command is on cooldown :( Cooldown will be over at {{ $db.ExpiresAt.Format "Mon 02 Jan 15:04:05" }} @@ -209,7 +209,7 @@ sorted by certain criteria. This is the only function interacting with multiple entries that doesn't return a slice. Since this function is fairly easy to understand, we'll start with that. As usual, first the syntax: -```go +```yag {{dbCount }} {{/* or */}} {{dbCount }} @@ -229,7 +229,7 @@ These functions return a slice of DB entry objects ordered by the value. `dbTopE `dbBottomEntries` by ascending value. Both of these are hard-limited to at most 100 entries (for premium as well), and this can be limited further with the `amount` argument. -```go +```yag {{dbTopEntries }} {{dbBottomEntries }} ``` @@ -240,7 +240,7 @@ using the `nSkip` argument. Now, to retrieve the value of each entry, we range over the given slice and access the `.Value` field: -```go +```yag {{$entries := dbTopEntries "someKey" 10 0}} {{range $entries}} Current Entry Value: {{.Value}} @@ -255,7 +255,7 @@ These two functions allow you to get multiple entries under one user ID with mat return a slice of entries sorted by value, just as the above functions. The only difference here is only the limitation to one `UserID` instead of all `UserID`s. -```go +```yag {{dbGetPattern }} {{/* or */}} {{dbGetPatternReverse }} @@ -269,7 +269,7 @@ code example, as it should be pretty clear how to do this. This function allows you to delete multiple entries in one go, instead of one at a time with `dbDel`. Its syntax is a little more intricate than other functions: -```go +```yag {{dbDelMultiple }} ``` @@ -286,7 +286,7 @@ most useful assigned to a variable. With all that in mind, the following example code deletes up to 100 matching entries with `Key`s matching the pattern `test%` and `UserID` of the current user, finally outputting the number of entries deleted: -```go +```yag {{$deleted := dbDelMultiple (sdict "userID" .User.ID "pattern" "test%") 100 0}} Deleted {{$deleted}} entries! ``` @@ -296,7 +296,7 @@ Deleted {{$deleted}} entries! This function returns the rank (that is, the position in an ordered list) of a specified entry in the set of entries matching criteria provided by `query`. -```go +```yag {{dbRank }} ``` @@ -309,7 +309,7 @@ matching criteria provided by `query`. As an example, to find the rank of the entry with the key `test` for the current user in all of this user's entries, you may want to use the following code: -```go +```yag {{$rank := dbRank (sdict "userID" .User.ID) .User.ID "test"}} The specified entry's rank is {{$rank}}. ``` @@ -351,7 +351,7 @@ that you might have to convert it back to its original type when retrieving. For to call to database will result in it becoming a `map[string] interface{}`. The following code will showcase this behavior: -```go +```yag {{$embed := cembed "description" "Serialization!"}} {{printf "Type before storing: %T" $embed}} {{dbSet .User.ID "serialization_example" $embed}} @@ -373,7 +373,7 @@ in scientific notation. Even converting back to an integer will not solve this, they will round ID numbers. To prevent this, simply convert them to a string before storing and converting back to `int` upon retrieving, like so: -```go +```yag {{ dbSet 2000 "someKey" (str .User.ID) }} {{ $userID_received := toInt (dbGet 2000 "someKey").Value }} {{ eq .User.ID $userID_received }} @@ -407,7 +407,7 @@ the `UserID` **or** `Key` differ. Each of the following line corresponds to and returns different database entries, since they don't share the same set of user ID and key. -```go +```yag {{ dbGet 20 "apple" }} {{ dbGet 20 "banana" }} {{ dbGet 30 "apple" }} diff --git a/content/learn/intermediate/outputs-2.md b/content/learn/intermediate/outputs-2.md index a008c5a..58c19eb 100644 --- a/content/learn/intermediate/outputs-2.md +++ b/content/learn/intermediate/outputs-2.md @@ -17,7 +17,7 @@ message after sending it. We will cover these functions in detail in the followi Let's get started with the simplest of them all, `sendMessage`. Its syntax is the following: -```go +```yag {{ sendMessage channel_id message_to_be_sent }} ``` @@ -33,7 +33,7 @@ By default, the bot will escape special mentions like `@everyone`, `@here`, and are not escaped by default). If you want to send a message with these mentions, you'll need to tell the bot to not escape them. You can do this by using the `sendMessageNoEscape` function instead of `sendMessage`. -```go +```yag {{ sendMessageNoEscape channel_id message_to_be_sent }} ``` @@ -42,13 +42,13 @@ escape them. You can do this by using the `sendMessageNoEscape` function instead If you want to store the ID of the message you just sent, for example to later edit it, use the `sendMessageRetID` function and assign the result to a variable. -```go +```yag {{ $messageID := sendMessageRetID channel_id message_to_be_sent }} ``` Naturally, we provide a variant of the `sendMessageRetID` function that does not escape mentions: -```go +```yag {{ $messageID := sendMessageNoEscapeRetID channel_id message_to_be_sent }} ``` @@ -63,7 +63,7 @@ structure as defined by the Discord API. We will illustrate this with a simple example. For a full breakdown of all available fields, please refer to our [custom embeds documentation](/docs/reference/custom-embeds). -```go +```yag {{ $embed := cembed "title" "This is a title" "description" "This is a description." @@ -96,7 +96,7 @@ field takes an integer color value, for which we can conveniently use hexadecima [Data Types 1](/learn/beginner/datatypes-1#integers), but it can also take a [decimal value](https://www.binaryhexconverter.com/hex-to-decimal-converter). -The `"fields"` field is a list (more precisely a *slice*) of dictionaries, where each dictionary represents a field in +The `"fields"` field is a list (more precisely a _slice_) of dictionaries, where each dictionary represents a field in the embed. Each field dictionary must contain a `"name"` and a `"value"` field, and can optionally contain an `"inline"` field. This field is a boolean that determines whether the field should be displayed inline with the previous field. @@ -120,7 +120,7 @@ For your convenience, we have [prefilled the above example][prefill] in the visu Sending a message is nice and all, but for the sake of keeping things clean, you might want to edit a message instead of creating a new one each time something changes. We provide the `editMessage` function for this purpose. -```go +```yag {{ editMessage channel_id message_id new_message_content }} ``` @@ -132,7 +132,7 @@ messages. For a quick demonstration, consider the following code: -```go +```yag {{ $messageID := sendMessageRetID nil "Hello, World!" }} {{ sleep 5 }} {{ editMessage nil $messageID "Goodbye, World!" }} @@ -149,7 +149,7 @@ fields, and provide the whole embed to `editMessage`. An elaborate example all within the same custom command looks like the following: -```go +```yag {{ $embed := cembed "title" "This is a title" "description" "This is a description." @@ -186,7 +186,7 @@ original embed object, convert and modify it as shown above, then send it back t `structToSdict` does not perform deep conversion. For a full conversion of an embed to a dictionary, you can use the following code snippet: -```go +```yag {{ if not .Message.Embeds }} {{/* no point converting non-existent embed */}} {{ return }} @@ -219,7 +219,7 @@ We learned how to send messages and embeds individually---we can also combine th have to use the `complexMessage` builder function. In this case, we will use the `"content"` and `"embed"` key to set the respective parts of our message: -```go +```yag {{ $embed := cembed "title" "This is a title" "description" "This is a description." diff --git a/scripts/THIRD_PARTY_LICENSES b/scripts/THIRD_PARTY_LICENSES new file mode 100644 index 0000000..4f2f037 --- /dev/null +++ b/scripts/THIRD_PARTY_LICENSES @@ -0,0 +1,26 @@ +The TextMate language definition for YAGPDB templates in yag.tmLanguage.json is adapted +from https://github.com/Ranger-4297/yagpdb-cc-ext. Its license is reproduced below. + +--- + +MIT License + +Copyright (c) 2023 Rhyker Wells + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/scripts/highlight.mjs b/scripts/highlight.mjs index 92df13b..490b05b 100644 --- a/scripts/highlight.mjs +++ b/scripts/highlight.mjs @@ -9,19 +9,24 @@ import { parseDocument } from 'htmlparser2'; import { findAll, textContent, replaceElement } from 'domutils'; import render from 'dom-serializer'; +const __dirname = dirname(fileURLToPath(import.meta.url)); + main(); async function main() { - const LIGHT_THEME = 'github-light-default'; - const DARK_THEME = 'github-dark-default'; + const LIGHT_THEME = 'vitesse-light'; + const DARK_THEME = 'vitesse-dark'; const start = Date.now(); - const files = await listBuiltContentFiles(); const highlighter = await createHighlighter({ themes: [LIGHT_THEME, DARK_THEME], langs: Object.keys(bundledLanguages), }); + const yagTemplateLang = JSON.parse(await readFile(join(__dirname, 'yag.tmLanguage.json'), { encoding: 'utf-8' })); + await highlighter.loadLanguage(yagTemplateLang); + + const files = await listBuiltContentFiles(); await Promise.all( files.map((filepath) => highlightFile(highlighter, filepath, { lightTheme: LIGHT_THEME, darkTheme: DARK_THEME })), ); @@ -31,7 +36,7 @@ async function main() { // Return the paths of all index.html files under the public/docs and public/learn directories. async function listBuiltContentFiles() { - const publicDir = join(dirname(fileURLToPath(import.meta.url)), '../public'); + const publicDir = join(__dirname, '../public'); const docsDir = join(publicDir, 'docs'); const docsIndexFiles = (await readdir(docsDir, { recursive: true, encoding: 'utf-8' })) diff --git a/scripts/yag.tmLanguage.json b/scripts/yag.tmLanguage.json new file mode 100644 index 0000000..a379222 --- /dev/null +++ b/scripts/yag.tmLanguage.json @@ -0,0 +1,129 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "yag", + "scopeName": "source.yag", + "patterns": [ + { + "begin": "\\{\\{(\\-\\s)?/\\*", + "end": "\\*/(\\s\\-)?\\}\\}", + "name": "punctuation.section.embedded.yag", + "contentName": "comment.block.yag" + }, + { + "begin": "\\{\\{(\\-\\s)?", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.yag" + } + }, + "end": "(\\s\\-)?\\}\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.yag" + } + }, + "patterns": [ + { + "match": ":?=", + "name": "keyword.operator.yag" + }, + { + "match": "\\b\\d+(\\.\\d+)?\\b", + "name": "constant.numeric.yag" + }, + { + "match": "\\$\\w+|\\$?\\.\\w*", + "name": "variable.other.yag" + }, + { + "match": "\\b(nil|true|false)\\b", + "name": "constant.language.yag" + }, + { + "match": "\\b(if|e(lse|nd)|r(ange|eturn)|t(emplate|ry)|b(loc|rea)k|define|w(ith|hile)|c(ontinue|atch))\\b", + "name": "keyword.control.yag" + }, + { + "match": "\\b(and|call|html|index|js|slice|urlquery|urlescape|urlunescape|l(t|en?)|not|or|print(f|ln)?|eq|ne|g(e|t))\\b", + "name": "support.function.yag" + }, + { + "match": "\\b(editMessage|editMessageNoEscape|pinMessage|publishMessage|publishResponse|sendDM|sendMessage|sendMessageNoEscape|sendMessageNoEscapeRetID|sendMessageRetID|sendTemplate|sendTemplateDM|unpinMessage|mentionEveryone|mentionHere|mentionRole|mentionRoleName|mentionRoleID|getRole|getRoleID|getRoleName|hasRole|hasRoleID|hasRoleName|targetHasRole|targetHasRoleID|targetHasRoleName|giveRole|giveRoleID|giveRoleName|addRole|addRoleID|addRoleName|takeRole|takeRoleID|takeRoleName|removeRole|removeRoleID|removeRoleName|setRoles|hasPermissions|targetHasPermissions|getTargetPermissionsIn|addMessageReactions|addReactions|addResponseReactions|deleteAllMessageReactions|deleteMessage|deleteMessageReaction|deleteResponse|deleteTrigger|getChannel|getChannelPins|getChannelOrThread|getPinCount|getMember|getMessage|getThread|addThreadMember|closeThread|createThread|deleteThread|editThread|openThread|removeThreadMember|createForumPost|deleteForumPost|pinForumPost|unpinForumPost|currentUserAgeHuman|currentUserAgeMinutes|currentUserCreated|reFind|reFindAll|reFindAllSubmatches|reReplace|reSplit|sleep|editChannelName|editChannelTopic|editNickname|onlineCount|onlineCountBots|sort|str|toString|toInt|toInt64|toFloat|toDuration|toRune|toByte|hasPrefix|hasSuffix|joinStr|lower|slice|split|title|trimSpace|upper|sanitizeText|reQuoteMeta|add|cbrt|div|fdiv|log|mathConst|max|min|mod|mult|pow|round|roundCeil|roundEven|roundFloor|sqrt|sub|bitwiseAnd|bitwiseOr|bitwiseXor|bitwiseNot|bitwiseAndNot|bitwiseLeftShift|bitwiseRightShift|humanizeThousands|dict|sdict|structToSdict|cembed|cbutton|cmenu|cmodal|cslice|complexMessage|complexMessageEdit|kindOf|adjective|in|inFold|json|jsonToSdict|noun|randInt|roleAbove|seq|shuffle|verb|hash|decodeBase64|encodeBase64|currentTime|parseTime|formatTime|loadLocation|newDate|snowflakeToTime|timestampToTime|weekNumber|humanizeDurationHours|humanizeDurationMinutes|humanizeDurationSeconds|humanizeTimeSinceDays|editResponse|editResponseNoEscape|ephemeralResponse|getResponse|sendModal|sendResponse|sendResponseNoEscape|sendResponseNoEscapeRetID|sendResponseRetID|updateMessage|updateMessageNoEscape|execTemplate|pastUsernames|pastNicknames|createTicket|exec|execAdmin|userArg|parseArgs|carg|execCC|scheduleUniqueCC|cancelScheduledUniqueCC|dbSet|dbSetExpire|dbIncr|dbGet|dbGetPattern|dbGetPatternReverse|dbDel|dbDelById|dbDelByID|dbDelMultiple|dbTopEntries|dbBottomEntries|dbCount|dbRank)\\b", + "name": "support.class.yag" + }, + { + "begin": "\"", + "end": "\"", + "name": "string.quoted.double.yag", + "patterns": [ + { + "include": "#string_placeholder" + }, + { + "include": "#string_escaped_char" + } + ] + }, + { + "begin": "'", + "end": "'", + "name": "string.quoted.single.yag", + "patterns": [ + { + "include": "#string_placeholder" + }, + { + "include": "#string_escaped_char" + } + ] + }, + { + "begin": "`", + "end": "`", + "name": "string.quoted.other.yag", + "patterns": [ + { + "include": "#string_placeholder" + } + ] + }, + { + "begin": "```", + "end": "```", + "name": "string.quoted.raw.yag", + "patterns": [ + { + "include": "#string_placeholder" + } + ] + } + ] + } + ], + "repository": { + "string_escaped_char": { + "patterns": [ + { + "match": "\\G(\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})|.)(?=')", + "name": "constant.character.escape.yag" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unknown-escape.yag" + } + ] + }, + "string_placeholder": { + "patterns": [ + { + "match": "(?x)%\n (\\d+\\$)? # field (argument #)\n [#0\\- +']* # flags\n [,;:_]? # separator character (AltiVec)\n ((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width\n (\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision\n [diouxXDOUeEfFgGaAcCsSqpnvtTbyYhHmMzZ%] # conversion type\n ", + "name": "constant.other.placeholder.yag" + }, + { + "match": "%", + "name": "invalid.illegal.placeholder.yag" + } + ] + } + } +}