From 4db4d2d43ed5c89f23911d139e4f67225eaaadb3 Mon Sep 17 00:00:00 2001 From: Zabuzard Date: Sun, 9 Oct 2022 09:33:25 +0200 Subject: [PATCH 01/31] First draft of format command --- application/build.gradle | 1 + .../togetherjava/tjbot/commands/Features.java | 2 + .../commands/formatter/FormatCodeCommand.java | 67 +++++++++++++++++++ .../commands/formatter/package-info.java | 11 +++ .../tjbot/formatter/Formatter.java | 4 +- 5 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/formatter/FormatCodeCommand.java create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java diff --git a/application/build.gradle b/application/build.gradle index 555c2b5c9d..6eddd152ee 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -44,6 +44,7 @@ dependencies { implementation project(':database') implementation project(':utils') + implementation project(':formatter') implementation 'net.dv8tion:JDA:5.0.0-alpha.20' diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java index 0aa49c3133..572b023e28 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java @@ -7,6 +7,7 @@ import org.togetherjava.tjbot.commands.basic.SuggestionsUpDownVoter; import org.togetherjava.tjbot.commands.basic.VcActivityCommand; import org.togetherjava.tjbot.commands.filesharing.FileSharingMessageListener; +import org.togetherjava.tjbot.commands.formatter.FormatCodeCommand; import org.togetherjava.tjbot.commands.help.*; import org.togetherjava.tjbot.commands.mathcommands.TeXCommand; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand; @@ -101,6 +102,7 @@ public static Collection createFeatures(JDA jda, Database database, Con features.add(new UserBannedDeleteRecentThreadsListener(database)); // Message context commands + features.add(new FormatCodeCommand()); // User context commands diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/formatter/FormatCodeCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/formatter/FormatCodeCommand.java new file mode 100644 index 0000000000..f1e067294e --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/formatter/FormatCodeCommand.java @@ -0,0 +1,67 @@ +package org.togetherjava.tjbot.commands.formatter; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.build.Commands; + +import org.togetherjava.tjbot.commands.BotCommandAdapter; +import org.togetherjava.tjbot.commands.CommandVisibility; +import org.togetherjava.tjbot.commands.MessageContextCommand; +import org.togetherjava.tjbot.formatter.Formatter; +import org.togetherjava.tjbot.formatter.tokenizer.Lexer; + +import java.awt.Color; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +// TODO Doc +public final class FormatCodeCommand extends BotCommandAdapter implements MessageContextCommand { + private static final Color AMBIENT_COLOR = Color.decode("#FDFD96"); + // TODO doc, lol + private static final Pattern CODE_BLOCK_EXTRACTOR_PATTERN = + Pattern.compile("```(?:java)?\\s*([\\w\\W]+)```|``?([\\w\\W]+)``?"); + + private final Lexer lexer; + private final Formatter formatter; + + // TODO doc + public FormatCodeCommand() { + super(Commands.message("format-code"), CommandVisibility.GUILD); + + lexer = new Lexer(); + formatter = new Formatter(); + } + + @Override + public void onMessageContext(MessageContextInteractionEvent event) { + String content = event.getTarget().getContentRaw(); + + Optional maybeCode = extractCode(content); + if (maybeCode.isEmpty()) { + event.reply("Could not find code in the message.").setEphemeral(true).queue(); + return; + } + + String formattedCode = formatCode(maybeCode.orElseThrow()); + MessageEmbed response = new EmbedBuilder().setTitle("Formatted code") + .setDescription(formattedCode) + .setColor(AMBIENT_COLOR) + .build(); + + event.replyEmbeds(response).queue(); + } + + private static Optional extractCode(CharSequence fullMessage) { + Matcher codeBlockMatcher = CODE_BLOCK_EXTRACTOR_PATTERN.matcher(fullMessage); + if (!codeBlockMatcher.find()) { + return Optional.empty(); + } + return Optional.of(codeBlockMatcher.group(1)); + } + + private String formatCode(String code) { + return formatter.format(code, lexer); + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java new file mode 100644 index 0000000000..7811de4559 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java @@ -0,0 +1,11 @@ +/** + * This package offers all the functionality for code formatting. The core class is + * {@link org.togetherjava.tjbot.commands.formatter.FormatCodeCommand}. + */ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package org.togetherjava.tjbot.commands.formatter; + +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/formatter/src/main/java/org/togetherjava/tjbot/formatter/Formatter.java b/formatter/src/main/java/org/togetherjava/tjbot/formatter/Formatter.java index 48b9f2ca25..bfd9de7d4b 100644 --- a/formatter/src/main/java/org/togetherjava/tjbot/formatter/Formatter.java +++ b/formatter/src/main/java/org/togetherjava/tjbot/formatter/Formatter.java @@ -127,12 +127,12 @@ private List
sectionize(List checkedTokens) { /** * Section POJR */ - private static record Section(List tokens, boolean isCodeSection) { + private record Section(List tokens, boolean isCodeSection) { } /** * CheckedToken POJR */ - private static record CheckedToken(Token token, boolean isCode) { + private record CheckedToken(Token token, boolean isCode) { } } From 6fa8d5ac6df7d5652d578929788426cca3b7562d Mon Sep 17 00:00:00 2001 From: Zabuzard Date: Mon, 10 Oct 2022 10:13:31 +0200 Subject: [PATCH 02/31] adding onMessageDeleted to message receiver --- .../tjbot/commands/MessageReceiver.java | 10 ++++ .../commands/MessageReceiverAdapter.java | 7 +++ .../commands/code/CodeMessageHandler.java | 50 +++++++++++++++++++ .../FormatCodeCommand.java | 18 +------ .../tjbot/commands/code/package-info.java | 10 ++++ .../commands/formatter/package-info.java | 11 ---- .../tjbot/commands/system/BotCore.java | 9 ++++ 7 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java rename application/src/main/java/org/togetherjava/tjbot/commands/{formatter => code}/FormatCodeCommand.java (71%) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/code/package-info.java delete mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java index b0aaf80d59..35843ead1c 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java @@ -1,5 +1,6 @@ package org.togetherjava.tjbot.commands; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; @@ -46,4 +47,13 @@ public interface MessageReceiver extends Feature { * message that was edited */ void onMessageUpdated(MessageUpdateEvent event); + + /** + * Triggered by the core system whenever an existing message was deleted in a text channel of a + * guild the bot has been added to. + * + * @param event the event that triggered this, containing information about the corresponding + * message that was deleted + */ + void onMessageDeleted(MessageDeleteEvent event); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java index 63a6bf841a..6a8f1a5fa3 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java @@ -1,5 +1,6 @@ package org.togetherjava.tjbot.commands; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; @@ -43,4 +44,10 @@ public void onMessageReceived(MessageReceivedEvent event) { public void onMessageUpdated(MessageUpdateEvent event) { // Adapter does not react by default, subclasses may change this behavior } + + @SuppressWarnings("NoopMethodInAbstractClass") + @Override + public void onMessageDeleted(MessageDeleteEvent event) { + // Adapter does not react by default, subclasses may change this behavior + } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java new file mode 100644 index 0000000000..0520f8aeea --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java @@ -0,0 +1,50 @@ +package org.togetherjava.tjbot.commands.code; + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageUpdateEvent; + +import org.togetherjava.tjbot.commands.MessageReceiverAdapter; + +import java.awt.Color; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class CodeMessageHandler extends MessageReceiverAdapter { + private static final Color AMBIENT_COLOR = Color.decode("#FDFD96"); + // TODO doc, lol + private static final Pattern CODE_BLOCK_EXTRACTOR_PATTERN = + Pattern.compile("```(?:java)?\\s*([\\w\\W]+)```|``?([\\w\\W]+)``?"); + + public CodeMessageHandler() { + super(Pattern.compile(".*")); + } + + @Override + public void onMessageReceived(MessageReceivedEvent event) { + String content = event.getMessage().getContentRaw(); + + Optional maybeCode = extractCode(content); + if (maybeCode.isEmpty()) { + return; + } + } + + @Override + public void onMessageUpdated(MessageUpdateEvent event) { + String content = event.getMessage().getContentRaw(); + + Optional maybeCode = extractCode(content); + if (maybeCode.isEmpty()) { + return; + } + } + + private static Optional extractCode(CharSequence fullMessage) { + Matcher codeBlockMatcher = CODE_BLOCK_EXTRACTOR_PATTERN.matcher(fullMessage); + if (!codeBlockMatcher.find()) { + return Optional.empty(); + } + return Optional.of(codeBlockMatcher.group(1)); + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/formatter/FormatCodeCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/FormatCodeCommand.java similarity index 71% rename from application/src/main/java/org/togetherjava/tjbot/commands/formatter/FormatCodeCommand.java rename to application/src/main/java/org/togetherjava/tjbot/commands/code/FormatCodeCommand.java index f1e067294e..acc0c63053 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/formatter/FormatCodeCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/FormatCodeCommand.java @@ -1,4 +1,4 @@ -package org.togetherjava.tjbot.commands.formatter; +package org.togetherjava.tjbot.commands.code; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; @@ -11,18 +11,10 @@ import org.togetherjava.tjbot.formatter.Formatter; import org.togetherjava.tjbot.formatter.tokenizer.Lexer; -import java.awt.Color; import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; // TODO Doc public final class FormatCodeCommand extends BotCommandAdapter implements MessageContextCommand { - private static final Color AMBIENT_COLOR = Color.decode("#FDFD96"); - // TODO doc, lol - private static final Pattern CODE_BLOCK_EXTRACTOR_PATTERN = - Pattern.compile("```(?:java)?\\s*([\\w\\W]+)```|``?([\\w\\W]+)``?"); - private final Lexer lexer; private final Formatter formatter; @@ -53,14 +45,6 @@ public void onMessageContext(MessageContextInteractionEvent event) { event.replyEmbeds(response).queue(); } - private static Optional extractCode(CharSequence fullMessage) { - Matcher codeBlockMatcher = CODE_BLOCK_EXTRACTOR_PATTERN.matcher(fullMessage); - if (!codeBlockMatcher.find()) { - return Optional.empty(); - } - return Optional.of(codeBlockMatcher.group(1)); - } - private String formatCode(String code) { return formatter.format(code, lexer); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/code/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/package-info.java new file mode 100644 index 0000000000..b8adb1ffd2 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/package-info.java @@ -0,0 +1,10 @@ +/** + * This package offers all the functionality for working with messages containing code. + */ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package org.togetherjava.tjbot.commands.code; + +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java deleted file mode 100644 index 7811de4559..0000000000 --- a/application/src/main/java/org/togetherjava/tjbot/commands/formatter/package-info.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * This package offers all the functionality for code formatting. The core class is - * {@link org.togetherjava.tjbot.commands.formatter.FormatCodeCommand}. - */ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package org.togetherjava.tjbot.commands.formatter; - -import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java index d0e4ec3ad6..90305621f1 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java @@ -9,6 +9,7 @@ import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; @@ -213,6 +214,14 @@ public void onMessageUpdate(final MessageUpdateEvent event) { } } + @Override + public void onMessageDelete(final MessageDeleteEvent event) { + if (event.isFromGuild()) { + getMessageReceiversSubscribedTo(event.getChannel()) + .forEach(messageReceiver -> messageReceiver.onMessageDeleted(event)); + } + } + private Stream getMessageReceiversSubscribedTo(Channel channel) { String channelName = channel.getName(); return channelNameToMessageReceiver.entrySet() From 09eddf54d7c4bfe57268d4239ddbced278dcc6a9 Mon Sep 17 00:00:00 2001 From: Zabuzard Date: Mon, 10 Oct 2022 10:48:47 +0200 Subject: [PATCH 03/31] some stuff --- .../commands/code/CodeMessageHandler.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java index 0520f8aeea..349df1b7fb 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java @@ -1,7 +1,11 @@ package org.togetherjava.tjbot.commands.code; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; @@ -10,6 +14,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +// TODO Also needs UserInteractor / BotCommandAdapter (can one class even implement both wrt +// prefixes? maybe split into two) public final class CodeMessageHandler extends MessageReceiverAdapter { private static final Color AMBIENT_COLOR = Color.decode("#FDFD96"); // TODO doc, lol @@ -28,6 +34,16 @@ public void onMessageReceived(MessageReceivedEvent event) { if (maybeCode.isEmpty()) { return; } + + + event.getMessage().reply(createCodeActionsResponse()).queue(); + } + + private static MessageCreateData createCodeActionsResponse() { + // TODO ... + return new MessageCreateBuilder().setContent("Detected code, here are some useful tools:") + .setActionRow(Button.primary("some id", "Format")) + .build(); } @Override @@ -38,6 +54,13 @@ public void onMessageUpdated(MessageUpdateEvent event) { if (maybeCode.isEmpty()) { return; } + + // TODO ... + } + + @Override + public void onMessageDeleted(MessageDeleteEvent event) { + // TODO ... } private static Optional extractCode(CharSequence fullMessage) { From 6834a02c0da11b1cead6f8bb5a21703f58acd5fb Mon Sep 17 00:00:00 2001 From: Zabuzard Date: Tue, 11 Oct 2022 10:14:14 +0200 Subject: [PATCH 04/31] moved code formatting responsibility over to the message handler --- .../togetherjava/tjbot/commands/Features.java | 4 +-- .../tjbot/commands/code/CodeAction.java | 7 +++++ .../commands/code/CodeMessageHandler.java | 11 +++++-- .../commands/code/FormatCodeCommand.java | 31 ++++--------------- 4 files changed, 24 insertions(+), 29 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/code/CodeAction.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java index 572b023e28..6f9e061369 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java @@ -6,8 +6,8 @@ import org.togetherjava.tjbot.commands.basic.RoleSelectCommand; import org.togetherjava.tjbot.commands.basic.SuggestionsUpDownVoter; import org.togetherjava.tjbot.commands.basic.VcActivityCommand; +import org.togetherjava.tjbot.commands.code.CodeMessageHandler; import org.togetherjava.tjbot.commands.filesharing.FileSharingMessageListener; -import org.togetherjava.tjbot.commands.formatter.FormatCodeCommand; import org.togetherjava.tjbot.commands.help.*; import org.togetherjava.tjbot.commands.mathcommands.TeXCommand; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand; @@ -95,6 +95,7 @@ public static Collection createFeatures(JDA jda, Database database, Con features.add(new MediaOnlyChannelListener(config)); features.add(new FileSharingMessageListener(config)); features.add(new BlacklistedAttachmentListener(config, modAuditLogWriter)); + features.add(new CodeMessageHandler()); // Event receivers features.add(new RejoinModerationRoleListener(actionsStore, config)); @@ -102,7 +103,6 @@ public static Collection createFeatures(JDA jda, Database database, Con features.add(new UserBannedDeleteRecentThreadsListener(database)); // Message context commands - features.add(new FormatCodeCommand()); // User context commands diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeAction.java new file mode 100644 index 0000000000..8d67c190b8 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeAction.java @@ -0,0 +1,7 @@ +package org.togetherjava.tjbot.commands.code; + +import net.dv8tion.jda.api.entities.MessageEmbed; + +interface CodeAction { + MessageEmbed apply(String code); +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java index 349df1b7fb..f46847a4eb 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java @@ -17,13 +17,17 @@ // TODO Also needs UserInteractor / BotCommandAdapter (can one class even implement both wrt // prefixes? maybe split into two) public final class CodeMessageHandler extends MessageReceiverAdapter { - private static final Color AMBIENT_COLOR = Color.decode("#FDFD96"); + static final Color AMBIENT_COLOR = Color.decode("#FDFD96"); // TODO doc, lol private static final Pattern CODE_BLOCK_EXTRACTOR_PATTERN = Pattern.compile("```(?:java)?\\s*([\\w\\W]+)```|``?([\\w\\W]+)``?"); + private final FormatCodeCommand formatCodeCommand; + public CodeMessageHandler() { super(Pattern.compile(".*")); + + formatCodeCommand = new FormatCodeCommand(); } @Override @@ -46,6 +50,8 @@ private static MessageCreateData createCodeActionsResponse() { .build(); } + // TODO onButtonClick thingy + @Override public void onMessageUpdated(MessageUpdateEvent event) { String content = event.getMessage().getContentRaw(); @@ -55,7 +61,8 @@ public void onMessageUpdated(MessageUpdateEvent event) { return; } - // TODO ... + // TODO Update existing message instead of reposting + event.getMessage().replyEmbeds(formatCodeCommand.apply(maybeCode.orElseThrow())).queue(); } @Override diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/code/FormatCodeCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/FormatCodeCommand.java index acc0c63053..6e192dddfe 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/code/FormatCodeCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/FormatCodeCommand.java @@ -2,47 +2,28 @@ import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; -import net.dv8tion.jda.api.interactions.commands.build.Commands; -import org.togetherjava.tjbot.commands.BotCommandAdapter; -import org.togetherjava.tjbot.commands.CommandVisibility; -import org.togetherjava.tjbot.commands.MessageContextCommand; import org.togetherjava.tjbot.formatter.Formatter; import org.togetherjava.tjbot.formatter.tokenizer.Lexer; -import java.util.Optional; - // TODO Doc -public final class FormatCodeCommand extends BotCommandAdapter implements MessageContextCommand { +final class FormatCodeCommand implements CodeAction { private final Lexer lexer; private final Formatter formatter; - // TODO doc - public FormatCodeCommand() { - super(Commands.message("format-code"), CommandVisibility.GUILD); - + FormatCodeCommand() { lexer = new Lexer(); formatter = new Formatter(); } @Override - public void onMessageContext(MessageContextInteractionEvent event) { - String content = event.getTarget().getContentRaw(); + public MessageEmbed apply(String code) { + String formattedCode = formatCode(code); - Optional maybeCode = extractCode(content); - if (maybeCode.isEmpty()) { - event.reply("Could not find code in the message.").setEphemeral(true).queue(); - return; - } - - String formattedCode = formatCode(maybeCode.orElseThrow()); - MessageEmbed response = new EmbedBuilder().setTitle("Formatted code") + return new EmbedBuilder().setTitle("Formatted code") .setDescription(formattedCode) - .setColor(AMBIENT_COLOR) + .setColor(CodeMessageHandler.AMBIENT_COLOR) .build(); - - event.replyEmbeds(response).queue(); } private String formatCode(String code) { From d2f0e3a0079db2741240d74da2f24acad8f80311 Mon Sep 17 00:00:00 2001 From: Zabuzard Date: Thu, 13 Oct 2022 12:14:21 +0200 Subject: [PATCH 05/31] Draft of final UX --- .../commands/code/CodeMessageHandler.java | 116 +++++++++++++++--- 1 file changed, 102 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java index f46847a4eb..dac338d9ca 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/code/CodeMessageHandler.java @@ -1,5 +1,8 @@ package org.togetherjava.tjbot.commands.code; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent; import net.dv8tion.jda.api.events.message.MessageDeleteEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; @@ -8,52 +11,126 @@ import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; +import org.togetherjava.tjbot.commands.UserInteractionType; +import org.togetherjava.tjbot.commands.UserInteractor; +import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; +import org.togetherjava.tjbot.commands.componentids.ComponentIdInteractor; import java.awt.Color; -import java.util.Optional; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -// TODO Also needs UserInteractor / BotCommandAdapter (can one class even implement both wrt -// prefixes? maybe split into two) -public final class CodeMessageHandler extends MessageReceiverAdapter { +public final class CodeMessageHandler extends MessageReceiverAdapter implements UserInteractor { static final Color AMBIENT_COLOR = Color.decode("#FDFD96"); // TODO doc, lol private static final Pattern CODE_BLOCK_EXTRACTOR_PATTERN = Pattern.compile("```(?:java)?\\s*([\\w\\W]+)```|``?([\\w\\W]+)``?"); + private final ComponentIdInteractor componentIdInteractor; private final FormatCodeCommand formatCodeCommand; + // TODO Use a cafeeine cache + private final Map originalMessageToCodeReply = + Collections.synchronizedMap(new HashMap<>()); + public CodeMessageHandler() { super(Pattern.compile(".*")); + componentIdInteractor = new ComponentIdInteractor(getInteractionType(), getName()); + formatCodeCommand = new FormatCodeCommand(); } + @Override + public String getName() { + return "code-actions"; + } + + @Override + public UserInteractionType getInteractionType() { + return UserInteractionType.OTHER; + } + + @Override + public void onSelectionMenu(SelectMenuInteractionEvent event, List args) { + throw new UnsupportedOperationException("Not used"); + } + + @Override + public void acceptComponentIdGenerator(ComponentIdGenerator generator) { + componentIdInteractor.acceptComponentIdGenerator(generator); + } + @Override public void onMessageReceived(MessageReceivedEvent event) { - String content = event.getMessage().getContentRaw(); + Message originalMessage = event.getMessage(); + String content = originalMessage.getContentRaw(); Optional maybeCode = extractCode(content); if (maybeCode.isEmpty()) { return; } - - event.getMessage().reply(createCodeActionsResponse()).queue(); + originalMessage.reply(createCodeReplyMessage(originalMessage.getIdLong())) + .map(replyMessage -> originalMessageToCodeReply.put(originalMessage.getIdLong(), + replyMessage.getIdLong())) + .queue(); } - private static MessageCreateData createCodeActionsResponse() { - // TODO ... + private MessageCreateData createCodeReplyMessage(long originalMessageId) { return new MessageCreateBuilder().setContent("Detected code, here are some useful tools:") - .setActionRow(Button.primary("some id", "Format")) + .setActionRow(Button.primary( + componentIdInteractor.generateComponentId(Long.toString(originalMessageId)), + "Format")) .build(); } - // TODO onButtonClick thingy + @Override + public void onButtonClick(ButtonInteractionEvent event, List args) { + long originalMessageId = Long.parseLong(args.get(0)); + + event.deferEdit().queue(); + + event.getChannel() + .retrieveMessageById(originalMessageId) + .mapToResult() + .flatMap(originalMessage -> { + if (originalMessage.isFailure()) { + return event.getHook() + .sendMessage( + "Sorry, I am unable to locate the original message that contained the code, was it deleted?") + .setEphemeral(true); + } + + // Restore in case bot was restarted in the meantime + originalMessageToCodeReply.put(originalMessageId, event.getMessageIdLong()); + + Optional maybeCode = extractCode(originalMessage.get().getContentRaw()); + if (maybeCode.isEmpty()) { + return event.getHook() + .sendMessage( + "Sorry, I am unable to locate any code in the original message, was it removed?") + .setEphemeral(true); + } + + List