Add custom args parser to allow spaces in arguments

Fixes #96 where worlds with spaces could not be
used with chunkmaster.

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/109/head
trivernis 4 years ago
parent f15dc646f6
commit aad4143e8a
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -1,6 +1,7 @@
package net.trivernis.chunkmaster.commands
import net.trivernis.chunkmaster.Chunkmaster
import net.trivernis.chunkmaster.lib.ArgParser
import net.trivernis.chunkmaster.lib.Subcommand
import org.bukkit.Server
import org.bukkit.command.Command
@ -11,6 +12,7 @@ import org.bukkit.command.TabCompleter
class CommandChunkmaster(private val chunkmaster: Chunkmaster, private val server: Server) : CommandExecutor,
TabCompleter {
private val commands = HashMap<String, Subcommand>()
private val argParser = ArgParser()
init {
registerCommands()
@ -36,7 +38,9 @@ class CommandChunkmaster(private val chunkmaster: Chunkmaster, private val serve
/**
* /chunkmaster command to handle all commands
*/
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
override fun onCommand(sender: CommandSender, command: Command, label: String, bukkitArgs: Array<out String>): Boolean {
val args = argParser.parseArguments(bukkitArgs.joinToString(" "))
if (args.isNotEmpty()) {
if (sender.hasPermission("chunkmaster.${args[0].toLowerCase()}")) {
return if (commands.containsKey(args[0])) {

@ -0,0 +1,77 @@
package net.trivernis.chunkmaster.lib
/**
* Better argument parser for command arguments
*/
class ArgParser {
private var input = ""
private var position = 0
private var currentChar = ' '
/**
* Parses arguments from a string and respects quotes
*/
fun parseArguments(arguments: String): List<String> {
if (arguments.isEmpty()) {
return emptyList()
}
input = arguments
position = 0
currentChar = input[position]
val args = ArrayList<String>()
var arg = ""
while (!endReached()) {
nextCharacter()
if (currentChar.isWhitespace()) {
if (arg.isNotBlank()) {
args.add(arg)
}
arg = ""
} else if (currentChar == '"') {
if (arg.isNotBlank()) {
args.add(arg)
}
arg = parseString()
if (arg.isNotBlank()) {
args.add(arg)
}
arg = ""
} else {
arg += currentChar
}
}
if (arg.isNotBlank()) {
args.add(arg)
}
return args
}
/**
* Parses an enquoted string
*/
private fun parseString(): String {
var output = ""
while (!endReached()) {
nextCharacter()
if (currentChar == '"') {
break
}
output += currentChar
}
return output
}
private fun nextCharacter() {
if (!endReached()) {
currentChar = input[position++]
}
}
private fun endReached(): Boolean {
return position >= input.length
}
}

@ -0,0 +1,49 @@
package net.trivernis.chunkmaster.lib
import io.kotest.matchers.shouldBe
import org.junit.Test
class ArgParserTest {
var argParser = ArgParser()
@Test
fun `it parses arguments`() {
argParser.parseArguments("first second third forth").shouldBe(listOf("first", "second", "third", "forth"))
}
@Test
fun `it parses quoted arguments as one argument`() {
argParser.parseArguments("first \"second with space\" third").shouldBe(listOf("first", "second with space", "third"))
argParser.parseArguments("\"first\" \"second\" \"third\"").shouldBe(listOf("first", "second", "third"))
}
@Test
fun `it parses single arguments`() {
argParser.parseArguments("one").shouldBe(listOf("one"))
argParser.parseArguments("\"one\"").shouldBe(listOf("one"))
}
@Test
fun `it parses no arguments`() {
argParser.parseArguments("").shouldBe(emptyList())
}
@Test
fun `it parses just whitespace as no arguments`() {
argParser.parseArguments(" ").shouldBe(emptyList())
argParser.parseArguments("\t\t").shouldBe(emptyList())
}
@Test
fun `it parses arguments with weird whitespace`() {
argParser.parseArguments(" first second \t third \n forth ").shouldBe(listOf("first", "second", "third", "forth"))
}
@Test
fun `it deals predictable with malformed input`() {
argParser.parseArguments("first \"second third fourth").shouldBe(listOf("first", "second third fourth"))
argParser.parseArguments("\"first second \"third\" fourth").shouldBe(listOf("first second ", "third", " fourth"))
argParser.parseArguments("first second third fourth\"").shouldBe(listOf("first", "second", "third", "fourth"))
argParser.parseArguments("\"").shouldBe(emptyList())
}
}

@ -1,8 +1,8 @@
package net.trivernis.chunkmaster
package net.trivernis.chunkmaster.lib
import io.kotest.matchers.string.shouldNotBeEmpty
import io.mockk.every
import io.mockk.mockk
import net.trivernis.chunkmaster.lib.LanguageManager
import net.trivernis.chunkmaster.Chunkmaster
import org.bukkit.configuration.file.FileConfiguration
import org.junit.Test
Loading…
Cancel
Save