feat: Improve arguments
* Add UserConverter * Add a way to specify default value
This commit is contained in:
parent
fce8afa2b2
commit
04472f8bfa
13 changed files with 119 additions and 21 deletions
|
@ -1,5 +1,6 @@
|
||||||
package io.github.null2264.tsukumogami.bot.core.module
|
package io.github.null2264.tsukumogami.bot.core.module
|
||||||
|
|
||||||
|
import io.github.null2264.tsukumogami.bot.core.module.arguments.Test2Arguments
|
||||||
import io.github.null2264.tsukumogami.bot.core.module.arguments.TestArguments
|
import io.github.null2264.tsukumogami.bot.core.module.arguments.TestArguments
|
||||||
import io.github.null2264.tsukumogami.core.module.api.botModules
|
import io.github.null2264.tsukumogami.core.module.api.botModules
|
||||||
import kotlinx.datetime.Clock
|
import kotlinx.datetime.Clock
|
||||||
|
@ -13,7 +14,7 @@ val generalModule = botModules("General") {
|
||||||
}
|
}
|
||||||
|
|
||||||
groups("group") {
|
groups("group") {
|
||||||
commands("test", arguments = ::TestArguments) { ctx, args -> ctx.send("Hello world ${args.test}") }
|
commands("test", arguments = ::Test2Arguments) { ctx, args -> ctx.send("Hello world ${args.user}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
commands("test", arguments = ::TestArguments) { ctx, args -> ctx.send("Hello world ${args.test}") }
|
commands("test", arguments = ::TestArguments) { ctx, args -> ctx.send("Hello world ${args.test}") }
|
||||||
|
|
|
@ -2,7 +2,14 @@ package io.github.null2264.tsukumogami.bot.core.module.arguments
|
||||||
|
|
||||||
import io.github.null2264.tsukumogami.core.commands.Arguments
|
import io.github.null2264.tsukumogami.core.commands.Arguments
|
||||||
import io.github.null2264.tsukumogami.core.commands.ext.string
|
import io.github.null2264.tsukumogami.core.commands.ext.string
|
||||||
|
import io.github.null2264.tsukumogami.core.commands.ext.user
|
||||||
|
|
||||||
class TestArguments : Arguments() {
|
class TestArguments : Arguments() {
|
||||||
val test by string("Test")
|
val test by string("Test") {
|
||||||
|
default("Lmao")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test2Arguments : Arguments() {
|
||||||
|
val user by user("User")
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ open class Bot internal constructor(): IGroup {
|
||||||
private fun getContext(message: Message): Context {
|
private fun getContext(message: Message): Context {
|
||||||
val candidate = message.content.parsePrefixCommandAndArguments()
|
val candidate = message.content.parsePrefixCommandAndArguments()
|
||||||
val context = Context(this, message, candidate?.first, candidate?.second?.toMutableList())
|
val context = Context(this, message, candidate?.first, candidate?.second?.toMutableList())
|
||||||
context.command = getCommand(context.candidate?.removeAt(0))
|
context.command = getCommand(context.pullCandidateOrNull())
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import dev.kord.rest.builder.message.allowedMentions
|
||||||
import io.github.null2264.tsukumogami.core.commands.Command
|
import io.github.null2264.tsukumogami.core.commands.Command
|
||||||
|
|
||||||
class Context(
|
class Context(
|
||||||
private val bot: Bot,
|
val bot: Bot,
|
||||||
private val message: Message,
|
private val message: Message,
|
||||||
/**
|
/**
|
||||||
* The prefix that used to invoke the command
|
* The prefix that used to invoke the command
|
||||||
|
@ -19,6 +19,9 @@ class Context(
|
||||||
val candidate: MutableList<String>?,
|
val candidate: MutableList<String>?,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user that invoked the command
|
||||||
|
*/
|
||||||
val author get() = message.author
|
val author get() = message.author
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +29,13 @@ class Context(
|
||||||
*/
|
*/
|
||||||
var command: Command? = null
|
var command: Command? = null
|
||||||
|
|
||||||
|
fun getCandidateOrNull() = candidate?.getOrNull(0)
|
||||||
|
fun pullCandidateOrNull() = candidate?.removeFirstOrNull()
|
||||||
|
fun pullCandidateIf(predicate: () -> Boolean): String? {
|
||||||
|
if (predicate()) return candidate?.removeFirstOrNull()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun send(content: String) = message.channel.createMessage(content)
|
suspend fun send(content: String) = message.channel.createMessage(content)
|
||||||
|
|
||||||
suspend fun reply(content: String, mentionsAuthor: Boolean = false) = message.channel.createMessage {
|
suspend fun reply(content: String, mentionsAuthor: Boolean = false) = message.channel.createMessage {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.github.null2264.tsukumogami.core.commands
|
package io.github.null2264.tsukumogami.core.commands
|
||||||
|
|
||||||
|
import io.github.null2264.tsukumogami.core.Context
|
||||||
import io.github.null2264.tsukumogami.core.commands.converters.Converter
|
import io.github.null2264.tsukumogami.core.commands.converters.Converter
|
||||||
|
|
||||||
abstract class Arguments {
|
abstract class Arguments {
|
||||||
|
@ -15,17 +16,13 @@ abstract class Arguments {
|
||||||
return converter
|
return converter
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun parse(values: List<String>?) {
|
suspend fun parse(context: Context) {
|
||||||
val currentValues = values?.toMutableList()
|
val currentValues = context.candidate?.toMutableList()
|
||||||
|
|
||||||
run {
|
run {
|
||||||
args.forEach { arg ->
|
args.forEach { arg ->
|
||||||
val value = try {
|
val value = currentValues?.removeFirstOrNull() ?: return@run
|
||||||
currentValues?.removeAt(0)
|
arg.converter.parse(context, value)
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
} ?: return@run
|
|
||||||
arg.converter.parse(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ open class Command(
|
||||||
|
|
||||||
open suspend fun invoke(context: Context) {
|
open suspend fun invoke(context: Context) {
|
||||||
val parsedArguments = arguments.call()
|
val parsedArguments = arguments.call()
|
||||||
parsedArguments.parse(context.candidate)
|
parsedArguments.parse(context)
|
||||||
handler.invoke(context, parsedArguments)
|
handler.invoke(context, parsedArguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ class Group(
|
||||||
override val allCommands: MutableMap<String, Command> = mutableMapOf()
|
override val allCommands: MutableMap<String, Command> = mutableMapOf()
|
||||||
|
|
||||||
override suspend fun invoke(context: Context) {
|
override suspend fun invoke(context: Context) {
|
||||||
val command = allCommands[context.candidate?.get(0)] ?: return
|
val command = allCommands[context.getCandidateOrNull()]
|
||||||
context.candidate?.removeAt(0)
|
context.pullCandidateIf { command != null } ?: return
|
||||||
context.command = command
|
context.command = command!!
|
||||||
command.invoke(context)
|
command.invoke(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.github.null2264.tsukumogami.core.commands.converters
|
package io.github.null2264.tsukumogami.core.commands.converters
|
||||||
|
|
||||||
|
import io.github.null2264.tsukumogami.core.Context
|
||||||
import io.github.null2264.tsukumogami.core.commands.Argument
|
import io.github.null2264.tsukumogami.core.commands.Argument
|
||||||
import io.github.null2264.tsukumogami.core.commands.Arguments
|
import io.github.null2264.tsukumogami.core.commands.Arguments
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
@ -10,9 +11,14 @@ abstract class Converter<OutputType: Any?> {
|
||||||
|
|
||||||
abstract var parsed: OutputType
|
abstract var parsed: OutputType
|
||||||
|
|
||||||
abstract suspend fun parse(input: String): OutputType
|
abstract suspend fun parse(context: Context, input: String): OutputType
|
||||||
|
|
||||||
operator fun getValue(thisRef: Arguments, property: KProperty<*>): OutputType {
|
operator fun getValue(thisRef: Arguments, property: KProperty<*>): OutputType {
|
||||||
return parsed
|
return this.parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
fun default(defaultValue: OutputType): OutputType {
|
||||||
|
this.parsed = defaultValue
|
||||||
|
return this.parsed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package io.github.null2264.tsukumogami.core.commands.converters.impl
|
package io.github.null2264.tsukumogami.core.commands.converters.impl
|
||||||
|
|
||||||
|
import io.github.null2264.tsukumogami.core.Context
|
||||||
import io.github.null2264.tsukumogami.core.commands.converters.Converter
|
import io.github.null2264.tsukumogami.core.commands.converters.Converter
|
||||||
|
|
||||||
class StringConverter : Converter<String>() {
|
class StringConverter : Converter<String>() {
|
||||||
|
|
||||||
override var parsed: String = ""
|
override var parsed: String = ""
|
||||||
|
|
||||||
override suspend fun parse(input: String): String {
|
override suspend fun parse(context: Context, input: String): String {
|
||||||
this.parsed = input
|
this.parsed = input
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package io.github.null2264.tsukumogami.core.commands.converters.impl
|
||||||
|
|
||||||
|
import dev.kord.common.entity.Snowflake
|
||||||
|
import dev.kord.core.entity.User
|
||||||
|
import io.github.null2264.tsukumogami.core.Context
|
||||||
|
import io.github.null2264.tsukumogami.core.annotation.TsukumogamiInternalApi
|
||||||
|
import io.github.null2264.tsukumogami.core.commands.converters.Converter
|
||||||
|
import io.github.null2264.tsukumogami.core.exceptions.CommandException
|
||||||
|
import io.github.null2264.tsukumogami.core.ext.users
|
||||||
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
|
|
||||||
|
class UserConverter : Converter<User>() {
|
||||||
|
|
||||||
|
override lateinit var parsed: User
|
||||||
|
|
||||||
|
override suspend fun parse(context: Context, input: String): User {
|
||||||
|
if (input.equals("me", true)) {
|
||||||
|
val user = context.author
|
||||||
|
if (user != null) {
|
||||||
|
this.parsed = user
|
||||||
|
return this.parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (input.equals("you", true)) {
|
||||||
|
this.parsed = context.bot.client.getSelf()
|
||||||
|
return this.parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parsed = context.findUser(input) ?:
|
||||||
|
throw CommandException("User not found")
|
||||||
|
|
||||||
|
return this.parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun Context.findUser(arg: String): User? =
|
||||||
|
if (arg.startsWith("<@") && arg.endsWith(">")) {
|
||||||
|
val id: String = arg.substring(2, arg.length - 1).replace("!", "")
|
||||||
|
|
||||||
|
try {
|
||||||
|
bot.client.getUser(Snowflake(id))
|
||||||
|
} catch (_: NumberFormatException) {
|
||||||
|
throw CommandException("Invalid user ID")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
bot.client.getUser(Snowflake(arg))
|
||||||
|
} catch (_: NumberFormatException) {
|
||||||
|
if (!arg.contains("#")) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
bot.client.users.firstOrNull { user ->
|
||||||
|
user.tag.equals(arg, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,19 @@
|
||||||
package io.github.null2264.tsukumogami.core.commands.ext
|
package io.github.null2264.tsukumogami.core.commands.ext
|
||||||
|
|
||||||
|
import dev.kord.core.entity.User
|
||||||
import io.github.null2264.tsukumogami.core.commands.Arguments
|
import io.github.null2264.tsukumogami.core.commands.Arguments
|
||||||
|
import io.github.null2264.tsukumogami.core.commands.converters.Converter
|
||||||
import io.github.null2264.tsukumogami.core.commands.converters.impl.StringConverter
|
import io.github.null2264.tsukumogami.core.commands.converters.impl.StringConverter
|
||||||
|
import io.github.null2264.tsukumogami.core.commands.converters.impl.UserConverter
|
||||||
|
|
||||||
fun Arguments.string(name: String) = args(name, StringConverter())
|
fun Arguments.string(name: String, declaration: Converter<String>.() -> Unit = {}): Converter<String> {
|
||||||
|
val converter = StringConverter()
|
||||||
|
declaration(converter)
|
||||||
|
return args(name, converter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Arguments.user(name: String, declaration: Converter<User>.() -> Unit = {}): Converter<User> {
|
||||||
|
val converter = UserConverter()
|
||||||
|
declaration(converter)
|
||||||
|
return args(name, converter)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.github.null2264.tsukumogami.core.ext
|
||||||
|
|
||||||
|
import dev.kord.core.Kord
|
||||||
|
import dev.kord.core.supplier.EntitySupplyStrategy
|
||||||
|
|
||||||
|
val Kord.users get() = with(EntitySupplyStrategy.cache).users
|
|
@ -4,7 +4,7 @@ import io.github.null2264.tsukumogami.core.Bot
|
||||||
import io.github.null2264.tsukumogami.core.commands.Command
|
import io.github.null2264.tsukumogami.core.commands.Command
|
||||||
import io.github.null2264.tsukumogami.core.commands.IGroup
|
import io.github.null2264.tsukumogami.core.commands.IGroup
|
||||||
|
|
||||||
class BotModule internal constructor(val name: String) : IGroup {
|
open class BotModule constructor(val name: String) : IGroup {
|
||||||
|
|
||||||
override val allCommands: MutableMap<String, Command> = mutableMapOf()
|
override val allCommands: MutableMap<String, Command> = mutableMapOf()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue