From ca273244e426fa9f7d2b57c01af16aacd0a42b31 Mon Sep 17 00:00:00 2001 From: Cleboost Date: Sun, 23 Feb 2025 18:09:34 +0100 Subject: [PATCH] =?UTF-8?q?feat=E2=9C=A8:=20add=20autocomplete=20command?= =?UTF-8?q?=20and=20update=20command=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- .../commands/utils/autocomplete.ts | 23 ++++++++++++++ .../interactions/commands/utils/handler.ts | 14 ++++++++- .../commands/utils/handler/autocomplete.ts | 18 +++++++++++ src/class/interactions/Command.ts | 26 ++++++++-------- src/class/interactions/SubCommand.ts | 30 ++++++++++++++++++- src/handlers/Command.ts | 10 +++++++ src/handlers/SubCommand.ts | 10 +++++++ 8 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 playground/src/interactions/commands/utils/autocomplete.ts create mode 100644 playground/src/interactions/commands/utils/handler/autocomplete.ts diff --git a/package.json b/package.json index 0fa9a3d..56e5b91 100644 --- a/package.json +++ b/package.json @@ -41,5 +41,6 @@ }, "engines": { "node": ">=16.6.0" - } + }, + "packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0" } diff --git a/playground/src/interactions/commands/utils/autocomplete.ts b/playground/src/interactions/commands/utils/autocomplete.ts new file mode 100644 index 0000000..df7803c --- /dev/null +++ b/playground/src/interactions/commands/utils/autocomplete.ts @@ -0,0 +1,23 @@ +import { Command } from "djs-core"; + +export default new Command() + .setName("autocomplete") + .setDescription("This is an autocomplete command") + .addStringOption((option) => + option + .setName("input") + .setDescription("This is an input") + .setAutocomplete(true) + .setRequired(true), + ) + .run((client, interaction) => { + const input = interaction.options.getString("input"); + return interaction.reply(`You selected ${input}`); + }) + .autoComplete((client, interaction) => { + return interaction.respond([ + { name: "Option 1", value: "option1" }, + { name: "Option 2", value: "option2" }, + { name: "Option 3", value: "option3" }, + ]); + }); diff --git a/playground/src/interactions/commands/utils/handler.ts b/playground/src/interactions/commands/utils/handler.ts index 4b3f7b7..b07dd5d 100644 --- a/playground/src/interactions/commands/utils/handler.ts +++ b/playground/src/interactions/commands/utils/handler.ts @@ -7,4 +7,16 @@ export default new SubCommandGroup() .addSubcommand((sub) => sub.setName("select").setDescription("Create select menu"), ) - .addSubcommand((sub) => sub.setName("modal").setDescription("Create modal")); + .addSubcommand((sub) => sub.setName("modal").setDescription("Create modal")) + .addSubcommand((sub) => + sub + .setName("autocomplete") + .setDescription("Create autocomplete") + .addStringOption((option) => + option + .setName("input") + .setDescription("This is an input") + .setAutocomplete(true) + .setRequired(true), + ), + ); diff --git a/playground/src/interactions/commands/utils/handler/autocomplete.ts b/playground/src/interactions/commands/utils/handler/autocomplete.ts new file mode 100644 index 0000000..a8849f5 --- /dev/null +++ b/playground/src/interactions/commands/utils/handler/autocomplete.ts @@ -0,0 +1,18 @@ +import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; +import { SubCommand } from "djs-core"; + +export default new SubCommand() + .run((client, interaction) => { + const input = interaction.options.getString("input"); + return interaction.reply({ + content: `You have selected: ${input}`, + }); + }) + .autoComplete((client, interaction) => { + return interaction.respond([ + { + name: "I am a fucking ping button", + value: "I am a fucking ping button", + }, + ]); + }); diff --git a/src/class/interactions/Command.ts b/src/class/interactions/Command.ts index 837bba5..18d7b2a 100644 --- a/src/class/interactions/Command.ts +++ b/src/class/interactions/Command.ts @@ -5,7 +5,6 @@ */ import { - CommandInteraction, ChatInputCommandInteraction, SlashCommandBuilder, SlashCommandUserOption, @@ -17,6 +16,7 @@ import { SlashCommandChannelOption, SlashCommandRoleOption, SlashCommandMentionableOption, + AutocompleteInteraction, } from "discord.js"; import BotClient from "../BotClient"; @@ -26,12 +26,12 @@ type CommandRunFn = ( ) => unknown; type CommandRunAutoCompleteFn = ( client: BotClient, - interaction: ChatInputCommandInteraction, + interaction: AutocompleteInteraction, ) => unknown; export default class Command extends SlashCommandBuilder { private runFn?: CommandRunFn; - private autocomplete?: CommandRunAutoCompleteFn; + private autocompleteFn?: CommandRunAutoCompleteFn; constructor() { super(); @@ -43,7 +43,7 @@ export default class Command extends SlashCommandBuilder { } autoComplete(fn: CommandRunAutoCompleteFn) { - this.autocomplete = fn; + this.autocompleteFn = fn; return this; } @@ -70,16 +70,16 @@ export default class Command extends SlashCommandBuilder { * DO NOT USE * Internal method to execute the function */ - executeAutoComplete(client: BotClient, interaction: CommandInteraction) { - if ( - this.autocomplete && - interaction instanceof ChatInputCommandInteraction - ) { - return this.autocomplete(client, interaction); - } - if (interaction instanceof CommandInteraction) { - return interaction.reply("Aucune action définie"); + executeAutoComplete(client: BotClient, interaction: AutocompleteInteraction) { + if (!this.autocompleteFn) { + client.logger.error( + `The command ${this.name} has no function to execute!`, + ); + return interaction.respond([ + { name: "Autocomplete not found", value: "Autocomplete not found" }, + ]); } + return this.autocompleteFn(client, interaction); } getDiscordCommand() { diff --git a/src/class/interactions/SubCommand.ts b/src/class/interactions/SubCommand.ts index 15672d6..d66c76d 100644 --- a/src/class/interactions/SubCommand.ts +++ b/src/class/interactions/SubCommand.ts @@ -4,7 +4,11 @@ * Licence: on the GitHub */ -import { ChatInputCommandInteraction, MessageFlags } from "discord.js"; +import { + AutocompleteInteraction, + ChatInputCommandInteraction, + MessageFlags, +} from "discord.js"; import BotClient from "../BotClient"; type SubCommandRunFn = ( @@ -12,14 +16,25 @@ type SubCommandRunFn = ( interaction: ChatInputCommandInteraction, ) => unknown; +type SubCommandAutoCompleteFn = ( + client: BotClient, + interaction: AutocompleteInteraction, +) => unknown; + export default class SubCommand { private runFn?: SubCommandRunFn; + private autoCompleteFn?: SubCommandAutoCompleteFn; run(fn: SubCommandRunFn) { this.runFn = fn; return this; } + autoComplete(fn: SubCommandAutoCompleteFn) { + this.autoCompleteFn = fn; + return this; + } + execute(client: BotClient, interaction: ChatInputCommandInteraction) { if (!this.runFn) { client.logger.error("The subcommand has no function to execute!"); @@ -30,4 +45,17 @@ export default class SubCommand { } return this.runFn(client, interaction); } + + executeAutoComplete(client: BotClient, interaction: AutocompleteInteraction) { + if (!this.autoCompleteFn) { + client.logger.error("The subcommand has no function to execute!"); + return interaction.respond([ + { + name: "The subcommand has no function to execute!", + value: "The subcommand has no function to execute!", + }, + ]); + } + return this.autoCompleteFn(client, interaction); + } } diff --git a/src/handlers/Command.ts b/src/handlers/Command.ts index 6e06522..25491b9 100644 --- a/src/handlers/Command.ts +++ b/src/handlers/Command.ts @@ -59,6 +59,16 @@ export default class CommandHandler extends Handler { this.client.on( Events.InteractionCreate, async (interaction: Interaction) => { + if (interaction.isAutocomplete()) { + const command: Command = this.collection.get( + interaction.commandName, + ) as Command; + if (!command) + return interaction.respond([ + { name: "Command not found", value: "Command not found" }, + ]); + return command.executeAutoComplete(this.client, interaction); + } if (!interaction.isCommand()) return; if (interaction.isContextMenuCommand()) return; if (interaction.options.getSubcommand(false)) return; diff --git a/src/handlers/SubCommand.ts b/src/handlers/SubCommand.ts index 6de6d60..6ad924d 100644 --- a/src/handlers/SubCommand.ts +++ b/src/handlers/SubCommand.ts @@ -84,6 +84,16 @@ export default class SubCommandHandler extends Handler { this.client.on( Events.InteractionCreate, async (interaction: Interaction) => { + if (interaction.isAutocomplete()) { + const subCommand: SubCommand | unknown = this.collection.get( + `${interaction.commandName}.${interaction.options.getSubcommand()}`, + ); + if (!subCommand || !(subCommand instanceof SubCommand)) + return interaction.respond([ + { name: "SubCommand not found", value: "SubCommand not found" }, + ]); + return subCommand.executeAutoComplete(this.client, interaction); + } if (!interaction.isCommand()) return; if (interaction.isContextMenuCommand()) return; if (!interaction.options.getSubcommand(false)) return;