mirror of
https://github.com/JakeWharton/mosaic.git
synced 2025-11-03 22:08:43 +08:00
Perform rudimentary ansi color level detection (#711)
There is a lot to add here, but this gets us off the ground.
This commit is contained in:
@ -2,7 +2,6 @@
|
|||||||
jetbrains-compose = "1.7.3"
|
jetbrains-compose = "1.7.3"
|
||||||
kotlin = "2.1.10"
|
kotlin = "2.1.10"
|
||||||
kotlinx-coroutines = "1.10.1"
|
kotlinx-coroutines = "1.10.1"
|
||||||
mordant = "3.0.2"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
kotlin-plugin-core = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
kotlin-plugin-core = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||||
@ -29,9 +28,6 @@ spotless-gradlePlugin = "com.diffplug.spotless:spotless-plugin-gradle:7.0.2"
|
|||||||
ktlint-core = "com.pinterest.ktlint:ktlint-cli:1.3.1"
|
ktlint-core = "com.pinterest.ktlint:ktlint-cli:1.3.1"
|
||||||
ktlint-composeRules = "io.nlopez.compose.rules:ktlint:0.4.22"
|
ktlint-composeRules = "io.nlopez.compose.rules:ktlint:0.4.22"
|
||||||
|
|
||||||
mordant-core = { module = "com.github.ajalt.mordant:mordant-core", version.ref = "mordant" }
|
|
||||||
mordant-jvmJna = { module = "com.github.ajalt.mordant:mordant-jvm-jna", version.ref = "mordant" }
|
|
||||||
|
|
||||||
clikt = "com.github.ajalt.clikt:clikt:5.0.3"
|
clikt = "com.github.ajalt.clikt:clikt:5.0.3"
|
||||||
codepoints = "de.cketti.unicode:kotlin-codepoints:0.9.0"
|
codepoints = "de.cketti.unicode:kotlin-codepoints:0.9.0"
|
||||||
finalizationHook = "com.jakewharton.finalization:finalization-hook:0.1.0"
|
finalizationHook = "com.jakewharton.finalization:finalization-hook:0.1.0"
|
||||||
|
|||||||
@ -22,7 +22,6 @@ kotlin {
|
|||||||
implementation projects.mosaicTerminal
|
implementation projects.mosaicTerminal
|
||||||
implementation libs.androidx.collection
|
implementation libs.androidx.collection
|
||||||
implementation libs.finalizationHook
|
implementation libs.finalizationHook
|
||||||
implementation libs.mordant.core
|
|
||||||
implementation libs.codepoints
|
implementation libs.codepoints
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,12 +33,6 @@ kotlin {
|
|||||||
implementation libs.assertk
|
implementation libs.assertk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jvmMain {
|
|
||||||
dependencies {
|
|
||||||
implementation libs.mordant.jvmJna
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compilerOptions.freeCompilerArgs.add('-Xexpect-actual-classes')
|
compilerOptions.freeCompilerArgs.add('-Xexpect-actual-classes')
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
package com.jakewharton.mosaic
|
package com.jakewharton.mosaic
|
||||||
|
|
||||||
import com.github.ajalt.mordant.rendering.AnsiLevel as MordantAnsiLevel
|
|
||||||
import com.jakewharton.mosaic.ui.AnsiLevel
|
|
||||||
import com.jakewharton.mosaic.ui.Color
|
import com.jakewharton.mosaic.ui.Color
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -49,15 +47,6 @@ internal const val ansiBgColorOffset = 10
|
|||||||
internal const val ansiSelectorColor256 = 5
|
internal const val ansiSelectorColor256 = 5
|
||||||
internal const val ansiSelectorColorRgb = 2
|
internal const val ansiSelectorColorRgb = 2
|
||||||
|
|
||||||
internal fun MordantAnsiLevel.toMosaicAnsiLevel(): AnsiLevel {
|
|
||||||
return when (this) {
|
|
||||||
MordantAnsiLevel.NONE -> AnsiLevel.NONE
|
|
||||||
MordantAnsiLevel.ANSI16 -> AnsiLevel.ANSI16
|
|
||||||
MordantAnsiLevel.ANSI256 -> AnsiLevel.ANSI256
|
|
||||||
MordantAnsiLevel.TRUECOLOR -> AnsiLevel.TRUECOLOR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// simpler version without full conversion to HSV
|
// simpler version without full conversion to HSV
|
||||||
// https://github.com/ajalt/colormath/blob/4a0cc9796c743cb4965407204ee63b40aaf22fca/colormath/src/commonMain/kotlin/com/github/ajalt/colormath/model/RGB.kt#L301
|
// https://github.com/ajalt/colormath/blob/4a0cc9796c743cb4965407204ee63b40aaf22fca/colormath/src/commonMain/kotlin/com/github/ajalt/colormath/model/RGB.kt#L301
|
||||||
internal fun Color.toAnsi16Code(): Int {
|
internal fun Color.toAnsi16Code(): Int {
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.LifecycleRegistry
|
import androidx.lifecycle.LifecycleRegistry
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
import com.github.ajalt.mordant.terminal.Terminal as MordantTerminal
|
|
||||||
import com.jakewharton.finalization.withFinalizationHook
|
import com.jakewharton.finalization.withFinalizationHook
|
||||||
import com.jakewharton.mosaic.layout.KeyEvent
|
import com.jakewharton.mosaic.layout.KeyEvent
|
||||||
import com.jakewharton.mosaic.layout.MosaicNode
|
import com.jakewharton.mosaic.layout.MosaicNode
|
||||||
@ -92,8 +91,6 @@ private const val StageDefaultQueries = 1
|
|||||||
private const val StageNormalOperation = 0
|
private const val StageNormalOperation = 0
|
||||||
|
|
||||||
internal suspend fun runMosaic(isTest: Boolean, content: @Composable () -> Unit) {
|
internal suspend fun runMosaic(isTest: Boolean, content: @Composable () -> Unit) {
|
||||||
val mordantTerminal = MordantTerminal()
|
|
||||||
|
|
||||||
// Entering raw mode can fail, so perform it before any additional control sequences which change
|
// Entering raw mode can fail, so perform it before any additional control sequences which change
|
||||||
// settings. We also need to be in character mode to query capabilities with control sequences.
|
// settings. We also need to be in character mode to query capabilities with control sequences.
|
||||||
val rawMode = if (!isTest && env("MOSAIC_RAW_MODE") != "false") {
|
val rawMode = if (!isTest && env("MOSAIC_RAW_MODE") != "false") {
|
||||||
@ -291,7 +288,7 @@ internal suspend fun runMosaic(isTest: Boolean, content: @Composable () -> Unit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
val rendering = createRendering(
|
val rendering = createRendering(
|
||||||
ansiLevel = mordantTerminal.terminalInfo.ansiLevel.toMosaicAnsiLevel(),
|
ansiLevel = detectAnsiLevel(),
|
||||||
synchronizedRendering = supportsSynchronizedRendering,
|
synchronizedRendering = supportsSynchronizedRendering,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -299,7 +296,7 @@ internal suspend fun runMosaic(isTest: Boolean, content: @Composable () -> Unit)
|
|||||||
val mosaicComposition = MosaicComposition(
|
val mosaicComposition = MosaicComposition(
|
||||||
coroutineContext = coroutineContext + clock,
|
coroutineContext = coroutineContext + clock,
|
||||||
onDraw = { rootNode ->
|
onDraw = { rootNode ->
|
||||||
mordantTerminal.rawPrint(rendering.render(rootNode).toString())
|
print(rendering.render(rootNode).toString())
|
||||||
},
|
},
|
||||||
keyEvents = keyEvents,
|
keyEvents = keyEvents,
|
||||||
terminalState = terminalState,
|
terminalState = terminalState,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.jakewharton.mosaic
|
|||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.ProvidableCompositionLocal
|
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
|
import com.jakewharton.mosaic.ui.AnsiLevel
|
||||||
import com.jakewharton.mosaic.ui.unit.IntSize
|
import com.jakewharton.mosaic.ui.unit.IntSize
|
||||||
import dev.drewhamilton.poko.Poko
|
import dev.drewhamilton.poko.Poko
|
||||||
|
|
||||||
@ -32,3 +33,20 @@ internal inline fun Terminal.copy(
|
|||||||
darkTheme: Boolean = this.darkTheme,
|
darkTheme: Boolean = this.darkTheme,
|
||||||
size: IntSize = this.size,
|
size: IntSize = this.size,
|
||||||
) = Terminal(focused, darkTheme, size)
|
) = Terminal(focused, darkTheme, size)
|
||||||
|
|
||||||
|
internal fun detectAnsiLevel(): AnsiLevel {
|
||||||
|
if (env("NO_COLOR").orEmpty().isNotEmpty()) {
|
||||||
|
return AnsiLevel.NONE
|
||||||
|
}
|
||||||
|
val term = env("COLORTERM") ?: env("TERM") ?: "dumb"
|
||||||
|
if (term.contains("24bit", ignoreCase = true) || term.contains("truecolor", ignoreCase = true)) {
|
||||||
|
return AnsiLevel.TRUECOLOR
|
||||||
|
}
|
||||||
|
if (term.contains("256")) {
|
||||||
|
return AnsiLevel.ANSI256
|
||||||
|
}
|
||||||
|
if (term != "dumb") {
|
||||||
|
return AnsiLevel.ANSI16
|
||||||
|
}
|
||||||
|
return AnsiLevel.NONE
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user