Skip to content

Commit

Permalink
Its own set of implementations for obtaining the terminal size on eac…
Browse files Browse the repository at this point in the history
…h platform
  • Loading branch information
EpicDima committed Jun 11, 2024
1 parent 3dffc85 commit c2c4d84
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 24 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spotless-gradlePlugin = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0"
ktlint-core = "com.pinterest.ktlint:ktlint-cli:1.3.0"
ktlint-composeRules = "io.nlopez.compose.rules:ktlint:0.4.4"

jansi = "org.fusesource.jansi:jansi:2.4.1"
jline3 = "org.jline:jline:3.26.1"
mordant = "com.github.ajalt.mordant:mordant:2.6.0"
codepoints = "de.cketti.unicode:kotlin-codepoints:0.8.0"

Expand Down
2 changes: 1 addition & 1 deletion mosaic-runtime/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ kotlin {
jvmMain {
dependsOn(concurrentMain)
dependencies {
implementation libs.jansi
implementation libs.jline3
}
}
nonJvmMain {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.jakewharton.mosaic

import com.jakewharton.mosaic.ui.unit.IntSize
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import platform.posix.STDIN_FILENO
import platform.posix.TIOCGWINSZ
import platform.posix.ioctl
import platform.posix.winsize

@OptIn(ExperimentalForeignApi::class)
internal actual fun getPlatformTerminalSize(): IntSize = memScoped {
val size = alloc<winsize>()
if (ioctl(STDIN_FILENO, TIOCGWINSZ, size) < 0) {
IntSize.Zero
} else {
IntSize(width = size.ws_col.toInt(), height = size.ws_row.toInt())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import androidx.compose.runtime.snapshots.Snapshot
import com.github.ajalt.mordant.terminal.Terminal as MordantTerminal
import com.jakewharton.mosaic.layout.MosaicNode
import com.jakewharton.mosaic.ui.BoxMeasurePolicy
import com.jakewharton.mosaic.ui.unit.IntSize
import kotlin.time.ExperimentalTime
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -98,24 +97,14 @@ public suspend fun runMosaic(body: suspend MosaicScope.() -> Unit): Unit = corou
}
}

val terminalInfo = mutableStateOf(
Terminal(
size = IntSize(terminal.info.width, terminal.info.height),
),
)

val terminalInfo = mutableStateOf(Terminal(size = getPlatformTerminalSize()))
launch(context = composeContext) {
var terminalSize = terminalInfo.value.size
while (true) {
val currentTerminalInfo = terminalInfo.value
if (terminal.info.updateTerminalSize() &&
(
currentTerminalInfo.size.width != terminal.info.width ||
currentTerminalInfo.size.height != terminal.info.height
)
) {
terminalInfo.value = Terminal(
size = IntSize(terminal.info.width, terminal.info.height),
)
val newTerminalSize = getPlatformTerminalSize()
if (newTerminalSize != terminalSize) {
terminalInfo.value = Terminal(size = newTerminalSize)
terminalSize = newTerminalSize
}
delay(50)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
package com.jakewharton.mosaic

import com.jakewharton.mosaic.ui.unit.IntSize

internal expect fun platformDisplay(chars: CharSequence)

internal expect fun getPlatformTerminalSize(): IntSize
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.jakewharton.mosaic

import com.jakewharton.mosaic.ui.unit.IntSize

private external val process: dynamic

internal actual fun getPlatformTerminalSize(): IntSize {
val size = process.stdout.getWindowSize()
return if (size == undefined) {
IntSize.Zero
} else {
IntSize(width = size[0] as Int, height = size[1] as Int)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.jakewharton.mosaic

import com.jakewharton.mosaic.ui.unit.IntSize
import java.nio.CharBuffer
import java.nio.charset.StandardCharsets.UTF_8
import org.fusesource.jansi.AnsiConsole
import org.jline.terminal.TerminalBuilder

private val out = AnsiConsole.out()!!.also { AnsiConsole.systemInstall() }
private val encoder = UTF_8.newEncoder()!!
/* invoking enterRawMode - it is a hack to use key events in samples */
private val terminal = TerminalBuilder.terminal().also { it.enterRawMode() }
private val out = terminal.output()
private val encoder = UTF_8.newEncoder()

internal actual fun platformDisplay(chars: CharSequence) {
// Write a single byte array to stdout to create an atomic visual change. If you instead write
Expand All @@ -20,3 +23,7 @@ internal actual fun platformDisplay(chars: CharSequence) {
// buffered and not processed until the next frame, or not at all on the final frame.
out.flush()
}

internal actual fun getPlatformTerminalSize(): IntSize {
return IntSize(terminal.width, terminal.height)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.jakewharton.mosaic

import com.jakewharton.mosaic.ui.unit.IntSize
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import platform.linux.ioctl
import platform.posix.STDIN_FILENO
import platform.posix.TIOCGWINSZ
import platform.posix.winsize

@OptIn(ExperimentalForeignApi::class)
internal actual fun getPlatformTerminalSize(): IntSize = memScoped {
val size = alloc<winsize>()
if (ioctl(STDIN_FILENO, TIOCGWINSZ.toULong(), size) < 0) {
IntSize.Zero
} else {
IntSize(width = size.ws_col.toInt(), height = size.ws_row.toInt())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.jakewharton.mosaic

import com.jakewharton.mosaic.ui.unit.IntSize
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import platform.windows.CONSOLE_SCREEN_BUFFER_INFO
import platform.windows.GetConsoleScreenBufferInfo
import platform.windows.GetStdHandle
import platform.windows.INVALID_HANDLE_VALUE
import platform.windows.STD_OUTPUT_HANDLE

@OptIn(ExperimentalForeignApi::class)
internal actual fun getPlatformTerminalSize(): IntSize = memScoped {
val csbi = alloc<CONSOLE_SCREEN_BUFFER_INFO>()
val stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE)
if (stdoutHandle == INVALID_HANDLE_VALUE) {
return@memScoped IntSize.Zero
}
if (GetConsoleScreenBufferInfo(stdoutHandle, csbi.ptr) == 0) {
return@memScoped IntSize.Zero
}
csbi.srWindow.run { IntSize(width = Right - Left + 1, height = Bottom - Top + 1) }
}
2 changes: 1 addition & 1 deletion samples/robot/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ application {

dependencies {
implementation projects.mosaicRuntime
implementation 'org.jline:jline:3.26.1'
implementation libs.jline3
}
2 changes: 1 addition & 1 deletion samples/rrtop/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ application {
dependencies {
implementation projects.mosaicRuntime
implementation 'org.jetbrains.kotlinx:kotlinx-datetime:0.6.0'
implementation 'org.jline:jline:3.26.1'
implementation libs.jline3
}

0 comments on commit c2c4d84

Please sign in to comment.