mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-04 04:56:49 +00:00
better parameters handling, implement import export
This commit is contained in:
parent
e4f38c76a9
commit
5198f7d83b
19 changed files with 250 additions and 174 deletions
|
|
@ -245,6 +245,8 @@ public partial class CommandTree
|
|||
Commands.MessageDelete(var param, var flags) => ctx.Execute<ProxiedMessage>(Message, m => m.GetMessage(ctx, param.target.MessageId, flags.GetReplyFormat(), true, false)),
|
||||
Commands.MessageEdit(var param, var flags) => ctx.Execute<ProxiedMessage>(MessageEdit, m => m.EditMessage(ctx, param.target.MessageId, param.new_content, flags.regex, flags.mutate_space, flags.append, flags.prepend, flags.clear_embeds, flags.clear_attachments)),
|
||||
Commands.MessageReproxy(var param, _) => ctx.Execute<ProxiedMessage>(MessageReproxy, m => m.ReproxyMessage(ctx, param.target.MessageId)),
|
||||
Commands.Import(var param, _) => ctx.Execute<ImportExport>(Import, m => m.Import(ctx, param.url)),
|
||||
Commands.Export(_, _) => ctx.Execute<ImportExport>(Export, m => m.Export(ctx)),
|
||||
_ =>
|
||||
// this should only ever occur when deving if commands are not implemented...
|
||||
ctx.Reply(
|
||||
|
|
@ -256,10 +258,6 @@ public partial class CommandTree
|
|||
return HandleConfigCommand(ctx);
|
||||
if (ctx.Match("serverconfig", "guildconfig", "scfg"))
|
||||
return HandleServerConfigCommand(ctx);
|
||||
if (ctx.Match("import"))
|
||||
return ctx.Execute<ImportExport>(Import, m => m.Import(ctx));
|
||||
if (ctx.Match("export"))
|
||||
return ctx.Execute<ImportExport>(Export, m => m.Export(ctx));
|
||||
if (ctx.Match("log"))
|
||||
if (ctx.Match("channel"))
|
||||
return ctx.Execute<ServerConfig>(LogChannel, m => m.SetLogChannel(ctx), true);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public static class ContextParametersExt
|
|||
);
|
||||
}
|
||||
|
||||
public static async Task<List<PKMember>> ParamResolveMembers(this Context ctx, string param_name)
|
||||
public static async Task<List<PKMember>?> ParamResolveMembers(this Context ctx, string param_name)
|
||||
{
|
||||
return await ctx.Parameters.ResolveParameter(
|
||||
ctx, param_name,
|
||||
|
|
@ -36,7 +36,7 @@ public static class ContextParametersExt
|
|||
);
|
||||
}
|
||||
|
||||
public static async Task<List<PKGroup>> ParamResolveGroups(this Context ctx, string param_name)
|
||||
public static async Task<List<PKGroup>?> ParamResolveGroups(this Context ctx, string param_name)
|
||||
{
|
||||
return await ctx.Parameters.ResolveParameter(
|
||||
ctx, param_name,
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ public class Parameters
|
|||
return new Parameter.ChannelRef(await ctx.Rest.GetChannelOrNull(channelId) ?? throw new PKError($"Channel {channelId} not found"));
|
||||
case uniffi.commands.Parameter.GuildRef(var guildId):
|
||||
return new Parameter.GuildRef(await ctx.Rest.GetGuildOrNull(guildId) ?? throw new PKError($"Guild {guildId} not found"));
|
||||
case uniffi.commands.Parameter.Null:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ public class ImportExport
|
|||
_dmCache = dmCache;
|
||||
}
|
||||
|
||||
public async Task Import(Context ctx)
|
||||
public async Task Import(Context ctx, string? inputUrl)
|
||||
{
|
||||
var inputUrl = ctx.RemainderOrNull() ?? ctx.Message.Attachments.FirstOrDefault()?.Url;
|
||||
inputUrl = inputUrl ?? ctx.Message.Attachments.FirstOrDefault()?.Url;
|
||||
if (inputUrl == null) throw Errors.NoImportFilePassed;
|
||||
|
||||
if (!Core.MiscUtils.TryMatchUri(inputUrl, out var url))
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ public class Switch
|
|||
await DoSwitchCommand(ctx, []);
|
||||
}
|
||||
|
||||
private async Task DoSwitchCommand(Context ctx, ICollection<PKMember> members)
|
||||
private async Task DoSwitchCommand(Context ctx, ICollection<PKMember>? members)
|
||||
{
|
||||
if (members == null) members = new List<PKMember>();
|
||||
// Make sure there are no dupes in the list
|
||||
// We do this by checking if removing duplicate member IDs results in a list of different length
|
||||
if (members.Select(m => m.Id).Distinct().Count() != members.Count) throw Errors.DuplicateSwitchMembers;
|
||||
|
|
@ -101,10 +102,12 @@ public class Switch
|
|||
await ctx.Reply($"{Emojis.Success} Switch moved to <t:{newSwitchTime}> ({newSwitchDeltaStr} ago).");
|
||||
}
|
||||
|
||||
public async Task SwitchEdit(Context ctx, List<PKMember> newMembers, bool newSwitch = false, bool first = false, bool remove = false, bool append = false, bool prepend = false)
|
||||
public async Task SwitchEdit(Context ctx, List<PKMember>? newMembers, bool newSwitch = false, bool first = false, bool remove = false, bool append = false, bool prepend = false)
|
||||
{
|
||||
ctx.CheckSystem();
|
||||
|
||||
if (newMembers == null) newMembers = new List<PKMember>();
|
||||
|
||||
await using var conn = await ctx.Database.Obtain();
|
||||
var currentSwitch = await ctx.Repository.GetLatestSwitch(ctx.System.Id);
|
||||
if (currentSwitch == null)
|
||||
|
|
@ -170,8 +173,10 @@ public class Switch
|
|||
await DoEditCommand(ctx, []);
|
||||
}
|
||||
|
||||
public async Task DoEditCommand(Context ctx, ICollection<PKMember> members)
|
||||
public async Task DoEditCommand(Context ctx, ICollection<PKMember>? members)
|
||||
{
|
||||
if (members == null) members = new List<PKMember>();
|
||||
|
||||
// Make sure there are no dupes in the list
|
||||
// We do this by checking if removing duplicate member IDs results in a list of different length
|
||||
if (members.Select(m => m.Id).Distinct().Count() != members.Count) throw Errors.DuplicateSwitchMembers;
|
||||
|
|
|
|||
|
|
@ -158,9 +158,9 @@ pub fn cmds() -> impl Iterator<Item = Command> {
|
|||
.map(apply_list_opts);
|
||||
|
||||
let group_modify_members_cmd = [
|
||||
command!(group_target, "add", MemberRefs => "group_add_member")
|
||||
command!(group_target, "add", Optional(MemberRefs) => "group_add_member")
|
||||
.flag(("all", ["a"])),
|
||||
command!(group_target, ("remove", ["delete", "del", "rem"]), MemberRefs => "group_remove_member")
|
||||
command!(group_target, ("remove", ["delete", "del", "rem"]), Optional(MemberRefs) => "group_remove_member")
|
||||
.flag(("all", ["a"])),
|
||||
]
|
||||
.into_iter();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use super::*;
|
|||
pub fn cmds() -> impl Iterator<Item = Command> {
|
||||
let help = ("help", ["h"]);
|
||||
[
|
||||
command!(("dashboard", ["dash"]) => "dashboard"),
|
||||
command!("explain" => "explain"),
|
||||
command!(help => "help")
|
||||
.flag(("foo", OpaqueString)) // todo: just for testing
|
||||
|
|
|
|||
|
|
@ -1 +1,9 @@
|
|||
use super::*;
|
||||
|
||||
pub fn cmds() -> impl Iterator<Item = Command> {
|
||||
[
|
||||
command!("import", Optional(("url", OpaqueStringRemainder)) => "import"),
|
||||
command!("export" => "export"),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,12 @@ pub mod system;
|
|||
|
||||
pub mod utils;
|
||||
|
||||
use command_parser::{command, command::Command, parameter::ParameterKind::*, tokens};
|
||||
use command_parser::{
|
||||
command,
|
||||
command::Command,
|
||||
parameter::{Optional, Parameter, ParameterKind::*, Remainder, Skip},
|
||||
tokens,
|
||||
};
|
||||
|
||||
pub fn all() -> impl Iterator<Item = Command> {
|
||||
(help::cmds())
|
||||
|
|
@ -34,6 +39,7 @@ pub fn all() -> impl Iterator<Item = Command> {
|
|||
.chain(autoproxy::cmds())
|
||||
.chain(debug::cmds())
|
||||
.chain(message::cmds())
|
||||
.chain(import_export::cmds())
|
||||
.map(|cmd| {
|
||||
cmd.hidden_flag(("plaintext", ["pt"]))
|
||||
.hidden_flag(("raw", ["r"]))
|
||||
|
|
|
|||
|
|
@ -182,11 +182,11 @@ pub fn cmds() -> impl Iterator<Item = Command> {
|
|||
[
|
||||
command!(member_keep_proxy => "member_keepproxy_show")
|
||||
.help("Shows a member's keep-proxy setting"),
|
||||
command!(member_keep_proxy, ("value", Toggle) => "member_keepproxy_update")
|
||||
command!(member_keep_proxy, Skip(("value", Toggle)) => "member_keepproxy_update")
|
||||
.help("Changes a member's keep-proxy setting"),
|
||||
command!(member_server_keep_proxy => "member_server_keepproxy_show")
|
||||
.help("Shows a member's server-specific keep-proxy setting"),
|
||||
command!(member_server_keep_proxy, ("value", Toggle) => "member_server_keepproxy_update")
|
||||
command!(member_server_keep_proxy, Skip(("value", Toggle)) => "member_server_keepproxy_update")
|
||||
.help("Changes a member's server-specific keep-proxy setting"),
|
||||
command!(member_server_keep_proxy, ("clear", ["c"]) => "member_server_keepproxy_clear")
|
||||
.flag(("yes", ["y"]))
|
||||
|
|
@ -303,9 +303,9 @@ pub fn cmds() -> impl Iterator<Item = Command> {
|
|||
.map(|cmd| cmd.flags(get_list_flags()));
|
||||
|
||||
let member_add_remove_group_cmds = [
|
||||
command!(member_group, "add", ("groups", GroupRefs) => "member_group_add")
|
||||
command!(member_group, "add", Optional(("groups", GroupRefs)) => "member_group_add")
|
||||
.help("Adds a member to one or more groups"),
|
||||
command!(member_group, ("remove", ["rem"]), ("groups", GroupRefs) => "member_group_remove")
|
||||
command!(member_group, ("remove", ["rem"]), Optional(("groups", GroupRefs)) => "member_group_remove")
|
||||
.help("Removes a member from one or more groups"),
|
||||
]
|
||||
.into_iter();
|
||||
|
|
|
|||
|
|
@ -9,23 +9,22 @@ pub fn cmds() -> impl Iterator<Item = Command> {
|
|||
let copy = ("copy", ["add", "duplicate", "dupe"]);
|
||||
let out = "out";
|
||||
|
||||
let edit_flags = [
|
||||
("first", ["f"]),
|
||||
("remove", ["r"]),
|
||||
("append", ["a"]),
|
||||
("prepend", ["p"]),
|
||||
];
|
||||
|
||||
[
|
||||
command!(switch, out => "switch_out"),
|
||||
command!(switch, r#move, OpaqueString => "switch_move"), // TODO: datetime parsing
|
||||
command!(switch, delete => "switch_delete").flag(("all", ["clear", "c"])),
|
||||
command!(switch, edit, out => "switch_edit_out"),
|
||||
command!(switch, edit, MemberRefs => "switch_edit")
|
||||
.flag(("first", ["f"]))
|
||||
.flag(("remove", ["r"]))
|
||||
.flag(("append", ["a"]))
|
||||
.flag(("prepend", ["p"])),
|
||||
command!(switch, copy, MemberRefs => "switch_copy")
|
||||
.flag(("first", ["f"]))
|
||||
.flag(("remove", ["r"]))
|
||||
.flag(("append", ["a"]))
|
||||
.flag(("prepend", ["p"])),
|
||||
command!(switch, edit, Optional(MemberRefs) => "switch_edit").flags(edit_flags),
|
||||
command!(switch, copy, Optional(MemberRefs) => "switch_copy").flags(edit_flags),
|
||||
command!(switch, ("commands", ["help"]) => "switch_commands"),
|
||||
command!(switch, MemberRefs => "switch_do"),
|
||||
command!(switch, Optional(MemberRefs) => "switch_do"),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ pub fn edit() -> impl Iterator<Item = Command> {
|
|||
let system_proxy_cmd = [
|
||||
command!(system_proxy => "system_show_proxy_current")
|
||||
.help("Shows your system's proxy setting for the guild you are in"),
|
||||
command!(system_proxy, Toggle => "system_toggle_proxy_current")
|
||||
command!(system_proxy, Skip(Toggle) => "system_toggle_proxy_current")
|
||||
.help("Toggle your system's proxy for the guild you are in"),
|
||||
command!(system_proxy, GuildRef => "system_show_proxy")
|
||||
.help("Shows your system's proxy setting for a guild"),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub enum FlagValueMatchError {
|
|||
pub struct Flag {
|
||||
name: SmolStr,
|
||||
aliases: Vec<SmolStr>,
|
||||
value: Option<ParameterKind>,
|
||||
value: Option<Parameter>,
|
||||
}
|
||||
|
||||
impl Display for Flag {
|
||||
|
|
@ -22,7 +22,7 @@ impl Display for Flag {
|
|||
write!(f, "-{}", self.name)?;
|
||||
if let Some(value) = self.value.as_ref() {
|
||||
write!(f, "=")?;
|
||||
Parameter::from(*value).fmt(f)?;
|
||||
value.fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -58,8 +58,8 @@ impl Flag {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn value(mut self, param: ParameterKind) -> Self {
|
||||
self.value = Some(param);
|
||||
pub fn value(mut self, param: impl Into<Parameter>) -> Self {
|
||||
self.value = Some(param.into());
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -72,8 +72,8 @@ impl Flag {
|
|||
&self.name
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Option<ParameterKind> {
|
||||
self.value
|
||||
pub fn get_value(&self) -> Option<&Parameter> {
|
||||
self.value.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_aliases(&self) -> impl Iterator<Item = &str> {
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ fn next_token<'a>(
|
|||
// iterate over tokens and run try_match
|
||||
for token in possible_tokens {
|
||||
let is_match_remaining_token =
|
||||
|token: &Token| matches!(token, Token::Parameter(param) if param.kind().remainder());
|
||||
|token: &Token| matches!(token, Token::Parameter(param) if param.is_remainder());
|
||||
// check if this is a token that matches the rest of the input
|
||||
let match_remaining = is_match_remaining_token(token);
|
||||
// either use matched param or rest of the input if matching remaining
|
||||
|
|
|
|||
|
|
@ -24,12 +24,23 @@ pub enum ParameterValue {
|
|||
PrivacyLevel(String),
|
||||
Toggle(bool),
|
||||
Avatar(String),
|
||||
Null,
|
||||
}
|
||||
|
||||
fn is_remainder(kind: ParameterKind) -> bool {
|
||||
matches!(
|
||||
kind,
|
||||
ParameterKind::OpaqueStringRemainder | ParameterKind::MemberRefs | ParameterKind::GroupRefs
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Parameter {
|
||||
name: SmolStr,
|
||||
kind: ParameterKind,
|
||||
remainder: bool,
|
||||
optional: bool,
|
||||
skip: bool,
|
||||
}
|
||||
|
||||
impl Parameter {
|
||||
|
|
@ -40,106 +51,36 @@ impl Parameter {
|
|||
pub fn kind(&self) -> ParameterKind {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Parameter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
pub fn remainder(mut self) -> Self {
|
||||
self.remainder = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn optional(mut self) -> Self {
|
||||
self.optional = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn skip(mut self) -> Self {
|
||||
self.skip = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_remainder(&self) -> bool {
|
||||
self.remainder
|
||||
}
|
||||
|
||||
pub fn is_optional(&self) -> bool {
|
||||
self.optional
|
||||
}
|
||||
|
||||
pub fn is_skip(&self) -> bool {
|
||||
self.skip
|
||||
}
|
||||
|
||||
pub fn match_value(&self, input: &str) -> Result<ParameterValue, SmolStr> {
|
||||
match self.kind {
|
||||
ParameterKind::OpaqueString => {
|
||||
write!(f, "[{}]", self.name)
|
||||
}
|
||||
ParameterKind::OpaqueStringRemainder => {
|
||||
write!(f, "[{}]...", self.name)
|
||||
}
|
||||
ParameterKind::MemberRef => write!(f, "<target member>"),
|
||||
ParameterKind::MemberRefs => write!(f, "<member 1> <member 2> <member 3>..."),
|
||||
ParameterKind::GroupRef => write!(f, "<target group>"),
|
||||
ParameterKind::GroupRefs => write!(f, "<group 1> <group 2> <group 3>..."),
|
||||
ParameterKind::SystemRef => write!(f, "<target system>"),
|
||||
ParameterKind::MessageRef => write!(f, "<target message>"),
|
||||
ParameterKind::ChannelRef => write!(f, "<target channel>"),
|
||||
ParameterKind::GuildRef => write!(f, "<target guild>"),
|
||||
ParameterKind::MemberPrivacyTarget => write!(f, "<privacy target>"),
|
||||
ParameterKind::GroupPrivacyTarget => write!(f, "<privacy target>"),
|
||||
ParameterKind::SystemPrivacyTarget => write!(f, "<privacy target>"),
|
||||
ParameterKind::PrivacyLevel => write!(f, "[privacy level]"),
|
||||
ParameterKind::Toggle => write!(f, "on/off"),
|
||||
ParameterKind::Avatar => write!(f, "<url|@mention>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParameterKind> for Parameter {
|
||||
fn from(value: ParameterKind) -> Self {
|
||||
Parameter {
|
||||
name: value.default_name().into(),
|
||||
kind: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&str, ParameterKind)> for Parameter {
|
||||
fn from((name, kind): (&str, ParameterKind)) -> Self {
|
||||
Parameter {
|
||||
name: name.into(),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ParameterKind {
|
||||
OpaqueString,
|
||||
OpaqueStringRemainder,
|
||||
MemberRef,
|
||||
MemberRefs,
|
||||
GroupRef,
|
||||
GroupRefs,
|
||||
SystemRef,
|
||||
MessageRef,
|
||||
ChannelRef,
|
||||
GuildRef,
|
||||
MemberPrivacyTarget,
|
||||
GroupPrivacyTarget,
|
||||
SystemPrivacyTarget,
|
||||
PrivacyLevel,
|
||||
Toggle,
|
||||
Avatar,
|
||||
}
|
||||
|
||||
impl ParameterKind {
|
||||
pub(crate) fn default_name(&self) -> &str {
|
||||
match self {
|
||||
ParameterKind::OpaqueString => "string",
|
||||
ParameterKind::OpaqueStringRemainder => "string",
|
||||
ParameterKind::MemberRef => "target",
|
||||
ParameterKind::MemberRefs => "targets",
|
||||
ParameterKind::GroupRef => "target",
|
||||
ParameterKind::GroupRefs => "targets",
|
||||
ParameterKind::SystemRef => "target",
|
||||
ParameterKind::MessageRef => "target",
|
||||
ParameterKind::ChannelRef => "target",
|
||||
ParameterKind::GuildRef => "target",
|
||||
ParameterKind::MemberPrivacyTarget => "member_privacy_target",
|
||||
ParameterKind::GroupPrivacyTarget => "group_privacy_target",
|
||||
ParameterKind::SystemPrivacyTarget => "system_privacy_target",
|
||||
ParameterKind::PrivacyLevel => "privacy_level",
|
||||
ParameterKind::Toggle => "toggle",
|
||||
ParameterKind::Avatar => "avatar",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn remainder(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
ParameterKind::OpaqueStringRemainder
|
||||
| ParameterKind::MemberRefs
|
||||
| ParameterKind::GroupRefs
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn match_value(&self, input: &str) -> Result<ParameterValue, SmolStr> {
|
||||
match self {
|
||||
// TODO: actually parse image url
|
||||
ParameterKind::OpaqueString | ParameterKind::OpaqueStringRemainder => {
|
||||
Ok(ParameterValue::OpaqueString(input.into()))
|
||||
|
|
@ -217,13 +158,130 @@ impl ParameterKind {
|
|||
.map_err(|_| SmolStr::new("invalid guild ID")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn skip_if_cant_match(&self) -> Option<Option<ParameterValue>> {
|
||||
impl Display for Parameter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.kind {
|
||||
ParameterKind::OpaqueString => {
|
||||
write!(f, "[{}]", self.name)
|
||||
}
|
||||
ParameterKind::OpaqueStringRemainder => {
|
||||
write!(f, "[{}]...", self.name)
|
||||
}
|
||||
ParameterKind::MemberRef => write!(f, "<target member>"),
|
||||
ParameterKind::MemberRefs => write!(f, "<member 1> <member 2> <member 3>..."),
|
||||
ParameterKind::GroupRef => write!(f, "<target group>"),
|
||||
ParameterKind::GroupRefs => write!(f, "<group 1> <group 2> <group 3>..."),
|
||||
ParameterKind::SystemRef => write!(f, "<target system>"),
|
||||
ParameterKind::MessageRef => write!(f, "<target message>"),
|
||||
ParameterKind::ChannelRef => write!(f, "<target channel>"),
|
||||
ParameterKind::GuildRef => write!(f, "<target guild>"),
|
||||
ParameterKind::MemberPrivacyTarget => write!(f, "<privacy target>"),
|
||||
ParameterKind::GroupPrivacyTarget => write!(f, "<privacy target>"),
|
||||
ParameterKind::SystemPrivacyTarget => write!(f, "<privacy target>"),
|
||||
ParameterKind::PrivacyLevel => write!(f, "[privacy level]"),
|
||||
ParameterKind::Toggle => write!(f, "on/off"),
|
||||
ParameterKind::Avatar => write!(f, "<url|@mention>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParameterKind> for Parameter {
|
||||
fn from(value: ParameterKind) -> Self {
|
||||
Parameter {
|
||||
name: value.default_name().into(),
|
||||
kind: value,
|
||||
remainder: is_remainder(value),
|
||||
optional: false,
|
||||
skip: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&str, ParameterKind)> for Parameter {
|
||||
fn from((name, kind): (&str, ParameterKind)) -> Self {
|
||||
Parameter {
|
||||
name: name.into(),
|
||||
kind,
|
||||
remainder: is_remainder(kind),
|
||||
optional: false,
|
||||
skip: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Optional<P: Into<Parameter>>(pub P);
|
||||
|
||||
impl<P: Into<Parameter>> From<Optional<P>> for Parameter {
|
||||
fn from(value: Optional<P>) -> Self {
|
||||
let p = value.0.into();
|
||||
p.optional()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Remainder<P: Into<Parameter>>(pub P);
|
||||
|
||||
impl<P: Into<Parameter>> From<Remainder<P>> for Parameter {
|
||||
fn from(value: Remainder<P>) -> Self {
|
||||
let p = value.0.into();
|
||||
p.remainder()
|
||||
}
|
||||
}
|
||||
|
||||
// todo(dusk): this is kind of annoying to use, should probably introduce
|
||||
// a way to match multiple parameters in a single parameter
|
||||
#[derive(Clone)]
|
||||
pub struct Skip<P: Into<Parameter>>(pub P);
|
||||
|
||||
impl<P: Into<Parameter>> From<Skip<P>> for Parameter {
|
||||
fn from(value: Skip<P>) -> Self {
|
||||
let p = value.0.into();
|
||||
p.skip()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ParameterKind {
|
||||
OpaqueString,
|
||||
OpaqueStringRemainder,
|
||||
MemberRef,
|
||||
MemberRefs,
|
||||
GroupRef,
|
||||
GroupRefs,
|
||||
SystemRef,
|
||||
MessageRef,
|
||||
ChannelRef,
|
||||
GuildRef,
|
||||
MemberPrivacyTarget,
|
||||
GroupPrivacyTarget,
|
||||
SystemPrivacyTarget,
|
||||
PrivacyLevel,
|
||||
Toggle,
|
||||
Avatar,
|
||||
}
|
||||
|
||||
impl ParameterKind {
|
||||
pub(crate) fn default_name(&self) -> &str {
|
||||
match self {
|
||||
ParameterKind::Toggle => Some(None),
|
||||
ParameterKind::MemberRefs => Some(Some(ParameterValue::MemberRefs(Vec::new()))),
|
||||
ParameterKind::GroupRefs => Some(Some(ParameterValue::GroupRefs(Vec::new()))),
|
||||
_ => None,
|
||||
ParameterKind::OpaqueString => "string",
|
||||
ParameterKind::OpaqueStringRemainder => "string",
|
||||
ParameterKind::MemberRef => "target",
|
||||
ParameterKind::MemberRefs => "targets",
|
||||
ParameterKind::GroupRef => "target",
|
||||
ParameterKind::GroupRefs => "targets",
|
||||
ParameterKind::SystemRef => "target",
|
||||
ParameterKind::MessageRef => "target",
|
||||
ParameterKind::ChannelRef => "target",
|
||||
ParameterKind::GuildRef => "target",
|
||||
ParameterKind::MemberPrivacyTarget => "member_privacy_target",
|
||||
ParameterKind::GroupPrivacyTarget => "group_privacy_target",
|
||||
ParameterKind::SystemPrivacyTarget => "system_privacy_target",
|
||||
ParameterKind::PrivacyLevel => "privacy_level",
|
||||
ParameterKind::Toggle => "toggle",
|
||||
ParameterKind::Avatar => "avatar",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::fmt::{Debug, Display};
|
|||
|
||||
use smol_str::SmolStr;
|
||||
|
||||
use crate::parameter::{Parameter, ParameterKind, ParameterValue};
|
||||
use crate::parameter::{Optional, Parameter, ParameterKind, ParameterValue};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Token {
|
||||
|
|
@ -46,9 +46,17 @@ impl Token {
|
|||
// short circuit on:
|
||||
return match self {
|
||||
// missing paramaters
|
||||
Self::Parameter(param) => Some(TokenMatchResult::MissingParameter {
|
||||
name: param.name().into(),
|
||||
}),
|
||||
Self::Parameter(param) => Some(
|
||||
param
|
||||
.is_optional()
|
||||
.then(|| TokenMatchResult::MatchedParameter {
|
||||
name: param.name().into(),
|
||||
value: ParameterValue::Null,
|
||||
})
|
||||
.unwrap_or_else(|| TokenMatchResult::MissingParameter {
|
||||
name: param.name().into(),
|
||||
}),
|
||||
),
|
||||
// everything else doesnt match if no input anyway
|
||||
Self::Value { .. } => None,
|
||||
// don't add a _ match here!
|
||||
|
|
@ -62,20 +70,14 @@ impl Token {
|
|||
Self::Value { name, aliases } => (aliases.iter().chain(std::iter::once(name)))
|
||||
.any(|v| v.eq(input))
|
||||
.then(|| TokenMatchResult::MatchedValue),
|
||||
Self::Parameter(param) => Some(match param.kind().match_value(input) {
|
||||
Self::Parameter(param) => Some(match param.match_value(input) {
|
||||
Ok(matched) => TokenMatchResult::MatchedParameter {
|
||||
name: param.name().into(),
|
||||
value: matched,
|
||||
},
|
||||
Err(err) => {
|
||||
if let Some(maybe_empty) = param.kind().skip_if_cant_match() {
|
||||
match maybe_empty {
|
||||
Some(matched) => TokenMatchResult::MatchedParameter {
|
||||
name: param.name().into(),
|
||||
value: matched,
|
||||
},
|
||||
None => return None,
|
||||
}
|
||||
if param.is_skip() {
|
||||
return None;
|
||||
} else {
|
||||
TokenMatchResult::ParameterMatchError {
|
||||
input: input.into(),
|
||||
|
|
@ -115,21 +117,10 @@ impl From<&str> for Token {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Parameter> for Token {
|
||||
fn from(value: Parameter) -> Self {
|
||||
Self::Parameter(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParameterKind> for Token {
|
||||
fn from(value: ParameterKind) -> Self {
|
||||
Self::from(Parameter::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&str, ParameterKind)> for Token {
|
||||
fn from(value: (&str, ParameterKind)) -> Self {
|
||||
Self::from(Parameter::from(value))
|
||||
// parameter -> Token::Parameter
|
||||
impl<P: Into<Parameter>> From<P> for Token {
|
||||
fn from(value: P) -> Self {
|
||||
Self::Parameter(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,19 +45,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
for param in &command_params {
|
||||
writeln!(
|
||||
&mut command_params_init,
|
||||
r#"@{name} = await ctx.ParamResolve{extract_fn_name}("{name}") ?? throw new PKError("this is a bug"),"#,
|
||||
r#"@{name} = await ctx.ParamResolve{extract_fn_name}("{name}"){throw_null},"#,
|
||||
name = param.name().replace("-", "_"),
|
||||
extract_fn_name = get_param_param_ty(param.kind()),
|
||||
throw_null = param
|
||||
.is_optional()
|
||||
.then_some("")
|
||||
.unwrap_or(" ?? throw new PKError(\"this is a bug\")"),
|
||||
)?;
|
||||
}
|
||||
let mut command_flags_init = String::new();
|
||||
for flag in &command.flags {
|
||||
if let Some(kind) = flag.get_value() {
|
||||
if let Some(param) = flag.get_value() {
|
||||
writeln!(
|
||||
&mut command_flags_init,
|
||||
r#"@{name} = await ctx.FlagResolve{extract_fn_name}("{name}"),"#,
|
||||
name = flag.get_name().replace("-", "_"),
|
||||
extract_fn_name = get_param_param_ty(kind),
|
||||
extract_fn_name = get_param_param_ty(param.kind()),
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
|
|
@ -109,19 +113,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
for param in &command_params {
|
||||
writeln!(
|
||||
&mut command_params_fields,
|
||||
r#"public required {ty} @{name};"#,
|
||||
r#"public required {ty}{nullable} @{name};"#,
|
||||
name = param.name().replace("-", "_"),
|
||||
ty = get_param_ty(param.kind()),
|
||||
nullable = param.is_optional().then_some("?").unwrap_or(""),
|
||||
)?;
|
||||
}
|
||||
let mut command_flags_fields = String::new();
|
||||
for flag in &command.flags {
|
||||
if let Some(kind) = flag.get_value() {
|
||||
if let Some(param) = flag.get_value() {
|
||||
writeln!(
|
||||
&mut command_flags_fields,
|
||||
r#"public {ty}? @{name};"#,
|
||||
name = flag.get_name().replace("-", "_"),
|
||||
ty = get_param_ty(kind),
|
||||
ty = get_param_ty(param.kind()),
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ interface Parameter {
|
|||
OpaqueString(string raw);
|
||||
Toggle(boolean toggle);
|
||||
Avatar(string avatar);
|
||||
Null();
|
||||
};
|
||||
dictionary ParsedCommand {
|
||||
string command_ref;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ pub enum Parameter {
|
|||
Avatar {
|
||||
avatar: String,
|
||||
},
|
||||
Null,
|
||||
}
|
||||
|
||||
impl From<ParameterValue> for Parameter {
|
||||
|
|
@ -93,6 +94,7 @@ impl From<ParameterValue> for Parameter {
|
|||
},
|
||||
ParameterValue::ChannelRef(channel_id) => Self::ChannelRef { channel_id },
|
||||
ParameterValue::GuildRef(guild_id) => Self::GuildRef { guild_id },
|
||||
ParameterValue::Null => Self::Null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue