feat: xterm DCS

This commit is contained in:
hstyi
2025-01-26 14:31:46 +08:00
committed by hstyi
parent 5df62d5d3e
commit 7ef81a0116
6 changed files with 90 additions and 49 deletions

View File

@@ -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
}
}

View File

@@ -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)
}
}
}

View File

@@ -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' -> {
state = TerminalState.DCS
}
// Start of Guarded Area (SPA is 0x96).

View File

@@ -7,7 +7,7 @@ import java.awt.datatransfer.StringSelection
class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader) :
AbstractProcessor(terminal, reader) {
private val args = StringBuilder()
private val systemCommandSequence = SystemCommandSequence()
private val colorPalette get() = terminal.getTerminalModel().getColorPalette()
companion object {
@@ -20,14 +20,7 @@ class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader
do {
val c = 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)
if (systemCommandSequence.process(reader.read())) {
break
}
@@ -42,7 +35,7 @@ class OperatingSystemCommandProcessor(terminal: Terminal, reader: TerminalReader
// process osc
processOperatingSystemCommandProcessor()
args.clear()
systemCommandSequence.reset()
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
*/
private fun processOperatingSystemCommandProcessor() {
val args = systemCommandSequence.getCommand()
val idx = args.indexOfFirst { it == ';' }
if (idx == -1) {
return

View File

@@ -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()
}
}

View File

@@ -129,7 +129,7 @@ private class MyProcessor(private val terminal: Terminal, reader: TerminalReader
TerminalState.CSI to ControlSequenceIntroducerProcessor(terminal, reader),
TerminalState.OSC to OperatingSystemCommandProcessor(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),
)