diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/prompt-toolkit/py3/prompt_toolkit/layout/screen.py | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/layout/screen.py')
-rw-r--r-- | contrib/python/prompt-toolkit/py3/prompt_toolkit/layout/screen.py | 654 |
1 files changed, 327 insertions, 327 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/layout/screen.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/layout/screen.py index aad253e8ad..deb2f43222 100644 --- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/layout/screen.py +++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/layout/screen.py @@ -1,327 +1,327 @@ -from collections import defaultdict -from typing import TYPE_CHECKING, Callable, DefaultDict, Dict, List, Optional, Tuple - -from prompt_toolkit.cache import FastDictCache -from prompt_toolkit.data_structures import Point -from prompt_toolkit.utils import get_cwidth - -if TYPE_CHECKING: - from .containers import Window - - -__all__ = [ - "Screen", - "Char", -] - - -class Char: - """ - Represent a single character in a :class:`.Screen`. - - This should be considered immutable. - - :param char: A single character (can be a double-width character). - :param style: A style string. (Can contain classnames.) - """ - - __slots__ = ("char", "style", "width") - - # If we end up having one of these special control sequences in the input string, - # we should display them as follows: - # Usually this happens after a "quoted insert". - display_mappings: Dict[str, str] = { - "\x00": "^@", # Control space - "\x01": "^A", - "\x02": "^B", - "\x03": "^C", - "\x04": "^D", - "\x05": "^E", - "\x06": "^F", - "\x07": "^G", - "\x08": "^H", - "\x09": "^I", - "\x0a": "^J", - "\x0b": "^K", - "\x0c": "^L", - "\x0d": "^M", - "\x0e": "^N", - "\x0f": "^O", - "\x10": "^P", - "\x11": "^Q", - "\x12": "^R", - "\x13": "^S", - "\x14": "^T", - "\x15": "^U", - "\x16": "^V", - "\x17": "^W", - "\x18": "^X", - "\x19": "^Y", - "\x1a": "^Z", - "\x1b": "^[", # Escape - "\x1c": "^\\", - "\x1d": "^]", - "\x1f": "^_", - "\x7f": "^?", # ASCII Delete (backspace). - # Special characters. All visualized like Vim does. - "\x80": "<80>", - "\x81": "<81>", - "\x82": "<82>", - "\x83": "<83>", - "\x84": "<84>", - "\x85": "<85>", - "\x86": "<86>", - "\x87": "<87>", - "\x88": "<88>", - "\x89": "<89>", - "\x8a": "<8a>", - "\x8b": "<8b>", - "\x8c": "<8c>", - "\x8d": "<8d>", - "\x8e": "<8e>", - "\x8f": "<8f>", - "\x90": "<90>", - "\x91": "<91>", - "\x92": "<92>", - "\x93": "<93>", - "\x94": "<94>", - "\x95": "<95>", - "\x96": "<96>", - "\x97": "<97>", - "\x98": "<98>", - "\x99": "<99>", - "\x9a": "<9a>", - "\x9b": "<9b>", - "\x9c": "<9c>", - "\x9d": "<9d>", - "\x9e": "<9e>", - "\x9f": "<9f>", - # For the non-breaking space: visualize like Emacs does by default. - # (Print a space, but attach the 'nbsp' class that applies the - # underline style.) - "\xa0": " ", - } - - def __init__(self, char: str = " ", style: str = "") -> None: - # If this character has to be displayed otherwise, take that one. - if char in self.display_mappings: - if char == "\xa0": - style += " class:nbsp " # Will be underlined. - else: - style += " class:control-character " - - char = self.display_mappings[char] - - self.char = char - self.style = style - - # Calculate width. (We always need this, so better to store it directly - # as a member for performance.) - self.width = get_cwidth(char) - - # In theory, `other` can be any type of object, but because of performance - # we don't want to do an `isinstance` check every time. We assume "other" - # is always a "Char". - def _equal(self, other: "Char") -> bool: - return self.char == other.char and self.style == other.style - - def _not_equal(self, other: "Char") -> bool: - # Not equal: We don't do `not char.__eq__` here, because of the - # performance of calling yet another function. - return self.char != other.char or self.style != other.style - - if not TYPE_CHECKING: - __eq__ = _equal - __ne__ = _not_equal - - def __repr__(self) -> str: - return "%s(%r, %r)" % (self.__class__.__name__, self.char, self.style) - - -_CHAR_CACHE: FastDictCache[Tuple[str, str], Char] = FastDictCache( - Char, size=1000 * 1000 -) -Transparent = "[transparent]" - - -class Screen: - """ - Two dimensional buffer of :class:`.Char` instances. - """ - - def __init__( - self, - default_char: Optional[Char] = None, - initial_width: int = 0, - initial_height: int = 0, - ) -> None: - - if default_char is None: - default_char2 = _CHAR_CACHE[" ", Transparent] - else: - default_char2 = default_char - - self.data_buffer: DefaultDict[int, DefaultDict[int, Char]] = defaultdict( - lambda: defaultdict(lambda: default_char2) - ) - - #: Escape sequences to be injected. - self.zero_width_escapes: DefaultDict[int, DefaultDict[int, str]] = defaultdict( - lambda: defaultdict(lambda: "") - ) - - #: Position of the cursor. - self.cursor_positions: Dict[ - "Window", Point - ] = {} # Map `Window` objects to `Point` objects. - - #: Visibility of the cursor. - self.show_cursor = True - - #: (Optional) Where to position the menu. E.g. at the start of a completion. - #: (We can't use the cursor position, because we don't want the - #: completion menu to change its position when we browse through all the - #: completions.) - self.menu_positions: Dict[ - "Window", Point - ] = {} # Map `Window` objects to `Point` objects. - - #: Currently used width/height of the screen. This will increase when - #: data is written to the screen. - self.width = initial_width or 0 - self.height = initial_height or 0 - - # Windows that have been drawn. (Each `Window` class will add itself to - # this list.) - self.visible_windows_to_write_positions: Dict["Window", "WritePosition"] = {} - - # List of (z_index, draw_func) - self._draw_float_functions: List[Tuple[int, Callable[[], None]]] = [] - - @property - def visible_windows(self) -> List["Window"]: - return list(self.visible_windows_to_write_positions.keys()) - - def set_cursor_position(self, window: "Window", position: Point) -> None: - """ - Set the cursor position for a given window. - """ - self.cursor_positions[window] = position - - def set_menu_position(self, window: "Window", position: Point) -> None: - """ - Set the cursor position for a given window. - """ - self.menu_positions[window] = position - - def get_cursor_position(self, window: "Window") -> Point: - """ - Get the cursor position for a given window. - Returns a `Point`. - """ - try: - return self.cursor_positions[window] - except KeyError: - return Point(x=0, y=0) - - def get_menu_position(self, window: "Window") -> Point: - """ - Get the menu position for a given window. - (This falls back to the cursor position if no menu position was set.) - """ - try: - return self.menu_positions[window] - except KeyError: - try: - return self.cursor_positions[window] - except KeyError: - return Point(x=0, y=0) - - def draw_with_z_index(self, z_index: int, draw_func: Callable[[], None]) -> None: - """ - Add a draw-function for a `Window` which has a >= 0 z_index. - This will be postponed until `draw_all_floats` is called. - """ - self._draw_float_functions.append((z_index, draw_func)) - - def draw_all_floats(self) -> None: - """ - Draw all float functions in order of z-index. - """ - # We keep looping because some draw functions could add new functions - # to this list. See `FloatContainer`. - while self._draw_float_functions: - # Sort the floats that we have so far by z_index. - functions = sorted(self._draw_float_functions, key=lambda item: item[0]) - - # Draw only one at a time, then sort everything again. Now floats - # might have been added. - self._draw_float_functions = functions[1:] - functions[0][1]() - - def append_style_to_content(self, style_str: str) -> None: - """ - For all the characters in the screen. - Set the style string to the given `style_str`. - """ - b = self.data_buffer - char_cache = _CHAR_CACHE - - append_style = " " + style_str - - for y, row in b.items(): - for x, char in row.items(): - b[y][x] = char_cache[char.char, char.style + append_style] - - def fill_area( - self, write_position: "WritePosition", style: str = "", after: bool = False - ) -> None: - """ - Fill the content of this area, using the given `style`. - The style is prepended before whatever was here before. - """ - if not style.strip(): - return - - xmin = write_position.xpos - xmax = write_position.xpos + write_position.width - char_cache = _CHAR_CACHE - data_buffer = self.data_buffer - - if after: - append_style = " " + style - prepend_style = "" - else: - append_style = "" - prepend_style = style + " " - - for y in range( - write_position.ypos, write_position.ypos + write_position.height - ): - row = data_buffer[y] - for x in range(xmin, xmax): - cell = row[x] - row[x] = char_cache[ - cell.char, prepend_style + cell.style + append_style - ] - - -class WritePosition: - def __init__(self, xpos: int, ypos: int, width: int, height: int) -> None: - assert height >= 0 - assert width >= 0 - # xpos and ypos can be negative. (A float can be partially visible.) - - self.xpos = xpos - self.ypos = ypos - self.width = width - self.height = height - - def __repr__(self) -> str: - return "%s(x=%r, y=%r, width=%r, height=%r)" % ( - self.__class__.__name__, - self.xpos, - self.ypos, - self.width, - self.height, - ) +from collections import defaultdict +from typing import TYPE_CHECKING, Callable, DefaultDict, Dict, List, Optional, Tuple + +from prompt_toolkit.cache import FastDictCache +from prompt_toolkit.data_structures import Point +from prompt_toolkit.utils import get_cwidth + +if TYPE_CHECKING: + from .containers import Window + + +__all__ = [ + "Screen", + "Char", +] + + +class Char: + """ + Represent a single character in a :class:`.Screen`. + + This should be considered immutable. + + :param char: A single character (can be a double-width character). + :param style: A style string. (Can contain classnames.) + """ + + __slots__ = ("char", "style", "width") + + # If we end up having one of these special control sequences in the input string, + # we should display them as follows: + # Usually this happens after a "quoted insert". + display_mappings: Dict[str, str] = { + "\x00": "^@", # Control space + "\x01": "^A", + "\x02": "^B", + "\x03": "^C", + "\x04": "^D", + "\x05": "^E", + "\x06": "^F", + "\x07": "^G", + "\x08": "^H", + "\x09": "^I", + "\x0a": "^J", + "\x0b": "^K", + "\x0c": "^L", + "\x0d": "^M", + "\x0e": "^N", + "\x0f": "^O", + "\x10": "^P", + "\x11": "^Q", + "\x12": "^R", + "\x13": "^S", + "\x14": "^T", + "\x15": "^U", + "\x16": "^V", + "\x17": "^W", + "\x18": "^X", + "\x19": "^Y", + "\x1a": "^Z", + "\x1b": "^[", # Escape + "\x1c": "^\\", + "\x1d": "^]", + "\x1f": "^_", + "\x7f": "^?", # ASCII Delete (backspace). + # Special characters. All visualized like Vim does. + "\x80": "<80>", + "\x81": "<81>", + "\x82": "<82>", + "\x83": "<83>", + "\x84": "<84>", + "\x85": "<85>", + "\x86": "<86>", + "\x87": "<87>", + "\x88": "<88>", + "\x89": "<89>", + "\x8a": "<8a>", + "\x8b": "<8b>", + "\x8c": "<8c>", + "\x8d": "<8d>", + "\x8e": "<8e>", + "\x8f": "<8f>", + "\x90": "<90>", + "\x91": "<91>", + "\x92": "<92>", + "\x93": "<93>", + "\x94": "<94>", + "\x95": "<95>", + "\x96": "<96>", + "\x97": "<97>", + "\x98": "<98>", + "\x99": "<99>", + "\x9a": "<9a>", + "\x9b": "<9b>", + "\x9c": "<9c>", + "\x9d": "<9d>", + "\x9e": "<9e>", + "\x9f": "<9f>", + # For the non-breaking space: visualize like Emacs does by default. + # (Print a space, but attach the 'nbsp' class that applies the + # underline style.) + "\xa0": " ", + } + + def __init__(self, char: str = " ", style: str = "") -> None: + # If this character has to be displayed otherwise, take that one. + if char in self.display_mappings: + if char == "\xa0": + style += " class:nbsp " # Will be underlined. + else: + style += " class:control-character " + + char = self.display_mappings[char] + + self.char = char + self.style = style + + # Calculate width. (We always need this, so better to store it directly + # as a member for performance.) + self.width = get_cwidth(char) + + # In theory, `other` can be any type of object, but because of performance + # we don't want to do an `isinstance` check every time. We assume "other" + # is always a "Char". + def _equal(self, other: "Char") -> bool: + return self.char == other.char and self.style == other.style + + def _not_equal(self, other: "Char") -> bool: + # Not equal: We don't do `not char.__eq__` here, because of the + # performance of calling yet another function. + return self.char != other.char or self.style != other.style + + if not TYPE_CHECKING: + __eq__ = _equal + __ne__ = _not_equal + + def __repr__(self) -> str: + return "%s(%r, %r)" % (self.__class__.__name__, self.char, self.style) + + +_CHAR_CACHE: FastDictCache[Tuple[str, str], Char] = FastDictCache( + Char, size=1000 * 1000 +) +Transparent = "[transparent]" + + +class Screen: + """ + Two dimensional buffer of :class:`.Char` instances. + """ + + def __init__( + self, + default_char: Optional[Char] = None, + initial_width: int = 0, + initial_height: int = 0, + ) -> None: + + if default_char is None: + default_char2 = _CHAR_CACHE[" ", Transparent] + else: + default_char2 = default_char + + self.data_buffer: DefaultDict[int, DefaultDict[int, Char]] = defaultdict( + lambda: defaultdict(lambda: default_char2) + ) + + #: Escape sequences to be injected. + self.zero_width_escapes: DefaultDict[int, DefaultDict[int, str]] = defaultdict( + lambda: defaultdict(lambda: "") + ) + + #: Position of the cursor. + self.cursor_positions: Dict[ + "Window", Point + ] = {} # Map `Window` objects to `Point` objects. + + #: Visibility of the cursor. + self.show_cursor = True + + #: (Optional) Where to position the menu. E.g. at the start of a completion. + #: (We can't use the cursor position, because we don't want the + #: completion menu to change its position when we browse through all the + #: completions.) + self.menu_positions: Dict[ + "Window", Point + ] = {} # Map `Window` objects to `Point` objects. + + #: Currently used width/height of the screen. This will increase when + #: data is written to the screen. + self.width = initial_width or 0 + self.height = initial_height or 0 + + # Windows that have been drawn. (Each `Window` class will add itself to + # this list.) + self.visible_windows_to_write_positions: Dict["Window", "WritePosition"] = {} + + # List of (z_index, draw_func) + self._draw_float_functions: List[Tuple[int, Callable[[], None]]] = [] + + @property + def visible_windows(self) -> List["Window"]: + return list(self.visible_windows_to_write_positions.keys()) + + def set_cursor_position(self, window: "Window", position: Point) -> None: + """ + Set the cursor position for a given window. + """ + self.cursor_positions[window] = position + + def set_menu_position(self, window: "Window", position: Point) -> None: + """ + Set the cursor position for a given window. + """ + self.menu_positions[window] = position + + def get_cursor_position(self, window: "Window") -> Point: + """ + Get the cursor position for a given window. + Returns a `Point`. + """ + try: + return self.cursor_positions[window] + except KeyError: + return Point(x=0, y=0) + + def get_menu_position(self, window: "Window") -> Point: + """ + Get the menu position for a given window. + (This falls back to the cursor position if no menu position was set.) + """ + try: + return self.menu_positions[window] + except KeyError: + try: + return self.cursor_positions[window] + except KeyError: + return Point(x=0, y=0) + + def draw_with_z_index(self, z_index: int, draw_func: Callable[[], None]) -> None: + """ + Add a draw-function for a `Window` which has a >= 0 z_index. + This will be postponed until `draw_all_floats` is called. + """ + self._draw_float_functions.append((z_index, draw_func)) + + def draw_all_floats(self) -> None: + """ + Draw all float functions in order of z-index. + """ + # We keep looping because some draw functions could add new functions + # to this list. See `FloatContainer`. + while self._draw_float_functions: + # Sort the floats that we have so far by z_index. + functions = sorted(self._draw_float_functions, key=lambda item: item[0]) + + # Draw only one at a time, then sort everything again. Now floats + # might have been added. + self._draw_float_functions = functions[1:] + functions[0][1]() + + def append_style_to_content(self, style_str: str) -> None: + """ + For all the characters in the screen. + Set the style string to the given `style_str`. + """ + b = self.data_buffer + char_cache = _CHAR_CACHE + + append_style = " " + style_str + + for y, row in b.items(): + for x, char in row.items(): + b[y][x] = char_cache[char.char, char.style + append_style] + + def fill_area( + self, write_position: "WritePosition", style: str = "", after: bool = False + ) -> None: + """ + Fill the content of this area, using the given `style`. + The style is prepended before whatever was here before. + """ + if not style.strip(): + return + + xmin = write_position.xpos + xmax = write_position.xpos + write_position.width + char_cache = _CHAR_CACHE + data_buffer = self.data_buffer + + if after: + append_style = " " + style + prepend_style = "" + else: + append_style = "" + prepend_style = style + " " + + for y in range( + write_position.ypos, write_position.ypos + write_position.height + ): + row = data_buffer[y] + for x in range(xmin, xmax): + cell = row[x] + row[x] = char_cache[ + cell.char, prepend_style + cell.style + append_style + ] + + +class WritePosition: + def __init__(self, xpos: int, ypos: int, width: int, height: int) -> None: + assert height >= 0 + assert width >= 0 + # xpos and ypos can be negative. (A float can be partially visible.) + + self.xpos = xpos + self.ypos = ypos + self.width = width + self.height = height + + def __repr__(self) -> str: + return "%s(x=%r, y=%r, width=%r, height=%r)" % ( + self.__class__.__name__, + self.xpos, + self.ypos, + self.width, + self.height, + ) |