pytermgui.context_managers
Ease-of-use context-manager classes & functions.
There isn't much (or any) additional functionality provided in this module,
most things are nicer-packaged combinations to already available methods from
pytermgui.ansi_interface
.
1""" 2Ease-of-use context-manager classes & functions. 3 4There isn't much (or any) additional functionality provided in this module, 5most things are nicer-packaged combinations to already available methods from 6`pytermgui.ansi_interface`. 7""" 8 9from __future__ import annotations 10 11from os import name 12from contextlib import contextmanager 13from typing import Callable, Generator, Any, Union, List 14 15from .ansi_interface import ( 16 save_cursor, 17 restore_cursor, 18 print_to, 19 show_cursor, 20 hide_cursor, 21 set_echo, 22 unset_echo, 23 set_alt_buffer, 24 unset_alt_buffer, 25 cursor_up, 26 report_mouse, 27 translate_mouse, 28 MouseEvent, 29) 30 31from .terminal import get_terminal 32 33# This is technically meant to be here, but it has to be in `input.py` due 34# to some package structure issues. 35from .input import timeout # pylint: disable=unused-import 36 37# TODO: Move this absolute beast to a types submodule 38MouseTranslator = Callable[[str], Union[List[Union[MouseEvent, None]], None]] 39 40 41@contextmanager 42def cursor_at(pos: tuple[int, int]) -> Generator[Callable[..., None], None, None]: 43 """Gets callable to print at `pos`, incrementing `y` on every print. 44 45 Args: 46 pos: The position to start printing at. Follows the order (columns, rows). 47 48 Yields: 49 A callable printing function. This function forwards all arguments to `print`, 50 but positions the cursor before doing so. After every call, the y position is 51 incremented. 52 """ 53 54 offset = 0 55 posx, posy = pos 56 57 def printer(*args: tuple[Any, ...]) -> None: 58 """Print to posx, current y""" 59 60 nonlocal offset 61 62 print_to((posx, posy + offset), *args) 63 offset += 1 64 65 try: 66 save_cursor() 67 yield printer 68 69 finally: 70 restore_cursor() 71 72 73@contextmanager 74def alt_buffer(echo: bool = False, cursor: bool = True) -> Generator[None, None, None]: 75 """Creates non-scrollable alt-buffer. 76 77 This is useful for retrieving original terminal state after program end. 78 79 Args: 80 echo: Whether `unset_echo` should be called on startup. 81 cursor: Whether `hide_cursor` should be called on startup. 82 """ 83 84 terminal = get_terminal() 85 86 try: 87 set_alt_buffer() 88 89 if not echo and name == "posix" and not terminal.is_interactive(): 90 unset_echo() 91 92 if not cursor: 93 hide_cursor() 94 95 yield 96 97 finally: 98 unset_alt_buffer() 99 100 if not echo and name == "posix" and not terminal.is_interactive(): 101 set_echo() 102 cursor_up() 103 104 if not cursor: 105 show_cursor() 106 cursor_up() 107 108 109@contextmanager 110def mouse_handler( 111 events: list[str], method: str = "decimal_xterm" 112) -> Generator[MouseTranslator | None, None, None]: 113 """Return a mouse handler function 114 115 See `help(report_mouse)` for help about all of the methods. 116 117 Args: 118 events: A list of `pytermgui.ansi_interface.report_mouse` events. 119 method: The method to use for reporting. Only `decimal_urxvt` and 120 `decimal_xterm` are currently supported. 121 122 Example use: 123 124 ```python3 125 import pytermgui as ptg 126 127 with ptg.mouse_handler(["press", "hover"]) as mouse: 128 while True: 129 event = mouse(ptg.getch()) 130 print(type(event)) 131 print(event.action) 132 print(event.position) 133 134 'pytermgui.ansi_interface.MouseEvent' 135 'pytermgui.ansi_interface.MouseAction.LEFT_CLICK' 136 (33, 55) 137 ``` 138 139 """ 140 141 event = None 142 try: 143 for event in events: 144 report_mouse(event, method=method) 145 146 yield lambda code: translate_mouse(code, method=method) 147 148 finally: 149 if event is not None: 150 report_mouse(event, method=method, stop=True)
@contextmanager
def
cursor_at( pos: tuple[int, int]) -> Generator[Callable[..., NoneType], NoneType, NoneType]:
42@contextmanager 43def cursor_at(pos: tuple[int, int]) -> Generator[Callable[..., None], None, None]: 44 """Gets callable to print at `pos`, incrementing `y` on every print. 45 46 Args: 47 pos: The position to start printing at. Follows the order (columns, rows). 48 49 Yields: 50 A callable printing function. This function forwards all arguments to `print`, 51 but positions the cursor before doing so. After every call, the y position is 52 incremented. 53 """ 54 55 offset = 0 56 posx, posy = pos 57 58 def printer(*args: tuple[Any, ...]) -> None: 59 """Print to posx, current y""" 60 61 nonlocal offset 62 63 print_to((posx, posy + offset), *args) 64 offset += 1 65 66 try: 67 save_cursor() 68 yield printer 69 70 finally: 71 restore_cursor()
Gets callable to print at pos
, incrementing y
on every print.
Args
- pos: The position to start printing at. Follows the order (columns, rows).
Yields
A callable printing function. This function forwards all arguments to
@contextmanager
def
alt_buffer( echo: bool = False, cursor: bool = True) -> Generator[NoneType, NoneType, NoneType]:
74@contextmanager 75def alt_buffer(echo: bool = False, cursor: bool = True) -> Generator[None, None, None]: 76 """Creates non-scrollable alt-buffer. 77 78 This is useful for retrieving original terminal state after program end. 79 80 Args: 81 echo: Whether `unset_echo` should be called on startup. 82 cursor: Whether `hide_cursor` should be called on startup. 83 """ 84 85 terminal = get_terminal() 86 87 try: 88 set_alt_buffer() 89 90 if not echo and name == "posix" and not terminal.is_interactive(): 91 unset_echo() 92 93 if not cursor: 94 hide_cursor() 95 96 yield 97 98 finally: 99 unset_alt_buffer() 100 101 if not echo and name == "posix" and not terminal.is_interactive(): 102 set_echo() 103 cursor_up() 104 105 if not cursor: 106 show_cursor() 107 cursor_up()
Creates non-scrollable alt-buffer.
This is useful for retrieving original terminal state after program end.
Args
- echo: Whether
unset_echo
should be called on startup. - cursor: Whether
hide_cursor
should be called on startup.
@contextmanager
def
mouse_handler( events: list[str], method: str = 'decimal_xterm') -> Generator[Optional[Callable[[str], Optional[List[Optional[pytermgui.ansi_interface.MouseEvent]]]]], NoneType, NoneType]:
110@contextmanager 111def mouse_handler( 112 events: list[str], method: str = "decimal_xterm" 113) -> Generator[MouseTranslator | None, None, None]: 114 """Return a mouse handler function 115 116 See `help(report_mouse)` for help about all of the methods. 117 118 Args: 119 events: A list of `pytermgui.ansi_interface.report_mouse` events. 120 method: The method to use for reporting. Only `decimal_urxvt` and 121 `decimal_xterm` are currently supported. 122 123 Example use: 124 125 ```python3 126 import pytermgui as ptg 127 128 with ptg.mouse_handler(["press", "hover"]) as mouse: 129 while True: 130 event = mouse(ptg.getch()) 131 print(type(event)) 132 print(event.action) 133 print(event.position) 134 135 'pytermgui.ansi_interface.MouseEvent' 136 'pytermgui.ansi_interface.MouseAction.LEFT_CLICK' 137 (33, 55) 138 ``` 139 140 """ 141 142 event = None 143 try: 144 for event in events: 145 report_mouse(event, method=method) 146 147 yield lambda code: translate_mouse(code, method=method) 148 149 finally: 150 if event is not None: 151 report_mouse(event, method=method, stop=True)
Return a mouse handler function
See help(report_mouse)
for help about all of the methods.
Args
- events: A list of
pytermgui.ansi_interface.report_mouse
events. - method: The method to use for reporting. Only
decimal_urxvt
anddecimal_xterm
are currently supported.
Example use:
import pytermgui as ptg
with ptg.mouse_handler(["press", "hover"]) as mouse:
while True:
event = mouse(ptg.getch())
print(type(event))
print(event.action)
print(event.position)
'pytermgui.ansi_interface.MouseEvent'
'pytermgui.ansi_interface.MouseAction.LEFT_CLICK'
(33, 55)