Skip to content

Commit 7fca580

Browse files
authored
feat(Pane[capture_pane]) Support new capture-pane flags (#614)
#### Pane.capture_pane() enhanced (#614) The {meth}`~libtmux.pane.Pane.capture_pane` method now supports 5 new parameters that expose additional tmux `capture-pane` flags: | Parameter | tmux Flag | Description | |-----------|-----------|-------------| | `escape_sequences` | `-e` | Include ANSI escape sequences (colors, attributes) | | `escape_non_printable` | `-C` | Escape non-printable chars as octal `\xxx` | | `join_wrapped` | `-J` | Join wrapped lines back together | | `preserve_trailing` | `-N` | Preserve trailing spaces at line ends | | `trim_trailing` | `-T` | Trim trailing empty positions (tmux 3.4+) | **Capturing colored output:** ```python # Capture with ANSI escape sequences preserved pane.send_keys('printf "\\033[31mRED\\033[0m"', enter=True) output = pane.capture_pane(escape_sequences=True) # Output contains: '\x1b[31mRED\x1b[0m' ``` **Joining wrapped lines:** ```python # Long lines that wrap are joined back together output = pane.capture_pane(join_wrapped=True) ``` **Version compatibility:** The `trim_trailing` parameter requires tmux 3.4+. If used with an older version, a warning is issued and the flag is ignored. All other parameters work with libtmux's minimum supported version (tmux 3.2a).
2 parents bd13b1e + 279b6d4 commit 7fca580

File tree

4 files changed

+640
-1
lines changed

4 files changed

+640
-1
lines changed

CHANGES

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,41 @@ $ uvx --from 'libtmux' --prerelease allow python
3434

3535
_Upcoming changes will be written here._
3636

37+
#### Pane.capture_pane() enhanced (#614)
38+
39+
The {meth}`~libtmux.pane.Pane.capture_pane` method now supports 5 new parameters
40+
that expose additional tmux `capture-pane` flags:
41+
42+
| Parameter | tmux Flag | Description |
43+
|-----------|-----------|-------------|
44+
| `escape_sequences` | `-e` | Include ANSI escape sequences (colors, attributes) |
45+
| `escape_non_printable` | `-C` | Escape non-printable chars as octal `\xxx` |
46+
| `join_wrapped` | `-J` | Join wrapped lines back together |
47+
| `preserve_trailing` | `-N` | Preserve trailing spaces at line ends |
48+
| `trim_trailing` | `-T` | Trim trailing empty positions (tmux 3.4+) |
49+
50+
**Capturing colored output:**
51+
52+
```python
53+
# Capture with ANSI escape sequences preserved
54+
pane.send_keys('printf "\\033[31mRED\\033[0m"', enter=True)
55+
output = pane.capture_pane(escape_sequences=True)
56+
# Output contains: '\x1b[31mRED\x1b[0m'
57+
```
58+
59+
**Joining wrapped lines:**
60+
61+
```python
62+
# Long lines that wrap are joined back together
63+
output = pane.capture_pane(join_wrapped=True)
64+
```
65+
66+
**Version compatibility:**
67+
68+
The `trim_trailing` parameter requires tmux 3.4+. If used with an older version,
69+
a warning is issued and the flag is ignored. All other parameters work with
70+
libtmux's minimum supported version (tmux 3.2a).
71+
3772
## libtmux 0.51.0 (2025-12-06)
3873

3974
### Breaking changes

docs/topics/pane_interaction.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,75 @@ True
131131
True
132132
```
133133

134+
### Capture with ANSI escape sequences
135+
136+
Capture colored output with escape sequences preserved using `escape_sequences=True`:
137+
138+
```python
139+
>>> import time
140+
141+
>>> pane.send_keys('printf "\\033[31mRED\\033[0m \\033[32mGREEN\\033[0m"')
142+
>>> time.sleep(0.1)
143+
144+
>>> # Capture with ANSI codes stripped (default)
145+
>>> output = pane.capture_pane()
146+
>>> 'RED' in '\\n'.join(output)
147+
True
148+
149+
>>> # Capture with ANSI escape sequences preserved
150+
>>> colored_output = pane.capture_pane(escape_sequences=True)
151+
>>> isinstance(colored_output, list)
152+
True
153+
```
154+
155+
### Join wrapped lines
156+
157+
Long lines that wrap in the terminal can be joined back together:
158+
159+
```python
160+
>>> import time
161+
162+
>>> # Send a very long line that will wrap
163+
>>> pane.send_keys('echo "' + 'x' * 200 + '"')
164+
>>> time.sleep(0.1)
165+
166+
>>> # Capture with wrapped lines joined
167+
>>> output = pane.capture_pane(join_wrapped=True)
168+
>>> isinstance(output, list)
169+
True
170+
```
171+
172+
### Preserve trailing spaces
173+
174+
By default, trailing spaces are trimmed. Use `preserve_trailing=True` to keep them:
175+
176+
```python
177+
>>> import time
178+
179+
>>> pane.send_keys('printf "text \\n"') # 3 trailing spaces
180+
>>> time.sleep(0.1)
181+
182+
>>> # Capture with trailing spaces preserved
183+
>>> output = pane.capture_pane(preserve_trailing=True)
184+
>>> isinstance(output, list)
185+
True
186+
```
187+
188+
### Capture flags summary
189+
190+
| Parameter | tmux Flag | Description |
191+
|-----------|-----------|-------------|
192+
| `escape_sequences` | `-e` | Include ANSI escape sequences (colors, attributes) |
193+
| `escape_non_printable` | `-C` | Escape non-printable chars as octal `\xxx` |
194+
| `join_wrapped` | `-J` | Join wrapped lines back together |
195+
| `preserve_trailing` | `-N` | Preserve trailing spaces at line ends |
196+
| `trim_trailing` | `-T` | Trim trailing empty positions (tmux 3.4+) |
197+
198+
:::{note}
199+
The `trim_trailing` parameter requires tmux 3.4+. If used with an older version,
200+
a warning is issued and the flag is ignored.
201+
:::
202+
134203
## Waiting for Output
135204

136205
A common pattern in automation is waiting for a command to complete.

src/libtmux/pane.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,14 @@ def capture_pane(
320320
self,
321321
start: t.Literal["-"] | int | None = None,
322322
end: t.Literal["-"] | int | None = None,
323+
*,
324+
escape_sequences: bool = False,
325+
escape_non_printable: bool = False,
326+
join_wrapped: bool = False,
327+
preserve_trailing: bool = False,
328+
trim_trailing: bool = False,
323329
) -> list[str]:
324-
"""Capture text from pane.
330+
r"""Capture text from pane.
325331
326332
``$ tmux capture-pane`` to pane.
327333
``$ tmux capture-pane -S -10`` to pane.
@@ -344,17 +350,74 @@ def capture_pane(
344350
Negative numbers are lines in the history.
345351
``-`` is the end of the visible pane.
346352
Default: None
353+
escape_sequences : bool, optional
354+
Include ANSI escape sequences for text and background attributes
355+
(``-e`` flag). Useful for capturing colored output.
356+
Default: False
357+
escape_non_printable : bool, optional
358+
Escape non-printable characters as octal ``\\xxx`` format
359+
(``-C`` flag). Useful for binary-safe capture.
360+
Default: False
361+
join_wrapped : bool, optional
362+
Join wrapped lines and preserve trailing spaces (``-J`` flag).
363+
Lines that were wrapped by tmux will be joined back together.
364+
Default: False
365+
preserve_trailing : bool, optional
366+
Preserve trailing spaces at each line's end (``-N`` flag).
367+
Default: False
368+
trim_trailing : bool, optional
369+
Trim trailing positions with no characters (``-T`` flag).
370+
Only includes characters up to the last used cell.
371+
Requires tmux 3.4+. If used with tmux < 3.4, a warning
372+
is issued and the flag is ignored.
373+
Default: False
347374
348375
Returns
349376
-------
350377
list[str]
351378
Captured pane content.
379+
380+
Examples
381+
--------
382+
>>> pane = window.split(shell='sh')
383+
>>> pane.capture_pane()
384+
['$']
385+
386+
>>> pane.send_keys('echo "Hello world"', enter=True)
387+
388+
>>> pane.capture_pane()
389+
['$ echo "Hello world"', 'Hello world', '$']
390+
391+
>>> print(chr(10).join(pane.capture_pane()))
392+
$ echo "Hello world"
393+
Hello world
394+
$
352395
"""
396+
import warnings
397+
398+
from libtmux.common import has_gte_version
399+
353400
cmd = ["capture-pane", "-p"]
354401
if start is not None:
355402
cmd.extend(["-S", str(start)])
356403
if end is not None:
357404
cmd.extend(["-E", str(end)])
405+
if escape_sequences:
406+
cmd.append("-e")
407+
if escape_non_printable:
408+
cmd.append("-C")
409+
if join_wrapped:
410+
cmd.append("-J")
411+
if preserve_trailing:
412+
cmd.append("-N")
413+
if trim_trailing:
414+
if has_gte_version("3.4"):
415+
cmd.append("-T")
416+
else:
417+
warnings.warn(
418+
"trim_trailing requires tmux 3.4+, ignoring",
419+
stacklevel=2,
420+
)
358421
return self.cmd(*cmd).stdout
359422

360423
def send_keys(

0 commit comments

Comments
 (0)