2
0
Эх сурвалжийг харах

Improve `/permissions listPermissions`

Karlatemp 4 жил өмнө
parent
commit
ffcc489455

+ 89 - 3
mirai-console/backend/mirai-console/src/command/BuiltInCommands.kt

@@ -39,6 +39,7 @@ import net.mamoe.mirai.console.internal.pluginManagerImpl
 import net.mamoe.mirai.console.internal.util.runIgnoreException
 import net.mamoe.mirai.console.permission.Permission
 import net.mamoe.mirai.console.permission.Permission.Companion.parentsWithSelf
+import net.mamoe.mirai.console.permission.PermissionId
 import net.mamoe.mirai.console.permission.PermissionService
 import net.mamoe.mirai.console.permission.PermissionService.Companion.cancel
 import net.mamoe.mirai.console.permission.PermissionService.Companion.findCorrespondingPermissionOrFail
@@ -273,9 +274,94 @@ public object BuiltInCommands {
         @Description("查看所有权限列表")
         @SubCommand("listPermissions", "lp")
         public suspend fun CommandSender.listPermissions() {
-            sendMessage(
-                PermissionService.INSTANCE.getRegisteredPermissions()
-                    .joinToString("\n") { it.id.toString() + "    " + it.description })
+            class PermTree(
+                val perm: Permission,
+                val sub: MutableList<PermissionId> = mutableListOf(),
+            )
+
+            val rootView = PermTree(PermissionService.INSTANCE.rootPermission)
+            val mappings = mutableMapOf<PermissionId, PermTree>()
+            val permListSnapshot = PermissionService.INSTANCE.getRegisteredPermissions().toList()
+
+            permListSnapshot.forEach { perm ->
+                mappings[perm.id] = PermTree(perm)
+            }
+            mappings[rootView.perm.id] = rootView
+
+            permListSnapshot.forEach { perm ->
+                if (perm.id == rootView.perm.id) return@forEach
+
+                val parentView = mappings[perm.parent.id] ?: error("Can't find parent of ${perm.id}: ${perm.parent.id}")
+                parentView.sub.add(perm.id)
+            }
+
+            mappings.values.forEach { view ->
+                view.sub.sortWith { p1, p2 ->
+                    val namespaceCompare = p1.namespace compareTo p2.namespace
+                    if (namespaceCompare != 0) return@sortWith namespaceCompare
+
+                    if (p1.name == p2.name) return@sortWith 0 // ?
+                    if (p1.name == "*") return@sortWith -1
+                    if (p2.name == "*") return@sortWith 1
+
+                    return@sortWith p1.name compareTo p2.name
+                }
+            }
+
+            //*:*
+            // |  `-
+            // |- .....
+            // |  |  `-
+            // |  |- ......
+            // |  |  |  `-
+            // |  |  |-
+            val prefixed = 50
+
+            fun renderDepth(depth: Int, sb: AnsiMessageBuilder) {
+                repeat(depth) { sb.append(" | ") }
+            }
+
+            fun render(depth: Int, view: PermTree, sb: AnsiMessageBuilder) {
+                kotlin.run { // render perm id
+                    var doReset = false
+                    val permId = view.perm.id
+                    if (permId == rootView.perm.id || permId.name.endsWith("*")) {
+                        doReset = true
+                        sb.red()
+                    }
+                    sb.append(permId)
+                    if (doReset) {
+                        sb.reset()
+                    }
+                }
+
+                val linePrefixLen =
+                    (depth * 3) + 1 + view.perm.id.let { it.name.length + it.namespace.length } + (if (depth == 0) 0 else 1)
+                val descFlatten = view.perm.description.replace("\r\n", "\n").replace("\r", "\n")
+                if (!descFlatten.contains('\n') && linePrefixLen < prefixed) {
+                    if (descFlatten.isNotBlank()) {
+                        repeat(prefixed - linePrefixLen) { sb.append(' ') }
+                        sb.append("    ").append(descFlatten)
+                    }
+                } else {
+                    descFlatten.splitToSequence('\n').forEach { line ->
+                        sb.append('\n')
+                        renderDepth(depth, sb)
+                        sb.append(" |  `- ").append(line)
+                    }
+                }
+                sb.append('\n')
+
+                view.sub.forEach { sub ->
+                    val subView = mappings[sub] ?: return@forEach
+                    renderDepth(depth, sb)
+                    sb.append(" |- ")
+                    render(depth + 1, subView, sb)
+                }
+            }
+            sendAnsiMessage {
+                render(0, rootView, this)
+            }
         }
     }