mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 20:05:02 -04:00
cli: enum parser
This commit is contained in:
parent
3ec82ad51f
commit
6e8fdb78fe
@ -15,7 +15,9 @@ package de.bixilon.minosoft.commands.nodes
|
|||||||
|
|
||||||
import de.bixilon.minosoft.commands.parser.ArgumentParser
|
import de.bixilon.minosoft.commands.parser.ArgumentParser
|
||||||
import de.bixilon.minosoft.commands.stack.CommandExecutor
|
import de.bixilon.minosoft.commands.stack.CommandExecutor
|
||||||
|
import de.bixilon.minosoft.commands.stack.CommandStack
|
||||||
import de.bixilon.minosoft.commands.suggestion.types.SuggestionType
|
import de.bixilon.minosoft.commands.suggestion.types.SuggestionType
|
||||||
|
import de.bixilon.minosoft.commands.util.CommandReader
|
||||||
|
|
||||||
class ArgumentNode : ExecutableNode {
|
class ArgumentNode : ExecutableNode {
|
||||||
private val parser: ArgumentParser<*>
|
private val parser: ArgumentParser<*>
|
||||||
@ -40,4 +42,11 @@ class ArgumentNode : ExecutableNode {
|
|||||||
super.addChild(node)
|
super.addChild(node)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun execute(reader: CommandReader, stack: CommandStack) {
|
||||||
|
reader.skipWhitespaces()
|
||||||
|
val parsed = parser.parse(reader)
|
||||||
|
stack.push(name, parsed)
|
||||||
|
super.execute(reader, stack)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ abstract class ExecutableNode(
|
|||||||
redirect: CommandNode? = null,
|
redirect: CommandNode? = null,
|
||||||
) : CommandNode(executable, redirect) {
|
) : CommandNode(executable, redirect) {
|
||||||
|
|
||||||
private fun execute(stack: CommandStack) {
|
protected fun execute(stack: CommandStack) {
|
||||||
try {
|
try {
|
||||||
executor?.invoke(stack)
|
executor?.invoke(stack)
|
||||||
} catch (exception: Throwable) {
|
} catch (exception: Throwable) {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.commands.parser.minosoft.enums
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.commands.errors.parser.ParserError
|
||||||
|
import de.bixilon.minosoft.commands.util.CommandReader
|
||||||
|
import de.bixilon.minosoft.commands.util.ReadResult
|
||||||
|
|
||||||
|
class EnumParseError(
|
||||||
|
reader: CommandReader,
|
||||||
|
result: ReadResult<*>,
|
||||||
|
) : ParserError(reader, result)
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.commands.parser.minosoft.enums
|
||||||
|
|
||||||
|
import de.bixilon.kutil.enums.ValuesEnum
|
||||||
|
import de.bixilon.minosoft.commands.errors.suggestion.NoSuggestionError
|
||||||
|
import de.bixilon.minosoft.commands.parser.ArgumentParser
|
||||||
|
import de.bixilon.minosoft.commands.parser.factory.ArgumentParserFactory
|
||||||
|
import de.bixilon.minosoft.commands.suggestion.ArraySuggestion
|
||||||
|
import de.bixilon.minosoft.commands.util.CommandReader
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
|
|
||||||
|
class EnumParser<E : Enum<*>>(
|
||||||
|
val values: ValuesEnum<E>,
|
||||||
|
) : ArgumentParser<E> {
|
||||||
|
override val examples: List<E> = values.VALUES.toList()
|
||||||
|
private val suggestion = ArraySuggestion(examples)
|
||||||
|
override val placeholder = ChatComponent.of("<enum>")
|
||||||
|
|
||||||
|
override fun parse(reader: CommandReader): E {
|
||||||
|
reader.readResult { reader.readEnum() }.let { return it.result ?: throw EnumParseError(reader, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CommandReader.readEnum(): E? {
|
||||||
|
return values.getOrNull(readString()?.lowercase()) // ToDo: Allow ordinals
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSuggestions(reader: CommandReader): List<E> {
|
||||||
|
val text = reader.readResult { reader.readString() }
|
||||||
|
if (text.result == null) {
|
||||||
|
return examples
|
||||||
|
}
|
||||||
|
return suggestion.suggest(text.result) ?: throw NoSuggestionError(reader, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : ArgumentParserFactory<EnumParser<*>> {
|
||||||
|
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:enum".toResourceLocation()
|
||||||
|
|
||||||
|
override fun build(connection: PlayConnection?) = TODO("Can not construct enum parser yet!")
|
||||||
|
|
||||||
|
override fun read(buffer: PlayInByteBuffer) = TODO("Can not construct enum parser yet!")
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ class CommandStack {
|
|||||||
stack.removeAll { index++ >= size }
|
stack.removeAll { index++ >= size }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun push(name: String, data: Any) {
|
fun push(name: String, data: Any?) {
|
||||||
stack.add(StackEntry(name, data))
|
stack.add(StackEntry(name, data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,19 +13,35 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.terminal.commands
|
package de.bixilon.minosoft.terminal.commands
|
||||||
|
|
||||||
|
import de.bixilon.kutil.enums.EnumUtil
|
||||||
|
import de.bixilon.kutil.enums.ValuesEnum
|
||||||
|
import de.bixilon.minosoft.commands.nodes.ArgumentNode
|
||||||
import de.bixilon.minosoft.commands.nodes.LiteralNode
|
import de.bixilon.minosoft.commands.nodes.LiteralNode
|
||||||
|
import de.bixilon.minosoft.commands.parser.minosoft.enums.EnumParser
|
||||||
|
|
||||||
object HelpCommand : Command {
|
object HelpCommand : Command {
|
||||||
|
|
||||||
override fun build(): LiteralNode {
|
override fun build(): LiteralNode {
|
||||||
return LiteralNode("help", setOf("?"), onlyDirectExecution = false, executor = {
|
return LiteralNode("help", setOf("?"), executor = { printHelp() })
|
||||||
printHelp(it["general"])
|
.addChild(ArgumentNode("subcommand", parser = EnumParser(HelpCommands), executor = { printHelp(it["subcommand"]!!) }))
|
||||||
})
|
|
||||||
.addChild(LiteralNode("general", executable = true))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun printHelp(subcommand: String?) {
|
fun printHelp() {
|
||||||
|
println("-------------- Minosoft help --------------")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printHelp(subcommand: HelpCommands) {
|
||||||
println("-------------- Minosoft help --------------")
|
println("-------------- Minosoft help --------------")
|
||||||
println("Subcommand: $subcommand")
|
println("Subcommand: $subcommand")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class HelpCommands {
|
||||||
|
GENERAL,
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object : ValuesEnum<HelpCommands> {
|
||||||
|
override val VALUES: Array<HelpCommands> = values()
|
||||||
|
override val NAME_MAP: Map<String, HelpCommands> = EnumUtil.getEnumValues(VALUES)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,11 @@ package de.bixilon.minosoft.commands.parser.brigadier.bool
|
|||||||
|
|
||||||
import de.bixilon.minosoft.commands.errors.suggestion.NoSuggestionError
|
import de.bixilon.minosoft.commands.errors.suggestion.NoSuggestionError
|
||||||
import de.bixilon.minosoft.commands.util.CommandReader
|
import de.bixilon.minosoft.commands.util.CommandReader
|
||||||
import org.junit.jupiter.api.Assertions.*
|
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.assertThrows
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
internal class BooleanParserTest {
|
internal class BooleanParserTest {
|
||||||
|
|
||||||
@ -35,19 +38,19 @@ internal class BooleanParserTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testCaseSensitivity() {
|
fun testCaseSensitivity() {
|
||||||
val reader = CommandReader("True")
|
val reader = CommandReader("True")
|
||||||
assertThrows(BooleanParseError::class.java) { (BooleanParser.parse(reader)) }
|
assertThrows<BooleanParseError> { (BooleanParser.parse(reader)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testEmpty() {
|
fun testEmpty() {
|
||||||
val reader = CommandReader("")
|
val reader = CommandReader("")
|
||||||
assertThrows(BooleanParseError::class.java) { (BooleanParser.parse(reader)) }
|
assertThrows<BooleanParseError> { (BooleanParser.parse(reader)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testTrash() {
|
fun testTrash() {
|
||||||
val reader = CommandReader("this is trash")
|
val reader = CommandReader("this is trash")
|
||||||
assertThrows(BooleanParseError::class.java) { (BooleanParser.parse(reader)) }
|
assertThrows<BooleanParseError> { (BooleanParser.parse(reader)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -83,6 +86,6 @@ internal class BooleanParserTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testNoSuggestion() {
|
fun testNoSuggestion() {
|
||||||
val reader = CommandReader("a")
|
val reader = CommandReader("a")
|
||||||
assertThrows(NoSuggestionError::class.java) { BooleanParser.getSuggestions(reader).size }
|
assertThrows<NoSuggestionError> { BooleanParser.getSuggestions(reader).size }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.commands.parser.minosoft.enums
|
||||||
|
|
||||||
|
import de.bixilon.kutil.enums.EnumUtil
|
||||||
|
import de.bixilon.kutil.enums.ValuesEnum
|
||||||
|
import de.bixilon.minosoft.commands.util.CommandReader
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.assertThrows
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal class EnumParserTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun checkFirst() {
|
||||||
|
val reader = CommandReader("FIRST")
|
||||||
|
val parser = EnumParser(Tests)
|
||||||
|
assertEquals(parser.parse(reader), Tests.FIRST)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun checkSecond() {
|
||||||
|
val reader = CommandReader("SECOND")
|
||||||
|
val parser = EnumParser(Tests)
|
||||||
|
assertEquals(parser.parse(reader), Tests.SECOND)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun checkCaseInsensitivity() {
|
||||||
|
val reader = CommandReader("sEcOnD")
|
||||||
|
val parser = EnumParser(Tests)
|
||||||
|
assertEquals(parser.parse(reader), Tests.SECOND)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun checkInvalid() {
|
||||||
|
val reader = CommandReader("invalid")
|
||||||
|
val parser = EnumParser(Tests)
|
||||||
|
assertThrows<EnumParseError> { parser.parse(reader) }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Tests {
|
||||||
|
FIRST,
|
||||||
|
SECOND,
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object : ValuesEnum<Tests> {
|
||||||
|
override val VALUES: Array<Tests> = values()
|
||||||
|
override val NAME_MAP: Map<String, Tests> = EnumUtil.getEnumValues(VALUES)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,8 +15,8 @@ package de.bixilon.minosoft.commands.util
|
|||||||
|
|
||||||
import de.bixilon.minosoft.commands.errors.reader.OutOfBoundsError
|
import de.bixilon.minosoft.commands.errors.reader.OutOfBoundsError
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.Assertions.assertThrows
|
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.assertThrows
|
||||||
|
|
||||||
internal class CommandReaderTest {
|
internal class CommandReaderTest {
|
||||||
@Test
|
@Test
|
||||||
@ -52,7 +52,7 @@ internal class CommandReaderTest {
|
|||||||
assertEquals(reader.read(), 'e'.code)
|
assertEquals(reader.read(), 'e'.code)
|
||||||
assertEquals(reader.read(), 's'.code)
|
assertEquals(reader.read(), 's'.code)
|
||||||
assertEquals(reader.read(), 't'.code)
|
assertEquals(reader.read(), 't'.code)
|
||||||
assertThrows(OutOfBoundsError::class.java) { reader.unsafeRead() }
|
assertThrows<OutOfBoundsError> { reader.unsafeRead() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user