diff --git a/PluralKit.Bot/CommandMeta/CommandTree.cs b/PluralKit.Bot/CommandMeta/CommandTree.cs index 9420b80a..d7c32fb4 100644 --- a/PluralKit.Bot/CommandMeta/CommandTree.cs +++ b/PluralKit.Bot/CommandMeta/CommandTree.cs @@ -282,7 +282,8 @@ public partial class CommandTree Commands.MessageInfo(var param, var flags) => ctx.Execute(Message, m => m.GetMessage(ctx, param.target.MessageId, flags.GetReplyFormat(), flags.delete, flags.author)), Commands.MessageAuthor(var param, var flags) => ctx.Execute(Message, m => m.GetMessage(ctx, param.target.MessageId, flags.GetReplyFormat(), false, true)), Commands.MessageDelete(var param, var flags) => ctx.Execute(Message, m => m.GetMessage(ctx, param.target.MessageId, flags.GetReplyFormat(), true, false)), - Commands.MessageEdit(var param, var flags) => ctx.Execute(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.MessageEditSpecified(var param, var flags) => ctx.Execute(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.MessageEdit(var param, var flags) => ctx.Execute(MessageEdit, m => m.EditMessage(ctx, null, param.new_content, flags.regex, flags.mutate_space, flags.append, flags.prepend, flags.clear_embeds, flags.clear_attachments)), Commands.MessageReproxySpecified(var param, _) => ctx.Execute(MessageReproxy, m => m.ReproxyMessage(ctx, param.msg.MessageId, param.member)), Commands.MessageReproxy(var param, _) => ctx.Execute(MessageReproxy, m => m.ReproxyMessage(ctx, null, param.member)), Commands.Import(var param, var flags) => ctx.Execute(Import, m => m.Import(ctx, param.url, flags.yes)), diff --git a/PluralKit.Bot/CommandSystem/Parameters.cs b/PluralKit.Bot/CommandSystem/Parameters.cs index 0278f661..cbde613d 100644 --- a/PluralKit.Bot/CommandSystem/Parameters.cs +++ b/PluralKit.Bot/CommandSystem/Parameters.cs @@ -9,24 +9,24 @@ namespace PluralKit.Bot; // corresponds to the ffi Paramater type, but with stricter types (also avoiding exposing ffi types!) public abstract record Parameter() { - public record MemberRef(PKMember member): Parameter; - public record MemberRefs(List members): Parameter; - public record GroupRef(PKGroup group): Parameter; - public record GroupRefs(List groups): Parameter; - public record SystemRef(PKSystem system): Parameter; - public record UserRef(User user): Parameter; - public record MessageRef(Message.Reference message): Parameter; - public record ChannelRef(Channel channel): Parameter; - public record GuildRef(Guild guild): Parameter; - public record MemberPrivacyTarget(MemberPrivacySubject target): Parameter; - public record GroupPrivacyTarget(GroupPrivacySubject target): Parameter; - public record SystemPrivacyTarget(SystemPrivacySubject target): Parameter; - public record PrivacyLevel(Core.PrivacyLevel level): Parameter; - public record Toggle(bool value): Parameter; - public record Opaque(string value): Parameter; - public record Number(int value): Parameter; - public record Avatar(ParsedImage avatar): Parameter; - public record ProxySwitchAction(SystemConfig.ProxySwitchAction action): Parameter; + public record MemberRef(PKMember member) : Parameter; + public record MemberRefs(List members) : Parameter; + public record GroupRef(PKGroup group) : Parameter; + public record GroupRefs(List groups) : Parameter; + public record SystemRef(PKSystem system) : Parameter; + public record UserRef(User user) : Parameter; + public record MessageRef(Message.Reference message) : Parameter; + public record ChannelRef(Channel channel) : Parameter; + public record GuildRef(Guild guild) : Parameter; + public record MemberPrivacyTarget(MemberPrivacySubject target) : Parameter; + public record GroupPrivacyTarget(GroupPrivacySubject target) : Parameter; + public record SystemPrivacyTarget(SystemPrivacySubject target) : Parameter; + public record PrivacyLevel(Core.PrivacyLevel level) : Parameter; + public record Toggle(bool value) : Parameter; + public record Opaque(string value) : Parameter; + public record Number(int value) : Parameter; + public record Avatar(ParsedImage avatar) : Parameter; + public record ProxySwitchAction(SystemConfig.ProxySwitchAction action) : Parameter; } public class Parameters @@ -48,6 +48,10 @@ public class Parameters _cb = command.@commandRef; _flags = command.@flags; _params = command.@params; + foreach (var param in _params) + { + Console.WriteLine($"{param.Key}: {param.Value}"); + } } else { diff --git a/crates/command_definitions/src/message.rs b/crates/command_definitions/src/message.rs index 06a5c0ca..f9bfec49 100644 --- a/crates/command_definitions/src/message.rs +++ b/crates/command_definitions/src/message.rs @@ -7,7 +7,7 @@ pub fn cmds() -> impl Iterator { let delete = ("delete", ["del", "d"]); let reproxy = ("reproxy", ["rp", "crimes", "crime"]); - let edit = tokens!(("edit", ["e"]), ("new_content", OpaqueStringRemainder)); + let edit = ("edit", ["e"]); let apply_edit = |cmd: Command| { cmd.flag(("append", ["a"])) .flag(("prepend", ["p"])) @@ -25,8 +25,9 @@ pub fn cmds() -> impl Iterator { .help("Shows information about a proxied message"), command!(message, author => "message_author").help("Shows the author of a proxied message"), command!(message, delete => "message_delete").help("Deletes a proxied message"), - apply_edit(command!(message, edit => "message_edit")), - apply_edit(command!(edit => "message_edit")), + apply_edit(command!(message, edit, ("new_content", OpaqueStringRemainder) => "message_edit_specified")), + apply_edit(command!(edit, Skip(MessageRef), ("new_content", OpaqueStringRemainder) => "message_edit_specified")), + apply_edit(command!(edit, ("new_content", OpaqueStringRemainder) => "message_edit")), command!(reproxy, ("member", MemberRef) => "message_reproxy") .help("Reproxies a message with a different member"), command!(reproxy, ("msg", MessageRef), ("member", MemberRef) => "message_reproxy_specified") diff --git a/crates/command_parser/src/lib.rs b/crates/command_parser/src/lib.rs index f33021cf..52807e7f 100644 --- a/crates/command_parser/src/lib.rs +++ b/crates/command_parser/src/lib.rs @@ -50,13 +50,13 @@ pub fn parse_command( let mut matched_tokens: Vec<(Tree, (Token, TokenMatchResult, usize))> = Vec::new(); let mut filtered_tokens: Vec = Vec::new(); loop { - println!( - "possible: {:?}", - local_tree - .possible_tokens() - .filter(|t| filtered_tokens.contains(t)) - .collect::>() - ); + // println!( + // "possible: {:?}", + // local_tree + // .possible_tokens() + // .filter(|t| filtered_tokens.contains(t)) + // .collect::>() + // ); let next = next_token( local_tree .possible_tokens() @@ -64,7 +64,7 @@ pub fn parse_command( &input, current_pos, ); - println!("next: {:?}", next); + // println!("next: {:?}", next); match &next { Some((found_token, result, new_pos)) => { match &result { diff --git a/crates/command_parser/src/parameter.rs b/crates/command_parser/src/parameter.rs index 77bfde8b..eaab7c8c 100644 --- a/crates/command_parser/src/parameter.rs +++ b/crates/command_parser/src/parameter.rs @@ -135,32 +135,41 @@ impl Parameter { return Ok(ParameterValue::MessageRef(None, None, message_id)); } - static RE: std::sync::LazyLock = std::sync::LazyLock::new(|| { + static SERVER_RE: std::sync::LazyLock = std::sync::LazyLock::new( + || { + regex::Regex::new( + r"https://(?:\w+\.)?discord(?:app)?\.com/channels/(?P\d+)/(?P\d+)/(?P\d+)", + ) + .unwrap() + }, + ); + + static DM_RE: std::sync::LazyLock = std::sync::LazyLock::new(|| { regex::Regex::new( - r"https://(?:\w+\.)?discord(?:app)?\.com/channels/(\d+)/(\d+)/(\d+)", + r"https://(?:\w+\.)?discord(?:app)?\.com/channels/@me/(?P\d+)/(?P\d+)", ) .unwrap() }); - if let Some(captures) = RE.captures(input) { - let guild_id = captures - .get(1) - .and_then(|m| m.as_str().parse::().ok()) - .ok_or_else(|| SmolStr::new("invalid guild ID in message link"))?; - let channel_id = captures - .get(2) - .and_then(|m| m.as_str().parse::().ok()) - .ok_or_else(|| SmolStr::new("invalid channel ID in message link"))?; - let message_id = captures - .get(3) - .and_then(|m| m.as_str().parse::().ok()) - .ok_or_else(|| SmolStr::new("invalid message ID in message link"))?; + if let Some(captures) = SERVER_RE.captures(input) { + let guild_id = captures.parse_id("guild")?; + let channel_id = captures.parse_id("channel")?; + let message_id = captures.parse_id("message")?; Ok(ParameterValue::MessageRef( Some(guild_id), Some(channel_id), message_id, )) + } else if let Some(captures) = DM_RE.captures(input) { + let channel_id = captures.parse_id("channel")?; + let message_id = captures.parse_id("message")?; + + Ok(ParameterValue::MessageRef( + None, + Some(channel_id), + message_id, + )) } else { Err(SmolStr::new("invalid message reference")) } @@ -560,3 +569,15 @@ impl FromStr for ProxySwitchAction { .ok_or_else(|| SmolStr::new("invalid proxy switch action, must be new/add/off")) } } + +trait ParseMessageLink { + fn parse_id(&self, name: &str) -> Result; +} + +impl ParseMessageLink for regex::Captures<'_> { + fn parse_id(&self, name: &str) -> Result { + self.name(name) + .and_then(|m| m.as_str().parse::().ok()) + .ok_or_else(|| SmolStr::new(format!("invalid {} in message link", name))) + } +} diff --git a/crates/commands/src/write_cs_glue.rs b/crates/commands/src/write_cs_glue.rs index 05340595..de1b5e74 100644 --- a/crates/commands/src/write_cs_glue.rs +++ b/crates/commands/src/write_cs_glue.rs @@ -51,8 +51,8 @@ fn main() -> Result<(), Box> { 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\")"), + .then(String::new) + .unwrap_or(format!(" ?? throw new PKError(\"parameter {} not found but was required, this is a bug in the command parser, for command: {}!\")", param.name(), command.cb)), )?; } let mut command_flags_init = String::new();