From aa18e826df1ef70ec2b0ed99d08efe833cec3bc2 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Thu, 4 Jan 2024 10:35:07 +0200 Subject: [PATCH] Console: autocomplete ALL THE THINGS! --- .../screens/devconsole/DevConsoleCommand.kt | 62 +++++++++++-------- .../ui/screens/devconsole/DevConsolePopup.kt | 4 +- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/core/src/com/unciv/ui/screens/devconsole/DevConsoleCommand.kt b/core/src/com/unciv/ui/screens/devconsole/DevConsoleCommand.kt index 3299ea4a36..8041fac255 100644 --- a/core/src/com/unciv/ui/screens/devconsole/DevConsoleCommand.kt +++ b/core/src/com/unciv/ui/screens/devconsole/DevConsoleCommand.kt @@ -10,24 +10,24 @@ import com.unciv.models.stats.Stat internal fun String.toCliInput() = this.lowercase().replace(" ","-") /** Returns the string to *add* to the existing command */ -fun getAutocompleteString(lastWord:String, allOptions:Iterable):String? { +fun getAutocompleteString(lastWord: String, allOptions: Collection):String? { val matchingOptions = allOptions.filter { it.toCliInput().startsWith(lastWord.toCliInput()) } if (matchingOptions.isEmpty()) return null - if (matchingOptions.size == 1) return matchingOptions.first().removePrefix(lastWord) + if (matchingOptions.size == 1) return matchingOptions.first().drop(lastWord.length) val firstOption = matchingOptions.first() for ((index, char) in firstOption.withIndex()) { if (matchingOptions.any { it.lastIndex < index } || matchingOptions.any { it[index] != char }) - return firstOption.substring(0, index).removePrefix(lastWord) + return firstOption.substring(0, index).drop(lastWord.length) } - return firstOption.removePrefix(lastWord) + return firstOption.drop(lastWord.length) } interface ConsoleCommand { fun handle(console: DevConsolePopup, params: List): DevConsoleResponse /** Returns the string to *add* to the existing command */ - fun autocomplete(params: List): String? = "" + fun autocomplete(console: DevConsolePopup, params: List): String? = "" } class ConsoleHintException(val hint:String):Exception() @@ -44,6 +44,36 @@ class ConsoleAction(val format: String, val action: (console: DevConsolePopup, p DevConsoleResponse.error(errorException.error) } } + + override fun autocomplete(console: DevConsolePopup, params: List): String? { + if (params.isEmpty()) return null + + val formatParams = format.split(" ").drop(2).map { + it.removeSurrounding("<",">").removeSurrounding("[","]").removeSurrounding("\"") + } + if (formatParams.size < params.size) return null + val formatParam = formatParams[params.lastIndex] + + val lastParam = params.last() + val options = when (formatParam) { + "civName" -> console.gameInfo.civilizations.map { it.civName } + "unitName" -> console.gameInfo.ruleset.units.keys + "promotionName" -> console.gameInfo.ruleset.unitPromotions.keys + "improvementName" -> console.gameInfo.ruleset.tileImprovements.keys + "featureName" -> console.gameInfo.ruleset.terrains.values.filter { it.type == TerrainType.TerrainFeature }.map { it.name } + "stat" -> Stat.names() + else -> listOf() + } + return getAutocompleteString(lastParam, options) + } + + fun validateFormat(format: String, params:List){ + val allParams = format.split(" ") + val requiredParamsAmount = allParams.count { it.startsWith('<') } + val optionalParamsAmount = allParams.count { it.startsWith('[') } + if (params.size < requiredParamsAmount || params.size > requiredParamsAmount + optionalParamsAmount) + throw ConsoleHintException("Format: $format") + } } interface ConsoleCommandNode : ConsoleCommand { @@ -57,10 +87,10 @@ interface ConsoleCommandNode : ConsoleCommand { return handler.handle(console, params.drop(1)) } - override fun autocomplete(params: List): String? { + override fun autocomplete(console: DevConsolePopup, params: List): String? { if (params.isEmpty()) return null val firstParam = params[0] - if (firstParam in subcommands) return subcommands[firstParam]!!.autocomplete(params.drop(1)) + if (firstParam in subcommands) return subcommands[firstParam]!!.autocomplete(console, params.drop(1)) return getAutocompleteString(firstParam, subcommands.keys) } } @@ -74,15 +104,6 @@ class ConsoleCommandRoot : ConsoleCommandNode { ) } - -fun validateFormat(format: String, params:List){ - val allParams = format.split(" ") - val requiredParamsAmount = allParams.count { it.startsWith('<') } - val optionalParamsAmount = allParams.count { it.startsWith('[') } - if (params.size < requiredParamsAmount || params.size > requiredParamsAmount + optionalParamsAmount) - throw ConsoleHintException("Format: $format") -} - class ConsoleUnitCommands : ConsoleCommandNode { override val subcommands = hashMapOf( @@ -269,13 +290,4 @@ class ConsoleCivCommands : ConsoleCommandNode { DevConsoleResponse.OK } ) - - override fun autocomplete(params: List): String? { - if (params.isNotEmpty()) - when (params[0]){ - "addstat" -> if (params.size == 2) - return getAutocompleteString(params[1], Stat.names()) - } - return super.autocomplete(params) - } } diff --git a/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt b/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt index 2ebe03991b..eac2ff6030 100644 --- a/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt +++ b/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt @@ -85,7 +85,9 @@ class DevConsolePopup(val screen: WorldScreen) : Popup(screen) { private fun getAutocomplete(): String { val params = getParams(textField.text) - return commandRoot.autocomplete(params) ?: "" + val result = commandRoot.autocomplete(this, params) + if (result.isNullOrEmpty()) return "" + return "$result " } internal fun getCivByName(name: String) = gameInfo.civilizations.firstOrNull { it.civName.toCliInput() == name.toCliInput() }