Skip to content

Commit

Permalink
impl argument processor (testing now)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt-MX committed Jul 2, 2024
1 parent 93be473 commit ac293c9
Show file tree
Hide file tree
Showing 24 changed files with 317 additions and 207 deletions.
1 change: 0 additions & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/.gradle/caches/paperweight/taskCache/reobfJar.log
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Command: C:\Program Files\Java\jdk-17\bin\java.exe -Xmx1G -classpath C:\Users\Mangr\.gradle\caches\modules-2\files-2.1\net.fabricmc\tiny-remapper\0.10.1\c293b2384ae12af74f407fa3aaa553bba4ac6763\tiny-remapper-0.10.1-fat.jar net.fabricmc.tinyremapper.Main D:\PC\Projects\KtBukkitGui\api\build\libs\ktgui-2.4.0-dev-all.jar D:\PC\Projects\KtBukkitGui\api\build\libs\api-2.4.0.jar C:\Users\Mangr\.gradle\caches\paperweight-userdev\ff775525efc29c3503a07d1006e63e5695a742b7505cf63e157d49d32419c69f\module\io.papermc.paper\dev-bundle\1.20.4-R0.1-SNAPSHOT\paperweight\setupCache\extractDevBundle.dir\data\mojang+yarn-spigot-reobf.tiny mojang+yarn spigot C:\Users\Mangr\.gradle\caches\paperweight-userdev\ff775525efc29c3503a07d1006e63e5695a742b7505cf63e157d49d32419c69f\module\io.papermc.paper\dev-bundle\1.20.4-R0.1-SNAPSHOT\paperweight\setupCache\applyMojangMappedPaperclipPatch.jar --threads=1
Finished after 2815.14 ms.
Command: C:\Program Files\Java\jdk-17\bin\java.exe -Xmx1G -classpath C:\Users\Mangr\.gradle\caches\modules-2\files-2.1\net.fabricmc\tiny-remapper\0.10.1\c293b2384ae12af74f407fa3aaa553bba4ac6763\tiny-remapper-0.10.1-fat.jar net.fabricmc.tinyremapper.Main D:\PC\Projects\KtBukkitGui\api\build\libs\ktgui-2.4.1-dev-all.jar D:\PC\Projects\KtBukkitGui\api\build\libs\api-2.4.1.jar C:\Users\Mangr\.gradle\caches\paperweight-userdev\ff775525efc29c3503a07d1006e63e5695a742b7505cf63e157d49d32419c69f\module\io.papermc.paper\dev-bundle\1.20.4-R0.1-SNAPSHOT\paperweight\setupCache\extractDevBundle.dir\data\mojang+yarn-spigot-reobf.tiny mojang+yarn spigot C:\Users\Mangr\.gradle\caches\paperweight-userdev\ff775525efc29c3503a07d1006e63e5695a742b7505cf63e157d49d32419c69f\module\io.papermc.paper\dev-bundle\1.20.4-R0.1-SNAPSHOT\paperweight\setupCache\applyMojangMappedPaperclipPatch.jar --threads=1
Finished after 3414.54 ms.
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ open class DeclarativeCommandBuilder(

operator fun FlagArgument.unaryPlus() = withFlag(this)
operator fun <T : Any> OptionArgument<T>.unaryPlus() = withOption(this)
operator fun <T : Any> Argument<T>.unaryPlus() = OptionArgument(this).unaryPlus()

fun getCurrentCommand(context: SuggestionInvocation<*>): Pair<SuggestionInvocation<*>, DeclarativeCommandBuilder?> {
val firstArg = context.rawArgs.firstOrNull()
Expand All @@ -217,24 +218,27 @@ open class DeclarativeCommandBuilder(
val cmdsList = cmds.flatten()

val list = context.rawArgs.toMutableList()
var suggestedArgs: List<String>? = null
val suggestedArgs = arrayListOf(*cmdsList.toTypedArray())

for (arg in expectedArguments) {
val processor = ArgumentProcessor(this, list)
val stringValue = arg.consume(processor) ?: continue
val result = arg.consume(processor)

suggestedArgs = getSuggestions(arg)?.getLastArgSuggestion(context)
if (result.isEmpty() && !arg.isRequired()) continue

val thisArgSuggestions = getSuggestions(arg)?.getLastArgSuggestion(context)
if (thisArgSuggestions != null) {
suggestedArgs.addAll(thisArgSuggestions)
}
}

// val arg = expectedArguments.getOrNull(context.rawArgs.size - 1)
// val suggestedArgs = getSuggestions(arg)?.getLastArgSuggestion(context)

return if (suggestedArgs != null) {
cmdsList + suggestedArgs
} else cmdsList
return suggestedArgs
}

fun nameEquals(arg: String) = name == arg || aliases.any { it == arg }
fun nameEquals(arg: String?) = name == arg || aliases.any { it == arg }

fun nameStarts(arg: String) = name.startsWith(arg, true) || aliases.any { it.startsWith(arg, true) }

Expand Down Expand Up @@ -291,42 +295,34 @@ open class DeclarativeCommandBuilder(
return
}

val argumentValues = hashMapOf<String, ArgumentContext<*>>()
val firstArg = context.rawArgs.firstOrNull()

var expectedArgumentIndex = 0
var providedArgumentIndex = 0
val cmd = subcommands.firstOrNull { it.nameEquals(firstArg) }
if (cmd != null) {
return cmd.invoke(
context.clone(context.rawArgs.subList(1, context.rawArgs.size))
)
}

// todo rewrite arguments processing to handle new ArgumentConsumer.
// Move onto args

while (providedArgumentIndex < context.rawArgs.size) {
val arg = context.rawArgs[providedArgumentIndex]
val argumentValues = hashMapOf<String, ArgumentContext<*>>()

// Check sub-commands
// todo could match multiple subcommands
val cmd = subcommands.firstOrNull { it.nameEquals(arg) }
if (cmd != null) {
return cmd.invoke(
context.clone(context.rawArgs.subList(1, context.rawArgs.size))
)
}
// var expectedArgumentIndex = 0
// var providedArgumentIndex = 0

// Check arguments
val expectedArg = expectedArguments.getOrNull(expectedArgumentIndex)
if (expectedArg != null) {
// Get full argument string using consumer
val consumed =
expectedArg.consumer.consume(context.rawArgs.subList(providedArgumentIndex, context.rawArgs.size))
providedArgumentIndex += consumed.size
val argumentProcessor = ArgumentProcessor(this, context.rawArgs)
for ((index, arg) in expectedArguments.withIndex()) {
if (argumentProcessor.done()) {
if (arg.isRequired()) {

// If the value is empty and IS required
if (expectedArg.isRequired() && consumed.isEmpty()) {
val missingArgContext =
InvalidArgContext(context.sender, context.alias, context.rawArgs, expectedArg, null)
InvalidArgContext(context.sender, context.alias, context.rawArgs, arg, null)

// Try and invoke this specific missing arg
if (expectedArg.invokeMissing(missingArgContext)) {
if (arg.invokeMissing(missingArgContext)) {
return
} else if (expectedArg.invokeInvalid(missingArgContext)) {
} else if (arg.invokeInvalid(missingArgContext)) {
return
}

Expand All @@ -338,69 +334,153 @@ open class DeclarativeCommandBuilder(
}

return
} else {
var isValid = expectedArg.validate(consumed)

val stringValue = consumed.joinToString(" ")
val actualValue = expectedArg.getValueOfString(this, context, consumed)

isValid = isValid && (expectedArg.isOptional() || actualValue != null)

if (!isValid) {
val invalidArgumentContext =
InvalidArgContext(context.sender, context.alias, context.rawArgs, expectedArg, stringValue)

if (expectedArg.invokeInvalid(invalidArgumentContext)) {
return
}

invalid.ifPresent { it.invoke(invalidArgumentContext) }
return
}

argumentValues[expectedArg.name()] = expectedArg.createContext(stringValue, actualValue)

expectedArgumentIndex++
}
} else {
if (unknownCommand.isPresent) {
unknownCommand.get().invoke(context)
} else {
context.reply(!"&cUnknown sub-command or arguments.")
}
return
continue
}
}

val missing = expectedArguments.filter { arg ->
!argumentValues.containsKey(arg.name())
}
val processorClone = argumentProcessor.clone()
val result = arg.consumer.consume(processorClone)
val actualValue = arg.getValueOfString(this, context, result.stringValue)

if (missing.isNotEmpty()) {
missing.forEach { arg ->
val missingArgContext =
InvalidArgContext(context.sender, context.alias, context.rawArgs, arg, null)
if (arg.isOptional() || (result.isEmpty() && actualValue != null)) {
argumentValues[arg.name()] = arg.createContext(result.stringValue, actualValue)
argumentProcessor.pointer = processorClone.pointer
argumentProcessor.optionsAndFlagsValues = processorClone.optionsAndFlagsValues
} else {
val invalidArgumentContext =
InvalidArgContext(context.sender, context.alias, context.rawArgs, arg, result.stringValue)

// Try and invoke this specific missing arg
if (arg.invokeMissing(missingArgContext)) {
return
} else if (arg.invokeInvalid(missingArgContext)) {
if (arg.invokeInvalid(invalidArgumentContext)) {
return
}

invalid.ifPresent { it.invoke(invalidArgumentContext) }
}
}

if (!argumentProcessor.done()) {
// Too many args, unknown command maybe?
if (unknownCommand.isPresent) {
unknownCommand.get().invoke(context)
} else {
context.reply(!"&cUnknown sub-command or arguments.")
}
return
}

val runnableContext =
RunnableCommandContext(context.sender, context.alias, context.rawArgs, argumentValues)

val executor =
runs.entries.firstOrNull { (clazz, _) ->
clazz.isAssignableFrom(context.sender.javaClass)
}
?: return context.reply(!"&cThis command can only be ran by ${runs.values.joinToString("/") { "${it.javaClass.simpleName}s" }}.")
val executor = runs.entries.firstOrNull { (clazz, _) ->
clazz.isAssignableFrom(context.sender.javaClass)
}
?: return context.reply(!"&cThis command can only be ran by ${runs.values.joinToString("/") { "${it.javaClass.simpleName}s" }}.")

executor.value.invoke(runnableContext)

// while (providedArgumentIndex < context.rawArgs.size) {
// val arg = context.rawArgs[providedArgumentIndex]
//
// // Check sub-commands
// // todo could match multiple subcommands
// val cmd = subcommands.firstOrNull { it.nameEquals(arg) }
// if (cmd != null) {
// return cmd.invoke(
// context.clone(context.rawArgs.subList(1, context.rawArgs.size))
// )
// }
//
// // Check arguments
// val expectedArg = expectedArguments.getOrNull(expectedArgumentIndex)
// if (expectedArg != null) {
// // Get full argument string using consumer
// val consumed =
// expectedArg.consumer.consume(context.rawArgs.subList(providedArgumentIndex, context.rawArgs.size))
// providedArgumentIndex += consumed.size
//
// // If the value is empty and IS required
// if (expectedArg.isRequired() && consumed.isEmpty()) {
// val missingArgContext =
// InvalidArgContext(context.sender, context.alias, context.rawArgs, expectedArg, null)
//
// // Try and invoke this specific missing arg
// if (expectedArg.invokeMissing(missingArgContext)) {
// return
// } else if (expectedArg.invokeInvalid(missingArgContext)) {
// return
// }
//
// // Invoke the global missing or invalid
// if (missing.isPresent) {
// missing.get().invoke(missingArgContext)
// } else if (invalid.isPresent) {
// invalid.get().invoke(missingArgContext)
// }
//
// return
// } else {
// var isValid = expectedArg.validate(consumed)
//
// val stringValue = consumed.joinToString(" ")
// val actualValue = expectedArg.getValueOfString(this, context, consumed)
//
// isValid = isValid && (expectedArg.isOptional() || actualValue != null)
//
// if (!isValid) {
// val invalidArgumentContext =
// InvalidArgContext(context.sender, context.alias, context.rawArgs, expectedArg, stringValue)
//
// if (expectedArg.invokeInvalid(invalidArgumentContext)) {
// return
// }
//
// invalid.ifPresent { it.invoke(invalidArgumentContext) }
// return
// }
//
// argumentValues[expectedArg.name()] = expectedArg.createContext(stringValue, actualValue)
//
// expectedArgumentIndex++
// }
// } else {
// if (unknownCommand.isPresent) {
// unknownCommand.get().invoke(context)
// } else {
// context.reply(!"&cUnknown sub-command or arguments.")
// }
// return
// }
// }
//
// val missing = expectedArguments.filter { arg ->
// !argumentValues.containsKey(arg.name())
// }
//
// if (missing.isNotEmpty()) {
// missing.forEach { arg ->
// val missingArgContext =
// InvalidArgContext(context.sender, context.alias, context.rawArgs, arg, null)
//
// // Try and invoke this specific missing arg
// if (arg.invokeMissing(missingArgContext)) {
// return
// } else if (arg.invokeInvalid(missingArgContext)) {
// return
// }
// }
// return
// }
//
// val runnableContext =
// RunnableCommandContext(context.sender, context.alias, context.rawArgs, argumentValues)
//
// val executor =
// runs.entries.firstOrNull { (clazz, _) ->
// clazz.isAssignableFrom(context.sender.javaClass)
// }
// ?: return context.reply(!"&cThis command can only be ran by ${runs.values.joinToString("/") { "${it.javaClass.simpleName}s" }}.")
//
// executor.value.invoke(runnableContext)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ open class Argument<T : Any>(
TODO()
}

open fun getDefaultSuggestions(): List<String>? {
open fun getDefaultSuggestions(): Collection<String>? {
val context = SuggestionInvocation(Optional.empty(), "", emptyList())
return if (suggests.isPresent) {
suggests.get().getSuggestion(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ class ArgumentProcessor(
val args: List<String>
) {
var pointer = 0
// Should be added to the command context
val optionsAndFlags = hashMapOf<String, String>()
var optionsAndFlagsValues = hashMapOf<String, Any>()

fun peek(i: Int) = args.getOrNull(pointer + i)
fun current() = peek(0)
Expand All @@ -20,15 +19,15 @@ class ArgumentProcessor(
val optionOrPointerId = command.optionsSyntax.removePrefixFrom(current()!!)

if (command.permittedFlags.any { it.chatName() == optionOrPointerId }) {
optionsAndFlags[optionOrPointerId] = true.toString()
optionsAndFlagsValues[optionOrPointerId] = true
pointer++
} else if (command.permittedOptions.any { it.name() == optionOrPointerId }) {
} else if (command.permittedOptions.any { it.chatName() == optionOrPointerId }) {

// TODO this should read the argument type args (does that make sense?)
// e.g '--test "hello world"' -> hello world

val value = peek(1) ?: continue
optionsAndFlags[optionOrPointerId] = value
optionsAndFlagsValues[optionOrPointerId] = value
pointer += 2
} else break
}
Expand All @@ -38,6 +37,13 @@ class ArgumentProcessor(

fun reset() {
this.pointer = 0
this.optionsAndFlags.clear()
this.optionsAndFlagsValues.clear()
}

fun clone() = ArgumentProcessor(command, args).apply {
this.optionsAndFlagsValues = this@ArgumentProcessor.optionsAndFlagsValues
this.pointer = this@ArgumentProcessor.pointer
}

fun done() = pointer >= args.size
}
Loading

0 comments on commit ac293c9

Please sign in to comment.