dimslash — Interaction-first command handler for dimscord.
dimslash provides a declarative, type-safe way to register and dispatch Discord interactions (slash commands, user/message context-menu commands, buttons, selects, modals, and autocomplete).
Getting started
- Create a DiscordClient and wrap it in an InteractionHandler.
- Register commands with the DSL helpers (addSlash, addUser, …).
- Call registerCommands once the gateway is ready.
- Forward incoming interactions to handleInteraction.
Minimal example
import dimscord, asyncdispatch, os import dimslash let discord = newDiscordClient(getEnv("DISCORD_TOKEN")) var handler = newInteractionHandler(discord, defaultGuildId = "YOUR_GUILD_ID") # Slash command — simple handler.addSlash("ping", "Replies with pong") do: await handler.reply(i, "pong") # Slash command — typed parameters handler.addSlash("sum", "Adds integers") do (i: Interaction, a: int, b: int): await handler.reply(i, "sum = " & $(a + b)) # User context-menu command handler.addUser("userinfo") do: let user = i.member.get.user await handler.reply(i, "User: " & user.username) # Message context-menu command handler.addMessage("quote") do: await handler.reply(i, "You quoted a message!") # Button handler handler.addButton("action:confirm") do: await handler.reply(i, "Confirmed!") # Select-menu handler handler.addSelect("color_picker") do: let choices = i.selectValues await handler.reply(i, "You picked: " & choices.join(", ")) # Modal submit handler handler.addModal("feedback_form") do: let answer = i.modalValue("feedback_text").get("(empty)") await handler.reply(i, "Thanks! " & answer) # Autocomplete — fallback for any option of "sum" handler.addAutocomplete("sum") do: await handler.suggest(i, @["1", "2", "3"]) proc onReady(s: Shard, r: Ready) {.event(discord).} = await handler.registerCommands() proc interactionCreate(s: Shard, i: Interaction) {.event(discord).} = discard await handler.handleInteraction(s, i) waitFor discord.startSession(gateway_intents = {giGuilds})
Architecture
::
InteractionHandler ├── CommandRegistry (stores all registered commands) ├── DSL helpers (addSlash, addUser, addButton …) ├── Dispatch (handleInteraction routes to callbacks) ├── Sync (registerCommands pushes to Discord API) └── Context helpers (reply, deferResponse, followup, suggest)
Module overview
| Module | Description |
|---|---|
| types | Core types: InteractionHandler, CommandRegistry, … |
| dsl | DSL helpers: addSlash, addUser, addMessage, … |
| slashargs | Typed extraction of slash-command options |
| componentargs | Helpers for component/modal payload extraction |
| registry | Internal command store |
| dispatch | Routes interactions to registered handlers |
| sync | Bulk-overwrites commands to Discord |
| context | Reply / defer / followup helpers |
Procs
proc newInteractionHandler(discord: DiscordClient; defaultGuildId = ""): InteractionHandler {. ...raises: [], tags: [], forbids: [].}
-
Creates a new InteractionHandler wired to the given DiscordClient.
The handler is the central object — it owns the CommandRegistry, provides the DSL helpers, dispatches incoming interactions, and synchronises commands to Discord.
Parameters
- discord – a dimscord DiscordClient (must already be constructed).
- defaultGuildId – when non-empty, registerCommands() targets this guild by default. Guild-scoped commands update instantly; global commands (empty string) can take up to an hour.
Typical usage
let discord = newDiscordClient(getEnv("DISCORD_TOKEN")) var handler = newInteractionHandler(discord, defaultGuildId = "123456789") # 1. Register commands handler.addSlash("ping", "Pong!") do: await handler.reply(i, "pong") # 2. Sync in onReady proc onReady(s: Shard, r: Ready) {.event(discord).} = await handler.registerCommands() # 3. Dispatch in interactionCreate proc interactionCreate(s: Shard, i: Interaction) {.event(discord).} = discard await handler.handleInteraction(s, i)
Example: cmd: -r:off -d:ssl
import dimscord let discord = newDiscordClient("TOKEN") # Global commands (may take up to 1 hour to propagate): var global = newInteractionHandler(discord) # Guild-scoped commands (instant update, great for development): var dev = newInteractionHandler(discord, defaultGuildId = "123456789")
Exports
-
newInvalidInteractionError, RegisteredCommand, HandlerError, InteractionHandler, CommandHandlerProc, newNotFoundError, newNotImplementedError, CommandKind, ensureImplemented, CommandRegistry, HandlerErrorKind, pairs, register, findAutocomplete, find, newRegistry, addAutocompleteForOption, addMessage, addSelect, addModal, addAutocompleteForOption, addUser, addAutocompleteForOption, slashOptionNames, addSlashProc, registerSlashOptionNames, addAutocomplete, addMessage, addSelect, addUser, hasSlashOption, addModal, addAutocomplete, addAutocomplete, addButton, addAutocomplete, addUser, addAutocomplete, addButton, addMessage, addSlash, handleInteraction, registerCommands, reply, followup, suggest, suggest, deferResponse, getSlashArg, requireSlashArg, focusedOptionName, getSlashArg, slashOptions, getSlashArg, getSlashArg, normalizeOptionName, requireSlashArg, getSlashArg, requireSlashArg, requireSlashArg, requireSlashArg, getSlashArg, focusedOption, requireSlashArg, focusedOptionValue, modalValues, modalValue, customId, selectValues