def legacy_windows_render(buffer: Iterable[Segment], term: LegacyWindowsTerm) -> None: """Makes appropriate Windows Console API calls based on the segments in the buffer. Args: buffer (Iterable[Segment]): Iterable of Segments to convert to Win32 API calls. term (LegacyWindowsTerm): Used to call the Windows Console API. """ for text, style, control in buffer: if not control: if style: term.write_styled(text, style) else: term.write_text(text) else: control_codes: Sequence[ControlCode] = control for control_code in control_codes: control_type = control_code[0] if control_type == ControlType.CURSOR_MOVE_TO: _, x, y = cast(Tuple[ControlType, int, int], control_code) term.move_cursor_to(WindowsCoordinates(row=y - 1, col=x - 1)) elif control_type == ControlType.CARRIAGE_RETURN: term.write_text("\r") elif control_type == ControlType.HOME: term.move_cursor_to(WindowsCoordinates(0, 0)) elif control_type == ControlType.CURSOR_UP: term.move_cursor_up() elif control_type == ControlType.CURSOR_DOWN: term.move_cursor_down() elif control_type == ControlType.CURSOR_FORWARD: term.move_cursor_forward() elif control_type == ControlType.CURSOR_BACKWARD: term.move_cursor_backward() elif control_type == ControlType.CURSOR_MOVE_TO_COLUMN: _, column = cast(Tuple[ControlType, int], control_code) term.move_cursor_to_column(column - 1) elif control_type == ControlType.HIDE_CURSOR: term.hide_cursor() elif control_type == ControlType.SHOW_CURSOR: term.show_cursor() elif control_type == ControlType.ERASE_IN_LINE: _, mode = cast(Tuple[ControlType, int], control_code) if mode == 0: term.erase_end_of_line() elif mode == 1: term.erase_start_of_line() elif mode == 2: term.erase_line() elif control_type == ControlType.SET_WINDOW_TITLE: _, title = cast(Tuple[ControlType, str], control_code) term.set_title(title)
def test_control_home(legacy_term_mock): buffer = [Segment("", None, [(ControlType.HOME, )])] legacy_windows_render(buffer, legacy_term_mock) legacy_term_mock.move_cursor_to.assert_called_once_with( WindowsCoordinates(0, 0))
def test_control_cursor_move_to(legacy_term_mock): buffer = [Segment("", None, [(ControlType.CURSOR_MOVE_TO, 20, 30)])] legacy_windows_render(buffer, legacy_term_mock) legacy_term_mock.move_cursor_to.assert_called_once_with( WindowsCoordinates(row=29, col=19))
def test_move_cursor_to_out_of_bounds_col(_, SetConsoleCursorPosition, win32_handle): coords = WindowsCoordinates(row=10, col=-4) term = LegacyWindowsTerm(sys.stdout) term.move_cursor_to(coords) assert not SetConsoleCursorPosition.called
def test_move_cursor_forward(_, SetConsoleCursorPosition, win32_handle): term = LegacyWindowsTerm(sys.stdout) term.move_cursor_forward() SetConsoleCursorPosition.assert_called_once_with( win32_handle, coords=WindowsCoordinates(row=CURSOR_Y, col=CURSOR_X + 1))
def test_move_cursor_to(_, SetConsoleCursorPosition, win32_handle): coords = WindowsCoordinates(row=4, col=5) term = LegacyWindowsTerm(sys.stdout) term.move_cursor_to(coords) SetConsoleCursorPosition.assert_called_once_with(win32_handle, coords=coords)
def test_move_cursor_to_column( SetConsoleCursorPosition, win32_console_getters, win32_handle ): term = LegacyWindowsTerm(sys.stdout) term.move_cursor_to_column(5) SetConsoleCursorPosition.assert_called_once_with( win32_handle, coords=WindowsCoordinates(CURSOR_Y, 5) )
def test_move_cursor_forward_newline_wrap(SetConsoleCursorPosition, win32_handle): cursor_at_end_of_line = StubScreenBufferInfo( dwCursorPosition=COORD(SCREEN_WIDTH - 1, CURSOR_Y)) with patch.object( _win32_console, "GetConsoleScreenBufferInfo", return_value=cursor_at_end_of_line, ): term = LegacyWindowsTerm(sys.stdout) term.move_cursor_forward() SetConsoleCursorPosition.assert_called_once_with( win32_handle, coords=WindowsCoordinates(row=CURSOR_Y + 1, col=0))
def test_erase_line(_, FillConsoleOutputAttribute, FillConsoleOutputCharacter, win32_handle): term = LegacyWindowsTerm(sys.stdout) term.erase_line() start = WindowsCoordinates(row=CURSOR_Y, col=0) FillConsoleOutputCharacter.assert_called_once_with(win32_handle, " ", length=SCREEN_WIDTH, start=start) FillConsoleOutputAttribute.assert_called_once_with( win32_handle, DEFAULT_STYLE_ATTRIBUTE, length=SCREEN_WIDTH, start=start)
def test_move_cursor_backward_prev_line_wrap( SetConsoleCursorPosition, win32_console_getters, win32_handle ): cursor_at_start_of_line = StubScreenBufferInfo( dwCursorPosition=COORD(0, CURSOR_Y) ) win32_console_getters[ "GetConsoleScreenBufferInfo" ].return_value = cursor_at_start_of_line term = LegacyWindowsTerm(sys.stdout) term.move_cursor_backward() SetConsoleCursorPosition.assert_called_once_with( win32_handle, coords=WindowsCoordinates(row=CURSOR_Y - 1, col=SCREEN_WIDTH - 1), )
def test_erase_start_of_line( FillConsoleOutputAttribute, FillConsoleOutputCharacter, win32_console_getters, win32_handle, ): term = LegacyWindowsTerm(sys.stdout) term.erase_start_of_line() start = WindowsCoordinates(CURSOR_Y, 0) FillConsoleOutputCharacter.assert_called_once_with( win32_handle, " ", length=CURSOR_X, start=start ) FillConsoleOutputAttribute.assert_called_once_with( win32_handle, DEFAULT_STYLE_ATTRIBUTE, length=CURSOR_X, start=start )
def test_screen_size(_): term = LegacyWindowsTerm(sys.stdout) assert term.screen_size == WindowsCoordinates(row=SCREEN_HEIGHT, col=SCREEN_WIDTH)
def test_cursor_position(_): term = LegacyWindowsTerm(sys.stdout) assert term.cursor_position == WindowsCoordinates(row=CURSOR_Y, col=CURSOR_X)
def test_windows_coordinates_to_ctype(): coord = WindowsCoordinates.from_param(WindowsCoordinates(row=1, col=2)) assert coord.X == 2 assert coord.Y == 1
import dataclasses import sys from unittest import mock from unittest.mock import patch import pytest from rich.style import Style if sys.platform == "win32": from rich import _win32_console from rich._win32_console import COORD, LegacyWindowsTerm, WindowsCoordinates CURSOR_X = 1 CURSOR_Y = 2 CURSOR_POSITION = WindowsCoordinates(row=CURSOR_Y, col=CURSOR_X) SCREEN_WIDTH = 20 SCREEN_HEIGHT = 30 DEFAULT_STYLE_ATTRIBUTE = 16 @dataclasses.dataclass class StubScreenBufferInfo: dwCursorPosition: COORD = COORD(CURSOR_X, CURSOR_Y) dwSize: COORD = COORD(SCREEN_WIDTH, SCREEN_HEIGHT) wAttributes: int = DEFAULT_STYLE_ATTRIBUTE pytestmark = pytest.mark.skipif(sys.platform != "win32", reason="windows only") def test_windows_coordinates_to_ctype(): coord = WindowsCoordinates.from_param(WindowsCoordinates(row=1, col=2))