Core LibraryGuides

Choose documentation 1

latest

Current version

latest
English

Prerelease This site documents an alpha of libtmux. Its structure, URLs and APIs are subject to change.

Ownership

Opening a Scala server owns a Java client. Closing that client releases its transport and local workers; it does not kill the tmux daemon. killServer is an explicit, separate operation. A borrowed facade leaves the original Java client under its existing owner’s control.

Direct-style scopes

Server.open returns an opaque Server, bounded by AutoCloseable, for scala.util.Using.resource or an explicit try/finally scope — the bound is the type’s own, so close() needs no forwarding of its own. Its close is idempotent. Server.fromJava borrows a client instead of owning one; closing that facade closes the Java client too, so a caller who only means to borrow keeps the original owner’s close() as the one that matters.

An opaque handle carries no Scala-side scope state of its own — no owned/closed/parent bookkeeping to keep in sync with Java’s. Whether a call through it fails after the owning Server closes is exactly Java’s own use-after-close contract (ServerClosedException), not a second policy this facade adds.

Effect scopes

cats.Server.resource acquires the client when its Resource runs. cats.Server.fromJava also returns a Resource, with borrowing semantics. Both scope the operations submitted through the returned facade. Release rejects new work, cancels queued and running operations, waits for their finalizers, and then closes the owned client if there is one.

Returning a handle or an unevaluated effect from the resource body does not extend its lifetime. The handle’s captured data remains available; executing its effect after release fails. Release cancels operations still running; an operation can finish before that cancellation reaches it. A caller that masks cancellation can receive a scope-closed failure instead of waiting indefinitely for a canceled child operation.

Partial acquisition failure and failure in the resource body still release what the resource acquired. Cancellation also waits for cleanup. Borrowing changes which client is closed, not the requirement to release the facade’s own work. If an external owner closes a borrowed transport while a request is dispatched, that request can fail with Java’s UNKNOWN dispatch outcome. The facade preserves that failure; it does not turn owner closure into a successful empty result or an automatic retry.

Here config selects an existing server with a session. The outer resource owns Java. The inner Scala scope borrows it, and the original client still answers after that scope ends:

import _root_.cats.effect.{IO, Resource}
import io.github.libtmux.{Server => JavaServer}
import io.github.libtmux.scaladsl.cats.{config => _, *}
import io.github.libtmux.scaladsl.cats.{Server => ScalaServer}
Resource
.make(IO.blocking(JavaServer.open(config)))(java => IO.blocking(java.close()))
.use { java =>
ScalaServer.fromJava[IO](java).use { server =>
server.sessions().flatMap(values => IO(assert(values.nonEmpty)))
}.flatMap(_ => IO.blocking(assert(java.isAlive())))
}

Java identity and one escape hatch

Every direct-style handle is opaque over its Java one — the same object, not a copy — so equality and hash code are Java’s own. A pane’s identity is physical; a window’s identity includes its captured session and window index. Borrowing does not replace that identity by reacquiring the same textual ID. Refresh follows the Java contract and can return a pane through a different window occurrence.

.asJava is the one escape hatch, on every handle, always public: opaque wrapping is free, so it is a zero-cost coercion, never a copy and never a second, more “unsafe” name to reach for. Code using the raw Java handle must still follow its ownership and threading contract. Reaching .asJava from an owned scope does not keep that client open past the Scala facade’s own close(); reaching it from a borrowed scope does not make the Scala facade its owner.

Control attachments

Control.attach on a captured session owns a separate process attachment to that capture’s process, started by the session’s transport. Control.attachUnfenced on a config and session id does not check the process. Releasing either stops its admitted requests before closing the attachment and preserves the daemon.

Acquire an output or event subscription inside the attachment’s resource and before starting its producer. Release the subscription before the attachment. An observation allows one active stream consumer; canceled consumption releases that slot. Releasing the observation closes its Java subscription and discards buffered events. Keep command and observation attachments separate when canceling a command must not end observation.

See execution for admission bounds, cancellation uncertainty, and the difference between a control acknowledgement and command completion.

Esc

Type to search.