# Pane interaction

Source: https://libtmux.org/en/tmux/topics/pane-interaction/

> Input defaults, screen capture, and waiting for a command to finish.

Send input to a pane and capture its screen to interact with a running program.
[Attach and send keys](https://libtmux.org/en/tmux/examples/attach-and-send-keys/) provides examples.
[Sending keys](https://libtmux.org/en/tmux/guides/sending-keys/) and [Capturing
output](https://libtmux.org/en/tmux/guides/capturing-output/) are task guides; this page covers input
defaults, capture ranges, and completion handling.

## Typing into a pane

Two questions come up every time you send something to a pane: should tmux
press Enter afterward, and should tmux interpret what you sent as key names
(`Enter`, `C-c`) rather than literal characters? Choose both explicitly when
a command depends on them.

### Python

**Type without Enter:** [`pane.send_keys(text, enter=False)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-send_keys/>)

**Type + Enter (default):** [`pane.send_keys(text)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-send_keys/>)

**How "literal" is chosen:** `literal=True` flag on the same method

### TypeScript

**Type without Enter:** `pane.sendKeys(text, { enter: false })`

**Type + Enter (default):** [`pane.sendKeys(text)`](<https://libtmux.org/en/ts/latest/reference/pane-pane-sendkeys/>)

**How "literal" is chosen:** `{ literal: true }` option

### Go

**Type without Enter:** `pane.SendKeys(ctx, SendKeysRequest{Command: &text,
SkipEnter: true})`

**Type + Enter (default):** `pane.SendKeys(ctx, SendKeysRequest{Command:
&text})`

**How "literal" is chosen:** `Literal: true` field

### Rust

**Type without Enter:** [`pane.send_keys(keys)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_keys/>): **always literal**, key names
typed as text

**Type + Enter (default):** [`pane.send_line(text)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_line/>)

**How "literal" is chosen:** [`send_keys`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_keys/>) sends literal text; [`send_key_names`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_key_names/>)
interprets tmux key names.

### Java

**Type without Enter:** [`pane.send(keys)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-send/>)

**Type + Enter (default):** [`pane.sendLine(command)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-sendline/>)

**How "literal" is chosen:** Separate text and key-sending methods.

### C#

**Type without Enter:** [`SendKeysAsync(new SendKeysRequest(text, enter: false))`](<https://libtmux.org/en/csharp/latest/reference/libtmux-pane-sendkeysasync/>)

**Type + Enter (default):** [`SendTextAsync(text)`](<https://libtmux.org/en/csharp/latest/reference/libtmux-pane-sendtextasync/>) (defaults `enter: true`)

**How "literal" is chosen:** [`SendKeysRequest.Literal`](<https://libtmux.org/en/csharp/latest/reference/libtmux-sendkeysrequest-literal/>) field;
[`SendTextAsync`](<https://libtmux.org/en/csharp/latest/reference/libtmux-pane-sendtextasync/>) hardcodes it

### C++

**Type without Enter:** [`pane->send_text(text)`](<https://libtmux.org/en/cxx/latest/reference/libtmux-pane-send_text/>)

**Type + Enter:** [`pane->send_text(text)`](<https://libtmux.org/en/cxx/latest/reference/libtmux-pane-send_text/>) then [`pane->send_key("Enter")`](<https://libtmux.org/en/cxx/latest/reference/libtmux-pane-send_key/>)
separately: no combined convenience exists

**How "literal" is chosen:** `send_text` is always literal; `send_key` is always
a key name

### Swift

**Type without Enter:** [`server.sendKeys([text], to: pane)`](<https://libtmux.org/en/swift/latest/reference/server-sendkeys(_-to-literally-)/>)

**Type + Enter (default):** `server.run(text, in: pane)` (sugar for
[`sendKeys([text, "Enter"], to: pane)`](<https://libtmux.org/en/swift/latest/reference/server-sendkeys(_-to-literally-)/>))

**How "literal" is chosen:** `literally: true` option on [`sendKeys`](<https://libtmux.org/en/swift/latest/reference/server-sendkeys(_-to-literally-)/>)

### Examples

[`send_keys`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_keys/>) sends literal text. Use [`send_key_names`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_key_names/>) for tmux key names.
Passing `"Enter"` to [`send_keys`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_keys/>) types those characters. [`send_line`](<https://libtmux.org/en/rs/latest/reference/pane-pane-send_line/>) appends a
carriage return and delivers it with the text in one tmux command.

`sendLine` appends a carriage return and delivers it with the text in one tmux
command.

Text and Enter can be separate tmux commands. If the second operation fails,
the text may already be in the pane. Check the current state before retrying;
repeating the whole request can duplicate input.

Send a command line and press Enter:

```python
pane.send_keys("echo hi", enter=False)  # type without pressing Enter
pane.send_keys("echo hi")               # default: presses Enter afterward
```

```typescript
await pane.sendKeys("echo hi", { enter: false });
await pane.sendKeys("echo hi");
```

```go
text := "printf 'hello\\n'"
if err := pane.SendKeys(ctx, tmux.SendKeysRequest{
    Command: &text,
    Literal: true,
}); err != nil {
    return fmt.Errorf("send command: %w", err)
}
```

```rust
pane.send_keys("echo hi").await?; // Always literal text.
pane.send_line("echo hi").await?; // text and Enter in one send-keys -l call
```

```java
pane.send("echo hi");     // no Enter
pane.sendLine("echo hi"); // text and \r in one send-keys -l call
```

```csharp
await pane.SendKeysAsync(new SendKeysRequest("echo hi", enter: false));
await pane.SendTextAsync("echo hi"); // defaults enter: true
```

```cpp
pane->send_text("echo hi");
pane->send_key("Enter"); // separate command: no combined convenience exists
```

```swift
try await server.sendKeys(["echo hi"], to: pane) // no Enter
try await server.run("echo hi", in: pane)        // sugar for sendKeys([text, "Enter"])
```

## Reading a pane back

Capture reads the pane's visible screen by default. Request scrollback when
you need earlier output. A capture is a snapshot of terminal contents, including
any input echoed by the application.

[`pane.Capture`](<https://libtmux.org/en/go/latest/reference/tmux-pane-capture/>) returns `([]string, error)`. Pass a [`context.Context`](<https://pkg.go.dev/context#Context>) with a
deadline and check the error before using the result. Set the start boundary to
[`tmux.CaptureBoundary`](<https://libtmux.org/en/go/latest/reference/tmux-captureboundary/>) to include scrollback. `End: tmux.CaptureBoundary`
includes the bottom of the visible pane.

```python
pane.capture_pane()
```

```typescript
await pane.capture();
```

```go
lines, err := pane.Capture(ctx, tmux.CapturePaneRequest{})
if err != nil {
    return fmt.Errorf("capture pane: %w", err)
}
for _, line := range lines {
    fmt.Println(line)
}
```

```rust
pane.capture().await?;
```

```java
pane.capture();
```

```csharp
await pane.CaptureAsync();
```

```cpp
pane->capture();
```

```swift
try await server.capture(pane)
```

## Waiting for something to finish

A send call completes when input reaches tmux. It does not wait for the shell
command to finish. Wait for expected output or a completion signal.

Poll capture output for a marker or use the [`wait_for`](<https://libtmux.org/en/py/latest/reference/libtmux-server-wait_for/>) signal channel when you
control the command. The test-support module provides
`libtmux.test.retry_until(condition, ...)` for arbitrary conditions.

[`server.waitForOutput(...)`](<https://libtmux.org/en/swift/latest/reference/server-waitforoutput(in-matching-stoppingat-requiringfreshoutput-startingat-timeout-taillimit-)/>) waits for a pattern in pane output and returns an
[`OutputWait`](<https://libtmux.org/en/swift/latest/reference/outputwait/>). Give the wait a timeout.

Use [`server.WaitFor`](<https://libtmux.org/en/go/latest/reference/tmux-server-waitfor/>) with a [`WaitForRequest`](<https://libtmux.org/en/go/latest/reference/tmux-waitforrequest/>) when the command can signal tmux's
`wait-for` channel. For streaming output, open [`pane.OpenObservation(ctx)`](<https://libtmux.org/en/go/latest/reference/tmux-pane-openobservation/>)
before sending input so the observation includes the command's first bytes.
Both paths take a context; cancellation bounds how long the caller waits.

For a new command whose exit status matters, use [`session.Run`](<https://libtmux.org/en/go/latest/reference/tmux-session-run/>) and inspect its
result. Capturing screen text alone cannot establish the command's exit status.

Use [`TmuxWaitChannel`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxwaitchannel/>) when the command can signal a named tmux `wait-for`
channel. Use a cancellation token to bound the wait.

[Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/) shows capture and waiting
examples. [Waiting and retrying](https://libtmux.org/en/tmux/topics/waiting-and-retry/) explains completion
conditions and timeouts.

<details>
<summary>tmux manual and source</summary>

The tmux manual defines [key-name and literal input](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1#L4457)
and [screen and history capture](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1#L2798).
A send operation delivers input; it does not establish the program's exit status.

</details>
