|
31 | 31 | import types |
32 | 32 |
|
33 | 33 | from libtmux._internal.types import StrPath |
| 34 | + from libtmux.textframe import TextFrame |
| 35 | + from libtmux.textframe.core import OverflowBehavior |
34 | 36 |
|
35 | 37 | from .server import Server |
36 | 38 | from .session import Session |
@@ -357,6 +359,93 @@ def capture_pane( |
357 | 359 | cmd.extend(["-E", str(end)]) |
358 | 360 | return self.cmd(*cmd).stdout |
359 | 361 |
|
| 362 | + def capture_frame( |
| 363 | + self, |
| 364 | + start: t.Literal["-"] | int | None = None, |
| 365 | + end: t.Literal["-"] | int | None = None, |
| 366 | + *, |
| 367 | + content_width: int | None = None, |
| 368 | + content_height: int | None = None, |
| 369 | + overflow_behavior: OverflowBehavior = "truncate", |
| 370 | + ) -> TextFrame: |
| 371 | + """Capture pane content as a TextFrame. |
| 372 | +
|
| 373 | + Combines :meth:`capture_pane` with :class:`~libtmux.textframe.TextFrame` |
| 374 | + for visualization and snapshot testing. |
| 375 | +
|
| 376 | + Parameters |
| 377 | + ---------- |
| 378 | + start : str | int, optional |
| 379 | + Starting line number (same as :meth:`capture_pane`). |
| 380 | + Zero is the first line of the visible pane. |
| 381 | + Positive numbers are lines in the visible pane. |
| 382 | + Negative numbers are lines in the history. |
| 383 | + ``-`` is the start of the history. |
| 384 | + Default: None |
| 385 | + end : str | int, optional |
| 386 | + Ending line number (same as :meth:`capture_pane`). |
| 387 | + Zero is the first line of the visible pane. |
| 388 | + Positive numbers are lines in the visible pane. |
| 389 | + Negative numbers are lines in the history. |
| 390 | + ``-`` is the end of the visible pane. |
| 391 | + Default: None |
| 392 | + content_width : int, optional |
| 393 | + Frame width. Defaults to pane's current width. |
| 394 | + content_height : int, optional |
| 395 | + Frame height. Defaults to pane's current height. |
| 396 | + overflow_behavior : OverflowBehavior, optional |
| 397 | + How to handle content that exceeds frame dimensions. |
| 398 | + Defaults to ``"truncate"`` since pane content may exceed |
| 399 | + nominal dimensions during terminal transitions. |
| 400 | +
|
| 401 | + Returns |
| 402 | + ------- |
| 403 | + :class:`~libtmux.textframe.TextFrame` |
| 404 | + Frame containing captured pane content. |
| 405 | +
|
| 406 | + Examples |
| 407 | + -------- |
| 408 | + >>> pane.send_keys('echo "Hello"', enter=True) |
| 409 | + >>> import time; time.sleep(0.1) |
| 410 | + >>> frame = pane.capture_frame(content_width=20, content_height=5) |
| 411 | + >>> 'Hello' in frame.render() |
| 412 | + True |
| 413 | +
|
| 414 | + >>> print(frame.render()) # doctest: +SKIP |
| 415 | + +--------------------+ |
| 416 | + |$ echo "Hello" | |
| 417 | + |Hello | |
| 418 | + |$ | |
| 419 | + | | |
| 420 | + | | |
| 421 | + +--------------------+ |
| 422 | + """ |
| 423 | + from libtmux.textframe import TextFrame as TextFrameClass |
| 424 | + |
| 425 | + # Capture content |
| 426 | + lines = self.capture_pane(start=start, end=end) |
| 427 | + |
| 428 | + # Use pane dimensions if not specified |
| 429 | + self.refresh() |
| 430 | + width = ( |
| 431 | + content_width if content_width is not None else int(self.pane_width or 80) |
| 432 | + ) |
| 433 | + height = ( |
| 434 | + content_height |
| 435 | + if content_height is not None |
| 436 | + else int(self.pane_height or 24) |
| 437 | + ) |
| 438 | + |
| 439 | + # Create and populate frame |
| 440 | + frame = TextFrameClass( |
| 441 | + content_width=width, |
| 442 | + content_height=height, |
| 443 | + overflow_behavior=overflow_behavior, |
| 444 | + ) |
| 445 | + frame.set_content(lines) |
| 446 | + |
| 447 | + return frame |
| 448 | + |
360 | 449 | def send_keys( |
361 | 450 | self, |
362 | 451 | cmd: str, |
|
0 commit comments