|
|
@@ -5,6 +5,7 @@
|
|
|
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
|
*
|
|
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
|
+ *
|
|
|
*/
|
|
|
|
|
|
@file:Suppress(
|
|
|
@@ -17,13 +18,16 @@
|
|
|
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING",
|
|
|
"EXPOSED_SUPER_CLASS"
|
|
|
)
|
|
|
-@file:OptIn(ConsoleInternalApi::class, ConsoleFrontEndImplementation::class, ConsolePureExperimentalApi::class)
|
|
|
+@file:OptIn(ConsoleInternalApi::class, ConsoleFrontEndImplementation::class, ConsoleTerminalExperimentalApi::class)
|
|
|
|
|
|
-package net.mamoe.mirai.console.pure
|
|
|
+package net.mamoe.mirai.console.terminal
|
|
|
|
|
|
|
|
|
import com.vdurmont.semver4j.Semver
|
|
|
-import kotlinx.coroutines.*
|
|
|
+import kotlinx.coroutines.CancellationException
|
|
|
+import kotlinx.coroutines.CoroutineExceptionHandler
|
|
|
+import kotlinx.coroutines.CoroutineName
|
|
|
+import kotlinx.coroutines.CoroutineScope
|
|
|
import net.mamoe.mirai.console.ConsoleFrontEndImplementation
|
|
|
import net.mamoe.mirai.console.MiraiConsole
|
|
|
import net.mamoe.mirai.console.MiraiConsoleFrontEndDescription
|
|
|
@@ -32,10 +36,10 @@ import net.mamoe.mirai.console.data.MultiFilePluginDataStorage
|
|
|
import net.mamoe.mirai.console.data.PluginDataStorage
|
|
|
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
|
|
|
import net.mamoe.mirai.console.plugin.loader.PluginLoader
|
|
|
-import net.mamoe.mirai.console.pure.ConsoleInputImpl.requestInput
|
|
|
+import net.mamoe.mirai.console.terminal.ConsoleInputImpl.requestInput
|
|
|
+import net.mamoe.mirai.console.terminal.noconsole.AllEmptyLineReader
|
|
|
+import net.mamoe.mirai.console.terminal.noconsole.NoConsole
|
|
|
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
|
|
-import net.mamoe.mirai.console.pure.noconsole.AllEmptyLineReader
|
|
|
-import net.mamoe.mirai.console.pure.noconsole.NoConsole
|
|
|
import net.mamoe.mirai.console.util.ConsoleInput
|
|
|
import net.mamoe.mirai.console.util.ConsoleInternalApi
|
|
|
import net.mamoe.mirai.console.util.NamedSupervisorJob
|
|
|
@@ -46,31 +50,28 @@ import org.jline.reader.LineReaderBuilder
|
|
|
import org.jline.reader.impl.completer.NullCompleter
|
|
|
import org.jline.terminal.Terminal
|
|
|
import org.jline.terminal.TerminalBuilder
|
|
|
+import org.jline.terminal.impl.AbstractWindowsTerminal
|
|
|
import java.nio.file.Path
|
|
|
import java.nio.file.Paths
|
|
|
-import java.time.Instant
|
|
|
-import java.time.LocalDateTime
|
|
|
-import java.time.ZoneId
|
|
|
-import java.time.format.DateTimeFormatter
|
|
|
|
|
|
/**
|
|
|
- * mirai-console-pure 后端实现
|
|
|
+ * mirai-console-terminal 后端实现
|
|
|
*
|
|
|
- * @see MiraiConsolePureLoader CLI 入口点
|
|
|
+ * @see MiraiConsoleTerminalLoader CLI 入口点
|
|
|
*/
|
|
|
@ConsoleExperimentalApi
|
|
|
-class MiraiConsoleImplementationPure
|
|
|
+class MiraiConsoleImplementationTerminal
|
|
|
@JvmOverloads constructor(
|
|
|
override val rootPath: Path = Paths.get(".").toAbsolutePath(),
|
|
|
override val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>> = listOf(lazy { JvmPluginLoader }),
|
|
|
override val frontEndDescription: MiraiConsoleFrontEndDescription = ConsoleFrontEndDescImpl,
|
|
|
- override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl = ConsoleCommandSenderImplPure,
|
|
|
+ override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl = ConsoleCommandSenderImplTerminal,
|
|
|
override val dataStorageForJvmPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")),
|
|
|
override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")),
|
|
|
override val configStorageForJvmPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config")),
|
|
|
override val configStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config")),
|
|
|
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(
|
|
|
- NamedSupervisorJob("MiraiConsoleImplementationPure") +
|
|
|
+ NamedSupervisorJob("MiraiConsoleImplementationTerminal") +
|
|
|
CoroutineExceptionHandler { coroutineContext, throwable ->
|
|
|
if (throwable is CancellationException) {
|
|
|
return@CoroutineExceptionHandler
|
|
|
@@ -94,30 +95,9 @@ class MiraiConsoleImplementationPure
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-private object ConsoleInputImpl : ConsoleInput {
|
|
|
- private val format = DateTimeFormatter.ofPattern("HH:mm:ss")
|
|
|
-
|
|
|
- override suspend fun requestInput(hint: String): String {
|
|
|
- return withContext(Dispatchers.IO) {
|
|
|
- lineReader.readLine(
|
|
|
- if (hint.isNotEmpty()) {
|
|
|
- lineReader.printAbove(
|
|
|
- Ansi.ansi()
|
|
|
- .fgCyan().a(LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()).format(format))
|
|
|
- .a(" ")
|
|
|
- .fgMagenta().a(hint)
|
|
|
- .reset()
|
|
|
- .toString()
|
|
|
- )
|
|
|
- "$hint > "
|
|
|
- } else "> "
|
|
|
- )
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
val lineReader: LineReader by lazy {
|
|
|
- if (ConsolePureSettings.noConsole) return@lazy AllEmptyLineReader
|
|
|
+ val terminal = terminal
|
|
|
+ if (terminal is NoConsole) return@lazy AllEmptyLineReader
|
|
|
|
|
|
LineReaderBuilder.builder()
|
|
|
.terminal(terminal)
|
|
|
@@ -126,7 +106,7 @@ val lineReader: LineReader by lazy {
|
|
|
}
|
|
|
|
|
|
val terminal: Terminal = run {
|
|
|
- if (ConsolePureSettings.noConsole) return@run NoConsole
|
|
|
+ if (ConsoleTerminalSettings.noConsole) return@run NoConsole
|
|
|
|
|
|
val dumb = System.getProperty("java.class.path")
|
|
|
.contains("idea_rt.jar") || System.getProperty("mirai.idea") !== null || System.getenv("mirai.idea") !== null
|
|
|
@@ -134,7 +114,33 @@ val terminal: Terminal = run {
|
|
|
runCatching {
|
|
|
TerminalBuilder.builder()
|
|
|
.dumb(dumb)
|
|
|
+ .paused(true)
|
|
|
.build()
|
|
|
+ .let { terminal ->
|
|
|
+ if (terminal is AbstractWindowsTerminal) {
|
|
|
+ val pumpField = runCatching {
|
|
|
+ AbstractWindowsTerminal::class.java.getDeclaredField("pump").also {
|
|
|
+ it.isAccessible = true
|
|
|
+ }
|
|
|
+ }.onFailure { err ->
|
|
|
+ err.printStackTrace()
|
|
|
+ return@let terminal.also { it.resume() }
|
|
|
+ }.getOrThrow()
|
|
|
+ var response = terminal
|
|
|
+ terminal.setOnClose {
|
|
|
+ response = NoConsole
|
|
|
+ }
|
|
|
+ terminal.resume()
|
|
|
+ val pumpThread = pumpField[terminal] as? Thread ?: return@let NoConsole
|
|
|
+ @Suppress("ControlFlowWithEmptyBody")
|
|
|
+ while (pumpThread.state == Thread.State.NEW);
|
|
|
+ Thread.sleep(1000)
|
|
|
+ terminal.setOnClose(null)
|
|
|
+ return@let response
|
|
|
+ }
|
|
|
+ terminal.resume()
|
|
|
+ terminal
|
|
|
+ }
|
|
|
}.recoverCatching {
|
|
|
TerminalBuilder.builder()
|
|
|
.jansi(true)
|
|
|
@@ -147,7 +153,7 @@ val terminal: Terminal = run {
|
|
|
}
|
|
|
|
|
|
private object ConsoleFrontEndDescImpl : MiraiConsoleFrontEndDescription {
|
|
|
- override val name: String get() = "Pure"
|
|
|
+ override val name: String get() = "Terminal"
|
|
|
override val vendor: String get() = "Mamoe Technologies"
|
|
|
override val version: Semver = net.mamoe.mirai.console.internal.MiraiConsoleBuildConstants.version
|
|
|
}
|