The direct-style facade runs operations immediately. The Cats facade constructs lazy effects: creating a read or mutation effect performs no tmux I/O, and evaluating it again repeats the operation. Both delegate commands and transport behavior to Java. Choose the direct-style server for ordinary synchronous code or the Cats server inside a managed effect scope.
Here config is a Java ServerConfig for an existing tmux server. The same
read effect observes the value present at each evaluation:
import _root_.cats.effect.IO
import io.github.libtmux.scaladsl.cats.{config => _, *}
import io.github.libtmux.scaladsl.cats.{Server => ScalaServer}
ScalaServer.resource[IO](config).use { server =>
val name = "scala-guide-session"
val read = server.hasSession(name)
for {
before <- read
_ <- server.newSession(name)
after <- read
_ <- IO {
assert(!before)
assert(after)
}
} yield ()
}Captured info, session windows, window panes, and client attachments are pure
reads: generated as plain values in both layers, never wrapped in F on the
Cats side, since the catalog marks them CAPTURED. A captured accessor that
answers a tmux subsystem instead — Server.hooks, Pane.options,
Server.shell, and the rest — is CAPTURED for the same reason, its own
construction touches no tmux state, but on the Cats side it answers that
subsystem's own wrapper class rather than the raw Java handle direct style
still returns; the subsystem's own reads and mutations then run through F
exactly as every other operation does. Filtering their immutable collections
does not refresh them. Listing, refresh, format expansion, pane mode
inspection, and mutation perform I/O. Pane.awaitText polls captured text.
Cats operations run through an interruptible blocking boundary,
including a server or control client's own acquisition step and every
subsystem operation reached through Server.hooks, Pane.options, and the
rest. An owned server
accepts maxConcurrentCalls from one through four. A borrowed server accepts
a positive bound, but that bound covers only calls through that facade. Its
owner must account for other users and the underlying transport's capacity.
Pane.awaitText and Pane.await reserve one facade call for work that can
release the wait (Execution.waiting), and require capacity of at least two.
Pane.run uses ordinary admission: its private completion channel is normally
signalled by the pane's shell.
This bounds admitted calls; it does not make Java I/O thread-free. Waiting operations occupy blocking workers, and process transport uses its own workers to service child processes. The limit does not bound the number of fibers a caller may queue. Use bounded effect traversal when submitting a large collection. Ordered traversal preserves result order, while concurrent tmux mutations can still reach the daemon in a different order.
Prompt cancellation depends on a borrowed transport honoring interruption and completing its cleanup.
Command timeouts start when Java receives the operation, after Scala admission. An effect timeout can bound admission and execution together, but cancellation still waits for the operation's cleanup. A timeout is not a promise that a dispatched mutation had no effect.
Ordinary failures preserve Java's exception and dispatch certainty: the sealed
LibTmuxException tree matches directly from Scala (see
errors), and DispatchException#safeToRetry
answers the question a caller usually has without a catalog lookup. A
NOT_DISPATCHED transport failure differs from UNKNOWN: the latter may have
changed tmux. Raw Server.cmd returns Java's own transport.CommandResult, so
a nonzero exit remains data with its stdout and stderr.
Cats cancellation interrupts local work, waits for owned cleanup, and ends in
Outcome.Canceled whether or not the command reached tmux. Cancellation carries
no error, so the facade does not turn it into one. To learn whether a canceled
command was dispatched, set an OperationObserver on the Java ServerConfig:
the process transport reports UNKNOWN for a command it interrupted after
starting. Treat a canceled mutation as possibly dispatched; the facade does not
retry it, roll it back, or switch transports. A daemon-side shell job can
continue after its requesting client is canceled. Closing a borrowed transport
from its owner can instead produce an ordinary Java UNKNOWN failure.
Control.acknowledge reports a protocol reply. accepted means a
successful reply frame arrived; deferred tmux work can still be running. Use a
separate completion signal for that work. Canceling an active control request
can close its attachment and affect queued requests and observations, so use
separate attachments when their lifetimes must be independent.
Control.isAlive reports whether that process is still running.
Control.standardError is the text that process wrote to its error stream,
at most 4096 bytes. standardErrorTruncated says the stream continued past
that bound. Control.watch asks tmux to push a format when its value
changes, and unwatch removes that name. A target that is not a pane or
window id watches the attached session.