feat: make autocomplete options working

This commit is contained in:
Jozef Steinhübl 2023-08-24 16:03:48 +02:00
parent 38acccfa2b
commit c4b21275f9
8 changed files with 86 additions and 15 deletions

View file

@ -1,10 +1,11 @@
import { SlashCommandStringOption } from "discord.js";
import { defineCommand } from "../loaders/commands";
import { AutocompleteContext } from "../structs/context/AutocompleteContext";
import { Option } from "../structs/Command";
import { InteractionCommandContext } from "../structs/context/CommandContext";
defineCommand({
name: "docs",
description: "Search at docs",
options: [
{
...new SlashCommandStringOption()
@ -13,9 +14,14 @@ defineCommand({
.setAutocomplete(true)
.setDescription("Select query")
.toJSON(),
run: (_: Option, context: AutocompleteContext) => {
return context.interaction.respond([{ name: "heh", value: "heh" }]);
run: (context: AutocompleteContext) => {
return context.respond([{ name: "heh", value: "heh" }]);
}
}
]
],
run: (context: InteractionCommandContext) => {
context.reply({
content: "ccc"
});
}
})

View file

@ -1,2 +1,5 @@
import "./version.ts";
import "./docs.ts";
import { registerCommands } from "../loaders/commands.ts";
await registerCommands();

View file

@ -4,6 +4,7 @@ import { InteractionCommandContext } from "../structs/context/CommandContext.ts"
export default defineCommand({
name: "version",
description: "Show version",
options: [],
run: (context: InteractionCommandContext) => {
context.interaction.reply({

View file

@ -1,18 +1,21 @@
import { Events, Interaction, ChatInputCommandInteraction } from "discord.js";
import { Events, Interaction, ChatInputCommandInteraction, AutocompleteInteraction } from "discord.js";
import { COMMANDS } from "../loaders/commands.ts";
import { defineListener } from "../loaders/listeners.ts";
import { InteractionCommandContext } from "../structs/context/CommandContext.ts";
import { AutocompleteContext } from "../structs/context/AutocompleteContext.ts";
import { StringOption } from "../structs/Command.ts";
defineListener({
event: Events.InteractionCreate,
run: (interaction: Interaction) => {
if (interaction.isChatInputCommand()) return handleCommand(interaction);
run: async(interaction: Interaction) => {
if (interaction.isChatInputCommand()) return await handleCommand(interaction);
if (interaction.isAutocomplete()) return await handleAutocomplete(interaction);
return;
}
})
function handleCommand(interaction: ChatInputCommandInteraction) {
async function handleCommand(interaction: ChatInputCommandInteraction) {
const command = COMMANDS.get(interaction.commandName);
if (!command || !command.run) {
@ -23,5 +26,37 @@ function handleCommand(interaction: ChatInputCommandInteraction) {
return;
}
command.run(new InteractionCommandContext(command, interaction));
const context = new InteractionCommandContext(command, interaction);
await Promise.resolve(command.run(context))
.catch(async error => {
context.reply({
content: `Something went wrong... ${error.message} (${error.code})`
});
});
}
async function handleAutocomplete(interaction: AutocompleteInteraction) {
const command = COMMANDS.get(interaction.commandName);
if (!command) return;
let options = command.options;
if (interaction.options.getSubcommandGroup(false))
options = options.find(o => o.name === interaction.options.getSubcommandGroup())?.options;
if (interaction.options.getSubcommand(false))
options = options.find(o => o.name === interaction.options.getSubcommand())?.options;
const focused = interaction.options.getFocused(true);
const option = options.find(o => o.name === focused.name) as StringOption;
if (!option) return;
const context = new AutocompleteContext(option, command, interaction);
await Promise.resolve(command.run(context))
.catch(async error => {
context.respond({
content: `Something went wrong... ${error.message} (${error.code})`
});
});
}

View file

@ -1,7 +1,27 @@
import { REST, Routes, SlashCommandBuilder } from "discord.js";
import { Bubu } from "../structs/Client.ts";
import type { Command } from "../structs/Command.ts";
export const COMMANDS: Map<string, Command> = new Map();
export const REST_CLIENT = new REST().setToken(process.env.DISCORD_TOKEN);
export function defineCommand<T extends Command>(command: T) {
COMMANDS.set(command.name, command);
}
export async function registerCommands() {
const commands = [...COMMANDS.values()];
await REST_CLIENT.put(
Routes.applicationCommands("995690041793839124"),
{
body: commands.map(d => ({
...new SlashCommandBuilder()
.setName(d.name)
.setDescription(d.description)
.toJSON(),
options: d.options
}))
}
)
}

View file

@ -14,7 +14,7 @@ export type Option = APIApplicationCommandAttachmentOption |
APIApplicationCommandSubcommandGroupOption |
StringOption;
interface StringOption {
export interface StringOption {
name: string;
name_localizations?: LocalizationMap;
description: string;
@ -25,11 +25,12 @@ interface StringOption {
type: ApplicationCommandOptionType.String;
autocomplete?: boolean;
choices?: APIApplicationCommandOptionChoice[];
run: (option: Option, interaction: AutocompleteContext) => any;
run: (interaction: AutocompleteContext) => any;
}
export interface Command {
name: string;
description: string;
options: Option[];
run?: (
context: CommandContext<true>

View file

@ -3,4 +3,3 @@ export interface Tag {
answer: string;
keywords: string[];
}

View file

@ -1,12 +1,14 @@
import { AutocompleteInteraction } from "discord.js";
import { Option } from "../Command.ts";
import { ApplicationCommandOptionChoiceData, AutocompleteInteraction } from "discord.js";
import { Command, Option } from "../Command.ts";
export class AutocompleteContext {
public option: Option;
public command: Command;
public interaction: AutocompleteInteraction;
public constructor(option: Option, interaction: AutocompleteInteraction) {
public constructor(option: Option, command: Command, interaction: AutocompleteInteraction) {
this.option = option;
this.command = command;
this.interaction = interaction;
}
@ -21,4 +23,8 @@ export class AutocompleteContext {
get options() {
return this.interaction.options;
}
public respond(options: ApplicationCommandOptionChoiceData[]) {
return this.interaction.respond(options);
}
}