From c31e94d53c35451f6f73a6d5ea243f7096546c5c Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 14 Nov 2026 16:25:44 -0600 Subject: [PATCH 1/3] Java(docs): Write the Window and Pane directories why: libtmux.org draws a "What is on here" table on the Java Server and Session pages, and the Window and Pane pages had none, so a reader had to scan every member to find how to split, send input or read output. The site folds a bold-led paragraph followed by a references paragraph or a `Label: refs` list into a row, and draws a table from three rows. what: - Add a "What is on here" section to the Window class doc with rows for reading the capture, panes, layout and size, moving and linking, changing the window, options and hooks, and formats and refreshing - Add one to the Pane class doc with rows for reading the capture, sending input, reading output, running and waiting, splitting and arranging, modes, changing the pane, options and hooks, and formats and refreshing - State per row what throws and what is a pure read of the capture, taken from each method's own doc and body --- .../src/main/java/io/github/libtmux/Pane.java | 89 +++++++++++++++++++ .../main/java/io/github/libtmux/Window.java | 63 +++++++++++++ 2 files changed, 152 insertions(+) diff --git a/libtmux/src/main/java/io/github/libtmux/Pane.java b/libtmux/src/main/java/io/github/libtmux/Pane.java index 5356fc9ca..a40b3c12d 100644 --- a/libtmux/src/main/java/io/github/libtmux/Pane.java +++ b/libtmux/src/main/java/io/github/libtmux/Pane.java @@ -40,6 +40,95 @@ * *

A method named for a captured field returns what {@link #info()} holds and does no I/O; * {@link #refresh()} reads again. Every other method asks tmux now. + * + *

What is on here

+ * + *

The methods fall into a few groups: + * + *

Reading the capture. Read what this capture stored about the pane, and the + * {@link Server} and {@link Window} it sits in, with no call to tmux. The id is stable and the index + * is state, since panes renumber as neighbours come and go. {@link #floating} is empty when the + * running tmux cannot say, which before 3.7 is always, and {@link #pid} is empty when tmux reported no + * process. {@link #currentPath} throws {@link LibTmuxException} when this JVM cannot represent the + * directory's name; {@link #currentPathText} is what tmux reported and never throws. + * + *

{@link #info}, {@link #id}, {@link #index}, {@link #active}, {@link #currentCommand}, + * {@link #floating}, {@link #size}, {@link #position}, {@link #edges}, {@link #title}, + * {@link #currentPath}, {@link #currentPathText}, {@link #pid}, {@link #server()}, {@link #window()} + * + *

Sending input. {@link #send} types keys without pressing Enter and + * {@link #sendLine} presses it, which is how a command gets run. {@link #sendKeys} resolves each entry + * through tmux's key table and types an unknown name as text; {@link #sendLiteral} types every entry + * as the characters it spells, so {@code C-c} is three characters. {@link #paste} delivers text as one + * block through a private buffer that is removed afterwards, throws {@link IllegalArgumentException} + * for text containing NUL, and throws {@link io.github.libtmux.exception.UnsupportedFeatureException} + * before tmux 3.4. {@link #noteTyped} tells a later wait about text that reached the pane without + * passing through this handle. + * + *

+ * + *

Reading output. {@link #capture()} returns the visible content, one element per + * line, read from tmux now rather than from the capture. Hand it a builder callback or a + * {@link CaptureSpec}, which may be reused across panes, to read part of the history; that throws + * {@link io.github.libtmux.exception.UnsupportedFeatureException} when the spec asks for something + * this server does not have. {@link #pipeTo} sends everything the pane prints to a shell command + * until {@link #stopPiping}. + * + *

{@link #capture}, {@link #pipeTo}, {@link #stopPiping}, {@link #clearHistory} + * + *

Running and waiting. {@link #run} runs a shell command to its end and answers + * with its exit status and output, and throws {@link IllegalStateException} when the pane is not + * running a POSIX shell. Reach for it first when the command is yours. When it is not, the waits poll + * the screen or the pane's state on a timer and answer with why they ended, which tells text that + * appeared from text that was already there; a pane killed mid-wait ends {@link #watchText} as an + * answer rather than an exception. A signal on a {@link Server#channel} is the one exact wait. + * {@link #dead} reads fresh whether the pane's process has exited, and throws + * {@link TargetGoneException} when the pane is gone from a server that still answers. + * + *

+ * + *

Splitting and arranging. Splitting divides this pane in half, from a builder + * callback or a reusable {@link SplitSpec}, and returns the pane that appeared. Break the pane out + * into a window of its own, join it into another window, swap it with another pane, resize it by a + * number of cells in one direction or to exact dimensions, or make it the active pane. An unnamed + * {@link #breakOut()} throws {@link io.github.libtmux.exception.UnsupportedFeatureException} on exact + * tmux 3.7, which a named break or 3.7a avoids. + * + *

+ * + *

Modes. Put the pane into copy mode, read live which mode it is in, as an + * {@link Optional} that is empty when it is showing its program, or leave whichever mode it is in. + * + *

{@link #copyMode}, {@link #mode}, {@link #exitMode} + * + *

Changing the pane. Retitle it, which returns a replacement capture because this + * handle keeps its original state; kill what runs here and start the pane's default command, a + * command in a directory, or a command you give; or close it. + * + *

{@link #retitle}, {@link #respawn}, {@link #respawnIn}, {@link #kill} + * + *

Options and hooks. These reach what is set on this pane alone. + * + *

{@link #options}, {@link #hooks} + * + *

Formats and refreshing. Expand a tmux format, or read several named variables, + * in this pane's context; or take a new capture to see the pane as it is now. Refreshing leaves this + * handle unchanged and returns the new one, and throws {@link TargetGoneException} if the pane is + * gone from a server that still answers. + * + *

{@link #expand}, {@link #variables}, {@link #refresh} */ public final class Pane { diff --git a/libtmux/src/main/java/io/github/libtmux/Window.java b/libtmux/src/main/java/io/github/libtmux/Window.java index 204e8ca35..65609ba8c 100644 --- a/libtmux/src/main/java/io/github/libtmux/Window.java +++ b/libtmux/src/main/java/io/github/libtmux/Window.java @@ -27,6 +27,69 @@ * *

A method named for a captured field returns what {@link #info()} holds and does no I/O; * {@link #refresh()} reads again. Every other method asks tmux now. + * + *

What is on here

+ * + *

The methods fall into a few groups: + * + *

Reading the capture. Read what this capture stored about the window, and the + * {@link Server} and {@link Session} it sits in, with no call to tmux. The id names the underlying + * window and the index names this link, so a window linked into two sessions has one id and two + * handles. A rename or a resize after the capture does not show in it. + * + *

{@link #info}, {@link #id}, {@link #index}, {@link #context}, {@link #name}, {@link #active}, + * {@link #linked}, {@link #size}, {@link #layout}, {@link #server()}, {@link #session()} + * + *

Panes. List this link's panes in tmux's order, or ask for the one tmux had + * active, as an {@link Optional}; both are pure reads of the capture and issue no command. Splitting + * divides the active pane in half, from a callback that fills in a builder or from a + * {@link SplitSpec} that can be reused across windows, and returns the pane that appeared. It throws + * {@link io.github.libtmux.exception.UnsupportedFeatureException} when the spec asks for something + * this server does not have. + * + *

+ * + *

Layout and size. Rearrange the panes into one of tmux's built-in layouts, step + * to the next or previous one, or rotate them. Read the arrangement with {@link #layout()} and hand it + * back to {@link #applyLayout}, which checks the string before tmux sees it and throws + * {@link IllegalArgumentException} for one tmux did not write. Resizing takes terminal cells. + * Synchronizing panes copies input typed into one pane into every pane of the window until it is + * stopped. + * + *

+ * + *

Moving and linking. Make the window the active one in its session, link it + * into another session so one window sits in both, move it to another session or to an exact index + * there, or remove one link. {@link #unlink} throws {@link LibTmuxException} when this is the + * window's only link, which tmux refuses to remove. + * + *

{@link #select}, {@link #linkTo}, {@link #unlink}, {@link #moveTo} + * + *

Changing the window. Rename it, which returns a replacement capture because + * this handle keeps its original state; kill what is running in it and start it again; show a popup + * over it, which needs an attached client; or close it. + * + *

{@link #rename}, {@link #respawn}, {@link #displayPopup}, {@link #kill} + * + *

Options and hooks. These reach what is set on this window alone, and every link + * to the window shares them. + * + *

{@link #options}, {@link #hooks} + * + *

Formats and refreshing. Expand a tmux format in this window's context, or take + * a new capture to see the window as it is now. Refreshing leaves this handle unchanged and returns + * the new one, and throws {@link TargetGoneException} if the window is no longer linked here, from a + * server that still answers. + * + *

{@link #expand}, {@link #refresh} */ public final class Window { From 1a94e08acf7f5d7e3c8c93fd7d66d68b499aee97 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 14 Nov 2026 16:25:44 -0600 Subject: [PATCH 2/3] Kotlin(docs): Write the Session, Window and Pane directories why: libtmux.org draws a "What is on here" table on the Kotlin Server page only. Session, Window and Pane hold most of the operations a reader looks for, and most of those are `suspend` extensions that the member list shows apart from the type. what: - Add a "What is on here" section to the Session, Window and Pane KDoc, in the shape of the Server one: bold-led rows, each followed by a paragraph of references - Link extension functions as `[name][Type.name]`, since several types share names such as kill, refresh and expand - State that a property or plain function reads the capture and every `suspend` extension asks tmux, and that Pane's waits take their own dispatcher --- .../kotlin/io/github/libtmux/kotlin/Pane.kt | 87 +++++++++++++++++++ .../io/github/libtmux/kotlin/Session.kt | 48 ++++++++++ .../kotlin/io/github/libtmux/kotlin/Window.kt | 66 ++++++++++++++ 3 files changed, 201 insertions(+) diff --git a/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Pane.kt b/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Pane.kt index 2b9de3952..8fbcf3114 100644 --- a/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Pane.kt +++ b/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Pane.kt @@ -22,6 +22,93 @@ import io.github.libtmux.Pane as JavaPane * Holds the Java handle privately, so a member here always wins over a same-named catalog-generated * extension in `PaneOperations.kt`. [Companion] hosts the generated query field namespace * (`Pane.command`, `Pane.active`, ...). + * + * A property or a plain function here reads the capture this handle came from and issues no command. + * Every `suspend` function asks tmux now, dispatched through the [Server]'s policy, except the waits, + * which run on their own dispatcher. + * + * # What is on here + * + * The members fall into a few groups: + * + * **Reading the capture.** [id], [index], [active], [currentCommand], [floating], [size], [position], + * [edges], [title], [currentPath] and [pid] read what this capture stored about the pane, and + * [window] and [server] are what it sits in. The id is stable and the index is state, since panes + * renumber as neighbours come and go. [floating] is null when the running tmux cannot say, which + * before 3.7 is always, and [pid] is null when tmux reported no process. [currentPath] throws when + * this JVM cannot represent the directory's name. + * + * [id], [index], [active], [currentCommand], [floating], [size], [position], [edges], [title], + * [currentPath], [pid], [window], [server] and [asJava] + * + * **Sending input.** [send][Pane.send] types keys without pressing Enter and + * [sendLine][Pane.sendLine] presses it, which is how a command gets run. [sendKeys][Pane.sendKeys] + * resolves each entry through tmux's key table and types an unknown name as text; + * [sendLiteral][Pane.sendLiteral] types every entry as the characters it spells, so `C-c` is three + * characters. [paste][Pane.paste] delivers text as one block through a private buffer that is + * removed afterwards, and it throws for text containing NUL and before tmux 3.4. + * [noteTyped][Pane.noteTyped] tells a later wait about text that reached the pane without passing + * through this handle. + * + * [send][Pane.send], [sendLine][Pane.sendLine], [sendKeys][Pane.sendKeys], + * [sendLiteral][Pane.sendLiteral], [paste][Pane.paste], [pasteBuffer][Pane.pasteBuffer] and + * [noteTyped][Pane.noteTyped] + * + * **Reading output.** [capture][Pane.capture] returns the visible content, one element per line, read + * from tmux now rather than from the capture. Give it a `CaptureSpec` to read part of the history; it + * throws when the spec asks for something this server does not have. [pipeTo][Pane.pipeTo] sends + * everything the pane prints to a shell command until [stopPiping][Pane.stopPiping], and + * [clearHistory][Pane.clearHistory] discards the scrollback. + * + * [capture][Pane.capture], [pipeTo][Pane.pipeTo], [stopPiping][Pane.stopPiping] and + * [clearHistory][Pane.clearHistory] + * + * **Running and waiting.** [run] runs a shell command to its end and answers with its exit status and + * output, and throws when the pane is not running a POSIX shell. Reach for it first when the command + * is yours. When it is not, [awaitText] and [await] poll the screen or the pane's state on a timer + * and answer with why they ended; a pane killed mid-wait ends [awaitText] as `TextOutcome.PANE_GONE` + * rather than an exception. Cancelling the coroutine interrupts a wait and is not a timeout. + * [dead][Pane.dead] reads fresh whether the pane's process has exited, and throws when the pane is + * gone from a server that still answers. + * + * [run], [awaitText], [await] and [dead][Pane.dead] + * + * **Splitting and arranging.** [split][Pane.split] divides this pane in half, or as a `SplitSpec` + * describes, and returns the pane that appeared. [breakOut][Pane.breakOut] moves the pane into a + * window of its own, [joinTo][Pane.joinTo] into another window, and [swapWith][Pane.swapWith] swaps + * it with another pane. [resize][Pane.resize] grows it by cells in one direction, + * [resizeTo][Pane.resizeTo] sets exact dimensions, and [select][Pane.select] makes it the active + * pane. An unnamed [breakOut][Pane.breakOut] throws on exact tmux 3.7, which a named break or 3.7a + * avoids. + * + * [split][Pane.split], [breakOut][Pane.breakOut], [joinTo][Pane.joinTo], [swapWith][Pane.swapWith], + * [resize][Pane.resize], [resizeTo][Pane.resizeTo] and [select][Pane.select] + * + * **Modes.** [copyMode][Pane.copyMode] puts the pane into copy mode, [mode][Pane.mode] reads live + * which mode it is in, null when it is showing its program, and [exitMode][Pane.exitMode] leaves + * whichever mode it is in. + * + * [copyMode][Pane.copyMode], [mode][Pane.mode] and [exitMode][Pane.exitMode] + * + * **Changing the pane.** [retitle][Pane.retitle] returns a replacement capture, because this handle + * keeps its original state. [respawn][Pane.respawn] kills what runs here and starts the pane's + * default command or one you give, [respawnIn][Pane.respawnIn] does so in a directory, and + * [kill][Pane.kill] closes the pane. + * + * [retitle][Pane.retitle], [respawn][Pane.respawn], [respawnIn][Pane.respawnIn] and + * [kill][Pane.kill] + * + * **Options and hooks.** [options] and [hooks] reach what is set on this pane alone. + * + * [options] and [hooks] + * + * **Formats and refreshing.** [expand][Pane.expand] expands a tmux format, and + * [variables][Pane.variables] reads several named variables, in this pane's context. + * [refresh][Pane.refresh] takes a new capture to see the pane as it is now. It leaves this handle + * unchanged and returns the new one, and throws if the pane is gone from a server that still + * answers. + * + * [expand][Pane.expand], [variables][Pane.variables] and [refresh][Pane.refresh] */ public class Pane internal constructor(internal val java: JavaPane, public val server: Server) { diff --git a/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Session.kt b/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Session.kt index 4e4ef8532..0a6e86ea5 100644 --- a/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Session.kt +++ b/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Session.kt @@ -9,6 +9,54 @@ import io.github.libtmux.Session as JavaSession * Holds the Java handle privately, so a member here always wins over a same-named catalog-generated * extension in `SessionOperations.kt`. [Companion] hosts the generated query field namespace * (`Session.name`, `Session.attached`, ...). + * + * A property or a plain function here reads the capture this handle came from and issues no command. + * Every `suspend` extension asks tmux now, dispatched through the [Server]'s policy. + * + * # What is on here + * + * The members fall into a few groups: + * + * **Reading the capture.** [id], [name] and [attached] read what this capture stored about the + * session, and [server] is the [Server] it lives on. The id is stable, the name is state a user may + * change at any time, and a rename or an attach after the capture does not show in it. + * + * [id], [name], [attached], [server] and [asJava] + * + * **Windows and panes.** [windows] lists the session's windows in tmux's order, and [activeWindow] + * and [activePane] are the window tmux had active and the active pane of that window, each null when + * the capture holds none. All three are pure reads and issue no command. [selectWindow][Session.selectWindow] + * makes a window the active one, [nextWindow][Session.nextWindow] and + * [previousWindow][Session.previousWindow] step to a neighbour with wrap-around, and + * [lastWindow][Session.lastWindow] goes back to the one that was active before. + * + * [windows], [activeWindow], [activePane], [selectWindow][Session.selectWindow], + * [nextWindow][Session.nextWindow], [previousWindow][Session.previousWindow] and + * [lastWindow][Session.lastWindow] + * + * **Changing the session.** [newWindow][Session.newWindow] creates a window from a name or a + * `WindowSpec` and returns the window tmux made. [rename][Session.rename] returns a replacement + * capture, because this handle keeps its original state. [setHistoryLimit][Session.setHistoryLimit] + * sets the scrollback retained by panes created in this session afterwards. + * [detachClients][Session.detachClients] leaves the session running, and [kill][Session.kill] takes + * every window with it. + * + * [newWindow][Session.newWindow], [rename][Session.rename], [setHistoryLimit][Session.setHistoryLimit], + * [detachClients][Session.detachClients] and [kill][Session.kill] + * + * **Options, environment, and hooks.** These reach what is set on this session alone: its own + * options, its own environment, which a process started in it is given on top of the server's, and + * its own hooks. The [Server] holds the global ones, which a session inherits. Each returns a + * wrapper whose own operations are `suspend`. + * + * [options], [environment] and [hooks] + * + * **Formats and refreshing.** [expand][Session.expand] expands a tmux format in this session's + * context, and [refresh][Session.refresh] takes a new capture to see the session as it is now. It + * leaves this handle unchanged and returns the new one, and throws if the session is gone from a + * server that still answers. + * + * [expand][Session.expand] and [refresh][Session.refresh] */ public class Session internal constructor(internal val java: JavaSession, public val server: Server) { diff --git a/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Window.kt b/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Window.kt index 566b9cd67..9e978dcdf 100644 --- a/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Window.kt +++ b/libtmux-kotlin/src/main/kotlin/io/github/libtmux/kotlin/Window.kt @@ -12,6 +12,72 @@ import io.github.libtmux.Window as JavaWindow * * Holds the Java handle privately, so a member here always wins over a same-named catalog-generated * extension in `WindowOperations.kt`. [Companion] hosts the generated query field namespace. + * + * A property or a plain function here reads the capture this handle came from and issues no command. + * Every `suspend` extension asks tmux now, dispatched through the [Server]'s policy. + * + * # What is on here + * + * The members fall into a few groups: + * + * **Reading the capture.** [id], [index], [context], [name], [active], [linked], [size] and [layout] + * read what this capture stored about the window, and [server] and [session] are the [Server] and + * [Session] it sits in. The id names the underlying window and the index names this link, so a window + * linked into two sessions has one id and two handles. A rename or a resize after the capture does + * not show in it. + * + * [id], [index], [context], [name], [active], [linked], [size], [layout], [server], [session] and + * [asJava] + * + * **Panes.** [panes] lists this link's panes in tmux's order and [activePane] is the one tmux had + * active, null when the capture holds none; both are pure reads. [split][Window.split] divides the + * active pane in half, or as a `SplitSpec` describes, and returns the pane that appeared. It throws + * when the spec asks for something this server does not have. + * + * [panes], [activePane] and [split][Window.split] + * + * **Layout and size.** [selectLayout][Window.selectLayout] rearranges the panes into one of tmux's + * built-in layouts, [nextLayout][Window.nextLayout] and [previousLayout][Window.previousLayout] step + * to a neighbour, and [rotate][Window.rotate] rotates the panes. Read the arrangement from [layout] + * and hand it back to [applyLayout][Window.applyLayout], which checks a string before tmux sees it. + * [resizeTo][Window.resizeTo] takes terminal cells. [synchronizePanes][Window.synchronizePanes] + * copies input typed into one pane into every pane of the window until + * [stopSynchronizingPanes][Window.stopSynchronizingPanes]. + * + * [selectLayout][Window.selectLayout], [nextLayout][Window.nextLayout], + * [previousLayout][Window.previousLayout], [applyLayout][Window.applyLayout], + * [rotate][Window.rotate], [resizeTo][Window.resizeTo], + * [synchronizePanes][Window.synchronizePanes] and + * [stopSynchronizingPanes][Window.stopSynchronizingPanes] + * + * **Moving and linking.** [select][Window.select] makes the window the active one in its session. + * [linkTo][Window.linkTo] links it into another session so one window sits in both, + * [moveTo][Window.moveTo] moves it to another session or to an exact index there, and + * [unlink][Window.unlink] removes one link and throws when it is the window's only one, which tmux + * refuses to remove. + * + * [select][Window.select], [linkTo][Window.linkTo], [moveTo][Window.moveTo] and + * [unlink][Window.unlink] + * + * **Changing the window.** [rename][Window.rename] returns a replacement capture, because this handle + * keeps its original state. [respawn][Window.respawn] kills what is running in the window and starts + * it again, [displayPopup][Window.displayPopup] shows a popup over it and needs an attached client, + * and [kill][Window.kill] closes it. + * + * [rename][Window.rename], [respawn][Window.respawn], [displayPopup][Window.displayPopup] and + * [kill][Window.kill] + * + * **Options and hooks.** [options] and [hooks] reach what is set on this window alone, and every link + * to the window shares them. + * + * [options] and [hooks] + * + * **Formats and refreshing.** [expand][Window.expand] expands a tmux format in this window's + * context, and [refresh][Window.refresh] takes a new capture to see the window as it is now. It + * leaves this handle unchanged and returns the new one, and throws if the window is no longer linked + * here, from a server that still answers. + * + * [expand][Window.expand] and [refresh][Window.refresh] */ public class Window internal constructor(internal val java: JavaWindow, public val server: Server) { From f97f0ac5f6e869d599eb043075b8f7c57fe034e5 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 14 Nov 2026 16:25:44 -0600 Subject: [PATCH 3/3] Scala(docs): Write the Session, Window and Pane directories why: libtmux.org shows the Scala Server directory on the scaladsl Server page, which is an opaque type, and the Session, Window and Pane pages had none. Their operations are extensions, so the member list does not group them by job. what: - Add a "What is on here" section to the doc comment of the Session, Window and Pane opaque types, where the Server one lives - Link every operation as `[[Type.name]]`, as the Server directory does for the operations of the other types - State that an operation beyond a pure read of the capture blocks the calling thread, that results are `Vector` and `Option`, and that Pane's waits are cancelled by interrupting the thread --- .../io/github/libtmux/scaladsl/Pane.scala | 98 +++++++++++++++++++ .../io/github/libtmux/scaladsl/Session.scala | 53 ++++++++++ .../io/github/libtmux/scaladsl/Window.scala | 70 +++++++++++++ 3 files changed, 221 insertions(+) diff --git a/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Pane.scala b/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Pane.scala index 9a89e3c78..e95ac475a 100644 --- a/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Pane.scala +++ b/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Pane.scala @@ -9,6 +9,104 @@ import scala.jdk.DurationConverters._ * identifies the physical pane; every operation beyond that is an extension, * generated from the operation catalog or handwritten where the catalog marks * it `WAIT`, `STREAM` or `LIFECYCLE`. + * + * A pure read of the capture issues no command; every other operation asks tmux + * now, blocking the calling thread. + * + * # What is on here + * + * The operations fall into a few groups: + * + * **Reading the capture.** [[Pane.id]], [[Pane.index]], [[Pane.active]], + * [[Pane.currentCommand]], [[Pane.floating]], [[Pane.size]], [[Pane.position]], + * [[Pane.edges]], [[Pane.title]], [[Pane.currentPath]], + * [[Pane.currentPathText]] and [[Pane.pid]] read what this capture stored about + * the pane, and [[Pane.window]] and [[Pane.server]] are what it sits in. The id + * is stable and the index is state, since panes renumber as neighbours come and + * go. [[Pane.floating]] is empty when the running tmux cannot say, which before + * 3.7 is always, and [[Pane.pid]] is empty when tmux reported no process. + * [[Pane.currentPath]] throws when this JVM cannot represent the directory's + * name; [[Pane.currentPathText]] is what tmux reported and never throws. + * + * [[Pane.info]], [[Pane.id]], [[Pane.index]], [[Pane.active]], + * [[Pane.currentCommand]], [[Pane.floating]], [[Pane.size]], [[Pane.position]], + * [[Pane.edges]], [[Pane.title]], [[Pane.currentPath]], + * [[Pane.currentPathText]], [[Pane.pid]], [[Pane.window]], [[Pane.server]] and + * [[Pane.asJava]] + * + * **Sending input.** [[Pane.send]] types keys without pressing Enter and + * [[Pane.sendLine]] presses it, which is how a command gets run. + * [[Pane.sendKeys]] resolves each entry through tmux's key table and types an + * unknown name as text; [[Pane.sendLiteral]] types every entry as the + * characters it spells, so `C-c` is three characters. [[Pane.paste]] delivers + * text as one block through a private buffer that is removed afterwards, and it + * throws for text containing NUL and before tmux 3.4. [[Pane.noteTyped]] tells + * a later wait about text that reached the pane without passing through this + * handle. + * + * [[Pane.send]], [[Pane.sendLine]], [[Pane.sendKeys]], [[Pane.sendLiteral]], + * [[Pane.paste]], [[Pane.pasteBuffer]] and [[Pane.noteTyped]] + * + * **Reading output.** [[Pane.capture]] returns the visible content as a + * `Vector` with one element per line, read from tmux now rather than from the + * capture. Give it a callback on a builder or a `CaptureSpec` to read part of + * the history; it throws when the spec asks for something this server does not + * have. [[Pane.pipeTo]] sends everything the pane prints to a shell command + * until [[Pane.stopPiping]], and [[Pane.clearHistory]] discards the scrollback. + * + * [[Pane.capture]], [[Pane.pipeTo]], [[Pane.stopPiping]] and + * [[Pane.clearHistory]] + * + * **Running and waiting.** [[Pane.run]] runs a shell command to its end and + * answers with its exit status and output, and throws when the pane is not + * running a POSIX shell. Reach for it first when the command is yours. When it + * is not, [[Pane.awaitText]] and [[Pane.await]] poll the screen or the pane's + * state on a timer and answer with why they ended; a pane killed mid-wait ends + * [[Pane.awaitText]] as `TextOutcome.PANE_GONE` rather than an exception. Each + * wait blocks its thread, and interrupting the thread cancels it with + * `InterruptedException`. [[Pane.dead]] reads fresh whether the pane's process + * has exited, and throws when the pane is gone from a server that still + * answers. + * + * [[Pane.run]], [[Pane.awaitText]], [[Pane.await]] and [[Pane.dead]] + * + * **Splitting and arranging.** [[Pane.split]] divides this pane in half, from a + * callback on a builder or a `SplitSpec`, and returns the pane that appeared. + * [[Pane.breakOut]] moves the pane into a window of its own, [[Pane.joinTo]] + * into another window, and [[Pane.swapWith]] swaps it with another pane. + * [[Pane.resize]] grows it by cells in one direction, [[Pane.resizeTo]] sets + * exact dimensions, and [[Pane.select]] makes it the active pane. An unnamed + * [[Pane.breakOut]] throws on exact tmux 3.7, which a named break or 3.7a + * avoids. + * + * [[Pane.split]], [[Pane.breakOut]], [[Pane.joinTo]], [[Pane.swapWith]], + * [[Pane.resize]], [[Pane.resizeTo]] and [[Pane.select]] + * + * **Modes.** [[Pane.copyMode]] puts the pane into copy mode, [[Pane.mode]] + * reads live which mode it is in, empty when it is showing its program, and + * [[Pane.exitMode]] leaves whichever mode it is in. + * + * [[Pane.copyMode]], [[Pane.mode]] and [[Pane.exitMode]] + * + * **Changing the pane.** [[Pane.retitle]] returns a replacement capture, + * because this handle keeps its original state. [[Pane.respawn]] kills what + * runs here and starts the pane's default command or one you give, + * [[Pane.respawnIn]] does so in a directory, and [[Pane.kill]] closes the pane. + * + * [[Pane.retitle]], [[Pane.respawn]], [[Pane.respawnIn]] and [[Pane.kill]] + * + * **Options and hooks.** [[Pane.options]] and [[Pane.hooks]] reach what is set + * on this pane alone. + * + * [[Pane.options]] and [[Pane.hooks]] + * + * **Formats and refreshing.** [[Pane.expand]] expands a tmux format, and + * [[Pane.variables]] reads several named variables, in this pane's context. + * [[Pane.refresh]] takes a new capture to see the pane as it is now. It leaves + * this handle unchanged and returns the new one, and throws if the pane is gone + * from a server that still answers. + * + * [[Pane.expand]], [[Pane.variables]] and [[Pane.refresh]] */ opaque type Pane = JavaPane diff --git a/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Session.scala b/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Session.scala index 26e7899dd..7ec9c1911 100644 --- a/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Session.scala +++ b/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Session.scala @@ -6,6 +6,59 @@ import io.github.libtmux.scaladsl.query.Expr /** A captured session, opaque over the Java handle; every operation beyond * equality is an extension, generated from the operation catalog or * handwritten where the catalog marks it `WAIT`, `STREAM` or `LIFECYCLE`. + * + * A pure read of the capture issues no command; every other operation asks tmux + * now, blocking the calling thread. + * + * # What is on here + * + * The operations fall into a few groups: + * + * **Reading the capture.** [[Session.id]], [[Session.name]] and + * [[Session.attached]] read what this capture stored about the session, and + * [[Session.server]] is the [[Server]] it lives on. The id is stable, the name + * is state a user may change at any time, and a rename or an attach after the + * capture does not show in it. + * + * [[Session.info]], [[Session.id]], [[Session.name]], [[Session.attached]], + * [[Session.server]] and [[Session.asJava]] + * + * **Windows and panes.** [[Session.windows]] lists the session's windows in + * tmux's order as a `Vector`, and [[Session.activeWindow]] and + * [[Session.activePane]] are the window tmux had active and the active pane of + * that window, each an `Option`. All three are pure reads. + * [[Session.selectWindow]] makes a window the active one, + * [[Session.nextWindow]] and [[Session.previousWindow]] step to a neighbour + * with wrap-around, and [[Session.lastWindow]] goes back to the one that was + * active before. + * + * [[Session.windows]], [[Session.activeWindow]], [[Session.activePane]], + * [[Session.selectWindow]], [[Session.nextWindow]], [[Session.previousWindow]] + * and [[Session.lastWindow]] + * + * **Changing the session.** [[Session.newWindow]] creates a window from a name, + * a callback on a builder, or a `WindowSpec`, and returns the window tmux made. + * [[Session.rename]] returns a replacement capture, because this handle keeps + * its original state. [[Session.setHistoryLimit]] sets the scrollback retained + * by panes created in this session afterwards. [[Session.detachClients]] leaves + * the session running, and [[Session.kill]] takes every window with it. + * + * [[Session.newWindow]], [[Session.rename]], [[Session.setHistoryLimit]], + * [[Session.detachClients]] and [[Session.kill]] + * + * **Options, environment, and hooks.** These reach what is set on this session + * alone: its own options, its own environment, which a process started in it is + * given on top of the server's, and its own hooks. The [[Server]] holds the + * global ones, which a session inherits. + * + * [[Session.options]], [[Session.environment]] and [[Session.hooks]] + * + * **Formats and refreshing.** [[Session.expand]] expands a tmux format in this + * session's context, and [[Session.refresh]] takes a new capture to see the + * session as it is now. It leaves this handle unchanged and returns the new + * one, and throws if the session is gone from a server that still answers. + * + * [[Session.expand]] and [[Session.refresh]] */ opaque type Session = JavaSession diff --git a/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Window.scala b/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Window.scala index 55b237969..b28c573dc 100644 --- a/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Window.scala +++ b/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Window.scala @@ -8,6 +8,76 @@ import io.github.libtmux.scaladsl.query.Expr * session has more than one placement. Every operation beyond equality is an * extension, generated from the operation catalog or handwritten where the * catalog marks it `WAIT`, `STREAM` or `LIFECYCLE`. + * + * A pure read of the capture issues no command; every other operation asks tmux + * now, blocking the calling thread. + * + * # What is on here + * + * The operations fall into a few groups: + * + * **Reading the capture.** [[Window.id]], [[Window.index]], [[Window.context]], + * [[Window.name]], [[Window.active]], [[Window.linked]], [[Window.size]] and + * [[Window.layout]] read what this capture stored about the window, and + * [[Window.server]] and [[Window.session]] are the [[Server]] and [[Session]] + * it sits in. The id names the underlying window and the index names this link, + * so a window linked into two sessions has one id and two handles. A rename or + * a resize after the capture does not show in it. + * + * [[Window.info]], [[Window.id]], [[Window.index]], [[Window.context]], + * [[Window.name]], [[Window.active]], [[Window.linked]], [[Window.size]], + * [[Window.layout]], [[Window.server]], [[Window.session]] and + * [[Window.asJava]] + * + * **Panes.** [[Window.panes]] lists this link's panes in tmux's order as a + * `Vector`, and [[Window.activePane]] is the one tmux had active, an `Option`; + * both are pure reads. [[Window.split]] divides the active pane in half, from a + * callback on a builder or a `SplitSpec`, and returns the pane that appeared. + * It throws when the spec asks for something this server does not have. + * + * [[Window.panes]], [[Window.activePane]] and [[Window.split]] + * + * **Layout and size.** [[Window.selectLayout]] rearranges the panes into one of + * tmux's built-in layouts, [[Window.nextLayout]] and [[Window.previousLayout]] + * step to a neighbour, and [[Window.rotate]] rotates the panes. Read the + * arrangement from [[Window.layout]] and hand it back to + * [[Window.applyLayout]], which checks a string before tmux sees it. + * [[Window.resizeTo]] takes terminal cells. [[Window.synchronizePanes]] copies + * input typed into one pane into every pane of the window until + * [[Window.stopSynchronizingPanes]]. + * + * [[Window.selectLayout]], [[Window.nextLayout]], [[Window.previousLayout]], + * [[Window.applyLayout]], [[Window.rotate]], [[Window.resizeTo]], + * [[Window.synchronizePanes]] and [[Window.stopSynchronizingPanes]] + * + * **Moving and linking.** [[Window.select]] makes the window the active one in + * its session. [[Window.linkTo]] links it into another session so one window + * sits in both, [[Window.moveTo]] moves it to another session or to an exact + * index there, and [[Window.unlink]] removes one link and throws when it is the + * window's only one, which tmux refuses to remove. + * + * [[Window.select]], [[Window.linkTo]], [[Window.moveTo]] and [[Window.unlink]] + * + * **Changing the window.** [[Window.rename]] returns a replacement capture, + * because this handle keeps its original state. [[Window.respawn]] kills what + * is running in the window and starts it again, [[Window.displayPopup]] shows a + * popup over it and needs an attached client, and [[Window.kill]] closes it. + * + * [[Window.rename]], [[Window.respawn]], [[Window.displayPopup]] and + * [[Window.kill]] + * + * **Options and hooks.** [[Window.options]] and [[Window.hooks]] reach what is + * set on this window alone, and every link to the window shares them. + * + * [[Window.options]] and [[Window.hooks]] + * + * **Formats and refreshing.** [[Window.expand]] expands a tmux format in this + * window's context, and [[Window.refresh]] takes a new capture to see the + * window as it is now. It leaves this handle unchanged and returns the new one, + * and throws if the window is no longer linked here, from a server that still + * answers. + * + * [[Window.expand]] and [[Window.refresh]] */ opaque type Window = JavaWindow