AdvancedTagscript 3.2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- TagScriptEngine/__init__.py +227 -0
- TagScriptEngine/_warnings.py +88 -0
- TagScriptEngine/adapter/__init__.py +50 -0
- TagScriptEngine/adapter/discordadapters.py +596 -0
- TagScriptEngine/adapter/functionadapter.py +23 -0
- TagScriptEngine/adapter/intadapter.py +22 -0
- TagScriptEngine/adapter/objectadapter.py +35 -0
- TagScriptEngine/adapter/redbotadapters.py +161 -0
- TagScriptEngine/adapter/stringadapter.py +47 -0
- TagScriptEngine/block/__init__.py +130 -0
- TagScriptEngine/block/allowedmentions.py +60 -0
- TagScriptEngine/block/assign.py +43 -0
- TagScriptEngine/block/breakblock.py +41 -0
- TagScriptEngine/block/case.py +63 -0
- TagScriptEngine/block/command.py +141 -0
- TagScriptEngine/block/comment.py +29 -0
- TagScriptEngine/block/control.py +149 -0
- TagScriptEngine/block/cooldown.py +95 -0
- TagScriptEngine/block/count.py +68 -0
- TagScriptEngine/block/embedblock.py +306 -0
- TagScriptEngine/block/fiftyfifty.py +34 -0
- TagScriptEngine/block/helpers.py +164 -0
- TagScriptEngine/block/loosevariablegetter.py +40 -0
- TagScriptEngine/block/mathblock.py +164 -0
- TagScriptEngine/block/randomblock.py +51 -0
- TagScriptEngine/block/range.py +56 -0
- TagScriptEngine/block/redirect.py +42 -0
- TagScriptEngine/block/replaceblock.py +110 -0
- TagScriptEngine/block/require_blacklist.py +79 -0
- TagScriptEngine/block/shortcutredirect.py +23 -0
- TagScriptEngine/block/stopblock.py +38 -0
- TagScriptEngine/block/strf.py +70 -0
- TagScriptEngine/block/strictvariablegetter.py +38 -0
- TagScriptEngine/block/substr.py +25 -0
- TagScriptEngine/block/urlencodeblock.py +41 -0
- TagScriptEngine/exceptions.py +105 -0
- TagScriptEngine/interface/__init__.py +14 -0
- TagScriptEngine/interface/adapter.py +75 -0
- TagScriptEngine/interface/block.py +124 -0
- TagScriptEngine/interpreter.py +502 -0
- TagScriptEngine/py.typed +0 -0
- TagScriptEngine/utils.py +71 -0
- TagScriptEngine/verb.py +160 -0
- advancedtagscript-3.2.3.dist-info/METADATA +99 -0
- advancedtagscript-3.2.3.dist-info/RECORD +48 -0
- advancedtagscript-3.2.3.dist-info/WHEEL +5 -0
- advancedtagscript-3.2.3.dist-info/licenses/LICENSE +1 -0
- advancedtagscript-3.2.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from typing import Any, Dict, Optional, Tuple, cast
|
|
3
|
+
|
|
4
|
+
import discord
|
|
5
|
+
|
|
6
|
+
from ..verb import Verb
|
|
7
|
+
from ..interface import SimpleAdapter
|
|
8
|
+
from ..utils import escape_content
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import redbot # noqa: F401
|
|
12
|
+
except ModuleNotFoundError:
|
|
13
|
+
_has_redbot = False
|
|
14
|
+
else:
|
|
15
|
+
_has_redbot = True
|
|
16
|
+
|
|
17
|
+
from redbot.core.bot import Red
|
|
18
|
+
from redbot.core.commands import Command
|
|
19
|
+
from redbot.core.utils.chat_formatting import humanize_number, humanize_list
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__all__: Tuple[str, ...] = ("RedCommandAdapter", "RedBotAdapter")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RedCommandAdapter(SimpleAdapter["Command"]):
|
|
26
|
+
if not _has_redbot:
|
|
27
|
+
raise ImportError("A Red-DiscordBot instance is required to use this.", name="redbot")
|
|
28
|
+
|
|
29
|
+
def __init__(self, base: Command, *, signature: Optional[str] = None) -> None:
|
|
30
|
+
super().__init__(base=base)
|
|
31
|
+
self.signature: Optional[str] = signature
|
|
32
|
+
|
|
33
|
+
def update_attributes(self) -> None:
|
|
34
|
+
command: Command = self.object
|
|
35
|
+
self._attributes.update(
|
|
36
|
+
{
|
|
37
|
+
"name": command.name,
|
|
38
|
+
"cog_name": getattr(command, "cog_name", None),
|
|
39
|
+
"description": getattr(command, "description", None),
|
|
40
|
+
"aliases": humanize_list(list(getattr(command, "aliases", []))) or "None",
|
|
41
|
+
"qualified_name": command.qualified_name,
|
|
42
|
+
"signature": self.signature,
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def get_value(self, ctx: Verb) -> str:
|
|
47
|
+
should_escape: bool = False
|
|
48
|
+
if ctx.parameter is None:
|
|
49
|
+
return_value: str = self.object.qualified_name
|
|
50
|
+
else:
|
|
51
|
+
try:
|
|
52
|
+
value: Any = self._attributes[ctx.parameter]
|
|
53
|
+
except KeyError:
|
|
54
|
+
return # type: ignore
|
|
55
|
+
if isinstance(value, tuple):
|
|
56
|
+
value, should_escape = value
|
|
57
|
+
return_value: str = str(value) if value is not None else None # type: ignore
|
|
58
|
+
return escape_content(return_value) if should_escape else return_value
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class RedBotAdapter(SimpleAdapter["Red"]):
|
|
62
|
+
"""
|
|
63
|
+
The ``{bot}`` block with no parameters returns the bot's name & discriminator,
|
|
64
|
+
but passing the attributes listed below to the block payload will return that attribute instead.
|
|
65
|
+
|
|
66
|
+
**Usage:** ``{bot([attribute])}``
|
|
67
|
+
|
|
68
|
+
**Payload:** None
|
|
69
|
+
|
|
70
|
+
**Parameter:** attribute, None
|
|
71
|
+
|
|
72
|
+
Attributes
|
|
73
|
+
----------
|
|
74
|
+
id
|
|
75
|
+
The bot's Discord ID.
|
|
76
|
+
name
|
|
77
|
+
The bot's username.
|
|
78
|
+
discriminator
|
|
79
|
+
The bot's discriminator.
|
|
80
|
+
nick
|
|
81
|
+
The bot's nickname, if they have one, else their username.
|
|
82
|
+
created_at
|
|
83
|
+
The bot's creation date.
|
|
84
|
+
timestamp
|
|
85
|
+
The bot's creation date as a UTC timestamp.
|
|
86
|
+
mention
|
|
87
|
+
A formatted text that pings the bot.
|
|
88
|
+
verified
|
|
89
|
+
If the bot is verified or not.
|
|
90
|
+
shard_count (*)
|
|
91
|
+
The bot's total shard count.
|
|
92
|
+
servers (*)
|
|
93
|
+
Total server/guild count of the bot.
|
|
94
|
+
channels (*)
|
|
95
|
+
Total number of channels visible to the bot.
|
|
96
|
+
visible_users (*)
|
|
97
|
+
Total number of users visible to the bot.
|
|
98
|
+
total_users (*)
|
|
99
|
+
The bot's total user count.
|
|
100
|
+
unique_users (*)
|
|
101
|
+
The bot's unique user count.
|
|
102
|
+
percentage_chunked (*)
|
|
103
|
+
Percentage of chunked guilds the bot has.
|
|
104
|
+
|
|
105
|
+
.. warning::
|
|
106
|
+
Attributes denoting `(*)` can only be used by the bot owner.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
if not _has_redbot:
|
|
110
|
+
raise ImportError("A Red-DiscordBot instance is required to use this.")
|
|
111
|
+
|
|
112
|
+
def __init__(self, base: Red, *, owner: bool = True) -> None:
|
|
113
|
+
super().__init__(base=base)
|
|
114
|
+
self.is_owner: bool = owner
|
|
115
|
+
|
|
116
|
+
def update_attributes(self) -> None:
|
|
117
|
+
self.user: discord.ClientUser = cast(discord.ClientUser, self.object.user)
|
|
118
|
+
created_at: datetime.datetime = getattr(
|
|
119
|
+
self.user, "created_at", None
|
|
120
|
+
) or discord.utils.snowflake_time(self.user.id)
|
|
121
|
+
self._attributes.update(
|
|
122
|
+
{
|
|
123
|
+
"id": self.user.id,
|
|
124
|
+
"name": self.user.name,
|
|
125
|
+
"discriminator": self.user.discriminator,
|
|
126
|
+
"nick": self.user.display_name,
|
|
127
|
+
"mention": self.user.display_avatar.url,
|
|
128
|
+
"created_at": created_at,
|
|
129
|
+
"timestamp": int(created_at.timestamp()),
|
|
130
|
+
"verified": self.user.verified,
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
if self.is_owner:
|
|
134
|
+
visible_users: int = sum(len(g.members) for g in self.object.guilds)
|
|
135
|
+
total_users: int = sum(
|
|
136
|
+
g.member_count if g.member_count else 0 for g in self.object.guilds
|
|
137
|
+
)
|
|
138
|
+
owner_attributes: Dict[str, Any] = {
|
|
139
|
+
"shard_count": humanize_number(self.object.bot.shard_count),
|
|
140
|
+
"servers": humanize_number(len(self.object.guilds)),
|
|
141
|
+
"channels": humanize_number(sum(len(g.channels) for g in self.object.guilds)),
|
|
142
|
+
"visible_users": humanize_number(visible_users),
|
|
143
|
+
"total_users": humanize_number(total_users),
|
|
144
|
+
"unique_users": humanize_number(len(self.object.users)),
|
|
145
|
+
"percentage_chunked": visible_users / total_users * 100,
|
|
146
|
+
}
|
|
147
|
+
self._attributes.update(owner_attributes)
|
|
148
|
+
|
|
149
|
+
def get_value(self, ctx: Verb) -> str:
|
|
150
|
+
should_escape: bool = False
|
|
151
|
+
if ctx.parameter is None:
|
|
152
|
+
return_value: str = "{0.name}#{0.discriminator}".format(self.user)
|
|
153
|
+
else:
|
|
154
|
+
try:
|
|
155
|
+
value: Any = self._attributes[ctx.parameter]
|
|
156
|
+
except KeyError:
|
|
157
|
+
return # type: ignore
|
|
158
|
+
if isinstance(value, tuple):
|
|
159
|
+
value, should_escape = value
|
|
160
|
+
return_value: str = str(value) if value is not None else None # type: ignore
|
|
161
|
+
return escape_content(return_value) if should_escape else return_value
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Tuple
|
|
4
|
+
|
|
5
|
+
from ..interface import Adapter
|
|
6
|
+
from ..utils import escape_content
|
|
7
|
+
from ..verb import Verb
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__: Tuple[str, ...] = ("StringAdapter",)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class StringAdapter(Adapter):
|
|
14
|
+
__slots__: Tuple[str, ...] = ("string", "escape_content")
|
|
15
|
+
|
|
16
|
+
def __init__(self, string: str, *, escape: bool = False) -> None:
|
|
17
|
+
self.string: str = str(string)
|
|
18
|
+
self.escape_content = escape
|
|
19
|
+
|
|
20
|
+
def __repr__(self) -> str:
|
|
21
|
+
return f"<{type(self).__qualname__} string={repr(self.string)}>"
|
|
22
|
+
|
|
23
|
+
def get_value(self, ctx: Verb) -> str:
|
|
24
|
+
return self.return_value(self.handle_ctx(ctx))
|
|
25
|
+
|
|
26
|
+
def handle_ctx(self, ctx: Verb) -> str:
|
|
27
|
+
if ctx.parameter is None:
|
|
28
|
+
return self.string
|
|
29
|
+
try:
|
|
30
|
+
if "+" not in ctx.parameter:
|
|
31
|
+
index = int(ctx.parameter) - 1
|
|
32
|
+
splitter = " " if ctx.payload is None else ctx.payload
|
|
33
|
+
return self.string.split(splitter)[index]
|
|
34
|
+
else:
|
|
35
|
+
index = int(ctx.parameter.replace("+", "")) - 1
|
|
36
|
+
splitter = " " if ctx.payload is None else ctx.payload
|
|
37
|
+
if ctx.parameter.startswith("+"):
|
|
38
|
+
return splitter.join(self.string.split(splitter)[: index + 1])
|
|
39
|
+
elif ctx.parameter.endswith("+"):
|
|
40
|
+
return splitter.join(self.string.split(splitter)[index:])
|
|
41
|
+
else:
|
|
42
|
+
return self.string.split(splitter)[index]
|
|
43
|
+
except Exception:
|
|
44
|
+
return self.string
|
|
45
|
+
|
|
46
|
+
def return_value(self, string: str) -> str:
|
|
47
|
+
return escape_content(string) if self.escape_content else string
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Tuple
|
|
4
|
+
|
|
5
|
+
# isort: off
|
|
6
|
+
from .helpers import (
|
|
7
|
+
implicit_bool as implicit_bool,
|
|
8
|
+
helper_parse_if as helper_parse_if,
|
|
9
|
+
helper_parse_list_if as helper_parse_list_if,
|
|
10
|
+
helper_split as helper_split,
|
|
11
|
+
easier_helper_split as easier_helper_split,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
# isort: on
|
|
15
|
+
from .allowedmentions import (
|
|
16
|
+
AllowedMentionsBlock as AllowedMentionsBlock,
|
|
17
|
+
)
|
|
18
|
+
from .assign import (
|
|
19
|
+
AssignmentBlock as AssignmentBlock,
|
|
20
|
+
)
|
|
21
|
+
from .breakblock import (
|
|
22
|
+
BreakBlock as BreakBlock,
|
|
23
|
+
)
|
|
24
|
+
from .command import (
|
|
25
|
+
CommandBlock as CommandBlock,
|
|
26
|
+
OverrideBlock as OverrideBlock,
|
|
27
|
+
SequentialGather as SequentialGather,
|
|
28
|
+
)
|
|
29
|
+
from .control import (
|
|
30
|
+
AllBlock as AllBlock,
|
|
31
|
+
AnyBlock as AnyBlock,
|
|
32
|
+
IfBlock as IfBlock,
|
|
33
|
+
)
|
|
34
|
+
from .cooldown import (
|
|
35
|
+
CooldownBlock as CooldownBlock,
|
|
36
|
+
)
|
|
37
|
+
from .embedblock import (
|
|
38
|
+
EmbedBlock as EmbedBlock,
|
|
39
|
+
)
|
|
40
|
+
from .fiftyfifty import (
|
|
41
|
+
FiftyFiftyBlock as FiftyFiftyBlock,
|
|
42
|
+
)
|
|
43
|
+
from .loosevariablegetter import (
|
|
44
|
+
LooseVariableGetterBlock as LooseVariableGetterBlock,
|
|
45
|
+
)
|
|
46
|
+
from .mathblock import (
|
|
47
|
+
MathBlock as MathBlock,
|
|
48
|
+
)
|
|
49
|
+
from .randomblock import (
|
|
50
|
+
RandomBlock as RandomBlock,
|
|
51
|
+
)
|
|
52
|
+
from .range import (
|
|
53
|
+
RangeBlock as RangeBlock,
|
|
54
|
+
)
|
|
55
|
+
from .redirect import (
|
|
56
|
+
RedirectBlock as RedirectBlock,
|
|
57
|
+
)
|
|
58
|
+
from .replaceblock import (
|
|
59
|
+
PythonBlock as PythonBlock,
|
|
60
|
+
ReplaceBlock as ReplaceBlock,
|
|
61
|
+
)
|
|
62
|
+
from .require_blacklist import (
|
|
63
|
+
BlacklistBlock as BlacklistBlock,
|
|
64
|
+
RequireBlock as RequireBlock,
|
|
65
|
+
)
|
|
66
|
+
from .shortcutredirect import (
|
|
67
|
+
ShortCutRedirectBlock as ShortCutRedirectBlock,
|
|
68
|
+
)
|
|
69
|
+
from .stopblock import (
|
|
70
|
+
StopBlock as StopBlock,
|
|
71
|
+
)
|
|
72
|
+
from .strf import (
|
|
73
|
+
StrfBlock as StrfBlock,
|
|
74
|
+
)
|
|
75
|
+
from .strictvariablegetter import (
|
|
76
|
+
StrictVariableGetterBlock as StrictVariableGetterBlock,
|
|
77
|
+
)
|
|
78
|
+
from .substr import (
|
|
79
|
+
SubstringBlock as SubstringBlock,
|
|
80
|
+
)
|
|
81
|
+
from .urlencodeblock import (
|
|
82
|
+
URLEncodeBlock as URLEncodeBlock,
|
|
83
|
+
)
|
|
84
|
+
from .case import (
|
|
85
|
+
UpperBlock as UpperBlock,
|
|
86
|
+
LowerBlock as LowerBlock,
|
|
87
|
+
)
|
|
88
|
+
from .count import (
|
|
89
|
+
CountBlock as CountBlock,
|
|
90
|
+
LengthBlock as LengthBlock,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
__all__: Tuple[str, ...] = (
|
|
94
|
+
"implicit_bool",
|
|
95
|
+
"helper_parse_if",
|
|
96
|
+
"helper_parse_list_if",
|
|
97
|
+
"helper_split",
|
|
98
|
+
"easier_helper_split",
|
|
99
|
+
"AllowedMentionsBlock",
|
|
100
|
+
"AllBlock",
|
|
101
|
+
"AnyBlock",
|
|
102
|
+
"AssignmentBlock",
|
|
103
|
+
"BlacklistBlock",
|
|
104
|
+
"BreakBlock",
|
|
105
|
+
"SequentialGather",
|
|
106
|
+
"CommandBlock",
|
|
107
|
+
"CooldownBlock",
|
|
108
|
+
"EmbedBlock",
|
|
109
|
+
"FiftyFiftyBlock",
|
|
110
|
+
"IfBlock",
|
|
111
|
+
"LooseVariableGetterBlock",
|
|
112
|
+
"MathBlock",
|
|
113
|
+
"OverrideBlock",
|
|
114
|
+
"PythonBlock",
|
|
115
|
+
"RandomBlock",
|
|
116
|
+
"RangeBlock",
|
|
117
|
+
"RedirectBlock",
|
|
118
|
+
"ReplaceBlock",
|
|
119
|
+
"RequireBlock",
|
|
120
|
+
"ShortCutRedirectBlock",
|
|
121
|
+
"StopBlock",
|
|
122
|
+
"StrfBlock",
|
|
123
|
+
"StrictVariableGetterBlock",
|
|
124
|
+
"SubstringBlock",
|
|
125
|
+
"URLEncodeBlock",
|
|
126
|
+
"UpperBlock",
|
|
127
|
+
"LowerBlock",
|
|
128
|
+
"CountBlock",
|
|
129
|
+
"LengthBlock",
|
|
130
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from typing import Dict, List, Optional, Tuple, Union
|
|
2
|
+
|
|
3
|
+
from ..interface import Block
|
|
4
|
+
from ..interpreter import Context
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AllowedMentionsBlock(Block):
|
|
8
|
+
"""
|
|
9
|
+
The ``{allowedmentions}`` block attempts to enable mentioning of roles.
|
|
10
|
+
Passing no parameter enables mentioning of all roles within the message
|
|
11
|
+
content. However passing a role name or ID to the block parameter allows
|
|
12
|
+
mentioning of that specific role only. Multiple role name or IDs can be
|
|
13
|
+
included, separated by a comma ",". By default, mentioning is only
|
|
14
|
+
triggered if the execution author has "manage server" permissions. However,
|
|
15
|
+
using the "override" keyword as a payload allows mentioning to be triggered
|
|
16
|
+
by anyone.
|
|
17
|
+
|
|
18
|
+
**Usage:** ``{allowedmentions(<role, None>):["override", None]}``
|
|
19
|
+
|
|
20
|
+
**Aliases:** ``mentions``
|
|
21
|
+
|
|
22
|
+
**Payload:** "override", None
|
|
23
|
+
|
|
24
|
+
**Parameter:** role, None
|
|
25
|
+
|
|
26
|
+
**Examples:** ::
|
|
27
|
+
|
|
28
|
+
{allowedmentions}
|
|
29
|
+
{allowedmentions:override}
|
|
30
|
+
{allowedmentions(@Admin, Moderator):override}
|
|
31
|
+
{allowedmentions(763522431151112265, 812949167190048769)}
|
|
32
|
+
{mentions(763522431151112265, 812949167190048769):override}
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
ACCEPTED_NAMES: Tuple[str, ...] = ("allowedmentions", "mentions")
|
|
36
|
+
PAYLOADS: Tuple[str, ...] = ("override",)
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def will_accept(cls, ctx: Context) -> bool:
|
|
40
|
+
if ctx.verb.payload and ctx.verb.payload not in cls.PAYLOADS:
|
|
41
|
+
return False
|
|
42
|
+
return super().will_accept(ctx)
|
|
43
|
+
|
|
44
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
45
|
+
actions: Optional[Dict[str, Union[bool, List[str]]]] = ctx.response.actions.get(
|
|
46
|
+
"allowed_mentions", None
|
|
47
|
+
)
|
|
48
|
+
if actions:
|
|
49
|
+
return None
|
|
50
|
+
if not (param := ctx.verb.parameter):
|
|
51
|
+
ctx.response.actions["allowed_mentions"] = {
|
|
52
|
+
"mentions": True,
|
|
53
|
+
"override": True if ctx.verb.payload else False,
|
|
54
|
+
}
|
|
55
|
+
return ""
|
|
56
|
+
ctx.response.actions["allowed_mentions"] = {
|
|
57
|
+
"mentions": [r.strip() for r in param.split(",")],
|
|
58
|
+
"override": True if ctx.verb.payload else False,
|
|
59
|
+
}
|
|
60
|
+
return ""
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Tuple
|
|
4
|
+
|
|
5
|
+
from ..adapter import StringAdapter
|
|
6
|
+
from ..interface import verb_required_block
|
|
7
|
+
from ..interpreter import Context
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__: Tuple[str, ...] = ("AssignmentBlock",)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AssignmentBlock(verb_required_block(False, parameter=True)): # type: ignore
|
|
14
|
+
"""
|
|
15
|
+
Variables are useful for choosing a value and referencing it later in a tag.
|
|
16
|
+
Variables can be referenced using brackets as any other block.
|
|
17
|
+
|
|
18
|
+
**Usage:** ``{=(<name>):<value>}``
|
|
19
|
+
|
|
20
|
+
**Aliases:** ``assign, let, var``
|
|
21
|
+
|
|
22
|
+
**Payload:** value
|
|
23
|
+
|
|
24
|
+
**Parameter:** name
|
|
25
|
+
|
|
26
|
+
**Examples:** ::
|
|
27
|
+
|
|
28
|
+
{=(prefix):!}
|
|
29
|
+
The prefix here is `{prefix}`.
|
|
30
|
+
# The prefix here is `!`.
|
|
31
|
+
|
|
32
|
+
{assign(day):Monday}
|
|
33
|
+
{if({day}==Wednesday):It's Wednesday my dudes!|The day is {day}.}
|
|
34
|
+
# The day is Monday.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
ACCEPTED_NAMES: Tuple[str, ...] = ("=", "assign", "let", "var")
|
|
38
|
+
|
|
39
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
40
|
+
if ctx.verb.parameter is None:
|
|
41
|
+
return None
|
|
42
|
+
ctx.response.variables[ctx.verb.parameter] = StringAdapter(str(ctx.verb.payload))
|
|
43
|
+
return ""
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Tuple, cast
|
|
4
|
+
|
|
5
|
+
from ..interface import Block
|
|
6
|
+
from ..interpreter import Context
|
|
7
|
+
from . import helper_parse_if
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__: Tuple[str, ...] = ("BreakBlock",)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BreakBlock(Block):
|
|
14
|
+
"""
|
|
15
|
+
The break block will force the tag output to only be the payload of this block, if the passed
|
|
16
|
+
expresssion evaluates true.
|
|
17
|
+
If no message is provided to the payload, the tag output will be empty.
|
|
18
|
+
|
|
19
|
+
This differs from the `StopBlock` as the stop block stops all tagscript processing and returns
|
|
20
|
+
its message while the break block continues to process blocks. If command blocks exist after
|
|
21
|
+
the break block, they will still execute.
|
|
22
|
+
|
|
23
|
+
**Usage:** ``{break(<expression>):[message]}``
|
|
24
|
+
|
|
25
|
+
**Aliases:** ``short, shortcircuit``
|
|
26
|
+
|
|
27
|
+
**Payload:** message
|
|
28
|
+
|
|
29
|
+
**Parameter:** expression
|
|
30
|
+
|
|
31
|
+
**Examples:** ::
|
|
32
|
+
|
|
33
|
+
{break({args}==):You did not provide any input.}
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
ACCEPTED_NAMES: Tuple[str, ...] = ("break", "shortcircuit", "short")
|
|
37
|
+
|
|
38
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
39
|
+
if helper_parse_if(cast(str, ctx.verb.parameter)):
|
|
40
|
+
ctx.response.body = ctx.verb.payload if ctx.verb.payload != None else "" # noqa: E711
|
|
41
|
+
return ""
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Tuple
|
|
4
|
+
|
|
5
|
+
from ..interface import Block
|
|
6
|
+
from ..interpreter import Context
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__: Tuple[str, ...] = ("UpperBlock", "LowerBlock")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UpperBlock(Block):
|
|
13
|
+
"""Converts the given text to uppercase.
|
|
14
|
+
|
|
15
|
+
**Usage:** ``{upper([text]))}``
|
|
16
|
+
|
|
17
|
+
**Aliases:** ``uppercase, upper``
|
|
18
|
+
|
|
19
|
+
**Payload:** None
|
|
20
|
+
|
|
21
|
+
**Parameter:** text
|
|
22
|
+
|
|
23
|
+
**Examples:** ::
|
|
24
|
+
|
|
25
|
+
The text is {lower(ThIs Is A TeXt)}!
|
|
26
|
+
# The text is THIS IS A TEXT!
|
|
27
|
+
|
|
28
|
+
You have entered {lower({args})}!
|
|
29
|
+
# You have entered HELLO WORLD!
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
ACCEPTED_NAMES: Tuple[str, ...] = ("upper", "uppercase")
|
|
33
|
+
|
|
34
|
+
def process(self, ctx: Context) -> str:
|
|
35
|
+
text = str(ctx.verb.parameter).upper()
|
|
36
|
+
return "" if text == "NONE" else text
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class LowerBlock(Block):
|
|
40
|
+
"""Converts the given text to lowercase.
|
|
41
|
+
|
|
42
|
+
**Usage:** ``{lower([text])}``
|
|
43
|
+
|
|
44
|
+
**Aliases:** ``lowercase, lower``
|
|
45
|
+
|
|
46
|
+
**Payload:** None
|
|
47
|
+
|
|
48
|
+
**Parameter:** text
|
|
49
|
+
|
|
50
|
+
**Examples:** ::
|
|
51
|
+
|
|
52
|
+
The text is {lower(ThIs Is A TeXt)}!
|
|
53
|
+
# The text is this is a text!
|
|
54
|
+
|
|
55
|
+
You have entered {lower({args})}!
|
|
56
|
+
# You have entered hello world!
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
ACCEPTED_NAMES: Tuple[str, ...] = ("lower", "lowercase")
|
|
60
|
+
|
|
61
|
+
def process(self, ctx: Context) -> str:
|
|
62
|
+
text = str(ctx.verb.parameter).lower()
|
|
63
|
+
return "" if text == "none" else text
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from types import TracebackType
|
|
5
|
+
from typing import Any, Awaitable, Generator, Iterator, List, Optional, Tuple, Type, TypeVar
|
|
6
|
+
|
|
7
|
+
from ..interface import Block, verb_required_block
|
|
8
|
+
from ..interpreter import Context
|
|
9
|
+
|
|
10
|
+
T = TypeVar("T")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
__all__: Tuple[str, ...] = ("CommandBlock", "OverrideBlock", "SequentialGather")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CommandBlock(verb_required_block(True, payload=True)): # type: ignore
|
|
17
|
+
"""
|
|
18
|
+
Run a command as if the tag invoker had ran it. Only 3 command
|
|
19
|
+
blocks can be used in a tag.
|
|
20
|
+
|
|
21
|
+
**Usage:** ``{command:<command>}``
|
|
22
|
+
|
|
23
|
+
**Aliases:** ``c, com, command``
|
|
24
|
+
|
|
25
|
+
**Payload:** command
|
|
26
|
+
|
|
27
|
+
**Parameter:** None
|
|
28
|
+
|
|
29
|
+
**Examples:** ::
|
|
30
|
+
|
|
31
|
+
{c:ping}
|
|
32
|
+
# invokes ping command
|
|
33
|
+
|
|
34
|
+
{c:ban {target(id)} Chatflood/spam}
|
|
35
|
+
# invokes ban command on the pinged user with the reason as "Chatflood/spam"
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
ACCEPTED_NAMES: Tuple[str, ...] = ("c", "com", "command")
|
|
39
|
+
|
|
40
|
+
def __init__(self, limit: int = 3):
|
|
41
|
+
self.limit = limit
|
|
42
|
+
super().__init__()
|
|
43
|
+
|
|
44
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
45
|
+
command = ctx.verb.payload.strip() # type: ignore
|
|
46
|
+
actions = ctx.response.actions.get("commands")
|
|
47
|
+
if actions:
|
|
48
|
+
if len(actions) >= self.limit:
|
|
49
|
+
return f"`COMMAND LIMIT REACHED ({self.limit})`"
|
|
50
|
+
else:
|
|
51
|
+
ctx.response.actions["commands"] = []
|
|
52
|
+
ctx.response.actions["commands"].append(command)
|
|
53
|
+
return ""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class OverrideBlock(Block):
|
|
57
|
+
"""
|
|
58
|
+
Override a command's permission requirements. This can override
|
|
59
|
+
mod, admin, or general user permission requirements when running commands
|
|
60
|
+
with the :ref:`Command Block`. Passing no parameter will default to overriding
|
|
61
|
+
all permissions.
|
|
62
|
+
|
|
63
|
+
In order to add a tag with the override block, the tag author must have ``Manage
|
|
64
|
+
Server`` permissions.
|
|
65
|
+
|
|
66
|
+
This will not override bot owner commands or command checks.
|
|
67
|
+
|
|
68
|
+
**Usage:** ``{override(["admin"|"mod"|"permissions"]):[command]}``
|
|
69
|
+
|
|
70
|
+
**Payload:** command
|
|
71
|
+
|
|
72
|
+
**Parameter:** "admin", "mod", "permissions"
|
|
73
|
+
|
|
74
|
+
**Examples:** ::
|
|
75
|
+
|
|
76
|
+
{override}
|
|
77
|
+
# overrides all commands and permissions
|
|
78
|
+
|
|
79
|
+
{override(admin)}
|
|
80
|
+
# overrides commands that require the admin role
|
|
81
|
+
|
|
82
|
+
{override(permissions)}
|
|
83
|
+
{override(mod)}
|
|
84
|
+
# overrides commands that require the mod role or have user permission requirements
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
ACCEPTED_NAMES: Tuple[str, ...] = ("override",)
|
|
88
|
+
|
|
89
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
90
|
+
param = ctx.verb.parameter
|
|
91
|
+
if not param:
|
|
92
|
+
ctx.response.actions["overrides"] = {"admin": True, "mod": True, "permissions": True}
|
|
93
|
+
return ""
|
|
94
|
+
|
|
95
|
+
param = param.strip().lower()
|
|
96
|
+
if param not in ("admin", "mod", "permissions"):
|
|
97
|
+
return None
|
|
98
|
+
overrides = ctx.response.actions.get(
|
|
99
|
+
"overrides", {"admin": False, "mod": False, "permissions": False}
|
|
100
|
+
)
|
|
101
|
+
overrides[param] = True
|
|
102
|
+
ctx.response.actions["overrides"] = overrides
|
|
103
|
+
return ""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class SequentialGather(Awaitable[T]):
|
|
107
|
+
"""
|
|
108
|
+
Use this to run commands sequentially.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
awaitables : Tuple[Awaitable[T]]
|
|
113
|
+
the awaitables to be run sequentially.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
`List[T]`
|
|
118
|
+
the result object.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
def __init__(self, *awaitables: Awaitable[T]) -> None:
|
|
122
|
+
self.__awaitables: Tuple[Awaitable[T], ...] = awaitables
|
|
123
|
+
self.__iterator: Iterator[Awaitable[T]] = iter(self.__awaitables)
|
|
124
|
+
self.__results: List[T] = []
|
|
125
|
+
self.__lock: asyncio.Lock = asyncio.Lock()
|
|
126
|
+
|
|
127
|
+
def __await__(self) -> Generator[Any, None, List[T]]:
|
|
128
|
+
return self.__aenter__().__await__()
|
|
129
|
+
|
|
130
|
+
async def __aenter__(self) -> List[T]:
|
|
131
|
+
async with self.__lock:
|
|
132
|
+
for coro in self.__iterator:
|
|
133
|
+
await asyncio.sleep(0.10)
|
|
134
|
+
result: T = await coro
|
|
135
|
+
self.__results.append(result)
|
|
136
|
+
return self.__results
|
|
137
|
+
|
|
138
|
+
async def __aexit__(
|
|
139
|
+
self, exc_type: Type[BaseException], exc_value: BaseException, traceback: TracebackType
|
|
140
|
+
) -> None:
|
|
141
|
+
pass
|