Skip to content

Commit 1b24b0b

Browse files
committed
refactor: enhance Kotlin-made config parser
1 parent 5c5a033 commit 1b24b0b

File tree

8 files changed

+104
-63
lines changed

8 files changed

+104
-63
lines changed

app/src/main/java/com/osfans/trime/data/base/DataManager.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ object DataManager {
5353
val userDataDir
5454
get() = File(prefs.profile.userDataDir).also { it.mkdirs() }
5555

56+
val prebuiltDataDir = File(sharedDataDir, "build")
57+
val stagingDir get() = File(userDataDir, "build")
58+
5659
/**
5760
* Return the absolute path of the compiled config file
5861
* based on given resource id.
@@ -62,9 +65,6 @@ object DataManager {
6265
*/
6366
@JvmStatic
6467
fun resolveDeployedResourcePath(resourceId: String): String {
65-
val stagingDir = File(userDataDir, "build")
66-
val prebuiltDataDir = File(sharedDataDir, "build")
67-
6868
val defaultPath = File(stagingDir, "$resourceId.yaml")
6969
if (!defaultPath.exists()) {
7070
val fallbackPath = File(prebuiltDataDir, "$resourceId.yaml")

app/src/main/java/com/osfans/trime/data/schema/Schema.kt

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,42 @@
55
package com.osfans.trime.data.schema
66

77
import com.osfans.trime.util.config.Config
8-
import kotlinx.serialization.Serializable
9-
import kotlinx.serialization.Transient
8+
import timber.log.Timber
109

11-
class Schema(
12-
schemaId: String = ".default",
10+
data class Schema(
11+
val switches: List<Switch>,
12+
val symbols: Map<String, Config>,
13+
val alphabet: String,
1314
) {
14-
private val config =
15-
if (schemaId == ".default") {
16-
Config.create("default")
17-
} else {
18-
Config.create("$schemaId.schema")
19-
}
20-
21-
val switches get() =
22-
config?.getList("switches")
23-
24-
val symbols get() =
25-
config?.getMap("punctuator/symbols")
26-
27-
val alphabet get() = config?.getString("speller/alphabet")
28-
29-
@Serializable
3015
data class Switch(
3116
val name: String = "",
3217
val options: List<String> = listOf(),
3318
val reset: Int = -1,
3419
val states: List<String> = listOf(),
35-
@Transient var enabled: Int = 0,
20+
var enabled: Int = 0,
3621
)
22+
23+
companion object {
24+
fun open(schemaId: String): Schema {
25+
val c = Config.openSchema(schemaId)
26+
return Schema(
27+
switches =
28+
c.getList("switches").mapNotNull decode@{ e ->
29+
try {
30+
Switch(
31+
name = e.getString("name"),
32+
options = e.getStringList("options"),
33+
reset = e.getInt("reset", -1),
34+
states = e.getStringList("states"),
35+
)
36+
} catch (e: Exception) {
37+
Timber.e(e, "Failed to decode switches of schema '$schemaId'")
38+
null
39+
}
40+
},
41+
symbols = c.getMap("punctuator/symbols"),
42+
alphabet = c.getString("speller/alphabet"),
43+
)
44+
}
45+
}
3746
}

app/src/main/java/com/osfans/trime/data/schema/SchemaManager.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,22 @@
55
package com.osfans.trime.data.schema
66

77
import com.osfans.trime.core.Rime
8-
import kotlinx.serialization.builtins.ListSerializer
98

109
object SchemaManager {
1110
private lateinit var currentSchema: Schema
1211
var visibleSwitches: List<Schema.Switch> = listOf()
1312

14-
private val defaultSchema = Schema()
15-
1613
@JvmStatic
1714
fun init(schemaId: String) {
18-
currentSchema = runCatching { Schema(schemaId) }.getOrDefault(defaultSchema)
19-
visibleSwitches = currentSchema.switches
20-
?.decode(ListSerializer(Schema.Switch.serializer()))
21-
?.filter { it.states.isNotEmpty() } ?: listOf() // 剔除没有 states 条目项的值,它们不作为开关使用
15+
currentSchema = Schema.open(schemaId)
16+
visibleSwitches =
17+
currentSchema.switches
18+
.filter { it.states.isNotEmpty() } // 剔除没有 states 条目项的值,它们不作为开关使用
2219
updateSwitchOptions()
2320
}
2421

2522
val activeSchema: Schema
26-
get() = runCatching { currentSchema }.getOrDefault(defaultSchema)
23+
get() = currentSchema
2724

2825
@JvmStatic
2926
fun updateSwitchOptions() {

app/src/main/java/com/osfans/trime/data/theme/ThemeFilesManager.kt

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,33 @@
55

66
package com.osfans.trime.data.theme
77

8-
import com.charleskorn.kaml.AnchorsAndAliases
9-
import com.charleskorn.kaml.Yaml
10-
import com.charleskorn.kaml.YamlConfiguration
11-
import com.charleskorn.kaml.YamlScalar
12-
import com.charleskorn.kaml.yamlMap
8+
import com.osfans.trime.data.base.DataManager
9+
import com.osfans.trime.util.config.Config
1310
import timber.log.Timber
1411
import java.io.File
1512

1613
object ThemeFilesManager {
17-
private val yaml =
18-
Yaml(
19-
configuration =
20-
YamlConfiguration(
21-
strictMode = false,
22-
anchorsAndAliases = AnchorsAndAliases.Permitted(null),
23-
),
24-
)
25-
2614
fun listThemes(dir: File): MutableList<ThemeItem> {
2715
val files = dir.listFiles { _, name -> name.endsWith("trime.yaml") } ?: return mutableListOf()
16+
val deployedMap = hashMapOf<String, String>()
17+
DataManager.stagingDir.list()?.forEach {
18+
deployedMap[it] = it
19+
}
20+
DataManager.prebuiltDataDir.list()?.forEach {
21+
deployedMap[it] = it
22+
}
2823
return files
2924
.sortedByDescending { it.lastModified() }
3025
.mapNotNull decode@{
3126
val item =
3227
runCatching {
33-
val map =
34-
yaml
35-
.parseToYamlNode(it.bufferedReader().readText())
36-
.yamlMap
3728
val configId = it.nameWithoutExtension
38-
val name = map.get<YamlScalar>("name")?.content ?: ""
29+
val name =
30+
if (deployedMap[it.name] != null) {
31+
Config.openConfig(configId).getString("name")
32+
} else {
33+
configId.removeSuffix(".trime")
34+
}
3935
ThemeItem(configId, name)
4036
}.getOrElse { e ->
4137
Timber.w("Failed to decode theme file ${it.absolutePath}: ${e.message}")

app/src/main/java/com/osfans/trime/ime/symbol/TabManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ object TabManager {
8888

8989
val symbolMaps = SchemaManager.activeSchema.symbols
9090
for ((key, value) in p) {
91-
if (symbolMaps?.containsKey(value) == true) {
91+
if (symbolMaps.containsKey(value)) {
9292
keysList.add(SimpleKeyBean(value, key))
9393
}
9494
}

app/src/main/java/com/osfans/trime/util/config/Config.kt

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,19 @@ class Config(
1414
private val data: ConfigData = ConfigData(),
1515
) {
1616
companion object {
17-
fun create(fileName: String): Config =
17+
fun openSchema(schemaId: String): Config =
1818
Config().apply {
19-
data.loadFromFile(DataManager.resolveDeployedResourcePath(fileName))
19+
loadFromFile(DataManager.resolveDeployedResourcePath("$schemaId.schema"))
20+
}
21+
22+
fun openConfig(configId: String): Config =
23+
Config().apply {
24+
loadFromFile(DataManager.resolveDeployedResourcePath(configId))
25+
}
26+
27+
fun openUserConfig(configId: String): Config =
28+
Config().apply {
29+
loadFromFile(DataManager.userDataDir.resolve("$configId.yaml").absolutePath)
2030
}
2131
}
2232

@@ -78,24 +88,46 @@ class Config(
7888
return runCatching { p?.getString() }.getOrNull() ?: defValue
7989
}
8090

81-
fun getItem(path: String): ConfigItem? {
91+
fun getItem(path: String): Config {
92+
Timber.d("read: $path")
93+
return Config().also {
94+
it.data.root = data.traverse(path)
95+
}
96+
}
97+
98+
fun getValue(path: String): Config {
99+
Timber.d("read: $path")
100+
return Config().also {
101+
it.data.root = data.traverse(path)?.configValue
102+
}
103+
}
104+
105+
fun getList(path: String): List<Config> {
82106
Timber.d("read: $path")
83-
return data.traverse(path)
107+
return data.traverse(path)?.configList?.map { v ->
108+
Config().also { it.data.root = v }
109+
} ?: emptyList()
84110
}
85111

86-
fun getValue(path: String): ConfigValue? {
112+
fun getStringList(path: String): List<String> {
87113
Timber.d("read: $path")
88-
return data.traverse(path)?.configValue
114+
return data.traverse(path)?.configList?.map { v ->
115+
v.configValue.getString()
116+
} ?: emptyList()
89117
}
90118

91-
fun getList(path: String): ConfigList? {
119+
fun getMap(path: String): Map<String, Config> {
92120
Timber.d("read: $path")
93-
return data.traverse(path)?.configList
121+
return data.traverse(path)?.configMap?.mapValues { (_, v) ->
122+
Config().also { it.data.root = v }
123+
} ?: emptyMap()
94124
}
95125

96-
fun getMap(path: String): ConfigMap? {
126+
fun getStringValueMap(path: String): Map<String, String> {
97127
Timber.d("read: $path")
98-
return data.traverse(path)?.configMap
128+
return data.traverse(path)?.configMap?.mapValues { (_, v) ->
129+
v.configValue.getString()
130+
} ?: emptyMap()
99131
}
100132

101133
fun getItem() = data.root

app/src/main/java/com/osfans/trime/util/config/ConfigData.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package com.osfans.trime.util.config
66

7+
import com.charleskorn.kaml.AnchorsAndAliases
78
import com.charleskorn.kaml.Yaml
89
import com.charleskorn.kaml.YamlConfiguration
910
import com.charleskorn.kaml.YamlException
@@ -41,6 +42,8 @@ class ConfigData {
4142
configuration =
4243
YamlConfiguration(
4344
strictMode = false,
45+
anchorsAndAliases = AnchorsAndAliases.Permitted(null),
46+
codePointLimit = CODE_POINT_LIMIT,
4447
),
4548
)
4649

@@ -79,4 +82,8 @@ class ConfigData {
7982
}
8083
return p
8184
}
85+
86+
companion object {
87+
private const val CODE_POINT_LIMIT = 6 * 1024 * 1024 // 6 MB
88+
}
8289
}

app/src/main/java/com/osfans/trime/util/config/ConfigTypes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import com.charleskorn.kaml.yamlScalar
1818
import kotlinx.serialization.DeserializationStrategy
1919

2020
/** Config item base class */
21-
abstract class ConfigItem(
21+
sealed class ConfigItem(
2222
val node: YamlNode,
2323
) {
2424
enum class ValueType {

0 commit comments

Comments
 (0)