mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: xterm DCS
This commit is contained in:
@@ -1,36 +0,0 @@
|
|||||||
package app.termora.terminal
|
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
|
|
||||||
class DeviceControlProcessor(private val terminal: Terminal) : Processor {
|
|
||||||
private val args = StringBuilder()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(DeviceControlProcessor::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun process(ch: Char): ProcessorState {
|
|
||||||
val state = when (ch) {
|
|
||||||
ControlCharacters.ST -> {
|
|
||||||
if (log.isWarnEnabled) {
|
|
||||||
log.warn("Ignore DCS: {}", args)
|
|
||||||
}
|
|
||||||
TerminalState.READY
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
args.append(ch)
|
|
||||||
TerminalState.DCS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == TerminalState.READY) {
|
|
||||||
args.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
return state
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package app.termora.terminal
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
class DeviceControlStringProcessor(terminal: Terminal, reader: TerminalReader) : AbstractProcessor(terminal, reader) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val log = LoggerFactory.getLogger(DeviceControlStringProcessor::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val systemCommandSequence = SystemCommandSequence()
|
||||||
|
|
||||||
|
override fun process(ch: Char): ProcessorState {
|
||||||
|
// 回退回去,然后重新读取出来
|
||||||
|
reader.addFirst(ch)
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
if (systemCommandSequence.process(reader.read())) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有检测到结束,那么退出重新来
|
||||||
|
if (reader.isEmpty()) {
|
||||||
|
return TerminalState.DCS
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (reader.isNotEmpty())
|
||||||
|
|
||||||
|
processCommand(systemCommandSequence.getCommand())
|
||||||
|
|
||||||
|
systemCommandSequence.reset()
|
||||||
|
|
||||||
|
return TerminalState.READY
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun processCommand(command: String) {
|
||||||
|
if (command.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (log.isWarnEnabled) {
|
||||||
|
log.warn("Cannot process command: {}", command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -128,9 +128,9 @@ class EscapeSequenceProcessor(terminal: Terminal, reader: TerminalReader) : Abst
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Device Control String (DCS is 0x90).
|
// Device Control String (DCS is 0x90).
|
||||||
'P' -> {
|
'P' -> {
|
||||||
|
state = TerminalState.DCS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start of Guarded Area (SPA is 0x96).
|
// Start of Guarded Area (SPA is 0x96).
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.awt.datatransfer.StringSelection
|
|||||||
|
|
||||||
class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader) :
|
class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader) :
|
||||||
AbstractProcessor(terminal, reader) {
|
AbstractProcessor(terminal, reader) {
|
||||||
private val args = StringBuilder()
|
private val systemCommandSequence = SystemCommandSequence()
|
||||||
private val colorPalette get() = terminal.getTerminalModel().getColorPalette()
|
private val colorPalette get() = terminal.getTerminalModel().getColorPalette()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -20,14 +20,7 @@ class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
val c = reader.read()
|
if (systemCommandSequence.process(reader.read())) {
|
||||||
args.append(c)
|
|
||||||
if (c == ControlCharacters.BEL || c == ControlCharacters.ST) {
|
|
||||||
args.deleteAt(args.lastIndex)
|
|
||||||
break
|
|
||||||
} else if (c == '\\' && args.length >= 2 && args[args.length - 2] == ControlCharacters.ESC) {
|
|
||||||
args.deleteAt(args.lastIndex)
|
|
||||||
args.deleteAt(args.lastIndex)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +35,7 @@ class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader
|
|||||||
// process osc
|
// process osc
|
||||||
processOperatingSystemCommandProcessor()
|
processOperatingSystemCommandProcessor()
|
||||||
|
|
||||||
args.clear()
|
systemCommandSequence.reset()
|
||||||
|
|
||||||
return TerminalState.READY
|
return TerminalState.READY
|
||||||
}
|
}
|
||||||
@@ -52,6 +45,7 @@ class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader
|
|||||||
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
*/
|
*/
|
||||||
private fun processOperatingSystemCommandProcessor() {
|
private fun processOperatingSystemCommandProcessor() {
|
||||||
|
val args = systemCommandSequence.getCommand()
|
||||||
val idx = args.indexOfFirst { it == ';' }
|
val idx = args.indexOfFirst { it == ';' }
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package app.termora.terminal
|
||||||
|
|
||||||
|
class SystemCommandSequence {
|
||||||
|
private var isTerminated = false
|
||||||
|
private val command = StringBuilder()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 返回 true 表示处理完毕
|
||||||
|
*/
|
||||||
|
fun process(c: Char): Boolean {
|
||||||
|
|
||||||
|
if (isTerminated) {
|
||||||
|
throw UnsupportedOperationException("Cannot be processed, call the reset method")
|
||||||
|
}
|
||||||
|
|
||||||
|
command.append(c)
|
||||||
|
if (c == ControlCharacters.BEL || c == ControlCharacters.ST) {
|
||||||
|
command.deleteAt(command.lastIndex)
|
||||||
|
isTerminated = true
|
||||||
|
} else if (c == '\\' && command.length >= 2 && command[command.length - 2] == ControlCharacters.ESC) {
|
||||||
|
command.deleteAt(command.lastIndex)
|
||||||
|
command.deleteAt(command.lastIndex)
|
||||||
|
isTerminated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return isTerminated
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCommand(): String {
|
||||||
|
return command.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
isTerminated = false
|
||||||
|
command.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -129,7 +129,7 @@ private class MyProcessor(private val terminal: Terminal, reader: TerminalReader
|
|||||||
TerminalState.CSI to ControlSequenceIntroducerProcessor(terminal, reader),
|
TerminalState.CSI to ControlSequenceIntroducerProcessor(terminal, reader),
|
||||||
TerminalState.OSC to OperatingSystemCommandProcessor(terminal, reader),
|
TerminalState.OSC to OperatingSystemCommandProcessor(terminal, reader),
|
||||||
TerminalState.ESC_LPAREN to EscapeDesignateCharacterSetProcessor(terminal, reader),
|
TerminalState.ESC_LPAREN to EscapeDesignateCharacterSetProcessor(terminal, reader),
|
||||||
TerminalState.DCS to DeviceControlProcessor(terminal),
|
TerminalState.DCS to DeviceControlStringProcessor(terminal, reader),
|
||||||
TerminalState.Text to TextProcessor(terminal, reader),
|
TerminalState.Text to TextProcessor(terminal, reader),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user