The Scala facades need Scala 3.9 and JDK 25 or newer, and tmux 3.2a through 3.7c on the machine they drive.
Three artifacts, all in group io.github.libtmux and all at the same version
as libtmux itself. %% adds the _3 suffix that marks a Scala 3 artifact.
They are on Maven Central and release with the Java artifacts.
libtmux-scala_3— direct-style handles, collections and the typed query DSL.libtmux-scala-cats_3— Cats Effect resources and FS2 observations.libtmux-scala-ox_3— an OxFlowover subscriptions and live views.
libraryDependencies += "io.github.libtmux" %% "libtmux-scala" % "<version>"For Cats Effect and FS2, or for Ox, add the matching module:
libraryDependencies += "io.github.libtmux" %% "libtmux-scala-cats" % "<version>"libraryDependencies += "io.github.libtmux" %% "libtmux-scala-ox" % "<version>"From Gradle or Maven, name the suffixed artifact directly:
io.github.libtmux:libtmux-scala_3:<version>. The core facade depends on
libtmux and the Scala 3 library, and on nothing else.
The function below takes three caller-supplied values and constructs a Java
ServerConfig before opening the Scala client:
| Parameter | Value to supply |
|---|---|
binary |
Absolute path to your tmux executable |
socket |
An isolated socket you own under /tmp/libtmux-java-dev/ |
configFile |
Your tmux configuration file, or /dev/null for none |
For example, choose /tmp/libtmux-java-dev/scala-start/socket; the function
creates its parent directory. Opening the client does not create tmux;
newSession does. The operation creates a session, splits its window, verifies
the resulting panes and kills that session. Closing the client is separate
from session cleanup. An existing server's other sessions remain running;
tmux normally exits when its final session closes.
Call firstClient with your three values from your application.
The final call in this tested snippet takes those inputs from the owned test
fixture's config; the function builds and uses its own configuration.
import io.github.libtmux.{
Layout, ServerConfig, ServerEndpoint, SessionSpec, SplitSpec
}
import io.github.libtmux.scaladsl.{config => _, *}
import java.nio.file.{Files, Path}
import java.time.Duration
import scala.util.Using
def firstClient(binary: String, socket: Path, configFile: Path): Unit = {
require(Path.of(binary).isAbsolute, "supply an absolute tmux executable")
val ownedSocket = socket.toAbsolutePath.normalize()
require(
ownedSocket.startsWith(Path.of("/tmp/libtmux-java-dev")) ||
ownedSocket.startsWith(Path.of("/tmp/libtmux-java-test")),
"choose a socket under an owned libtmux Java directory"
)
Files.createDirectories(ownedSocket.getParent)
val selected = ServerConfig.builder()
.binary(binary)
.endpoint(ServerEndpoint.socketPath(ownedSocket))
.configFile(configFile)
.defaultTimeout(Duration.ofMillis(800))
.build()
Using.resource(Server.open(selected)) { server =>
val session = server.newSession(
SessionSpec.builder().named("scala-start").running("cat", "-").build()
)
try {
val window = session.windows.head
val second = window.split(
SplitSpec.builder().running("cat", "-").build()
)
window.selectLayout(Layout.EVEN_HORIZONTAL)
second.select()
// window.panes is CAPTURED: it answers from window's own frozen capture, taken before the
// split, so this refreshes first rather than reading stale data.
val panes = window.refresh().panes
assert(panes.size == 2)
assert(panes.exists(_.info.id().value() == second.info.id().value()))
} finally session.kill()
}
}
config.endpoint() match {
case endpoint: ServerEndpoint.SocketPath =>
firstClient(
config.binaryPath(),
endpoint.path(),
config.configFile().orElse(Path.of("/dev/null"))
)
case _ => throw new IllegalArgumentException("an explicit socket is required")
}Timeouts are scala.concurrent.duration.FiniteDuration at every public entry
point, converted once at the boundary: pane.awaitText("$", 5.seconds)
never surfaces java.time.Duration to the caller.
Follow with queries, ownership, then execution. For immediate access without the facade, use the direct Java guide.
The facades build with the rest of the repository, from its root:
$ ./gradlew :libtmux-scala:check :libtmux-scala-cats:check :libtmux-scala-ox:checkThe real-tmux suites run with the Java ones in integration-tests:
$ ./gradlew :integration-tests:test --tests 'io.github.libtmux.scaladsl.*'Format Scala sources before committing:
$ ./gradlew spotlessApplyThe API documentation, with a browser for every source it documents, generated
operations included, starts at libtmux-scala/build/docs/scaladoc/index.html:
$ ./gradlew :libtmux-scala:scaladocSiteBegin with direct-style Server or Cats Server.