Skip to content

Commit

Permalink
[6.0.10] update command system
Browse files Browse the repository at this point in the history
  • Loading branch information
Bkm016 committed Feb 27, 2023
1 parent 6da0783 commit b849ae5
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import taboolib.common.platform.command.component.CommandComponent
import taboolib.common.platform.command.component.CommandComponentDynamic
import taboolib.common.platform.command.component.CommandComponentLiteral
import taboolib.common.platform.function.adaptCommandSender
import taboolib.common.util.getFirst

/**
* TabooLib
Expand All @@ -20,14 +21,22 @@ data class CommandContext<T>(
val command: CommandStructure,
val name: String,
val commandCompound: CommandBase,
internal val rawArgs: Array<String>,
val newParser: Boolean,
internal var rawArgs: Array<String>,
internal var index: Int = 0,
internal var currentComponent: CommandComponent? = null
internal var currentComponent: CommandComponent? = null,
) {

/** 命令行解析器 */
internal val lineParser = if (newParser) CommandLineParser(rawArgs.joinToString(" ")).parse() else null

/**
* 获取命令发送者
* 实际参数
* 用于进行命令逻辑判断,与 rawArgs 不同,rawArgs 表示用户输入参数
*/
internal val realArgs = lineParser?.args?.toTypedArray() ?: rawArgs

/** 获取命令发送者 */
fun sender(): ProxyCommandSender {
return if (sender is ProxyCommandSender) sender else adaptCommandSender(sender as Any)
}
Expand All @@ -42,20 +51,63 @@ data class CommandContext<T>(

/**
* 检查命令发送者是否持有权限
* @param permission 权限
* @return 是否持有权限
*/
fun checkPermission(permission: String): Boolean {
return sender().hasPermission(permission)
}

/**
* 是否持有选项
* @param id 选项名称
* @return 是否持有选项
* @throws IllegalStateException 如果当前命令不支持新的命令解析器
*/
fun hasOption(id: String): Boolean {
lineParser ?: error("This command does not support the new parser.")
return lineParser.options.containsKey(id)
}

/**
* 获取选项
* @param id 选项名称
* @return 选项值
* @throws IllegalStateException 如果当前命令不支持新的命令解析器
*/
fun option(vararg id: String): String? {
lineParser ?: error("This command does not support the new parser.")
return id.getFirst { lineParser.options[it] }
}

/**
* 获取所有选项
* @return 选项列表
* @throws IllegalStateException 如果当前命令不支持新的命令解析器
*/
fun options(): Map<String, String> {
lineParser ?: error("This command does not support the new parser.")
return lineParser.options
}

/**
* 取全部参数,对当前位置之后的参数进行拼接
* @return 全部参数
*/
fun args(): Array<String> {
return rawArgs.filterIndexed { i, _ -> i <= index }.toTypedArray().also { it[index] = "${it[index]} ${rawArgs.filterIndexed { i, _ -> i > index }.joinToString(" ")}".trim() }
// 新的命令解析器
if (lineParser != null) {
return lineParser.args.toTypedArray()
}
// 原版命令解析器
val arr = rawArgs.filterIndexed { i, _ -> i <= index }.toTypedArray()
arr[index] = "${arr[index]} ${rawArgs.filterIndexed { i, _ -> i > index }.joinToString(" ")}".trim()
return arr
}

/**
* 取当前位置参数,对当前位置之后的参数进行拼接
* @return 当前位置参数
*/
fun self(): String {
return args()[index]
Expand Down Expand Up @@ -121,9 +173,11 @@ data class CommandContext<T>(
if (command != other.command) return false
if (name != other.name) return false
if (commandCompound != other.commandCompound) return false
if (newParser != other.newParser) return false
if (!rawArgs.contentEquals(other.rawArgs)) return false
if (index != other.index) return false
if (currentComponent != other.currentComponent) return false
if (lineParser != other.lineParser) return false
return true
}

Expand All @@ -132,9 +186,11 @@ data class CommandContext<T>(
result = 31 * result + command.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + commandCompound.hashCode()
result = 31 * result + newParser.hashCode()
result = 31 * result + rawArgs.contentHashCode()
result = 31 * result + index
result = 31 * result + (currentComponent?.hashCode() ?: 0)
result = 31 * result + (lineParser?.hashCode() ?: 0)
return result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package taboolib.common.platform.command

/**
* TabooLib
* taboolib.common.platform.command.CommandLineParser
*
* @author 坏黑
* @since 2023/2/27 09:28
*/
class CommandLineParser(val line: String) {

/** 支持转义的字符 */
val escapes = arrayOf('\'', '\"', '=', '-', ':', '\\')

/** 选项 */
val options = mutableMapOf<String, String>()

/** 参数 */
val args = mutableListOf<String>()

/** 当前文本块 */
val value = StringBuilder()

/** 引用 */
var quote = false

/** 选项 */
var option = false

/** 选项名称 */
val optionName = StringBuilder()

/**
* 识别一种命令格式:[选项] [参数]
* 例如:-a -b 1 2 3
* 选项:{a=, b=}
* 参数:[1, 2, 3]
*
* 选项可以使用等号赋值,例如:-a=1 -b=2 1 2 3
* 此时选项为:{a=1, b=2}
* 此时参数为:[1, 2, 3]
*
* 参数可以使用双引号或单引号包裹,例如:/test -a='N M S L' "1 2 3"
* 此时选项为:{a=N M S L}
* 此时参数为:[1 2 3]
*
* 引号可以使用反斜杠转义,例如:/test -a='N M S L' \"1 2 3\"
* 此时选项为:{a=N M S L}
* 此时参数为:["1, 2, 3"]
*/
fun parse(): CommandLineParser {
var i = 0
val len = line.length
while (i < len) {
val c = line[i]
when {
// 转义字符
c == '\\' && i + 1 < line.length && escapes.contains(line[i + 1]) -> {
value += line[i + 1]
i += 2
}
// 引号
c == '\'' || c == '\"' -> {
// 引号结束
if (quote) {
close()
}
quote = !quote
i++
}
// 空格
c == ' ' && !quote -> {
close()
i++
}
// 选项
c == '-' && !quote -> {
option = true
i++
}
// 选项名称
option && c == '=' || c == ':' -> {
optionName += value
value.clear()
i++
}
// 其他文本
else -> {
value += c
i++
}
}
}
close()
return this
}

/** 结束 */
fun close() {
// 先关闭选项,否则会导致选项名称丢失
closeOption()
// 再关闭参数
closeValue()
}

/** 结束参数 */
fun closeValue() {
if (value.isNotEmpty()) {
args += value.toString()
value.clear()
}
}

/** 结束选项 */
fun closeOption() {
if (option) {
if (optionName.isNotEmpty()) {
options[optionName.toString()] = value.toString()
} else {
options[value.toString()] = ""
}
optionName.clear()
value.clear()
option = false
}
}

operator fun StringBuilder.plusAssign(c: Char) {
this.append(c)
}

operator fun StringBuilder.plusAssign(s: String) {
this.append(s)
}

operator fun StringBuilder.plusAssign(s: StringBuilder) {
this.append(s)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fun command(
permissionMessage: String = "",
permissionDefault: PermissionDefault = PermissionDefault.OP,
permissionChildren: Map<String, PermissionDefault> = emptyMap(),
newParser: Boolean = false,
commandBuilder: CommandBase.() -> Unit,
) {
registerCommand(
Expand All @@ -36,15 +37,15 @@ fun command(

override fun execute(sender: ProxyCommandSender, command: CommandStructure, name: String, args: Array<String>): Boolean {
val commandBase = CommandBase().also(commandBuilder)
return commandBase.execute(CommandContext(sender, command, name, commandBase, args))
return commandBase.execute(CommandContext(sender, command, name, commandBase, newParser, args))
}
},
// 创建补全器
object : CommandCompleter {

override fun execute(sender: ProxyCommandSender, command: CommandStructure, name: String, args: Array<String>): List<String>? {
val commandBase = CommandBase().also(commandBuilder)
return commandBase.suggest(CommandContext(sender, command, name, commandBase, args))
return commandBase.suggest(CommandContext(sender, command, name, commandBase, newParser, args))
}
},
// 传入原始命令构建器
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fun CommandComponentDynamic.suggestUncheck(suggest: () -> List<String>?): Comman
* 创建参数补全(仅布尔值)
*/
fun CommandComponentDynamic.suggestBoolean(): CommandComponentDynamic {
return suggest { listOf("true", "false") }
return suggest { listOf("true", "false", "t", "f") }
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ fun <T> CommandContext<T>.floatOrNull(id: String): Float? {
* @throws IllegalStateException 参数不存在,或者参数不是整型
*/
fun <T> CommandContext<T>.bool(id: String): Boolean {
return get(id).equals("true", true)
val value = get(id)
return value.equals("true", true) || value.equals("1", true)
}

/**
Expand All @@ -84,5 +85,6 @@ fun <T> CommandContext<T>.bool(id: String): Boolean {
* @return 指定位置的输入参数
*/
fun <T> CommandContext<T>.boolOrNull(id: String): Boolean? {
return getOrNull(id)?.equals("true", true)
val value = getOrNull(id) ?: return null
return value.equals("true", true) || value.equals("1", true)
}
Loading

0 comments on commit b849ae5

Please sign in to comment.