|
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 |
@@ -420,6 +422,93 @@ def capture_pane( |
420 | 422 | ) |
421 | 423 | return self.cmd(*cmd).stdout |
422 | 424 |
|
| 425 | + def capture_frame( |
| 426 | + self, |
| 427 | + start: t.Literal["-"] | int | None = None, |
| 428 | + end: t.Literal["-"] | int | None = None, |
| 429 | + *, |
| 430 | + content_width: int | None = None, |
| 431 | + content_height: int | None = None, |
| 432 | + overflow_behavior: OverflowBehavior = "truncate", |
| 433 | + ) -> TextFrame: |
| 434 | + """Capture pane content as a TextFrame. |
| 435 | +
|
| 436 | + Combines :meth:`capture_pane` with :class:`~libtmux.textframe.TextFrame` |
| 437 | + for visualization and snapshot testing. |
| 438 | +
|
| 439 | + Parameters |
| 440 | + ---------- |
| 441 | + start : str | int, optional |
| 442 | + Starting line number (same as :meth:`capture_pane`). |
| 443 | + Zero is the first line of the visible pane. |
| 444 | + Positive numbers are lines in the visible pane. |
| 445 | + Negative numbers are lines in the history. |
| 446 | + ``-`` is the start of the history. |
| 447 | + Default: None |
| 448 | + end : str | int, optional |
| 449 | + Ending line number (same as :meth:`capture_pane`). |
| 450 | + Zero is the first line of the visible pane. |
| 451 | + Positive numbers are lines in the visible pane. |
| 452 | + Negative numbers are lines in the history. |
| 453 | + ``-`` is the end of the visible pane. |
| 454 | + Default: None |
| 455 | + content_width : int, optional |
| 456 | + Frame width. Defaults to pane's current width. |
| 457 | + content_height : int, optional |
| 458 | + Frame height. Defaults to pane's current height. |
| 459 | + overflow_behavior : OverflowBehavior, optional |
| 460 | + How to handle content that exceeds frame dimensions. |
| 461 | + Defaults to ``"truncate"`` since pane content may exceed |
| 462 | + nominal dimensions during terminal transitions. |
| 463 | +
|
| 464 | + Returns |
| 465 | + ------- |
| 466 | + :class:`~libtmux.textframe.TextFrame` |
| 467 | + Frame containing captured pane content. |
| 468 | +
|
| 469 | + Examples |
| 470 | + -------- |
| 471 | + >>> pane.send_keys('echo "Hello"', enter=True) |
| 472 | + >>> import time; time.sleep(0.1) |
| 473 | + >>> frame = pane.capture_frame(content_width=20, content_height=5) |
| 474 | + >>> 'Hello' in frame.render() |
| 475 | + True |
| 476 | +
|
| 477 | + >>> print(frame.render()) # doctest: +SKIP |
| 478 | + +--------------------+ |
| 479 | + |$ echo "Hello" | |
| 480 | + |Hello | |
| 481 | + |$ | |
| 482 | + | | |
| 483 | + | | |
| 484 | + +--------------------+ |
| 485 | + """ |
| 486 | + from libtmux.textframe import TextFrame as TextFrameClass |
| 487 | + |
| 488 | + # Capture content |
| 489 | + lines = self.capture_pane(start=start, end=end) |
| 490 | + |
| 491 | + # Use pane dimensions if not specified |
| 492 | + self.refresh() |
| 493 | + width = ( |
| 494 | + content_width if content_width is not None else int(self.pane_width or 80) |
| 495 | + ) |
| 496 | + height = ( |
| 497 | + content_height |
| 498 | + if content_height is not None |
| 499 | + else int(self.pane_height or 24) |
| 500 | + ) |
| 501 | + |
| 502 | + # Create and populate frame |
| 503 | + frame = TextFrameClass( |
| 504 | + content_width=width, |
| 505 | + content_height=height, |
| 506 | + overflow_behavior=overflow_behavior, |
| 507 | + ) |
| 508 | + frame.set_content(lines) |
| 509 | + |
| 510 | + return frame |
| 511 | + |
423 | 512 | def send_keys( |
424 | 513 | self, |
425 | 514 | cmd: str, |
|
0 commit comments