mirror of
https://github.com/JakeWharton/mosaic.git
synced 2025-10-27 20:26:21 +08:00
Parse system theme events (#539)
This commit is contained in:
@ -24,6 +24,14 @@ public final class com/jakewharton/mosaic/terminal/event/BracketedPasteEvent : c
|
|||||||
public fun toString ()Ljava/lang/String;
|
public fun toString ()Ljava/lang/String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class com/jakewharton/mosaic/terminal/event/DeviceStatusReportEvent : com/jakewharton/mosaic/terminal/event/Event {
|
||||||
|
public fun <init> (Ljava/lang/String;)V
|
||||||
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
public final fun getData ()Ljava/lang/String;
|
||||||
|
public fun hashCode ()I
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract interface class com/jakewharton/mosaic/terminal/event/Event {
|
public abstract interface class com/jakewharton/mosaic/terminal/event/Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +51,14 @@ public final class com/jakewharton/mosaic/terminal/event/PrimaryDeviceAttributes
|
|||||||
public fun toString ()Ljava/lang/String;
|
public fun toString ()Ljava/lang/String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class com/jakewharton/mosaic/terminal/event/SystemThemeEvent : com/jakewharton/mosaic/terminal/event/Event {
|
||||||
|
public fun <init> (Z)V
|
||||||
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
public fun hashCode ()I
|
||||||
|
public final fun isDark ()Z
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
public final class com/jakewharton/mosaic/terminal/event/UnknownEvent : com/jakewharton/mosaic/terminal/event/Event {
|
public final class com/jakewharton/mosaic/terminal/event/UnknownEvent : com/jakewharton/mosaic/terminal/event/Event {
|
||||||
public fun <init> (Ljava/lang/String;[B)V
|
public fun <init> (Ljava/lang/String;[B)V
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
|||||||
@ -19,6 +19,17 @@ final class com.jakewharton.mosaic.terminal.event/BracketedPasteEvent : com.jake
|
|||||||
final fun toString(): kotlin/String // com.jakewharton.mosaic.terminal.event/BracketedPasteEvent.toString|toString(){}[0]
|
final fun toString(): kotlin/String // com.jakewharton.mosaic.terminal.event/BracketedPasteEvent.toString|toString(){}[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent : com.jakewharton.mosaic.terminal.event/Event { // com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent|null[0]
|
||||||
|
constructor <init>(kotlin/String) // com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent.<init>|<init>(kotlin.String){}[0]
|
||||||
|
|
||||||
|
final val data // com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent.data|{}data[0]
|
||||||
|
final fun <get-data>(): kotlin/String // com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent.data.<get-data>|<get-data>(){}[0]
|
||||||
|
|
||||||
|
final fun equals(kotlin/Any?): kotlin/Boolean // com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent.equals|equals(kotlin.Any?){}[0]
|
||||||
|
final fun hashCode(): kotlin/Int // com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent.hashCode|hashCode(){}[0]
|
||||||
|
final fun toString(): kotlin/String // com.jakewharton.mosaic.terminal.event/DeviceStatusReportEvent.toString|toString(){}[0]
|
||||||
|
}
|
||||||
|
|
||||||
final class com.jakewharton.mosaic.terminal.event/FocusEvent : com.jakewharton.mosaic.terminal.event/Event { // com.jakewharton.mosaic.terminal.event/FocusEvent|null[0]
|
final class com.jakewharton.mosaic.terminal.event/FocusEvent : com.jakewharton.mosaic.terminal.event/Event { // com.jakewharton.mosaic.terminal.event/FocusEvent|null[0]
|
||||||
constructor <init>(kotlin/Boolean) // com.jakewharton.mosaic.terminal.event/FocusEvent.<init>|<init>(kotlin.Boolean){}[0]
|
constructor <init>(kotlin/Boolean) // com.jakewharton.mosaic.terminal.event/FocusEvent.<init>|<init>(kotlin.Boolean){}[0]
|
||||||
|
|
||||||
@ -41,6 +52,17 @@ final class com.jakewharton.mosaic.terminal.event/PrimaryDeviceAttributesEvent :
|
|||||||
final fun toString(): kotlin/String // com.jakewharton.mosaic.terminal.event/PrimaryDeviceAttributesEvent.toString|toString(){}[0]
|
final fun toString(): kotlin/String // com.jakewharton.mosaic.terminal.event/PrimaryDeviceAttributesEvent.toString|toString(){}[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class com.jakewharton.mosaic.terminal.event/SystemThemeEvent : com.jakewharton.mosaic.terminal.event/Event { // com.jakewharton.mosaic.terminal.event/SystemThemeEvent|null[0]
|
||||||
|
constructor <init>(kotlin/Boolean) // com.jakewharton.mosaic.terminal.event/SystemThemeEvent.<init>|<init>(kotlin.Boolean){}[0]
|
||||||
|
|
||||||
|
final val isDark // com.jakewharton.mosaic.terminal.event/SystemThemeEvent.isDark|{}isDark[0]
|
||||||
|
final fun <get-isDark>(): kotlin/Boolean // com.jakewharton.mosaic.terminal.event/SystemThemeEvent.isDark.<get-isDark>|<get-isDark>(){}[0]
|
||||||
|
|
||||||
|
final fun equals(kotlin/Any?): kotlin/Boolean // com.jakewharton.mosaic.terminal.event/SystemThemeEvent.equals|equals(kotlin.Any?){}[0]
|
||||||
|
final fun hashCode(): kotlin/Int // com.jakewharton.mosaic.terminal.event/SystemThemeEvent.hashCode|hashCode(){}[0]
|
||||||
|
final fun toString(): kotlin/String // com.jakewharton.mosaic.terminal.event/SystemThemeEvent.toString|toString(){}[0]
|
||||||
|
}
|
||||||
|
|
||||||
final class com.jakewharton.mosaic.terminal.event/UnknownEvent : com.jakewharton.mosaic.terminal.event/Event { // com.jakewharton.mosaic.terminal.event/UnknownEvent|null[0]
|
final class com.jakewharton.mosaic.terminal.event/UnknownEvent : com.jakewharton.mosaic.terminal.event/Event { // com.jakewharton.mosaic.terminal.event/UnknownEvent|null[0]
|
||||||
constructor <init>(kotlin/String, kotlin/ByteArray) // com.jakewharton.mosaic.terminal.event/UnknownEvent.<init>|<init>(kotlin.String;kotlin.ByteArray){}[0]
|
constructor <init>(kotlin/String, kotlin/ByteArray) // com.jakewharton.mosaic.terminal.event/UnknownEvent.<init>|<init>(kotlin.String;kotlin.ByteArray){}[0]
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package com.jakewharton.mosaic.terminal
|
|||||||
import com.jakewharton.mosaic.terminal.event.BracketedPasteEvent
|
import com.jakewharton.mosaic.terminal.event.BracketedPasteEvent
|
||||||
import com.jakewharton.mosaic.terminal.event.CodepointEvent
|
import com.jakewharton.mosaic.terminal.event.CodepointEvent
|
||||||
import com.jakewharton.mosaic.terminal.event.DecModeReport
|
import com.jakewharton.mosaic.terminal.event.DecModeReport
|
||||||
import com.jakewharton.mosaic.terminal.event.DeviceStatusReportString
|
import com.jakewharton.mosaic.terminal.event.DeviceStatusReportEvent
|
||||||
import com.jakewharton.mosaic.terminal.event.Event
|
import com.jakewharton.mosaic.terminal.event.Event
|
||||||
import com.jakewharton.mosaic.terminal.event.FocusEvent
|
import com.jakewharton.mosaic.terminal.event.FocusEvent
|
||||||
import com.jakewharton.mosaic.terminal.event.KeyEscape
|
import com.jakewharton.mosaic.terminal.event.KeyEscape
|
||||||
@ -11,6 +11,7 @@ import com.jakewharton.mosaic.terminal.event.KittyGraphicsEvent
|
|||||||
import com.jakewharton.mosaic.terminal.event.MouseEvent
|
import com.jakewharton.mosaic.terminal.event.MouseEvent
|
||||||
import com.jakewharton.mosaic.terminal.event.PrimaryDeviceAttributesEvent
|
import com.jakewharton.mosaic.terminal.event.PrimaryDeviceAttributesEvent
|
||||||
import com.jakewharton.mosaic.terminal.event.ResizeEvent
|
import com.jakewharton.mosaic.terminal.event.ResizeEvent
|
||||||
|
import com.jakewharton.mosaic.terminal.event.SystemThemeEvent
|
||||||
import com.jakewharton.mosaic.terminal.event.UnknownEvent
|
import com.jakewharton.mosaic.terminal.event.UnknownEvent
|
||||||
|
|
||||||
private const val BufferSize = 8 * 1024
|
private const val BufferSize = 8 * 1024
|
||||||
@ -333,6 +334,38 @@ public class TerminalParser(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
'n'.code -> {
|
||||||
|
if (buffer[b3Index].toInt() == '?'.code) {
|
||||||
|
val delimiter = buffer.indexOfOrDefault(';'.code.toByte(), start + 3, finalIndex, finalIndex)
|
||||||
|
when (buffer.parseIntDigits(start + 3, delimiter)) {
|
||||||
|
997 -> {
|
||||||
|
if (delimiter + 2 == finalIndex) {
|
||||||
|
val p2 = buffer[delimiter + 1].toInt()
|
||||||
|
if (p2 == '1'.code) {
|
||||||
|
return SystemThemeEvent(isDark = true)
|
||||||
|
}
|
||||||
|
if (p2 == '2'.code) {
|
||||||
|
return SystemThemeEvent(isDark = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UnknownEvent(
|
||||||
|
context = "CSI ? 997 ; p2 n sequence has invalid p2",
|
||||||
|
bytes = buffer.copyOfRange(start, end),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
return DeviceStatusReportEvent(
|
||||||
|
data = buffer.decodeToString(start + 3, finalIndex),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UnknownEvent(
|
||||||
|
context = "CSI .. n sequence without leading ?",
|
||||||
|
bytes = buffer.copyOfRange(start, end),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
'c'.code -> {
|
'c'.code -> {
|
||||||
if (buffer[b3Index].toInt() == '?'.code) {
|
if (buffer[b3Index].toInt() == '?'.code) {
|
||||||
val data = buffer.decodeToString(start + 3, finalIndex)
|
val data = buffer.decodeToString(start + 3, finalIndex)
|
||||||
@ -417,7 +450,7 @@ public class TerminalParser(
|
|||||||
buffer[start + 2].toInt() == '>'.code &&
|
buffer[start + 2].toInt() == '>'.code &&
|
||||||
buffer[start + 3].toInt() == '|'.code
|
buffer[start + 3].toInt() == '|'.code
|
||||||
) {
|
) {
|
||||||
DeviceStatusReportString(
|
DeviceStatusReportEvent(
|
||||||
data = buffer.decodeToString(start + 4, stIndex),
|
data = buffer.decodeToString(start + 4, stIndex),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -29,6 +29,8 @@ internal inline fun ByteArray.indexOfFirstOrElse(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteArray.parseIntDigits(start: Int, end: Int): Int {
|
internal fun ByteArray.parseIntDigits(start: Int, end: Int): Int {
|
||||||
|
// TODO This needs an orElse path for parsing failure on non-digits.
|
||||||
|
|
||||||
var value = 0
|
var value = 0
|
||||||
for (i in start until end) {
|
for (i in start until end) {
|
||||||
value *= 10
|
value *= 10
|
||||||
|
|||||||
@ -84,8 +84,14 @@ public class PrimaryDeviceAttributesEvent(
|
|||||||
public val data: String,
|
public val data: String,
|
||||||
) : Event
|
) : Event
|
||||||
|
|
||||||
internal data class DeviceStatusReportString(
|
@Poko
|
||||||
val data: String,
|
public class DeviceStatusReportEvent(
|
||||||
|
public val data: String,
|
||||||
|
) : Event
|
||||||
|
|
||||||
|
@Poko
|
||||||
|
public class SystemThemeEvent(
|
||||||
|
public val isDark: Boolean,
|
||||||
) : Event
|
) : Event
|
||||||
|
|
||||||
internal data class KittyGraphicsEvent(
|
internal data class KittyGraphicsEvent(
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.jakewharton.mosaic.terminal
|
||||||
|
|
||||||
|
import assertk.assertThat
|
||||||
|
import assertk.assertions.isEqualTo
|
||||||
|
import com.jakewharton.mosaic.terminal.event.SystemThemeEvent
|
||||||
|
import com.jakewharton.mosaic.terminal.event.UnknownEvent
|
||||||
|
import kotlin.test.AfterTest
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
class TerminalParserCsiSystemThemeEventTest {
|
||||||
|
private val writer = Tty.stdinWriter()
|
||||||
|
private val parser = TerminalParser(writer.reader, true)
|
||||||
|
|
||||||
|
@AfterTest fun after() {
|
||||||
|
writer.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun dark() {
|
||||||
|
writer.writeHex("1b5b3f3939373b316e")
|
||||||
|
assertThat(parser.next()).isEqualTo(SystemThemeEvent(isDark = true))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun light() {
|
||||||
|
writer.writeHex("1b5b3f3939373b326e")
|
||||||
|
assertThat(parser.next()).isEqualTo(SystemThemeEvent(isDark = false))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun missingP2() {
|
||||||
|
writer.writeHex("1b5b3f3939373b6e")
|
||||||
|
assertThat(parser.next()).isEqualTo(
|
||||||
|
UnknownEvent(
|
||||||
|
context = "CSI ? 997 ; p2 n sequence has invalid p2",
|
||||||
|
bytes = "1b5b3f3939373b6e".hexToByteArray(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun unknownP2() {
|
||||||
|
writer.writeHex("1b5b3f3939373b346e")
|
||||||
|
assertThat(parser.next()).isEqualTo(
|
||||||
|
UnknownEvent(
|
||||||
|
context = "CSI ? 997 ; p2 n sequence has invalid p2",
|
||||||
|
bytes = "1b5b3f3939373b346e".hexToByteArray(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun tooLongP2() {
|
||||||
|
writer.writeHex("1b5b3f3939373b31316e")
|
||||||
|
assertThat(parser.next()).isEqualTo(
|
||||||
|
UnknownEvent(
|
||||||
|
context = "CSI ? 997 ; p2 n sequence has invalid p2",
|
||||||
|
bytes = "1b5b3f3939373b31316e".hexToByteArray(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -75,6 +75,7 @@ private class RawModeEchoCommand : CliktCommand("raw-mode-echo") {
|
|||||||
}
|
}
|
||||||
if (all || colorQuery) {
|
if (all || colorQuery) {
|
||||||
print("\u001b[?996n") // Color scheme request
|
print("\u001b[?996n") // Color scheme request
|
||||||
|
print("\u001b[?2031h") // Color scheme enable
|
||||||
}
|
}
|
||||||
|
|
||||||
val reader = Tty.stdinReader()
|
val reader = Tty.stdinReader()
|
||||||
|
|||||||
Reference in New Issue
Block a user