Skip to content

Commit

Permalink
Merge pull request #56 from Kyando2/select
Browse files Browse the repository at this point in the history
Add support for select options with select!
  • Loading branch information
xxxAnn authored Feb 18, 2022
2 parents f841f68 + 5c24ff2 commit 83f9160
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 7 deletions.
34 changes: 33 additions & 1 deletion src/client/handlers.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export command!,
component!,
modal!
modal!,
select!

"""
command!(
Expand Down Expand Up @@ -72,6 +73,13 @@ function generate_command_func(f::Function)
g
end

function generate_select_command_func(f::Function)
g = (ctx::Context) -> begin
f(ctx, ctx.interaction.data.values)
end
g
end

function makeargs(ctx::Context, args)
v = []
args = args[2:end]
Expand Down Expand Up @@ -127,6 +135,30 @@ function component!(f::Function, c::Client, custom_id::AbstractString; auto_ack:
if auto_update_ack push!(c.auto_update_ack, custom_id) end
return Component(custom_id=custom_id; kwargs...)
end

"""
select!(
f::Function
c::Client
custom_id::AbstractString
args::Vector{Tuple}
kwargs...
)
Adds a handler for INTERACTION CREATE gateway events where the InteractionData's `custom_id` field matches `custom_id`.
The `f` parameter signature should be:
```
(ctx::Context, choices::Vector{String}) -> Any
```
"""
function select!(f::Function, c::Client, custom_id::AbstractString, args...; auto_ack::Bool=true, auto_update_ack::Bool=true, kwargs...)
add_handler!(c, OnInteractionCreate(generate_select_command_func(f); custom_id=custom_id))
if !auto_ack push!(c.no_auto_ack, custom_id) end
if auto_update_ack push!(c.auto_update_ack, custom_id) end
if length(args) == 0 throw(FieldRequired("options", "SelectOption")) end
return Component(custom_id=custom_id; options=[SelectOption(a...) for a in args], type=3, kwargs...)
end

"""
handle(
c::Client
Expand Down
8 changes: 7 additions & 1 deletion src/types/exception.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ struct NamingError <: Exception
reason::String
end

struct FieldRequired <: Exception
field::String
structname::String
end

NamingError(a::AbstractString, nameof::String) = NamingError(a, nameof, "it may be too long or contain invalid characters.")

Base.showerror(io::IO, e::NamingError) = print(io, "Name $(e.invalid_name) is an invalid name for `$(e.name_of)`` because `$(e.reason)`.")
Base.showerror(io::IO, e::NamingError) = print(io, "Name $(e.invalid_name) is an invalid name for `$(e.name_of)` because `$(e.reason)`.")
Base.showerror(io::IO, e::FieldRequired) = print(io, "Field `$(e.field)` is required to construct a `$(e.structname)`.")
8 changes: 8 additions & 0 deletions src/types/interaction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ struct SelectOption <: DiscordObject
end
@boilerplate SelectOption :constructors :docs :lower :merge :mock

function SelectOption(label, value, args...)
if length(args)>0
r = [:description, :emoji, :default]
t = Dict([(r[x+1], args[x+1]) for x in 0:length(args)])
SelectOption(; label=label, value=value, t...)
else SelectOption(; label=label, value=value) end
end

"""
An interactable component.
More details [here](https://discord.com/developers/docs/interactions/message-components).
Expand Down
11 changes: 10 additions & 1 deletion src/utils/helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -650,14 +650,23 @@ end
Helper function that is equivalent to calling `extops(ctx.interaction.data.options)`
"""
opt(ctx::Context) = ismissing(ctx.interaction.data.components) ? extops(ctx.interaction.data.options) : Dict([(comp.custom_id, comp.value) for comp in vcat([c.components for c in ctx.interaction.data.components]...)])
function opt(ctx::Context)
if ismissing(ctx.interaction.data.components)
extops(ctx.interaction.data.options)
else
extops(ctx.interaction.data.components, :custom_id)
end
end
"""
extops(ops::Vector)
Creates a Dict of `option name` -> `option value` for the given vector of [`ApplicationCommandOption`](@ref).
If the option is of `Subcommand` type, creates a dict for all its subcommands.
"""
extops(ops::Vector) = Dict([(op.name, Int(op.type) < 3 ? extops(op.options) : op.value) for op in ops])
extops(ops::Vector, kf::Symbol) = extops(ops, kf, :value)
extops(ops::Vector, kf::Symbol, kv::Symbol) = Dict([(getproperty(comp, kf), getproperty(comp, kv)) for comp in vcat([c.components for c in ops]...)])

"""
Return an empty `Dict` if the list of options used is missing.
"""
Expand Down
14 changes: 10 additions & 4 deletions test/fulltest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,17 @@ command!(client, TESTGUILD, "water", "Water a plant", legacy=false, options=[
reply(client, ctx, components=[cm], content="$(mention(ctx)) watered their plant for $(howmuch) hours. So much that the plant grew taller than them!")
end

command!(client, TESTGUILD, "test", "Test something", legacy=false, auto_ack=false) do ctx
cm = Component(; type=4, custom_id="name", label="Name", style=1)
modal!(client, "ttest", ctx, components=[cm], title="test") do context, name
reply(client, context, raw=true, content="Your name is $(name)")
command!(client, TESTGUILD, "test", "Test something", legacy=false) do ctx
cm = select!(
client,
"class",
("Rogue", "rogue"),
("Mage", "mage");
max_values=1
) do context, choices
reply(client, context, content="You chose $(choices[1])")
end
reply(client, ctx, components=[cm], content="What class you want noob?")
end

command!(client, TESTGUILD, "quit", "Ends the bot process!") do (ctx)
Expand Down

0 comments on commit 83f9160

Please sign in to comment.