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