summaryrefslogtreecommitdiffstats
path: root/contrib/python/prompt-toolkit/py3/prompt_toolkit/output
diff options
context:
space:
mode:
authorshadchin <[email protected]>2022-02-10 16:44:39 +0300
committerDaniil Cherednik <[email protected]>2022-02-10 16:44:39 +0300
commite9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch)
tree64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/prompt-toolkit/py3/prompt_toolkit/output
parent2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff)
Restoring authorship annotation for <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/output')
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/__init__.py26
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/base.py628
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/color_depth.py116
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/conemu.py118
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py152
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/vt100.py1440
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/win32.py1354
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/windows10.py208
8 files changed, 2021 insertions, 2021 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/__init__.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/__init__.py
index ccfebf6ac43..7b90b476bd3 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/__init__.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/__init__.py
@@ -1,13 +1,13 @@
-from .base import DummyOutput, Output
-from .color_depth import ColorDepth
-from .defaults import create_output
-
-__all__ = [
- # Base.
- "Output",
- "DummyOutput",
- # Color depth.
- "ColorDepth",
- # Defaults.
- "create_output",
-]
+from .base import DummyOutput, Output
+from .color_depth import ColorDepth
+from .defaults import create_output
+
+__all__ = [
+ # Base.
+ "Output",
+ "DummyOutput",
+ # Color depth.
+ "ColorDepth",
+ # Defaults.
+ "create_output",
+]
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/base.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/base.py
index ee2c42457e1..c78677bc8b2 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/base.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/base.py
@@ -1,146 +1,146 @@
-"""
-Interface for an output.
-"""
-from abc import ABCMeta, abstractmethod
-from typing import Optional, TextIO
-
+"""
+Interface for an output.
+"""
+from abc import ABCMeta, abstractmethod
+from typing import Optional, TextIO
+
from prompt_toolkit.cursor_shapes import CursorShape
-from prompt_toolkit.data_structures import Size
-from prompt_toolkit.styles import Attrs
-
-from .color_depth import ColorDepth
-
-__all__ = [
- "Output",
- "DummyOutput",
-]
-
-
-class Output(metaclass=ABCMeta):
- """
- Base class defining the output interface for a
- :class:`~prompt_toolkit.renderer.Renderer`.
-
- Actual implementations are
- :class:`~prompt_toolkit.output.vt100.Vt100_Output` and
- :class:`~prompt_toolkit.output.win32.Win32Output`.
- """
-
- stdout: Optional[TextIO] = None
-
- @abstractmethod
- def fileno(self) -> int:
- "Return the file descriptor to which we can write for the output."
-
- @abstractmethod
- def encoding(self) -> str:
- """
- Return the encoding for this output, e.g. 'utf-8'.
- (This is used mainly to know which characters are supported by the
- output the data, so that the UI can provide alternatives, when
- required.)
- """
-
- @abstractmethod
- def write(self, data: str) -> None:
- "Write text (Terminal escape sequences will be removed/escaped.)"
-
- @abstractmethod
- def write_raw(self, data: str) -> None:
- "Write text."
-
- @abstractmethod
- def set_title(self, title: str) -> None:
- "Set terminal title."
-
- @abstractmethod
- def clear_title(self) -> None:
- "Clear title again. (or restore previous title.)"
-
- @abstractmethod
- def flush(self) -> None:
- "Write to output stream and flush."
-
- @abstractmethod
- def erase_screen(self) -> None:
- """
- Erases the screen with the background colour and moves the cursor to
- home.
- """
-
- @abstractmethod
- def enter_alternate_screen(self) -> None:
- "Go to the alternate screen buffer. (For full screen applications)."
-
- @abstractmethod
- def quit_alternate_screen(self) -> None:
- "Leave the alternate screen buffer."
-
- @abstractmethod
- def enable_mouse_support(self) -> None:
- "Enable mouse."
-
- @abstractmethod
- def disable_mouse_support(self) -> None:
- "Disable mouse."
-
- @abstractmethod
- def erase_end_of_line(self) -> None:
- """
- Erases from the current cursor position to the end of the current line.
- """
-
- @abstractmethod
- def erase_down(self) -> None:
- """
- Erases the screen from the current line down to the bottom of the
- screen.
- """
-
- @abstractmethod
- def reset_attributes(self) -> None:
- "Reset color and styling attributes."
-
- @abstractmethod
- def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
- "Set new color and styling attributes."
-
- @abstractmethod
- def disable_autowrap(self) -> None:
- "Disable auto line wrapping."
-
- @abstractmethod
- def enable_autowrap(self) -> None:
- "Enable auto line wrapping."
-
- @abstractmethod
- def cursor_goto(self, row: int = 0, column: int = 0) -> None:
- "Move cursor position."
-
- @abstractmethod
- def cursor_up(self, amount: int) -> None:
- "Move cursor `amount` place up."
-
- @abstractmethod
- def cursor_down(self, amount: int) -> None:
- "Move cursor `amount` place down."
-
- @abstractmethod
- def cursor_forward(self, amount: int) -> None:
- "Move cursor `amount` place forward."
-
- @abstractmethod
- def cursor_backward(self, amount: int) -> None:
- "Move cursor `amount` place backward."
-
- @abstractmethod
- def hide_cursor(self) -> None:
- "Hide cursor."
-
- @abstractmethod
- def show_cursor(self) -> None:
- "Show cursor."
-
+from prompt_toolkit.data_structures import Size
+from prompt_toolkit.styles import Attrs
+
+from .color_depth import ColorDepth
+
+__all__ = [
+ "Output",
+ "DummyOutput",
+]
+
+
+class Output(metaclass=ABCMeta):
+ """
+ Base class defining the output interface for a
+ :class:`~prompt_toolkit.renderer.Renderer`.
+
+ Actual implementations are
+ :class:`~prompt_toolkit.output.vt100.Vt100_Output` and
+ :class:`~prompt_toolkit.output.win32.Win32Output`.
+ """
+
+ stdout: Optional[TextIO] = None
+
+ @abstractmethod
+ def fileno(self) -> int:
+ "Return the file descriptor to which we can write for the output."
+
+ @abstractmethod
+ def encoding(self) -> str:
+ """
+ Return the encoding for this output, e.g. 'utf-8'.
+ (This is used mainly to know which characters are supported by the
+ output the data, so that the UI can provide alternatives, when
+ required.)
+ """
+
+ @abstractmethod
+ def write(self, data: str) -> None:
+ "Write text (Terminal escape sequences will be removed/escaped.)"
+
+ @abstractmethod
+ def write_raw(self, data: str) -> None:
+ "Write text."
+
+ @abstractmethod
+ def set_title(self, title: str) -> None:
+ "Set terminal title."
+
+ @abstractmethod
+ def clear_title(self) -> None:
+ "Clear title again. (or restore previous title.)"
+
+ @abstractmethod
+ def flush(self) -> None:
+ "Write to output stream and flush."
+
+ @abstractmethod
+ def erase_screen(self) -> None:
+ """
+ Erases the screen with the background colour and moves the cursor to
+ home.
+ """
+
+ @abstractmethod
+ def enter_alternate_screen(self) -> None:
+ "Go to the alternate screen buffer. (For full screen applications)."
+
+ @abstractmethod
+ def quit_alternate_screen(self) -> None:
+ "Leave the alternate screen buffer."
+
+ @abstractmethod
+ def enable_mouse_support(self) -> None:
+ "Enable mouse."
+
+ @abstractmethod
+ def disable_mouse_support(self) -> None:
+ "Disable mouse."
+
+ @abstractmethod
+ def erase_end_of_line(self) -> None:
+ """
+ Erases from the current cursor position to the end of the current line.
+ """
+
+ @abstractmethod
+ def erase_down(self) -> None:
+ """
+ Erases the screen from the current line down to the bottom of the
+ screen.
+ """
+
+ @abstractmethod
+ def reset_attributes(self) -> None:
+ "Reset color and styling attributes."
+
+ @abstractmethod
+ def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
+ "Set new color and styling attributes."
+
+ @abstractmethod
+ def disable_autowrap(self) -> None:
+ "Disable auto line wrapping."
+
+ @abstractmethod
+ def enable_autowrap(self) -> None:
+ "Enable auto line wrapping."
+
+ @abstractmethod
+ def cursor_goto(self, row: int = 0, column: int = 0) -> None:
+ "Move cursor position."
+
+ @abstractmethod
+ def cursor_up(self, amount: int) -> None:
+ "Move cursor `amount` place up."
+
+ @abstractmethod
+ def cursor_down(self, amount: int) -> None:
+ "Move cursor `amount` place down."
+
+ @abstractmethod
+ def cursor_forward(self, amount: int) -> None:
+ "Move cursor `amount` place forward."
+
+ @abstractmethod
+ def cursor_backward(self, amount: int) -> None:
+ "Move cursor `amount` place backward."
+
+ @abstractmethod
+ def hide_cursor(self) -> None:
+ "Hide cursor."
+
+ @abstractmethod
+ def show_cursor(self) -> None:
+ "Show cursor."
+
@abstractmethod
def set_cursor_shape(self, cursor_shape: CursorShape) -> None:
"Set cursor shape to block, beam or underline."
@@ -149,181 +149,181 @@ class Output(metaclass=ABCMeta):
def reset_cursor_shape(self) -> None:
"Reset cursor shape."
- def ask_for_cpr(self) -> None:
- """
- Asks for a cursor position report (CPR).
- (VT100 only.)
- """
-
- @property
- def responds_to_cpr(self) -> bool:
- """
- `True` if the `Application` can expect to receive a CPR response after
- calling `ask_for_cpr` (this will come back through the corresponding
- `Input`).
-
- This is used to determine the amount of available rows we have below
- the cursor position. In the first place, we have this so that the drop
- down autocompletion menus are sized according to the available space.
-
- On Windows, we don't need this, there we have
- `get_rows_below_cursor_position`.
- """
- return False
-
- @abstractmethod
- def get_size(self) -> Size:
- "Return the size of the output window."
-
- def bell(self) -> None:
- "Sound bell."
-
- def enable_bracketed_paste(self) -> None:
- "For vt100 only."
-
- def disable_bracketed_paste(self) -> None:
- "For vt100 only."
-
- def reset_cursor_key_mode(self) -> None:
- """
- For vt100 only.
- Put the terminal in normal cursor mode (instead of application mode).
-
- See: https://vt100.net/docs/vt100-ug/chapter3.html
- """
-
- def scroll_buffer_to_prompt(self) -> None:
- "For Win32 only."
-
- def get_rows_below_cursor_position(self) -> int:
- "For Windows only."
- raise NotImplementedError
-
- @abstractmethod
- def get_default_color_depth(self) -> ColorDepth:
- """
- Get default color depth for this output.
-
- This value will be used if no color depth was explicitely passed to the
- `Application`.
-
- .. note::
-
- If the `$PROMPT_TOOLKIT_COLOR_DEPTH` environment variable has been
- set, then `outputs.defaults.create_output` will pass this value to
- the implementation as the default_color_depth, which is returned
- here. (This is not used when the output corresponds to a
- prompt_toolkit SSH/Telnet session.)
- """
-
-
-class DummyOutput(Output):
- """
- For testing. An output class that doesn't render anything.
- """
-
- def fileno(self) -> int:
- "There is no sensible default for fileno()."
- raise NotImplementedError
-
- def encoding(self) -> str:
- return "utf-8"
-
- def write(self, data: str) -> None:
- pass
-
- def write_raw(self, data: str) -> None:
- pass
-
- def set_title(self, title: str) -> None:
- pass
-
- def clear_title(self) -> None:
- pass
-
- def flush(self) -> None:
- pass
-
- def erase_screen(self) -> None:
- pass
-
- def enter_alternate_screen(self) -> None:
- pass
-
- def quit_alternate_screen(self) -> None:
- pass
-
- def enable_mouse_support(self) -> None:
- pass
-
- def disable_mouse_support(self) -> None:
- pass
-
- def erase_end_of_line(self) -> None:
- pass
-
- def erase_down(self) -> None:
- pass
-
- def reset_attributes(self) -> None:
- pass
-
- def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
- pass
-
- def disable_autowrap(self) -> None:
- pass
-
- def enable_autowrap(self) -> None:
- pass
-
- def cursor_goto(self, row: int = 0, column: int = 0) -> None:
- pass
-
- def cursor_up(self, amount: int) -> None:
- pass
-
- def cursor_down(self, amount: int) -> None:
- pass
-
- def cursor_forward(self, amount: int) -> None:
- pass
-
- def cursor_backward(self, amount: int) -> None:
- pass
-
- def hide_cursor(self) -> None:
- pass
-
- def show_cursor(self) -> None:
- pass
-
+ def ask_for_cpr(self) -> None:
+ """
+ Asks for a cursor position report (CPR).
+ (VT100 only.)
+ """
+
+ @property
+ def responds_to_cpr(self) -> bool:
+ """
+ `True` if the `Application` can expect to receive a CPR response after
+ calling `ask_for_cpr` (this will come back through the corresponding
+ `Input`).
+
+ This is used to determine the amount of available rows we have below
+ the cursor position. In the first place, we have this so that the drop
+ down autocompletion menus are sized according to the available space.
+
+ On Windows, we don't need this, there we have
+ `get_rows_below_cursor_position`.
+ """
+ return False
+
+ @abstractmethod
+ def get_size(self) -> Size:
+ "Return the size of the output window."
+
+ def bell(self) -> None:
+ "Sound bell."
+
+ def enable_bracketed_paste(self) -> None:
+ "For vt100 only."
+
+ def disable_bracketed_paste(self) -> None:
+ "For vt100 only."
+
+ def reset_cursor_key_mode(self) -> None:
+ """
+ For vt100 only.
+ Put the terminal in normal cursor mode (instead of application mode).
+
+ See: https://vt100.net/docs/vt100-ug/chapter3.html
+ """
+
+ def scroll_buffer_to_prompt(self) -> None:
+ "For Win32 only."
+
+ def get_rows_below_cursor_position(self) -> int:
+ "For Windows only."
+ raise NotImplementedError
+
+ @abstractmethod
+ def get_default_color_depth(self) -> ColorDepth:
+ """
+ Get default color depth for this output.
+
+ This value will be used if no color depth was explicitely passed to the
+ `Application`.
+
+ .. note::
+
+ If the `$PROMPT_TOOLKIT_COLOR_DEPTH` environment variable has been
+ set, then `outputs.defaults.create_output` will pass this value to
+ the implementation as the default_color_depth, which is returned
+ here. (This is not used when the output corresponds to a
+ prompt_toolkit SSH/Telnet session.)
+ """
+
+
+class DummyOutput(Output):
+ """
+ For testing. An output class that doesn't render anything.
+ """
+
+ def fileno(self) -> int:
+ "There is no sensible default for fileno()."
+ raise NotImplementedError
+
+ def encoding(self) -> str:
+ return "utf-8"
+
+ def write(self, data: str) -> None:
+ pass
+
+ def write_raw(self, data: str) -> None:
+ pass
+
+ def set_title(self, title: str) -> None:
+ pass
+
+ def clear_title(self) -> None:
+ pass
+
+ def flush(self) -> None:
+ pass
+
+ def erase_screen(self) -> None:
+ pass
+
+ def enter_alternate_screen(self) -> None:
+ pass
+
+ def quit_alternate_screen(self) -> None:
+ pass
+
+ def enable_mouse_support(self) -> None:
+ pass
+
+ def disable_mouse_support(self) -> None:
+ pass
+
+ def erase_end_of_line(self) -> None:
+ pass
+
+ def erase_down(self) -> None:
+ pass
+
+ def reset_attributes(self) -> None:
+ pass
+
+ def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
+ pass
+
+ def disable_autowrap(self) -> None:
+ pass
+
+ def enable_autowrap(self) -> None:
+ pass
+
+ def cursor_goto(self, row: int = 0, column: int = 0) -> None:
+ pass
+
+ def cursor_up(self, amount: int) -> None:
+ pass
+
+ def cursor_down(self, amount: int) -> None:
+ pass
+
+ def cursor_forward(self, amount: int) -> None:
+ pass
+
+ def cursor_backward(self, amount: int) -> None:
+ pass
+
+ def hide_cursor(self) -> None:
+ pass
+
+ def show_cursor(self) -> None:
+ pass
+
def set_cursor_shape(self, cursor_shape: CursorShape) -> None:
pass
def reset_cursor_shape(self) -> None:
pass
- def ask_for_cpr(self) -> None:
- pass
-
- def bell(self) -> None:
- pass
-
- def enable_bracketed_paste(self) -> None:
- pass
-
- def disable_bracketed_paste(self) -> None:
- pass
-
- def scroll_buffer_to_prompt(self) -> None:
- pass
-
- def get_size(self) -> Size:
- return Size(rows=40, columns=80)
-
- def get_rows_below_cursor_position(self) -> int:
- return 40
-
- def get_default_color_depth(self) -> ColorDepth:
- return ColorDepth.DEPTH_1_BIT
+ def ask_for_cpr(self) -> None:
+ pass
+
+ def bell(self) -> None:
+ pass
+
+ def enable_bracketed_paste(self) -> None:
+ pass
+
+ def disable_bracketed_paste(self) -> None:
+ pass
+
+ def scroll_buffer_to_prompt(self) -> None:
+ pass
+
+ def get_size(self) -> Size:
+ return Size(rows=40, columns=80)
+
+ def get_rows_below_cursor_position(self) -> int:
+ return 40
+
+ def get_default_color_depth(self) -> ColorDepth:
+ return ColorDepth.DEPTH_1_BIT
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/color_depth.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/color_depth.py
index 9756c206af4..a6166bacafb 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/color_depth.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/color_depth.py
@@ -1,58 +1,58 @@
-import os
-from enum import Enum
-from typing import Optional
-
-__all__ = [
- "ColorDepth",
-]
-
-
-class ColorDepth(str, Enum):
- """
- Possible color depth values for the output.
- """
-
- value: str
-
- #: One color only.
- DEPTH_1_BIT = "DEPTH_1_BIT"
-
- #: ANSI Colors.
- DEPTH_4_BIT = "DEPTH_4_BIT"
-
- #: The default.
- DEPTH_8_BIT = "DEPTH_8_BIT"
-
- #: 24 bit True color.
- DEPTH_24_BIT = "DEPTH_24_BIT"
-
- # Aliases.
- MONOCHROME = DEPTH_1_BIT
- ANSI_COLORS_ONLY = DEPTH_4_BIT
- DEFAULT = DEPTH_8_BIT
- TRUE_COLOR = DEPTH_24_BIT
-
- @classmethod
- def from_env(cls) -> Optional["ColorDepth"]:
- """
- Return the color depth if the $PROMPT_TOOLKIT_COLOR_DEPTH environment
- variable has been set.
-
- This is a way to enforce a certain color depth in all prompt_toolkit
- applications.
- """
- # Check the `PROMPT_TOOLKIT_COLOR_DEPTH` environment variable.
- all_values = [i.value for i in ColorDepth]
- if os.environ.get("PROMPT_TOOLKIT_COLOR_DEPTH") in all_values:
- return cls(os.environ["PROMPT_TOOLKIT_COLOR_DEPTH"])
-
- return None
-
- @classmethod
- def default(cls) -> "ColorDepth":
- """
- Return the default color depth for the default output.
- """
- from .defaults import create_output
-
- return create_output().get_default_color_depth()
+import os
+from enum import Enum
+from typing import Optional
+
+__all__ = [
+ "ColorDepth",
+]
+
+
+class ColorDepth(str, Enum):
+ """
+ Possible color depth values for the output.
+ """
+
+ value: str
+
+ #: One color only.
+ DEPTH_1_BIT = "DEPTH_1_BIT"
+
+ #: ANSI Colors.
+ DEPTH_4_BIT = "DEPTH_4_BIT"
+
+ #: The default.
+ DEPTH_8_BIT = "DEPTH_8_BIT"
+
+ #: 24 bit True color.
+ DEPTH_24_BIT = "DEPTH_24_BIT"
+
+ # Aliases.
+ MONOCHROME = DEPTH_1_BIT
+ ANSI_COLORS_ONLY = DEPTH_4_BIT
+ DEFAULT = DEPTH_8_BIT
+ TRUE_COLOR = DEPTH_24_BIT
+
+ @classmethod
+ def from_env(cls) -> Optional["ColorDepth"]:
+ """
+ Return the color depth if the $PROMPT_TOOLKIT_COLOR_DEPTH environment
+ variable has been set.
+
+ This is a way to enforce a certain color depth in all prompt_toolkit
+ applications.
+ """
+ # Check the `PROMPT_TOOLKIT_COLOR_DEPTH` environment variable.
+ all_values = [i.value for i in ColorDepth]
+ if os.environ.get("PROMPT_TOOLKIT_COLOR_DEPTH") in all_values:
+ return cls(os.environ["PROMPT_TOOLKIT_COLOR_DEPTH"])
+
+ return None
+
+ @classmethod
+ def default(cls) -> "ColorDepth":
+ """
+ Return the default color depth for the default output.
+ """
+ from .defaults import create_output
+
+ return create_output().get_default_color_depth()
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/conemu.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/conemu.py
index f1af406b8ca..ee1ac41d4d7 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/conemu.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/conemu.py
@@ -1,59 +1,59 @@
-from typing import Any, Optional, TextIO
-
-from prompt_toolkit.data_structures import Size
-
-from .base import Output
-from .color_depth import ColorDepth
-from .vt100 import Vt100_Output
-from .win32 import Win32Output
-
-__all__ = [
- "ConEmuOutput",
-]
-
-
-class ConEmuOutput:
- """
- ConEmu (Windows) output abstraction.
-
- ConEmu is a Windows console application, but it also supports ANSI escape
- sequences. This output class is actually a proxy to both `Win32Output` and
- `Vt100_Output`. It uses `Win32Output` for console sizing and scrolling, but
- all cursor movements and scrolling happens through the `Vt100_Output`.
-
- This way, we can have 256 colors in ConEmu and Cmder. Rendering will be
- even a little faster as well.
-
- http://conemu.github.io/
- http://gooseberrycreative.com/cmder/
- """
-
- def __init__(
- self, stdout: TextIO, default_color_depth: Optional[ColorDepth] = None
- ) -> None:
- self.win32_output = Win32Output(stdout, default_color_depth=default_color_depth)
- self.vt100_output = Vt100_Output(
- stdout, lambda: Size(0, 0), default_color_depth=default_color_depth
- )
-
- @property
- def responds_to_cpr(self) -> bool:
- return False # We don't need this on Windows.
-
- def __getattr__(self, name: str) -> Any:
- if name in (
- "get_size",
- "get_rows_below_cursor_position",
- "enable_mouse_support",
- "disable_mouse_support",
- "scroll_buffer_to_prompt",
- "get_win32_screen_buffer_info",
- "enable_bracketed_paste",
- "disable_bracketed_paste",
- ):
- return getattr(self.win32_output, name)
- else:
- return getattr(self.vt100_output, name)
-
-
-Output.register(ConEmuOutput)
+from typing import Any, Optional, TextIO
+
+from prompt_toolkit.data_structures import Size
+
+from .base import Output
+from .color_depth import ColorDepth
+from .vt100 import Vt100_Output
+from .win32 import Win32Output
+
+__all__ = [
+ "ConEmuOutput",
+]
+
+
+class ConEmuOutput:
+ """
+ ConEmu (Windows) output abstraction.
+
+ ConEmu is a Windows console application, but it also supports ANSI escape
+ sequences. This output class is actually a proxy to both `Win32Output` and
+ `Vt100_Output`. It uses `Win32Output` for console sizing and scrolling, but
+ all cursor movements and scrolling happens through the `Vt100_Output`.
+
+ This way, we can have 256 colors in ConEmu and Cmder. Rendering will be
+ even a little faster as well.
+
+ http://conemu.github.io/
+ http://gooseberrycreative.com/cmder/
+ """
+
+ def __init__(
+ self, stdout: TextIO, default_color_depth: Optional[ColorDepth] = None
+ ) -> None:
+ self.win32_output = Win32Output(stdout, default_color_depth=default_color_depth)
+ self.vt100_output = Vt100_Output(
+ stdout, lambda: Size(0, 0), default_color_depth=default_color_depth
+ )
+
+ @property
+ def responds_to_cpr(self) -> bool:
+ return False # We don't need this on Windows.
+
+ def __getattr__(self, name: str) -> Any:
+ if name in (
+ "get_size",
+ "get_rows_below_cursor_position",
+ "enable_mouse_support",
+ "disable_mouse_support",
+ "scroll_buffer_to_prompt",
+ "get_win32_screen_buffer_info",
+ "enable_bracketed_paste",
+ "disable_bracketed_paste",
+ ):
+ return getattr(self.win32_output, name)
+ else:
+ return getattr(self.vt100_output, name)
+
+
+Output.register(ConEmuOutput)
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py
index e2a1ef95e99..bd4bf950c43 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py
@@ -1,31 +1,31 @@
-import sys
-from typing import Optional, TextIO, cast
-
-from prompt_toolkit.utils import (
- get_bell_environment_variable,
- get_term_environment_variable,
- is_conemu_ansi,
- is_windows,
-)
-
+import sys
+from typing import Optional, TextIO, cast
+
+from prompt_toolkit.utils import (
+ get_bell_environment_variable,
+ get_term_environment_variable,
+ is_conemu_ansi,
+ is_windows,
+)
+
from .base import DummyOutput, Output
-from .color_depth import ColorDepth
+from .color_depth import ColorDepth
from .plain_text import PlainTextOutput
-
-__all__ = [
- "create_output",
-]
-
-
-def create_output(
+
+__all__ = [
+ "create_output",
+]
+
+
+def create_output(
stdout: Optional[TextIO] = None, always_prefer_tty: bool = False
-) -> Output:
- """
- Return an :class:`~prompt_toolkit.output.Output` instance for the command
- line.
-
- :param stdout: The stdout object
- :param always_prefer_tty: When set, look for `sys.stderr` if `sys.stdout`
+) -> Output:
+ """
+ Return an :class:`~prompt_toolkit.output.Output` instance for the command
+ line.
+
+ :param stdout: The stdout object
+ :param always_prefer_tty: When set, look for `sys.stderr` if `sys.stdout`
is not a TTY. Useful if `sys.stdout` is redirected to a file, but we
still want user input and output on the terminal.
@@ -33,26 +33,26 @@ def create_output(
it's redirected to a file), then a `PlainTextOutput` will be returned.
That way, tools like `print_formatted_text` will write plain text into
that file.
- """
- # Consider TERM, PROMPT_TOOLKIT_BELL, and PROMPT_TOOLKIT_COLOR_DEPTH
- # environment variables. Notice that PROMPT_TOOLKIT_COLOR_DEPTH value is
- # the default that's used if the Application doesn't override it.
- term_from_env = get_term_environment_variable()
- bell_from_env = get_bell_environment_variable()
- color_depth_from_env = ColorDepth.from_env()
-
- if stdout is None:
- # By default, render to stdout. If the output is piped somewhere else,
- # render to stderr.
- stdout = sys.stdout
-
- if always_prefer_tty:
- for io in [sys.stdout, sys.stderr]:
+ """
+ # Consider TERM, PROMPT_TOOLKIT_BELL, and PROMPT_TOOLKIT_COLOR_DEPTH
+ # environment variables. Notice that PROMPT_TOOLKIT_COLOR_DEPTH value is
+ # the default that's used if the Application doesn't override it.
+ term_from_env = get_term_environment_variable()
+ bell_from_env = get_bell_environment_variable()
+ color_depth_from_env = ColorDepth.from_env()
+
+ if stdout is None:
+ # By default, render to stdout. If the output is piped somewhere else,
+ # render to stderr.
+ stdout = sys.stdout
+
+ if always_prefer_tty:
+ for io in [sys.stdout, sys.stderr]:
if io is not None and io.isatty():
# (This is `None` when using `pythonw.exe` on Windows.)
- stdout = io
- break
-
+ stdout = io
+ break
+
# If the output is still `None`, use a DummyOutput.
# This happens for instance on Windows, when running the application under
# `pythonw.exe`. In that case, there won't be a terminal Window, and
@@ -60,42 +60,42 @@ def create_output(
if stdout is None:
return DummyOutput()
- # If the patch_stdout context manager has been used, then sys.stdout is
- # replaced by this proxy. For prompt_toolkit applications, we want to use
- # the real stdout.
- from prompt_toolkit.patch_stdout import StdoutProxy
-
- while isinstance(stdout, StdoutProxy):
- stdout = stdout.original_stdout
-
- if is_windows():
- from .conemu import ConEmuOutput
- from .win32 import Win32Output
- from .windows10 import Windows10_Output, is_win_vt100_enabled
-
- if is_win_vt100_enabled():
- return cast(
- Output,
- Windows10_Output(stdout, default_color_depth=color_depth_from_env),
- )
- if is_conemu_ansi():
- return cast(
- Output, ConEmuOutput(stdout, default_color_depth=color_depth_from_env)
- )
- else:
- return Win32Output(stdout, default_color_depth=color_depth_from_env)
- else:
- from .vt100 import Vt100_Output
-
+ # If the patch_stdout context manager has been used, then sys.stdout is
+ # replaced by this proxy. For prompt_toolkit applications, we want to use
+ # the real stdout.
+ from prompt_toolkit.patch_stdout import StdoutProxy
+
+ while isinstance(stdout, StdoutProxy):
+ stdout = stdout.original_stdout
+
+ if is_windows():
+ from .conemu import ConEmuOutput
+ from .win32 import Win32Output
+ from .windows10 import Windows10_Output, is_win_vt100_enabled
+
+ if is_win_vt100_enabled():
+ return cast(
+ Output,
+ Windows10_Output(stdout, default_color_depth=color_depth_from_env),
+ )
+ if is_conemu_ansi():
+ return cast(
+ Output, ConEmuOutput(stdout, default_color_depth=color_depth_from_env)
+ )
+ else:
+ return Win32Output(stdout, default_color_depth=color_depth_from_env)
+ else:
+ from .vt100 import Vt100_Output
+
# Stdout is not a TTY? Render as plain text.
# This is mostly useful if stdout is redirected to a file, and
# `print_formatted_text` is used.
if not stdout.isatty():
return PlainTextOutput(stdout)
- return Vt100_Output.from_pty(
- stdout,
- term=term_from_env,
- default_color_depth=color_depth_from_env,
- enable_bell=bell_from_env,
- )
+ return Vt100_Output.from_pty(
+ stdout,
+ term=term_from_env,
+ default_color_depth=color_depth_from_env,
+ enable_bell=bell_from_env,
+ )
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/vt100.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/vt100.py
index fe7f85dae7a..05862672862 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/vt100.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/vt100.py
@@ -1,669 +1,669 @@
-"""
-Output for vt100 terminals.
-
-A lot of thanks, regarding outputting of colors, goes to the Pygments project:
-(We don't rely on Pygments anymore, because many things are very custom, and
-everything has been highly optimized.)
-http://pygments.org/
-"""
-import io
-import os
-import sys
-from typing import (
- Callable,
- Dict,
- Hashable,
- Iterable,
- List,
- Optional,
- Sequence,
- Set,
- TextIO,
- Tuple,
-)
-
+"""
+Output for vt100 terminals.
+
+A lot of thanks, regarding outputting of colors, goes to the Pygments project:
+(We don't rely on Pygments anymore, because many things are very custom, and
+everything has been highly optimized.)
+http://pygments.org/
+"""
+import io
+import os
+import sys
+from typing import (
+ Callable,
+ Dict,
+ Hashable,
+ Iterable,
+ List,
+ Optional,
+ Sequence,
+ Set,
+ TextIO,
+ Tuple,
+)
+
from prompt_toolkit.cursor_shapes import CursorShape
-from prompt_toolkit.data_structures import Size
-from prompt_toolkit.output import Output
-from prompt_toolkit.styles import ANSI_COLOR_NAMES, Attrs
-from prompt_toolkit.utils import is_dumb_terminal
-
-from .color_depth import ColorDepth
+from prompt_toolkit.data_structures import Size
+from prompt_toolkit.output import Output
+from prompt_toolkit.styles import ANSI_COLOR_NAMES, Attrs
+from prompt_toolkit.utils import is_dumb_terminal
+
+from .color_depth import ColorDepth
from .flush_stdout import flush_stdout
-
-__all__ = [
- "Vt100_Output",
-]
-
-
-FG_ANSI_COLORS = {
- "ansidefault": 39,
- # Low intensity.
- "ansiblack": 30,
- "ansired": 31,
- "ansigreen": 32,
- "ansiyellow": 33,
- "ansiblue": 34,
- "ansimagenta": 35,
- "ansicyan": 36,
- "ansigray": 37,
- # High intensity.
- "ansibrightblack": 90,
- "ansibrightred": 91,
- "ansibrightgreen": 92,
- "ansibrightyellow": 93,
- "ansibrightblue": 94,
- "ansibrightmagenta": 95,
- "ansibrightcyan": 96,
- "ansiwhite": 97,
-}
-
-BG_ANSI_COLORS = {
- "ansidefault": 49,
- # Low intensity.
- "ansiblack": 40,
- "ansired": 41,
- "ansigreen": 42,
- "ansiyellow": 43,
- "ansiblue": 44,
- "ansimagenta": 45,
- "ansicyan": 46,
- "ansigray": 47,
- # High intensity.
- "ansibrightblack": 100,
- "ansibrightred": 101,
- "ansibrightgreen": 102,
- "ansibrightyellow": 103,
- "ansibrightblue": 104,
- "ansibrightmagenta": 105,
- "ansibrightcyan": 106,
- "ansiwhite": 107,
-}
-
-
-ANSI_COLORS_TO_RGB = {
- "ansidefault": (
- 0x00,
- 0x00,
- 0x00,
- ), # Don't use, 'default' doesn't really have a value.
- "ansiblack": (0x00, 0x00, 0x00),
- "ansigray": (0xE5, 0xE5, 0xE5),
- "ansibrightblack": (0x7F, 0x7F, 0x7F),
- "ansiwhite": (0xFF, 0xFF, 0xFF),
- # Low intensity.
- "ansired": (0xCD, 0x00, 0x00),
- "ansigreen": (0x00, 0xCD, 0x00),
- "ansiyellow": (0xCD, 0xCD, 0x00),
- "ansiblue": (0x00, 0x00, 0xCD),
- "ansimagenta": (0xCD, 0x00, 0xCD),
- "ansicyan": (0x00, 0xCD, 0xCD),
- # High intensity.
- "ansibrightred": (0xFF, 0x00, 0x00),
- "ansibrightgreen": (0x00, 0xFF, 0x00),
- "ansibrightyellow": (0xFF, 0xFF, 0x00),
- "ansibrightblue": (0x00, 0x00, 0xFF),
- "ansibrightmagenta": (0xFF, 0x00, 0xFF),
- "ansibrightcyan": (0x00, 0xFF, 0xFF),
-}
-
-
-assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
-assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
-assert set(ANSI_COLORS_TO_RGB) == set(ANSI_COLOR_NAMES)
-
-
-def _get_closest_ansi_color(r: int, g: int, b: int, exclude: Sequence[str] = ()) -> str:
- """
- Find closest ANSI color. Return it by name.
-
- :param r: Red (Between 0 and 255.)
- :param g: Green (Between 0 and 255.)
- :param b: Blue (Between 0 and 255.)
- :param exclude: A tuple of color names to exclude. (E.g. ``('ansired', )``.)
- """
- exclude = list(exclude)
-
- # When we have a bit of saturation, avoid the gray-like colors, otherwise,
- # too often the distance to the gray color is less.
- saturation = abs(r - g) + abs(g - b) + abs(b - r) # Between 0..510
-
- if saturation > 30:
- exclude.extend(["ansilightgray", "ansidarkgray", "ansiwhite", "ansiblack"])
-
- # Take the closest color.
- # (Thanks to Pygments for this part.)
- distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
- match = "ansidefault"
-
- for name, (r2, g2, b2) in ANSI_COLORS_TO_RGB.items():
- if name != "ansidefault" and name not in exclude:
- d = (r - r2) ** 2 + (g - g2) ** 2 + (b - b2) ** 2
-
- if d < distance:
- match = name
- distance = d
-
- return match
-
-
-_ColorCodeAndName = Tuple[int, str]
-
-
-class _16ColorCache:
- """
- Cache which maps (r, g, b) tuples to 16 ansi colors.
-
- :param bg: Cache for background colors, instead of foreground.
- """
-
- def __init__(self, bg: bool = False) -> None:
- self.bg = bg
- self._cache: Dict[Hashable, _ColorCodeAndName] = {}
-
- def get_code(
- self, value: Tuple[int, int, int], exclude: Sequence[str] = ()
- ) -> _ColorCodeAndName:
- """
- Return a (ansi_code, ansi_name) tuple. (E.g. ``(44, 'ansiblue')``.) for
- a given (r,g,b) value.
- """
- key: Hashable = (value, tuple(exclude))
- cache = self._cache
-
- if key not in cache:
- cache[key] = self._get(value, exclude)
-
- return cache[key]
-
- def _get(
- self, value: Tuple[int, int, int], exclude: Sequence[str] = ()
- ) -> _ColorCodeAndName:
-
- r, g, b = value
- match = _get_closest_ansi_color(r, g, b, exclude=exclude)
-
- # Turn color name into code.
- if self.bg:
- code = BG_ANSI_COLORS[match]
- else:
- code = FG_ANSI_COLORS[match]
-
- return code, match
-
-
-class _256ColorCache(Dict[Tuple[int, int, int], int]):
- """
- Cache which maps (r, g, b) tuples to 256 colors.
- """
-
- def __init__(self) -> None:
- # Build color table.
- colors: List[Tuple[int, int, int]] = []
-
- # colors 0..15: 16 basic colors
- colors.append((0x00, 0x00, 0x00)) # 0
- colors.append((0xCD, 0x00, 0x00)) # 1
- colors.append((0x00, 0xCD, 0x00)) # 2
- colors.append((0xCD, 0xCD, 0x00)) # 3
- colors.append((0x00, 0x00, 0xEE)) # 4
- colors.append((0xCD, 0x00, 0xCD)) # 5
- colors.append((0x00, 0xCD, 0xCD)) # 6
- colors.append((0xE5, 0xE5, 0xE5)) # 7
- colors.append((0x7F, 0x7F, 0x7F)) # 8
- colors.append((0xFF, 0x00, 0x00)) # 9
- colors.append((0x00, 0xFF, 0x00)) # 10
- colors.append((0xFF, 0xFF, 0x00)) # 11
- colors.append((0x5C, 0x5C, 0xFF)) # 12
- colors.append((0xFF, 0x00, 0xFF)) # 13
- colors.append((0x00, 0xFF, 0xFF)) # 14
- colors.append((0xFF, 0xFF, 0xFF)) # 15
-
- # colors 16..232: the 6x6x6 color cube
- valuerange = (0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF)
-
- for i in range(217):
- r = valuerange[(i // 36) % 6]
- g = valuerange[(i // 6) % 6]
- b = valuerange[i % 6]
- colors.append((r, g, b))
-
- # colors 233..253: grayscale
- for i in range(1, 22):
- v = 8 + i * 10
- colors.append((v, v, v))
-
- self.colors = colors
-
- def __missing__(self, value: Tuple[int, int, int]) -> int:
- r, g, b = value
-
- # Find closest color.
- # (Thanks to Pygments for this!)
- distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
- match = 0
-
- for i, (r2, g2, b2) in enumerate(self.colors):
- if i >= 16: # XXX: We ignore the 16 ANSI colors when mapping RGB
- # to the 256 colors, because these highly depend on
- # the color scheme of the terminal.
- d = (r - r2) ** 2 + (g - g2) ** 2 + (b - b2) ** 2
-
- if d < distance:
- match = i
- distance = d
-
- # Turn color name into code.
- self[value] = match
- return match
-
-
-_16_fg_colors = _16ColorCache(bg=False)
-_16_bg_colors = _16ColorCache(bg=True)
-_256_colors = _256ColorCache()
-
-
-class _EscapeCodeCache(Dict[Attrs, str]):
- """
- Cache for VT100 escape codes. It maps
- (fgcolor, bgcolor, bold, underline, strike, reverse) tuples to VT100
- escape sequences.
-
- :param true_color: When True, use 24bit colors instead of 256 colors.
- """
-
- def __init__(self, color_depth: ColorDepth) -> None:
- self.color_depth = color_depth
-
- def __missing__(self, attrs: Attrs) -> str:
- (
- fgcolor,
- bgcolor,
- bold,
- underline,
- strike,
- italic,
- blink,
- reverse,
- hidden,
- ) = attrs
- parts: List[str] = []
-
- parts.extend(self._colors_to_code(fgcolor or "", bgcolor or ""))
-
- if bold:
- parts.append("1")
- if italic:
- parts.append("3")
- if blink:
- parts.append("5")
- if underline:
- parts.append("4")
- if reverse:
- parts.append("7")
- if hidden:
- parts.append("8")
- if strike:
- parts.append("9")
-
- if parts:
- result = "\x1b[0;" + ";".join(parts) + "m"
- else:
- result = "\x1b[0m"
-
- self[attrs] = result
- return result
-
- def _color_name_to_rgb(self, color: str) -> Tuple[int, int, int]:
- "Turn 'ffffff', into (0xff, 0xff, 0xff)."
- try:
- rgb = int(color, 16)
- except ValueError:
- raise
- else:
- r = (rgb >> 16) & 0xFF
- g = (rgb >> 8) & 0xFF
- b = rgb & 0xFF
- return r, g, b
-
- def _colors_to_code(self, fg_color: str, bg_color: str) -> Iterable[str]:
- """
- Return a tuple with the vt100 values that represent this color.
- """
- # When requesting ANSI colors only, and both fg/bg color were converted
- # to ANSI, ensure that the foreground and background color are not the
- # same. (Unless they were explicitly defined to be the same color.)
- fg_ansi = ""
-
- def get(color: str, bg: bool) -> List[int]:
- nonlocal fg_ansi
-
- table = BG_ANSI_COLORS if bg else FG_ANSI_COLORS
-
- if not color or self.color_depth == ColorDepth.DEPTH_1_BIT:
- return []
-
- # 16 ANSI colors. (Given by name.)
- elif color in table:
- return [table[color]]
-
- # RGB colors. (Defined as 'ffffff'.)
- else:
- try:
- rgb = self._color_name_to_rgb(color)
- except ValueError:
- return []
-
- # When only 16 colors are supported, use that.
- if self.color_depth == ColorDepth.DEPTH_4_BIT:
- if bg: # Background.
- if fg_color != bg_color:
- exclude = [fg_ansi]
- else:
- exclude = []
- code, name = _16_bg_colors.get_code(rgb, exclude=exclude)
- return [code]
- else: # Foreground.
- code, name = _16_fg_colors.get_code(rgb)
- fg_ansi = name
- return [code]
-
- # True colors. (Only when this feature is enabled.)
- elif self.color_depth == ColorDepth.DEPTH_24_BIT:
- r, g, b = rgb
- return [(48 if bg else 38), 2, r, g, b]
-
- # 256 RGB colors.
- else:
- return [(48 if bg else 38), 5, _256_colors[rgb]]
-
- result: List[int] = []
- result.extend(get(fg_color, False))
- result.extend(get(bg_color, True))
-
- return map(str, result)
-
-
-def _get_size(fileno: int) -> Tuple[int, int]:
- """
- Get the size of this pseudo terminal.
-
- :param fileno: stdout.fileno()
- :returns: A (rows, cols) tuple.
- """
- size = os.get_terminal_size(fileno)
- return size.lines, size.columns
-
-
-class Vt100_Output(Output):
- """
- :param get_size: A callable which returns the `Size` of the output terminal.
- :param stdout: Any object with has a `write` and `flush` method + an 'encoding' property.
- :param term: The terminal environment variable. (xterm, xterm-256color, linux, ...)
- :param write_binary: Encode the output before writing it. If `True` (the
- default), the `stdout` object is supposed to expose an `encoding` attribute.
- """
-
- # For the error messages. Only display "Output is not a terminal" once per
- # file descriptor.
- _fds_not_a_terminal: Set[int] = set()
-
- def __init__(
- self,
- stdout: TextIO,
- get_size: Callable[[], Size],
- term: Optional[str] = None,
- write_binary: bool = True,
- default_color_depth: Optional[ColorDepth] = None,
- enable_bell: bool = True,
- ) -> None:
-
- assert all(hasattr(stdout, a) for a in ("write", "flush"))
-
- if write_binary:
- assert hasattr(stdout, "encoding")
-
- self._buffer: List[str] = []
- self.stdout: TextIO = stdout
- self.write_binary = write_binary
- self.default_color_depth = default_color_depth
- self._get_size = get_size
- self.term = term
- self.enable_bell = enable_bell
-
- # Cache for escape codes.
- self._escape_code_caches: Dict[ColorDepth, _EscapeCodeCache] = {
- ColorDepth.DEPTH_1_BIT: _EscapeCodeCache(ColorDepth.DEPTH_1_BIT),
- ColorDepth.DEPTH_4_BIT: _EscapeCodeCache(ColorDepth.DEPTH_4_BIT),
- ColorDepth.DEPTH_8_BIT: _EscapeCodeCache(ColorDepth.DEPTH_8_BIT),
- ColorDepth.DEPTH_24_BIT: _EscapeCodeCache(ColorDepth.DEPTH_24_BIT),
- }
-
+
+__all__ = [
+ "Vt100_Output",
+]
+
+
+FG_ANSI_COLORS = {
+ "ansidefault": 39,
+ # Low intensity.
+ "ansiblack": 30,
+ "ansired": 31,
+ "ansigreen": 32,
+ "ansiyellow": 33,
+ "ansiblue": 34,
+ "ansimagenta": 35,
+ "ansicyan": 36,
+ "ansigray": 37,
+ # High intensity.
+ "ansibrightblack": 90,
+ "ansibrightred": 91,
+ "ansibrightgreen": 92,
+ "ansibrightyellow": 93,
+ "ansibrightblue": 94,
+ "ansibrightmagenta": 95,
+ "ansibrightcyan": 96,
+ "ansiwhite": 97,
+}
+
+BG_ANSI_COLORS = {
+ "ansidefault": 49,
+ # Low intensity.
+ "ansiblack": 40,
+ "ansired": 41,
+ "ansigreen": 42,
+ "ansiyellow": 43,
+ "ansiblue": 44,
+ "ansimagenta": 45,
+ "ansicyan": 46,
+ "ansigray": 47,
+ # High intensity.
+ "ansibrightblack": 100,
+ "ansibrightred": 101,
+ "ansibrightgreen": 102,
+ "ansibrightyellow": 103,
+ "ansibrightblue": 104,
+ "ansibrightmagenta": 105,
+ "ansibrightcyan": 106,
+ "ansiwhite": 107,
+}
+
+
+ANSI_COLORS_TO_RGB = {
+ "ansidefault": (
+ 0x00,
+ 0x00,
+ 0x00,
+ ), # Don't use, 'default' doesn't really have a value.
+ "ansiblack": (0x00, 0x00, 0x00),
+ "ansigray": (0xE5, 0xE5, 0xE5),
+ "ansibrightblack": (0x7F, 0x7F, 0x7F),
+ "ansiwhite": (0xFF, 0xFF, 0xFF),
+ # Low intensity.
+ "ansired": (0xCD, 0x00, 0x00),
+ "ansigreen": (0x00, 0xCD, 0x00),
+ "ansiyellow": (0xCD, 0xCD, 0x00),
+ "ansiblue": (0x00, 0x00, 0xCD),
+ "ansimagenta": (0xCD, 0x00, 0xCD),
+ "ansicyan": (0x00, 0xCD, 0xCD),
+ # High intensity.
+ "ansibrightred": (0xFF, 0x00, 0x00),
+ "ansibrightgreen": (0x00, 0xFF, 0x00),
+ "ansibrightyellow": (0xFF, 0xFF, 0x00),
+ "ansibrightblue": (0x00, 0x00, 0xFF),
+ "ansibrightmagenta": (0xFF, 0x00, 0xFF),
+ "ansibrightcyan": (0x00, 0xFF, 0xFF),
+}
+
+
+assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+assert set(ANSI_COLORS_TO_RGB) == set(ANSI_COLOR_NAMES)
+
+
+def _get_closest_ansi_color(r: int, g: int, b: int, exclude: Sequence[str] = ()) -> str:
+ """
+ Find closest ANSI color. Return it by name.
+
+ :param r: Red (Between 0 and 255.)
+ :param g: Green (Between 0 and 255.)
+ :param b: Blue (Between 0 and 255.)
+ :param exclude: A tuple of color names to exclude. (E.g. ``('ansired', )``.)
+ """
+ exclude = list(exclude)
+
+ # When we have a bit of saturation, avoid the gray-like colors, otherwise,
+ # too often the distance to the gray color is less.
+ saturation = abs(r - g) + abs(g - b) + abs(b - r) # Between 0..510
+
+ if saturation > 30:
+ exclude.extend(["ansilightgray", "ansidarkgray", "ansiwhite", "ansiblack"])
+
+ # Take the closest color.
+ # (Thanks to Pygments for this part.)
+ distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
+ match = "ansidefault"
+
+ for name, (r2, g2, b2) in ANSI_COLORS_TO_RGB.items():
+ if name != "ansidefault" and name not in exclude:
+ d = (r - r2) ** 2 + (g - g2) ** 2 + (b - b2) ** 2
+
+ if d < distance:
+ match = name
+ distance = d
+
+ return match
+
+
+_ColorCodeAndName = Tuple[int, str]
+
+
+class _16ColorCache:
+ """
+ Cache which maps (r, g, b) tuples to 16 ansi colors.
+
+ :param bg: Cache for background colors, instead of foreground.
+ """
+
+ def __init__(self, bg: bool = False) -> None:
+ self.bg = bg
+ self._cache: Dict[Hashable, _ColorCodeAndName] = {}
+
+ def get_code(
+ self, value: Tuple[int, int, int], exclude: Sequence[str] = ()
+ ) -> _ColorCodeAndName:
+ """
+ Return a (ansi_code, ansi_name) tuple. (E.g. ``(44, 'ansiblue')``.) for
+ a given (r,g,b) value.
+ """
+ key: Hashable = (value, tuple(exclude))
+ cache = self._cache
+
+ if key not in cache:
+ cache[key] = self._get(value, exclude)
+
+ return cache[key]
+
+ def _get(
+ self, value: Tuple[int, int, int], exclude: Sequence[str] = ()
+ ) -> _ColorCodeAndName:
+
+ r, g, b = value
+ match = _get_closest_ansi_color(r, g, b, exclude=exclude)
+
+ # Turn color name into code.
+ if self.bg:
+ code = BG_ANSI_COLORS[match]
+ else:
+ code = FG_ANSI_COLORS[match]
+
+ return code, match
+
+
+class _256ColorCache(Dict[Tuple[int, int, int], int]):
+ """
+ Cache which maps (r, g, b) tuples to 256 colors.
+ """
+
+ def __init__(self) -> None:
+ # Build color table.
+ colors: List[Tuple[int, int, int]] = []
+
+ # colors 0..15: 16 basic colors
+ colors.append((0x00, 0x00, 0x00)) # 0
+ colors.append((0xCD, 0x00, 0x00)) # 1
+ colors.append((0x00, 0xCD, 0x00)) # 2
+ colors.append((0xCD, 0xCD, 0x00)) # 3
+ colors.append((0x00, 0x00, 0xEE)) # 4
+ colors.append((0xCD, 0x00, 0xCD)) # 5
+ colors.append((0x00, 0xCD, 0xCD)) # 6
+ colors.append((0xE5, 0xE5, 0xE5)) # 7
+ colors.append((0x7F, 0x7F, 0x7F)) # 8
+ colors.append((0xFF, 0x00, 0x00)) # 9
+ colors.append((0x00, 0xFF, 0x00)) # 10
+ colors.append((0xFF, 0xFF, 0x00)) # 11
+ colors.append((0x5C, 0x5C, 0xFF)) # 12
+ colors.append((0xFF, 0x00, 0xFF)) # 13
+ colors.append((0x00, 0xFF, 0xFF)) # 14
+ colors.append((0xFF, 0xFF, 0xFF)) # 15
+
+ # colors 16..232: the 6x6x6 color cube
+ valuerange = (0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF)
+
+ for i in range(217):
+ r = valuerange[(i // 36) % 6]
+ g = valuerange[(i // 6) % 6]
+ b = valuerange[i % 6]
+ colors.append((r, g, b))
+
+ # colors 233..253: grayscale
+ for i in range(1, 22):
+ v = 8 + i * 10
+ colors.append((v, v, v))
+
+ self.colors = colors
+
+ def __missing__(self, value: Tuple[int, int, int]) -> int:
+ r, g, b = value
+
+ # Find closest color.
+ # (Thanks to Pygments for this!)
+ distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
+ match = 0
+
+ for i, (r2, g2, b2) in enumerate(self.colors):
+ if i >= 16: # XXX: We ignore the 16 ANSI colors when mapping RGB
+ # to the 256 colors, because these highly depend on
+ # the color scheme of the terminal.
+ d = (r - r2) ** 2 + (g - g2) ** 2 + (b - b2) ** 2
+
+ if d < distance:
+ match = i
+ distance = d
+
+ # Turn color name into code.
+ self[value] = match
+ return match
+
+
+_16_fg_colors = _16ColorCache(bg=False)
+_16_bg_colors = _16ColorCache(bg=True)
+_256_colors = _256ColorCache()
+
+
+class _EscapeCodeCache(Dict[Attrs, str]):
+ """
+ Cache for VT100 escape codes. It maps
+ (fgcolor, bgcolor, bold, underline, strike, reverse) tuples to VT100
+ escape sequences.
+
+ :param true_color: When True, use 24bit colors instead of 256 colors.
+ """
+
+ def __init__(self, color_depth: ColorDepth) -> None:
+ self.color_depth = color_depth
+
+ def __missing__(self, attrs: Attrs) -> str:
+ (
+ fgcolor,
+ bgcolor,
+ bold,
+ underline,
+ strike,
+ italic,
+ blink,
+ reverse,
+ hidden,
+ ) = attrs
+ parts: List[str] = []
+
+ parts.extend(self._colors_to_code(fgcolor or "", bgcolor or ""))
+
+ if bold:
+ parts.append("1")
+ if italic:
+ parts.append("3")
+ if blink:
+ parts.append("5")
+ if underline:
+ parts.append("4")
+ if reverse:
+ parts.append("7")
+ if hidden:
+ parts.append("8")
+ if strike:
+ parts.append("9")
+
+ if parts:
+ result = "\x1b[0;" + ";".join(parts) + "m"
+ else:
+ result = "\x1b[0m"
+
+ self[attrs] = result
+ return result
+
+ def _color_name_to_rgb(self, color: str) -> Tuple[int, int, int]:
+ "Turn 'ffffff', into (0xff, 0xff, 0xff)."
+ try:
+ rgb = int(color, 16)
+ except ValueError:
+ raise
+ else:
+ r = (rgb >> 16) & 0xFF
+ g = (rgb >> 8) & 0xFF
+ b = rgb & 0xFF
+ return r, g, b
+
+ def _colors_to_code(self, fg_color: str, bg_color: str) -> Iterable[str]:
+ """
+ Return a tuple with the vt100 values that represent this color.
+ """
+ # When requesting ANSI colors only, and both fg/bg color were converted
+ # to ANSI, ensure that the foreground and background color are not the
+ # same. (Unless they were explicitly defined to be the same color.)
+ fg_ansi = ""
+
+ def get(color: str, bg: bool) -> List[int]:
+ nonlocal fg_ansi
+
+ table = BG_ANSI_COLORS if bg else FG_ANSI_COLORS
+
+ if not color or self.color_depth == ColorDepth.DEPTH_1_BIT:
+ return []
+
+ # 16 ANSI colors. (Given by name.)
+ elif color in table:
+ return [table[color]]
+
+ # RGB colors. (Defined as 'ffffff'.)
+ else:
+ try:
+ rgb = self._color_name_to_rgb(color)
+ except ValueError:
+ return []
+
+ # When only 16 colors are supported, use that.
+ if self.color_depth == ColorDepth.DEPTH_4_BIT:
+ if bg: # Background.
+ if fg_color != bg_color:
+ exclude = [fg_ansi]
+ else:
+ exclude = []
+ code, name = _16_bg_colors.get_code(rgb, exclude=exclude)
+ return [code]
+ else: # Foreground.
+ code, name = _16_fg_colors.get_code(rgb)
+ fg_ansi = name
+ return [code]
+
+ # True colors. (Only when this feature is enabled.)
+ elif self.color_depth == ColorDepth.DEPTH_24_BIT:
+ r, g, b = rgb
+ return [(48 if bg else 38), 2, r, g, b]
+
+ # 256 RGB colors.
+ else:
+ return [(48 if bg else 38), 5, _256_colors[rgb]]
+
+ result: List[int] = []
+ result.extend(get(fg_color, False))
+ result.extend(get(bg_color, True))
+
+ return map(str, result)
+
+
+def _get_size(fileno: int) -> Tuple[int, int]:
+ """
+ Get the size of this pseudo terminal.
+
+ :param fileno: stdout.fileno()
+ :returns: A (rows, cols) tuple.
+ """
+ size = os.get_terminal_size(fileno)
+ return size.lines, size.columns
+
+
+class Vt100_Output(Output):
+ """
+ :param get_size: A callable which returns the `Size` of the output terminal.
+ :param stdout: Any object with has a `write` and `flush` method + an 'encoding' property.
+ :param term: The terminal environment variable. (xterm, xterm-256color, linux, ...)
+ :param write_binary: Encode the output before writing it. If `True` (the
+ default), the `stdout` object is supposed to expose an `encoding` attribute.
+ """
+
+ # For the error messages. Only display "Output is not a terminal" once per
+ # file descriptor.
+ _fds_not_a_terminal: Set[int] = set()
+
+ def __init__(
+ self,
+ stdout: TextIO,
+ get_size: Callable[[], Size],
+ term: Optional[str] = None,
+ write_binary: bool = True,
+ default_color_depth: Optional[ColorDepth] = None,
+ enable_bell: bool = True,
+ ) -> None:
+
+ assert all(hasattr(stdout, a) for a in ("write", "flush"))
+
+ if write_binary:
+ assert hasattr(stdout, "encoding")
+
+ self._buffer: List[str] = []
+ self.stdout: TextIO = stdout
+ self.write_binary = write_binary
+ self.default_color_depth = default_color_depth
+ self._get_size = get_size
+ self.term = term
+ self.enable_bell = enable_bell
+
+ # Cache for escape codes.
+ self._escape_code_caches: Dict[ColorDepth, _EscapeCodeCache] = {
+ ColorDepth.DEPTH_1_BIT: _EscapeCodeCache(ColorDepth.DEPTH_1_BIT),
+ ColorDepth.DEPTH_4_BIT: _EscapeCodeCache(ColorDepth.DEPTH_4_BIT),
+ ColorDepth.DEPTH_8_BIT: _EscapeCodeCache(ColorDepth.DEPTH_8_BIT),
+ ColorDepth.DEPTH_24_BIT: _EscapeCodeCache(ColorDepth.DEPTH_24_BIT),
+ }
+
# Keep track of whether the cursor shape was ever changed.
# (We don't restore the cursor shape if it was never changed - by
# default, we don't change them.)
self._cursor_shape_changed = False
- @classmethod
- def from_pty(
- cls,
- stdout: TextIO,
- term: Optional[str] = None,
- default_color_depth: Optional[ColorDepth] = None,
- enable_bell: bool = True,
- ) -> "Vt100_Output":
- """
- Create an Output class from a pseudo terminal.
- (This will take the dimensions by reading the pseudo
- terminal attributes.)
- """
- fd: Optional[int]
- # Normally, this requires a real TTY device, but people instantiate
- # this class often during unit tests as well. For convenience, we print
- # an error message, use standard dimensions, and go on.
- try:
- fd = stdout.fileno()
- except io.UnsupportedOperation:
- fd = None
-
- if not stdout.isatty() and (fd is None or fd not in cls._fds_not_a_terminal):
- msg = "Warning: Output is not a terminal (fd=%r).\n"
- sys.stderr.write(msg % fd)
- sys.stderr.flush()
- if fd is not None:
- cls._fds_not_a_terminal.add(fd)
-
- def get_size() -> Size:
- # If terminal (incorrectly) reports its size as 0, pick a
- # reasonable default. See
- # https://github.com/ipython/ipython/issues/10071
- rows, columns = (None, None)
-
- # It is possible that `stdout` is no longer a TTY device at this
- # point. In that case we get an `OSError` in the ioctl call in
- # `get_size`. See:
- # https://github.com/prompt-toolkit/python-prompt-toolkit/pull/1021
- try:
- rows, columns = _get_size(stdout.fileno())
- except OSError:
- pass
- return Size(rows=rows or 24, columns=columns or 80)
-
- return cls(
- stdout,
- get_size,
- term=term,
- default_color_depth=default_color_depth,
- enable_bell=enable_bell,
- )
-
- def get_size(self) -> Size:
- return self._get_size()
-
- def fileno(self) -> int:
- "Return file descriptor."
- return self.stdout.fileno()
-
- def encoding(self) -> str:
- "Return encoding used for stdout."
- return self.stdout.encoding
-
- def write_raw(self, data: str) -> None:
- """
- Write raw data to output.
- """
- self._buffer.append(data)
-
- def write(self, data: str) -> None:
- """
- Write text to output.
- (Removes vt100 escape codes. -- used for safely writing text.)
- """
- self._buffer.append(data.replace("\x1b", "?"))
-
- def set_title(self, title: str) -> None:
- """
- Set terminal title.
- """
- if self.term not in (
- "linux",
- "eterm-color",
- ): # Not supported by the Linux console.
- self.write_raw(
- "\x1b]2;%s\x07" % title.replace("\x1b", "").replace("\x07", "")
- )
-
- def clear_title(self) -> None:
- self.set_title("")
-
- def erase_screen(self) -> None:
- """
- Erases the screen with the background colour and moves the cursor to
- home.
- """
- self.write_raw("\x1b[2J")
-
- def enter_alternate_screen(self) -> None:
- self.write_raw("\x1b[?1049h\x1b[H")
-
- def quit_alternate_screen(self) -> None:
- self.write_raw("\x1b[?1049l")
-
- def enable_mouse_support(self) -> None:
- self.write_raw("\x1b[?1000h")
-
- # Enable mouse-drag support.
- self.write_raw("\x1b[?1003h")
-
- # Enable urxvt Mouse mode. (For terminals that understand this.)
- self.write_raw("\x1b[?1015h")
-
- # Also enable Xterm SGR mouse mode. (For terminals that understand this.)
- self.write_raw("\x1b[?1006h")
-
- # Note: E.g. lxterminal understands 1000h, but not the urxvt or sgr
- # extensions.
-
- def disable_mouse_support(self) -> None:
- self.write_raw("\x1b[?1000l")
- self.write_raw("\x1b[?1015l")
- self.write_raw("\x1b[?1006l")
- self.write_raw("\x1b[?1003l")
-
- def erase_end_of_line(self) -> None:
- """
- Erases from the current cursor position to the end of the current line.
- """
- self.write_raw("\x1b[K")
-
- def erase_down(self) -> None:
- """
- Erases the screen from the current line down to the bottom of the
- screen.
- """
- self.write_raw("\x1b[J")
-
- def reset_attributes(self) -> None:
- self.write_raw("\x1b[0m")
-
- def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
- """
- Create new style and output.
-
- :param attrs: `Attrs` instance.
- """
- # Get current depth.
- escape_code_cache = self._escape_code_caches[color_depth]
-
- # Write escape character.
- self.write_raw(escape_code_cache[attrs])
-
- def disable_autowrap(self) -> None:
- self.write_raw("\x1b[?7l")
-
- def enable_autowrap(self) -> None:
- self.write_raw("\x1b[?7h")
-
- def enable_bracketed_paste(self) -> None:
- self.write_raw("\x1b[?2004h")
-
- def disable_bracketed_paste(self) -> None:
- self.write_raw("\x1b[?2004l")
-
- def reset_cursor_key_mode(self) -> None:
- """
- For vt100 only.
- Put the terminal in cursor mode (instead of application mode).
- """
- # Put the terminal in cursor mode. (Instead of application mode.)
- self.write_raw("\x1b[?1l")
-
- def cursor_goto(self, row: int = 0, column: int = 0) -> None:
- """
- Move cursor position.
- """
- self.write_raw("\x1b[%i;%iH" % (row, column))
-
- def cursor_up(self, amount: int) -> None:
- if amount == 0:
- pass
- elif amount == 1:
- self.write_raw("\x1b[A")
- else:
- self.write_raw("\x1b[%iA" % amount)
-
- def cursor_down(self, amount: int) -> None:
- if amount == 0:
- pass
- elif amount == 1:
- # Note: Not the same as '\n', '\n' can cause the window content to
- # scroll.
- self.write_raw("\x1b[B")
- else:
- self.write_raw("\x1b[%iB" % amount)
-
- def cursor_forward(self, amount: int) -> None:
- if amount == 0:
- pass
- elif amount == 1:
- self.write_raw("\x1b[C")
- else:
- self.write_raw("\x1b[%iC" % amount)
-
- def cursor_backward(self, amount: int) -> None:
- if amount == 0:
- pass
- elif amount == 1:
- self.write_raw("\b") # '\x1b[D'
- else:
- self.write_raw("\x1b[%iD" % amount)
-
- def hide_cursor(self) -> None:
- self.write_raw("\x1b[?25l")
-
- def show_cursor(self) -> None:
- self.write_raw("\x1b[?12l\x1b[?25h") # Stop blinking cursor and show.
-
+ @classmethod
+ def from_pty(
+ cls,
+ stdout: TextIO,
+ term: Optional[str] = None,
+ default_color_depth: Optional[ColorDepth] = None,
+ enable_bell: bool = True,
+ ) -> "Vt100_Output":
+ """
+ Create an Output class from a pseudo terminal.
+ (This will take the dimensions by reading the pseudo
+ terminal attributes.)
+ """
+ fd: Optional[int]
+ # Normally, this requires a real TTY device, but people instantiate
+ # this class often during unit tests as well. For convenience, we print
+ # an error message, use standard dimensions, and go on.
+ try:
+ fd = stdout.fileno()
+ except io.UnsupportedOperation:
+ fd = None
+
+ if not stdout.isatty() and (fd is None or fd not in cls._fds_not_a_terminal):
+ msg = "Warning: Output is not a terminal (fd=%r).\n"
+ sys.stderr.write(msg % fd)
+ sys.stderr.flush()
+ if fd is not None:
+ cls._fds_not_a_terminal.add(fd)
+
+ def get_size() -> Size:
+ # If terminal (incorrectly) reports its size as 0, pick a
+ # reasonable default. See
+ # https://github.com/ipython/ipython/issues/10071
+ rows, columns = (None, None)
+
+ # It is possible that `stdout` is no longer a TTY device at this
+ # point. In that case we get an `OSError` in the ioctl call in
+ # `get_size`. See:
+ # https://github.com/prompt-toolkit/python-prompt-toolkit/pull/1021
+ try:
+ rows, columns = _get_size(stdout.fileno())
+ except OSError:
+ pass
+ return Size(rows=rows or 24, columns=columns or 80)
+
+ return cls(
+ stdout,
+ get_size,
+ term=term,
+ default_color_depth=default_color_depth,
+ enable_bell=enable_bell,
+ )
+
+ def get_size(self) -> Size:
+ return self._get_size()
+
+ def fileno(self) -> int:
+ "Return file descriptor."
+ return self.stdout.fileno()
+
+ def encoding(self) -> str:
+ "Return encoding used for stdout."
+ return self.stdout.encoding
+
+ def write_raw(self, data: str) -> None:
+ """
+ Write raw data to output.
+ """
+ self._buffer.append(data)
+
+ def write(self, data: str) -> None:
+ """
+ Write text to output.
+ (Removes vt100 escape codes. -- used for safely writing text.)
+ """
+ self._buffer.append(data.replace("\x1b", "?"))
+
+ def set_title(self, title: str) -> None:
+ """
+ Set terminal title.
+ """
+ if self.term not in (
+ "linux",
+ "eterm-color",
+ ): # Not supported by the Linux console.
+ self.write_raw(
+ "\x1b]2;%s\x07" % title.replace("\x1b", "").replace("\x07", "")
+ )
+
+ def clear_title(self) -> None:
+ self.set_title("")
+
+ def erase_screen(self) -> None:
+ """
+ Erases the screen with the background colour and moves the cursor to
+ home.
+ """
+ self.write_raw("\x1b[2J")
+
+ def enter_alternate_screen(self) -> None:
+ self.write_raw("\x1b[?1049h\x1b[H")
+
+ def quit_alternate_screen(self) -> None:
+ self.write_raw("\x1b[?1049l")
+
+ def enable_mouse_support(self) -> None:
+ self.write_raw("\x1b[?1000h")
+
+ # Enable mouse-drag support.
+ self.write_raw("\x1b[?1003h")
+
+ # Enable urxvt Mouse mode. (For terminals that understand this.)
+ self.write_raw("\x1b[?1015h")
+
+ # Also enable Xterm SGR mouse mode. (For terminals that understand this.)
+ self.write_raw("\x1b[?1006h")
+
+ # Note: E.g. lxterminal understands 1000h, but not the urxvt or sgr
+ # extensions.
+
+ def disable_mouse_support(self) -> None:
+ self.write_raw("\x1b[?1000l")
+ self.write_raw("\x1b[?1015l")
+ self.write_raw("\x1b[?1006l")
+ self.write_raw("\x1b[?1003l")
+
+ def erase_end_of_line(self) -> None:
+ """
+ Erases from the current cursor position to the end of the current line.
+ """
+ self.write_raw("\x1b[K")
+
+ def erase_down(self) -> None:
+ """
+ Erases the screen from the current line down to the bottom of the
+ screen.
+ """
+ self.write_raw("\x1b[J")
+
+ def reset_attributes(self) -> None:
+ self.write_raw("\x1b[0m")
+
+ def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
+ """
+ Create new style and output.
+
+ :param attrs: `Attrs` instance.
+ """
+ # Get current depth.
+ escape_code_cache = self._escape_code_caches[color_depth]
+
+ # Write escape character.
+ self.write_raw(escape_code_cache[attrs])
+
+ def disable_autowrap(self) -> None:
+ self.write_raw("\x1b[?7l")
+
+ def enable_autowrap(self) -> None:
+ self.write_raw("\x1b[?7h")
+
+ def enable_bracketed_paste(self) -> None:
+ self.write_raw("\x1b[?2004h")
+
+ def disable_bracketed_paste(self) -> None:
+ self.write_raw("\x1b[?2004l")
+
+ def reset_cursor_key_mode(self) -> None:
+ """
+ For vt100 only.
+ Put the terminal in cursor mode (instead of application mode).
+ """
+ # Put the terminal in cursor mode. (Instead of application mode.)
+ self.write_raw("\x1b[?1l")
+
+ def cursor_goto(self, row: int = 0, column: int = 0) -> None:
+ """
+ Move cursor position.
+ """
+ self.write_raw("\x1b[%i;%iH" % (row, column))
+
+ def cursor_up(self, amount: int) -> None:
+ if amount == 0:
+ pass
+ elif amount == 1:
+ self.write_raw("\x1b[A")
+ else:
+ self.write_raw("\x1b[%iA" % amount)
+
+ def cursor_down(self, amount: int) -> None:
+ if amount == 0:
+ pass
+ elif amount == 1:
+ # Note: Not the same as '\n', '\n' can cause the window content to
+ # scroll.
+ self.write_raw("\x1b[B")
+ else:
+ self.write_raw("\x1b[%iB" % amount)
+
+ def cursor_forward(self, amount: int) -> None:
+ if amount == 0:
+ pass
+ elif amount == 1:
+ self.write_raw("\x1b[C")
+ else:
+ self.write_raw("\x1b[%iC" % amount)
+
+ def cursor_backward(self, amount: int) -> None:
+ if amount == 0:
+ pass
+ elif amount == 1:
+ self.write_raw("\b") # '\x1b[D'
+ else:
+ self.write_raw("\x1b[%iD" % amount)
+
+ def hide_cursor(self) -> None:
+ self.write_raw("\x1b[?25l")
+
+ def show_cursor(self) -> None:
+ self.write_raw("\x1b[?12l\x1b[?25h") # Stop blinking cursor and show.
+
def set_cursor_shape(self, cursor_shape: CursorShape) -> None:
if cursor_shape == CursorShape._NEVER_CHANGE:
return
@@ -689,65 +689,65 @@ class Vt100_Output(Output):
# Reset cursor shape.
self.write_raw("\x1b[0 q")
- def flush(self) -> None:
- """
- Write to output stream and flush.
- """
- if not self._buffer:
- return
-
- data = "".join(self._buffer)
- self._buffer = []
-
+ def flush(self) -> None:
+ """
+ Write to output stream and flush.
+ """
+ if not self._buffer:
+ return
+
+ data = "".join(self._buffer)
+ self._buffer = []
+
flush_stdout(self.stdout, data, write_binary=self.write_binary)
-
- def ask_for_cpr(self) -> None:
- """
- Asks for a cursor position report (CPR).
- """
- self.write_raw("\x1b[6n")
- self.flush()
-
- @property
- def responds_to_cpr(self) -> bool:
- # When the input is a tty, we assume that CPR is supported.
- # It's not when the input is piped from Pexpect.
- if os.environ.get("PROMPT_TOOLKIT_NO_CPR", "") == "1":
- return False
-
- if is_dumb_terminal(self.term):
- return False
- try:
- return self.stdout.isatty()
- except ValueError:
- return False # ValueError: I/O operation on closed file
-
- def bell(self) -> None:
- "Sound bell."
- if self.enable_bell:
- self.write_raw("\a")
- self.flush()
-
- def get_default_color_depth(self) -> ColorDepth:
- """
- Return the default color depth for a vt100 terminal, according to the
- our term value.
-
- We prefer 256 colors almost always, because this is what most terminals
- support these days, and is a good default.
- """
- if self.default_color_depth is not None:
- return self.default_color_depth
-
- term = self.term
-
- if term is None:
- return ColorDepth.DEFAULT
-
- if is_dumb_terminal(term):
- return ColorDepth.DEPTH_1_BIT
-
- if term in ("linux", "eterm-color"):
- return ColorDepth.DEPTH_4_BIT
-
- return ColorDepth.DEFAULT
+
+ def ask_for_cpr(self) -> None:
+ """
+ Asks for a cursor position report (CPR).
+ """
+ self.write_raw("\x1b[6n")
+ self.flush()
+
+ @property
+ def responds_to_cpr(self) -> bool:
+ # When the input is a tty, we assume that CPR is supported.
+ # It's not when the input is piped from Pexpect.
+ if os.environ.get("PROMPT_TOOLKIT_NO_CPR", "") == "1":
+ return False
+
+ if is_dumb_terminal(self.term):
+ return False
+ try:
+ return self.stdout.isatty()
+ except ValueError:
+ return False # ValueError: I/O operation on closed file
+
+ def bell(self) -> None:
+ "Sound bell."
+ if self.enable_bell:
+ self.write_raw("\a")
+ self.flush()
+
+ def get_default_color_depth(self) -> ColorDepth:
+ """
+ Return the default color depth for a vt100 terminal, according to the
+ our term value.
+
+ We prefer 256 colors almost always, because this is what most terminals
+ support these days, and is a good default.
+ """
+ if self.default_color_depth is not None:
+ return self.default_color_depth
+
+ term = self.term
+
+ if term is None:
+ return ColorDepth.DEFAULT
+
+ if is_dumb_terminal(term):
+ return ColorDepth.DEPTH_1_BIT
+
+ if term in ("linux", "eterm-color"):
+ return ColorDepth.DEPTH_4_BIT
+
+ return ColorDepth.DEFAULT
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/win32.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/win32.py
index ca55bfdc6f6..abfd61774be 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/win32.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/win32.py
@@ -1,685 +1,685 @@
-import os
+import os
from ctypes import ArgumentError, byref, c_char, c_long, c_uint, c_ulong, pointer
-
-from ..utils import SPHINX_AUTODOC_RUNNING
-
-# Do not import win32-specific stuff when generating documentation.
-# Otherwise RTD would be unable to generate docs for this module.
-if not SPHINX_AUTODOC_RUNNING:
- from ctypes import windll
-
-from ctypes.wintypes import DWORD, HANDLE
-from typing import Callable, Dict, List, Optional, TextIO, Tuple, Type, TypeVar, Union
-
+
+from ..utils import SPHINX_AUTODOC_RUNNING
+
+# Do not import win32-specific stuff when generating documentation.
+# Otherwise RTD would be unable to generate docs for this module.
+if not SPHINX_AUTODOC_RUNNING:
+ from ctypes import windll
+
+from ctypes.wintypes import DWORD, HANDLE
+from typing import Callable, Dict, List, Optional, TextIO, Tuple, Type, TypeVar, Union
+
from prompt_toolkit.cursor_shapes import CursorShape
-from prompt_toolkit.data_structures import Size
-from prompt_toolkit.styles import ANSI_COLOR_NAMES, Attrs
-from prompt_toolkit.utils import get_cwidth
-from prompt_toolkit.win32_types import (
- CONSOLE_SCREEN_BUFFER_INFO,
- COORD,
- SMALL_RECT,
- STD_INPUT_HANDLE,
- STD_OUTPUT_HANDLE,
-)
-
-from .base import Output
-from .color_depth import ColorDepth
-
-__all__ = [
- "Win32Output",
-]
-
-
-def _coord_byval(coord: COORD) -> c_long:
- """
- Turns a COORD object into a c_long.
- This will cause it to be passed by value instead of by reference. (That is what I think at least.)
-
- When running ``ptipython`` is run (only with IPython), we often got the following error::
-
- Error in 'SetConsoleCursorPosition'.
- ArgumentError("argument 2: <class 'TypeError'>: wrong type",)
- argument 2: <class 'TypeError'>: wrong type
-
- It was solved by turning ``COORD`` parameters into a ``c_long`` like this.
-
- More info: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx
- """
- return c_long(coord.Y * 0x10000 | coord.X & 0xFFFF)
-
-
-#: If True: write the output of the renderer also to the following file. This
-#: is very useful for debugging. (e.g.: to see that we don't write more bytes
-#: than required.)
-_DEBUG_RENDER_OUTPUT = False
-_DEBUG_RENDER_OUTPUT_FILENAME = r"prompt-toolkit-windows-output.log"
-
-
-class NoConsoleScreenBufferError(Exception):
- """
- Raised when the application is not running inside a Windows Console, but
- the user tries to instantiate Win32Output.
- """
-
- def __init__(self) -> None:
- # Are we running in 'xterm' on Windows, like git-bash for instance?
- xterm = "xterm" in os.environ.get("TERM", "")
-
- if xterm:
- message = (
- "Found %s, while expecting a Windows console. "
- 'Maybe try to run this program using "winpty" '
- "or run it in cmd.exe instead. Or otherwise, "
- "in case of Cygwin, use the Python executable "
- "that is compiled for Cygwin." % os.environ["TERM"]
- )
- else:
- message = "No Windows console found. Are you running cmd.exe?"
- super().__init__(message)
-
-
-_T = TypeVar("_T")
-
-
-class Win32Output(Output):
- """
- I/O abstraction for rendering to Windows consoles.
- (cmd.exe and similar.)
- """
-
- def __init__(
- self,
- stdout: TextIO,
- use_complete_width: bool = False,
- default_color_depth: Optional[ColorDepth] = None,
- ) -> None:
- self.use_complete_width = use_complete_width
- self.default_color_depth = default_color_depth
-
- self._buffer: List[str] = []
- self.stdout: TextIO = stdout
- self.hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
-
- self._in_alternate_screen = False
- self._hidden = False
-
- self.color_lookup_table = ColorLookupTable()
-
- # Remember the default console colors.
- info = self.get_win32_screen_buffer_info()
- self.default_attrs = info.wAttributes if info else 15
-
- if _DEBUG_RENDER_OUTPUT:
- self.LOG = open(_DEBUG_RENDER_OUTPUT_FILENAME, "ab")
-
- def fileno(self) -> int:
- "Return file descriptor."
- return self.stdout.fileno()
-
- def encoding(self) -> str:
- "Return encoding used for stdout."
- return self.stdout.encoding
-
- def write(self, data: str) -> None:
- if self._hidden:
- data = " " * get_cwidth(data)
-
- self._buffer.append(data)
-
- def write_raw(self, data: str) -> None:
- "For win32, there is no difference between write and write_raw."
- self.write(data)
-
- def get_size(self) -> Size:
- info = self.get_win32_screen_buffer_info()
-
- # We take the width of the *visible* region as the size. Not the width
- # of the complete screen buffer. (Unless use_complete_width has been
- # set.)
- if self.use_complete_width:
- width = info.dwSize.X
- else:
- width = info.srWindow.Right - info.srWindow.Left
-
- height = info.srWindow.Bottom - info.srWindow.Top + 1
-
- # We avoid the right margin, windows will wrap otherwise.
- maxwidth = info.dwSize.X - 1
- width = min(maxwidth, width)
-
- # Create `Size` object.
- return Size(rows=height, columns=width)
-
- def _winapi(self, func: Callable[..., _T], *a: object, **kw: object) -> _T:
- """
- Flush and call win API function.
- """
- self.flush()
-
- if _DEBUG_RENDER_OUTPUT:
- self.LOG.write(("%r" % func.__name__).encode("utf-8") + b"\n")
- self.LOG.write(
- b" " + ", ".join(["%r" % i for i in a]).encode("utf-8") + b"\n"
- )
- self.LOG.write(
- b" "
- + ", ".join(["%r" % type(i) for i in a]).encode("utf-8")
- + b"\n"
- )
- self.LOG.flush()
-
- try:
- return func(*a, **kw)
- except ArgumentError as e:
- if _DEBUG_RENDER_OUTPUT:
- self.LOG.write(
- (" Error in %r %r %s\n" % (func.__name__, e, e)).encode("utf-8")
- )
-
- raise
-
- def get_win32_screen_buffer_info(self) -> CONSOLE_SCREEN_BUFFER_INFO:
- """
- Return Screen buffer info.
- """
- # NOTE: We don't call the `GetConsoleScreenBufferInfo` API through
- # `self._winapi`. Doing so causes Python to crash on certain 64bit
- # Python versions. (Reproduced with 64bit Python 2.7.6, on Windows
- # 10). It is not clear why. Possibly, it has to do with passing
- # these objects as an argument, or through *args.
-
- # The Python documentation contains the following - possibly related - warning:
- # ctypes does not support passing unions or structures with
- # bit-fields to functions by value. While this may work on 32-bit
- # x86, it's not guaranteed by the library to work in the general
- # case. Unions and structures with bit-fields should always be
- # passed to functions by pointer.
-
- # Also see:
- # - https://github.com/ipython/ipython/issues/10070
- # - https://github.com/jonathanslenders/python-prompt-toolkit/issues/406
- # - https://github.com/jonathanslenders/python-prompt-toolkit/issues/86
-
- self.flush()
- sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
- success = windll.kernel32.GetConsoleScreenBufferInfo(
- self.hconsole, byref(sbinfo)
- )
-
- # success = self._winapi(windll.kernel32.GetConsoleScreenBufferInfo,
- # self.hconsole, byref(sbinfo))
-
- if success:
- return sbinfo
- else:
- raise NoConsoleScreenBufferError
-
- def set_title(self, title: str) -> None:
- """
- Set terminal title.
- """
- self._winapi(windll.kernel32.SetConsoleTitleW, title)
-
- def clear_title(self) -> None:
- self._winapi(windll.kernel32.SetConsoleTitleW, "")
-
- def erase_screen(self) -> None:
- start = COORD(0, 0)
- sbinfo = self.get_win32_screen_buffer_info()
- length = sbinfo.dwSize.X * sbinfo.dwSize.Y
-
- self.cursor_goto(row=0, column=0)
- self._erase(start, length)
-
- def erase_down(self) -> None:
- sbinfo = self.get_win32_screen_buffer_info()
- size = sbinfo.dwSize
-
- start = sbinfo.dwCursorPosition
- length = (size.X - size.X) + size.X * (size.Y - sbinfo.dwCursorPosition.Y)
-
- self._erase(start, length)
-
- def erase_end_of_line(self) -> None:
- """"""
- sbinfo = self.get_win32_screen_buffer_info()
- start = sbinfo.dwCursorPosition
- length = sbinfo.dwSize.X - sbinfo.dwCursorPosition.X
-
- self._erase(start, length)
-
- def _erase(self, start: COORD, length: int) -> None:
- chars_written = c_ulong()
-
- self._winapi(
- windll.kernel32.FillConsoleOutputCharacterA,
- self.hconsole,
- c_char(b" "),
- DWORD(length),
- _coord_byval(start),
- byref(chars_written),
- )
-
- # Reset attributes.
- sbinfo = self.get_win32_screen_buffer_info()
- self._winapi(
- windll.kernel32.FillConsoleOutputAttribute,
- self.hconsole,
- sbinfo.wAttributes,
- length,
- _coord_byval(start),
- byref(chars_written),
- )
-
- def reset_attributes(self) -> None:
- "Reset the console foreground/background color."
- self._winapi(
- windll.kernel32.SetConsoleTextAttribute, self.hconsole, self.default_attrs
- )
- self._hidden = False
-
- def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
- (
- fgcolor,
- bgcolor,
- bold,
- underline,
- strike,
- italic,
- blink,
- reverse,
- hidden,
- ) = attrs
- self._hidden = bool(hidden)
-
- # Start from the default attributes.
- win_attrs: int = self.default_attrs
-
- if color_depth != ColorDepth.DEPTH_1_BIT:
- # Override the last four bits: foreground color.
- if fgcolor:
- win_attrs = win_attrs & ~0xF
- win_attrs |= self.color_lookup_table.lookup_fg_color(fgcolor)
-
- # Override the next four bits: background color.
- if bgcolor:
- win_attrs = win_attrs & ~0xF0
- win_attrs |= self.color_lookup_table.lookup_bg_color(bgcolor)
-
- # Reverse: swap these four bits groups.
- if reverse:
- win_attrs = (
- (win_attrs & ~0xFF)
- | ((win_attrs & 0xF) << 4)
- | ((win_attrs & 0xF0) >> 4)
- )
-
- self._winapi(windll.kernel32.SetConsoleTextAttribute, self.hconsole, win_attrs)
-
- def disable_autowrap(self) -> None:
- # Not supported by Windows.
- pass
-
- def enable_autowrap(self) -> None:
- # Not supported by Windows.
- pass
-
- def cursor_goto(self, row: int = 0, column: int = 0) -> None:
- pos = COORD(X=column, Y=row)
- self._winapi(
- windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)
- )
-
- def cursor_up(self, amount: int) -> None:
- sr = self.get_win32_screen_buffer_info().dwCursorPosition
- pos = COORD(X=sr.X, Y=sr.Y - amount)
- self._winapi(
- windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)
- )
-
- def cursor_down(self, amount: int) -> None:
- self.cursor_up(-amount)
-
- def cursor_forward(self, amount: int) -> None:
- sr = self.get_win32_screen_buffer_info().dwCursorPosition
- # assert sr.X + amount >= 0, 'Negative cursor position: x=%r amount=%r' % (sr.X, amount)
-
- pos = COORD(X=max(0, sr.X + amount), Y=sr.Y)
- self._winapi(
- windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)
- )
-
- def cursor_backward(self, amount: int) -> None:
- self.cursor_forward(-amount)
-
- def flush(self) -> None:
- """
- Write to output stream and flush.
- """
- if not self._buffer:
- # Only flush stdout buffer. (It could be that Python still has
- # something in its buffer. -- We want to be sure to print that in
- # the correct color.)
- self.stdout.flush()
- return
-
- data = "".join(self._buffer)
-
- if _DEBUG_RENDER_OUTPUT:
- self.LOG.write(("%r" % data).encode("utf-8") + b"\n")
- self.LOG.flush()
-
- # Print characters one by one. This appears to be the best solution
- # in oder to avoid traces of vertical lines when the completion
- # menu disappears.
- for b in data:
- written = DWORD()
-
- retval = windll.kernel32.WriteConsoleW(
- self.hconsole, b, 1, byref(written), None
- )
- assert retval != 0
-
- self._buffer = []
-
- def get_rows_below_cursor_position(self) -> int:
- info = self.get_win32_screen_buffer_info()
- return info.srWindow.Bottom - info.dwCursorPosition.Y + 1
-
- def scroll_buffer_to_prompt(self) -> None:
- """
- To be called before drawing the prompt. This should scroll the console
- to left, with the cursor at the bottom (if possible).
- """
- # Get current window size
- info = self.get_win32_screen_buffer_info()
- sr = info.srWindow
- cursor_pos = info.dwCursorPosition
-
- result = SMALL_RECT()
-
- # Scroll to the left.
- result.Left = 0
- result.Right = sr.Right - sr.Left
-
- # Scroll vertical
- win_height = sr.Bottom - sr.Top
- if 0 < sr.Bottom - cursor_pos.Y < win_height - 1:
- # no vertical scroll if cursor already on the screen
- result.Bottom = sr.Bottom
- else:
- result.Bottom = max(win_height, cursor_pos.Y)
- result.Top = result.Bottom - win_height
-
- # Scroll API
- self._winapi(
- windll.kernel32.SetConsoleWindowInfo, self.hconsole, True, byref(result)
- )
-
- def enter_alternate_screen(self) -> None:
- """
- Go to alternate screen buffer.
- """
- if not self._in_alternate_screen:
- GENERIC_READ = 0x80000000
- GENERIC_WRITE = 0x40000000
-
- # Create a new console buffer and activate that one.
- handle = HANDLE(
- self._winapi(
- windll.kernel32.CreateConsoleScreenBuffer,
- GENERIC_READ | GENERIC_WRITE,
- DWORD(0),
- None,
- DWORD(1),
- None,
- )
- )
-
- self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, handle)
- self.hconsole = handle
- self._in_alternate_screen = True
-
- def quit_alternate_screen(self) -> None:
- """
- Make stdout again the active buffer.
- """
- if self._in_alternate_screen:
- stdout = HANDLE(
- self._winapi(windll.kernel32.GetStdHandle, STD_OUTPUT_HANDLE)
- )
- self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, stdout)
- self._winapi(windll.kernel32.CloseHandle, self.hconsole)
- self.hconsole = stdout
- self._in_alternate_screen = False
-
- def enable_mouse_support(self) -> None:
- ENABLE_MOUSE_INPUT = 0x10
-
- # This `ENABLE_QUICK_EDIT_MODE` flag needs to be cleared for mouse
- # support to work, but it's possible that it was already cleared
- # before.
- ENABLE_QUICK_EDIT_MODE = 0x0040
-
- handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
-
- original_mode = DWORD()
- self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
- self._winapi(
- windll.kernel32.SetConsoleMode,
- handle,
- (original_mode.value | ENABLE_MOUSE_INPUT) & ~ENABLE_QUICK_EDIT_MODE,
- )
-
- def disable_mouse_support(self) -> None:
- ENABLE_MOUSE_INPUT = 0x10
- handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
-
- original_mode = DWORD()
- self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
- self._winapi(
- windll.kernel32.SetConsoleMode,
- handle,
- original_mode.value & ~ENABLE_MOUSE_INPUT,
- )
-
- def hide_cursor(self) -> None:
- pass
-
- def show_cursor(self) -> None:
- pass
-
+from prompt_toolkit.data_structures import Size
+from prompt_toolkit.styles import ANSI_COLOR_NAMES, Attrs
+from prompt_toolkit.utils import get_cwidth
+from prompt_toolkit.win32_types import (
+ CONSOLE_SCREEN_BUFFER_INFO,
+ COORD,
+ SMALL_RECT,
+ STD_INPUT_HANDLE,
+ STD_OUTPUT_HANDLE,
+)
+
+from .base import Output
+from .color_depth import ColorDepth
+
+__all__ = [
+ "Win32Output",
+]
+
+
+def _coord_byval(coord: COORD) -> c_long:
+ """
+ Turns a COORD object into a c_long.
+ This will cause it to be passed by value instead of by reference. (That is what I think at least.)
+
+ When running ``ptipython`` is run (only with IPython), we often got the following error::
+
+ Error in 'SetConsoleCursorPosition'.
+ ArgumentError("argument 2: <class 'TypeError'>: wrong type",)
+ argument 2: <class 'TypeError'>: wrong type
+
+ It was solved by turning ``COORD`` parameters into a ``c_long`` like this.
+
+ More info: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx
+ """
+ return c_long(coord.Y * 0x10000 | coord.X & 0xFFFF)
+
+
+#: If True: write the output of the renderer also to the following file. This
+#: is very useful for debugging. (e.g.: to see that we don't write more bytes
+#: than required.)
+_DEBUG_RENDER_OUTPUT = False
+_DEBUG_RENDER_OUTPUT_FILENAME = r"prompt-toolkit-windows-output.log"
+
+
+class NoConsoleScreenBufferError(Exception):
+ """
+ Raised when the application is not running inside a Windows Console, but
+ the user tries to instantiate Win32Output.
+ """
+
+ def __init__(self) -> None:
+ # Are we running in 'xterm' on Windows, like git-bash for instance?
+ xterm = "xterm" in os.environ.get("TERM", "")
+
+ if xterm:
+ message = (
+ "Found %s, while expecting a Windows console. "
+ 'Maybe try to run this program using "winpty" '
+ "or run it in cmd.exe instead. Or otherwise, "
+ "in case of Cygwin, use the Python executable "
+ "that is compiled for Cygwin." % os.environ["TERM"]
+ )
+ else:
+ message = "No Windows console found. Are you running cmd.exe?"
+ super().__init__(message)
+
+
+_T = TypeVar("_T")
+
+
+class Win32Output(Output):
+ """
+ I/O abstraction for rendering to Windows consoles.
+ (cmd.exe and similar.)
+ """
+
+ def __init__(
+ self,
+ stdout: TextIO,
+ use_complete_width: bool = False,
+ default_color_depth: Optional[ColorDepth] = None,
+ ) -> None:
+ self.use_complete_width = use_complete_width
+ self.default_color_depth = default_color_depth
+
+ self._buffer: List[str] = []
+ self.stdout: TextIO = stdout
+ self.hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
+
+ self._in_alternate_screen = False
+ self._hidden = False
+
+ self.color_lookup_table = ColorLookupTable()
+
+ # Remember the default console colors.
+ info = self.get_win32_screen_buffer_info()
+ self.default_attrs = info.wAttributes if info else 15
+
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG = open(_DEBUG_RENDER_OUTPUT_FILENAME, "ab")
+
+ def fileno(self) -> int:
+ "Return file descriptor."
+ return self.stdout.fileno()
+
+ def encoding(self) -> str:
+ "Return encoding used for stdout."
+ return self.stdout.encoding
+
+ def write(self, data: str) -> None:
+ if self._hidden:
+ data = " " * get_cwidth(data)
+
+ self._buffer.append(data)
+
+ def write_raw(self, data: str) -> None:
+ "For win32, there is no difference between write and write_raw."
+ self.write(data)
+
+ def get_size(self) -> Size:
+ info = self.get_win32_screen_buffer_info()
+
+ # We take the width of the *visible* region as the size. Not the width
+ # of the complete screen buffer. (Unless use_complete_width has been
+ # set.)
+ if self.use_complete_width:
+ width = info.dwSize.X
+ else:
+ width = info.srWindow.Right - info.srWindow.Left
+
+ height = info.srWindow.Bottom - info.srWindow.Top + 1
+
+ # We avoid the right margin, windows will wrap otherwise.
+ maxwidth = info.dwSize.X - 1
+ width = min(maxwidth, width)
+
+ # Create `Size` object.
+ return Size(rows=height, columns=width)
+
+ def _winapi(self, func: Callable[..., _T], *a: object, **kw: object) -> _T:
+ """
+ Flush and call win API function.
+ """
+ self.flush()
+
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG.write(("%r" % func.__name__).encode("utf-8") + b"\n")
+ self.LOG.write(
+ b" " + ", ".join(["%r" % i for i in a]).encode("utf-8") + b"\n"
+ )
+ self.LOG.write(
+ b" "
+ + ", ".join(["%r" % type(i) for i in a]).encode("utf-8")
+ + b"\n"
+ )
+ self.LOG.flush()
+
+ try:
+ return func(*a, **kw)
+ except ArgumentError as e:
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG.write(
+ (" Error in %r %r %s\n" % (func.__name__, e, e)).encode("utf-8")
+ )
+
+ raise
+
+ def get_win32_screen_buffer_info(self) -> CONSOLE_SCREEN_BUFFER_INFO:
+ """
+ Return Screen buffer info.
+ """
+ # NOTE: We don't call the `GetConsoleScreenBufferInfo` API through
+ # `self._winapi`. Doing so causes Python to crash on certain 64bit
+ # Python versions. (Reproduced with 64bit Python 2.7.6, on Windows
+ # 10). It is not clear why. Possibly, it has to do with passing
+ # these objects as an argument, or through *args.
+
+ # The Python documentation contains the following - possibly related - warning:
+ # ctypes does not support passing unions or structures with
+ # bit-fields to functions by value. While this may work on 32-bit
+ # x86, it's not guaranteed by the library to work in the general
+ # case. Unions and structures with bit-fields should always be
+ # passed to functions by pointer.
+
+ # Also see:
+ # - https://github.com/ipython/ipython/issues/10070
+ # - https://github.com/jonathanslenders/python-prompt-toolkit/issues/406
+ # - https://github.com/jonathanslenders/python-prompt-toolkit/issues/86
+
+ self.flush()
+ sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
+ success = windll.kernel32.GetConsoleScreenBufferInfo(
+ self.hconsole, byref(sbinfo)
+ )
+
+ # success = self._winapi(windll.kernel32.GetConsoleScreenBufferInfo,
+ # self.hconsole, byref(sbinfo))
+
+ if success:
+ return sbinfo
+ else:
+ raise NoConsoleScreenBufferError
+
+ def set_title(self, title: str) -> None:
+ """
+ Set terminal title.
+ """
+ self._winapi(windll.kernel32.SetConsoleTitleW, title)
+
+ def clear_title(self) -> None:
+ self._winapi(windll.kernel32.SetConsoleTitleW, "")
+
+ def erase_screen(self) -> None:
+ start = COORD(0, 0)
+ sbinfo = self.get_win32_screen_buffer_info()
+ length = sbinfo.dwSize.X * sbinfo.dwSize.Y
+
+ self.cursor_goto(row=0, column=0)
+ self._erase(start, length)
+
+ def erase_down(self) -> None:
+ sbinfo = self.get_win32_screen_buffer_info()
+ size = sbinfo.dwSize
+
+ start = sbinfo.dwCursorPosition
+ length = (size.X - size.X) + size.X * (size.Y - sbinfo.dwCursorPosition.Y)
+
+ self._erase(start, length)
+
+ def erase_end_of_line(self) -> None:
+ """"""
+ sbinfo = self.get_win32_screen_buffer_info()
+ start = sbinfo.dwCursorPosition
+ length = sbinfo.dwSize.X - sbinfo.dwCursorPosition.X
+
+ self._erase(start, length)
+
+ def _erase(self, start: COORD, length: int) -> None:
+ chars_written = c_ulong()
+
+ self._winapi(
+ windll.kernel32.FillConsoleOutputCharacterA,
+ self.hconsole,
+ c_char(b" "),
+ DWORD(length),
+ _coord_byval(start),
+ byref(chars_written),
+ )
+
+ # Reset attributes.
+ sbinfo = self.get_win32_screen_buffer_info()
+ self._winapi(
+ windll.kernel32.FillConsoleOutputAttribute,
+ self.hconsole,
+ sbinfo.wAttributes,
+ length,
+ _coord_byval(start),
+ byref(chars_written),
+ )
+
+ def reset_attributes(self) -> None:
+ "Reset the console foreground/background color."
+ self._winapi(
+ windll.kernel32.SetConsoleTextAttribute, self.hconsole, self.default_attrs
+ )
+ self._hidden = False
+
+ def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
+ (
+ fgcolor,
+ bgcolor,
+ bold,
+ underline,
+ strike,
+ italic,
+ blink,
+ reverse,
+ hidden,
+ ) = attrs
+ self._hidden = bool(hidden)
+
+ # Start from the default attributes.
+ win_attrs: int = self.default_attrs
+
+ if color_depth != ColorDepth.DEPTH_1_BIT:
+ # Override the last four bits: foreground color.
+ if fgcolor:
+ win_attrs = win_attrs & ~0xF
+ win_attrs |= self.color_lookup_table.lookup_fg_color(fgcolor)
+
+ # Override the next four bits: background color.
+ if bgcolor:
+ win_attrs = win_attrs & ~0xF0
+ win_attrs |= self.color_lookup_table.lookup_bg_color(bgcolor)
+
+ # Reverse: swap these four bits groups.
+ if reverse:
+ win_attrs = (
+ (win_attrs & ~0xFF)
+ | ((win_attrs & 0xF) << 4)
+ | ((win_attrs & 0xF0) >> 4)
+ )
+
+ self._winapi(windll.kernel32.SetConsoleTextAttribute, self.hconsole, win_attrs)
+
+ def disable_autowrap(self) -> None:
+ # Not supported by Windows.
+ pass
+
+ def enable_autowrap(self) -> None:
+ # Not supported by Windows.
+ pass
+
+ def cursor_goto(self, row: int = 0, column: int = 0) -> None:
+ pos = COORD(X=column, Y=row)
+ self._winapi(
+ windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)
+ )
+
+ def cursor_up(self, amount: int) -> None:
+ sr = self.get_win32_screen_buffer_info().dwCursorPosition
+ pos = COORD(X=sr.X, Y=sr.Y - amount)
+ self._winapi(
+ windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)
+ )
+
+ def cursor_down(self, amount: int) -> None:
+ self.cursor_up(-amount)
+
+ def cursor_forward(self, amount: int) -> None:
+ sr = self.get_win32_screen_buffer_info().dwCursorPosition
+ # assert sr.X + amount >= 0, 'Negative cursor position: x=%r amount=%r' % (sr.X, amount)
+
+ pos = COORD(X=max(0, sr.X + amount), Y=sr.Y)
+ self._winapi(
+ windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos)
+ )
+
+ def cursor_backward(self, amount: int) -> None:
+ self.cursor_forward(-amount)
+
+ def flush(self) -> None:
+ """
+ Write to output stream and flush.
+ """
+ if not self._buffer:
+ # Only flush stdout buffer. (It could be that Python still has
+ # something in its buffer. -- We want to be sure to print that in
+ # the correct color.)
+ self.stdout.flush()
+ return
+
+ data = "".join(self._buffer)
+
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG.write(("%r" % data).encode("utf-8") + b"\n")
+ self.LOG.flush()
+
+ # Print characters one by one. This appears to be the best solution
+ # in oder to avoid traces of vertical lines when the completion
+ # menu disappears.
+ for b in data:
+ written = DWORD()
+
+ retval = windll.kernel32.WriteConsoleW(
+ self.hconsole, b, 1, byref(written), None
+ )
+ assert retval != 0
+
+ self._buffer = []
+
+ def get_rows_below_cursor_position(self) -> int:
+ info = self.get_win32_screen_buffer_info()
+ return info.srWindow.Bottom - info.dwCursorPosition.Y + 1
+
+ def scroll_buffer_to_prompt(self) -> None:
+ """
+ To be called before drawing the prompt. This should scroll the console
+ to left, with the cursor at the bottom (if possible).
+ """
+ # Get current window size
+ info = self.get_win32_screen_buffer_info()
+ sr = info.srWindow
+ cursor_pos = info.dwCursorPosition
+
+ result = SMALL_RECT()
+
+ # Scroll to the left.
+ result.Left = 0
+ result.Right = sr.Right - sr.Left
+
+ # Scroll vertical
+ win_height = sr.Bottom - sr.Top
+ if 0 < sr.Bottom - cursor_pos.Y < win_height - 1:
+ # no vertical scroll if cursor already on the screen
+ result.Bottom = sr.Bottom
+ else:
+ result.Bottom = max(win_height, cursor_pos.Y)
+ result.Top = result.Bottom - win_height
+
+ # Scroll API
+ self._winapi(
+ windll.kernel32.SetConsoleWindowInfo, self.hconsole, True, byref(result)
+ )
+
+ def enter_alternate_screen(self) -> None:
+ """
+ Go to alternate screen buffer.
+ """
+ if not self._in_alternate_screen:
+ GENERIC_READ = 0x80000000
+ GENERIC_WRITE = 0x40000000
+
+ # Create a new console buffer and activate that one.
+ handle = HANDLE(
+ self._winapi(
+ windll.kernel32.CreateConsoleScreenBuffer,
+ GENERIC_READ | GENERIC_WRITE,
+ DWORD(0),
+ None,
+ DWORD(1),
+ None,
+ )
+ )
+
+ self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, handle)
+ self.hconsole = handle
+ self._in_alternate_screen = True
+
+ def quit_alternate_screen(self) -> None:
+ """
+ Make stdout again the active buffer.
+ """
+ if self._in_alternate_screen:
+ stdout = HANDLE(
+ self._winapi(windll.kernel32.GetStdHandle, STD_OUTPUT_HANDLE)
+ )
+ self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, stdout)
+ self._winapi(windll.kernel32.CloseHandle, self.hconsole)
+ self.hconsole = stdout
+ self._in_alternate_screen = False
+
+ def enable_mouse_support(self) -> None:
+ ENABLE_MOUSE_INPUT = 0x10
+
+ # This `ENABLE_QUICK_EDIT_MODE` flag needs to be cleared for mouse
+ # support to work, but it's possible that it was already cleared
+ # before.
+ ENABLE_QUICK_EDIT_MODE = 0x0040
+
+ handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
+
+ original_mode = DWORD()
+ self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
+ self._winapi(
+ windll.kernel32.SetConsoleMode,
+ handle,
+ (original_mode.value | ENABLE_MOUSE_INPUT) & ~ENABLE_QUICK_EDIT_MODE,
+ )
+
+ def disable_mouse_support(self) -> None:
+ ENABLE_MOUSE_INPUT = 0x10
+ handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
+
+ original_mode = DWORD()
+ self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
+ self._winapi(
+ windll.kernel32.SetConsoleMode,
+ handle,
+ original_mode.value & ~ENABLE_MOUSE_INPUT,
+ )
+
+ def hide_cursor(self) -> None:
+ pass
+
+ def show_cursor(self) -> None:
+ pass
+
def set_cursor_shape(self, cursor_shape: CursorShape) -> None:
pass
def reset_cursor_shape(self) -> None:
pass
- @classmethod
- def win32_refresh_window(cls) -> None:
- """
- Call win32 API to refresh the whole Window.
-
- This is sometimes necessary when the application paints background
- for completion menus. When the menu disappears, it leaves traces due
- to a bug in the Windows Console. Sending a repaint request solves it.
- """
- # Get console handle
- handle = HANDLE(windll.kernel32.GetConsoleWindow())
-
- RDW_INVALIDATE = 0x0001
- windll.user32.RedrawWindow(handle, None, None, c_uint(RDW_INVALIDATE))
-
- def get_default_color_depth(self) -> ColorDepth:
- """
- Return the default color depth for a windows terminal.
-
- Contrary to the Vt100 implementation, this doesn't depend on a $TERM
- variable.
- """
- if self.default_color_depth is not None:
- return self.default_color_depth
-
- # For now, by default, always use 4 bit color on Windows 10 by default,
- # even when vt100 escape sequences with
- # ENABLE_VIRTUAL_TERMINAL_PROCESSING are supported. We don't have a
- # reliable way yet to know whether our console supports true color or
- # only 4-bit.
- return ColorDepth.DEPTH_4_BIT
-
-
-class FOREGROUND_COLOR:
- BLACK = 0x0000
- BLUE = 0x0001
- GREEN = 0x0002
- CYAN = 0x0003
- RED = 0x0004
- MAGENTA = 0x0005
- YELLOW = 0x0006
- GRAY = 0x0007
- INTENSITY = 0x0008 # Foreground color is intensified.
-
-
-class BACKGROUND_COLOR:
- BLACK = 0x0000
- BLUE = 0x0010
- GREEN = 0x0020
- CYAN = 0x0030
- RED = 0x0040
- MAGENTA = 0x0050
- YELLOW = 0x0060
- GRAY = 0x0070
- INTENSITY = 0x0080 # Background color is intensified.
-
-
-def _create_ansi_color_dict(
- color_cls: Union[Type[FOREGROUND_COLOR], Type[BACKGROUND_COLOR]]
-) -> Dict[str, int]:
- "Create a table that maps the 16 named ansi colors to their Windows code."
- return {
- "ansidefault": color_cls.BLACK,
- "ansiblack": color_cls.BLACK,
- "ansigray": color_cls.GRAY,
- "ansibrightblack": color_cls.BLACK | color_cls.INTENSITY,
- "ansiwhite": color_cls.GRAY | color_cls.INTENSITY,
- # Low intensity.
- "ansired": color_cls.RED,
- "ansigreen": color_cls.GREEN,
- "ansiyellow": color_cls.YELLOW,
- "ansiblue": color_cls.BLUE,
- "ansimagenta": color_cls.MAGENTA,
- "ansicyan": color_cls.CYAN,
- # High intensity.
- "ansibrightred": color_cls.RED | color_cls.INTENSITY,
- "ansibrightgreen": color_cls.GREEN | color_cls.INTENSITY,
- "ansibrightyellow": color_cls.YELLOW | color_cls.INTENSITY,
- "ansibrightblue": color_cls.BLUE | color_cls.INTENSITY,
- "ansibrightmagenta": color_cls.MAGENTA | color_cls.INTENSITY,
- "ansibrightcyan": color_cls.CYAN | color_cls.INTENSITY,
- }
-
-
-FG_ANSI_COLORS = _create_ansi_color_dict(FOREGROUND_COLOR)
-BG_ANSI_COLORS = _create_ansi_color_dict(BACKGROUND_COLOR)
-
-assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
-assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
-
-
-class ColorLookupTable:
- """
- Inspired by pygments/formatters/terminal256.py
- """
-
- def __init__(self) -> None:
- self._win32_colors = self._build_color_table()
-
- # Cache (map color string to foreground and background code).
- self.best_match: Dict[str, Tuple[int, int]] = {}
-
- @staticmethod
- def _build_color_table() -> List[Tuple[int, int, int, int, int]]:
- """
- Build an RGB-to-256 color conversion table
- """
- FG = FOREGROUND_COLOR
- BG = BACKGROUND_COLOR
-
- return [
- (0x00, 0x00, 0x00, FG.BLACK, BG.BLACK),
- (0x00, 0x00, 0xAA, FG.BLUE, BG.BLUE),
- (0x00, 0xAA, 0x00, FG.GREEN, BG.GREEN),
- (0x00, 0xAA, 0xAA, FG.CYAN, BG.CYAN),
- (0xAA, 0x00, 0x00, FG.RED, BG.RED),
- (0xAA, 0x00, 0xAA, FG.MAGENTA, BG.MAGENTA),
- (0xAA, 0xAA, 0x00, FG.YELLOW, BG.YELLOW),
- (0x88, 0x88, 0x88, FG.GRAY, BG.GRAY),
- (0x44, 0x44, 0xFF, FG.BLUE | FG.INTENSITY, BG.BLUE | BG.INTENSITY),
- (0x44, 0xFF, 0x44, FG.GREEN | FG.INTENSITY, BG.GREEN | BG.INTENSITY),
- (0x44, 0xFF, 0xFF, FG.CYAN | FG.INTENSITY, BG.CYAN | BG.INTENSITY),
- (0xFF, 0x44, 0x44, FG.RED | FG.INTENSITY, BG.RED | BG.INTENSITY),
- (0xFF, 0x44, 0xFF, FG.MAGENTA | FG.INTENSITY, BG.MAGENTA | BG.INTENSITY),
- (0xFF, 0xFF, 0x44, FG.YELLOW | FG.INTENSITY, BG.YELLOW | BG.INTENSITY),
- (0x44, 0x44, 0x44, FG.BLACK | FG.INTENSITY, BG.BLACK | BG.INTENSITY),
- (0xFF, 0xFF, 0xFF, FG.GRAY | FG.INTENSITY, BG.GRAY | BG.INTENSITY),
- ]
-
- def _closest_color(self, r: int, g: int, b: int) -> Tuple[int, int]:
- distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
- fg_match = 0
- bg_match = 0
-
- for r_, g_, b_, fg_, bg_ in self._win32_colors:
- rd = r - r_
- gd = g - g_
- bd = b - b_
-
- d = rd * rd + gd * gd + bd * bd
-
- if d < distance:
- fg_match = fg_
- bg_match = bg_
- distance = d
- return fg_match, bg_match
-
- def _color_indexes(self, color: str) -> Tuple[int, int]:
- indexes = self.best_match.get(color, None)
- if indexes is None:
- try:
- rgb = int(str(color), 16)
- except ValueError:
- rgb = 0
-
- r = (rgb >> 16) & 0xFF
- g = (rgb >> 8) & 0xFF
- b = rgb & 0xFF
- indexes = self._closest_color(r, g, b)
- self.best_match[color] = indexes
- return indexes
-
- def lookup_fg_color(self, fg_color: str) -> int:
- """
- Return the color for use in the
- `windll.kernel32.SetConsoleTextAttribute` API call.
-
- :param fg_color: Foreground as text. E.g. 'ffffff' or 'red'
- """
- # Foreground.
- if fg_color in FG_ANSI_COLORS:
- return FG_ANSI_COLORS[fg_color]
- else:
- return self._color_indexes(fg_color)[0]
-
- def lookup_bg_color(self, bg_color: str) -> int:
- """
- Return the color for use in the
- `windll.kernel32.SetConsoleTextAttribute` API call.
-
- :param bg_color: Background as text. E.g. 'ffffff' or 'red'
- """
- # Background.
- if bg_color in BG_ANSI_COLORS:
- return BG_ANSI_COLORS[bg_color]
- else:
- return self._color_indexes(bg_color)[1]
+ @classmethod
+ def win32_refresh_window(cls) -> None:
+ """
+ Call win32 API to refresh the whole Window.
+
+ This is sometimes necessary when the application paints background
+ for completion menus. When the menu disappears, it leaves traces due
+ to a bug in the Windows Console. Sending a repaint request solves it.
+ """
+ # Get console handle
+ handle = HANDLE(windll.kernel32.GetConsoleWindow())
+
+ RDW_INVALIDATE = 0x0001
+ windll.user32.RedrawWindow(handle, None, None, c_uint(RDW_INVALIDATE))
+
+ def get_default_color_depth(self) -> ColorDepth:
+ """
+ Return the default color depth for a windows terminal.
+
+ Contrary to the Vt100 implementation, this doesn't depend on a $TERM
+ variable.
+ """
+ if self.default_color_depth is not None:
+ return self.default_color_depth
+
+ # For now, by default, always use 4 bit color on Windows 10 by default,
+ # even when vt100 escape sequences with
+ # ENABLE_VIRTUAL_TERMINAL_PROCESSING are supported. We don't have a
+ # reliable way yet to know whether our console supports true color or
+ # only 4-bit.
+ return ColorDepth.DEPTH_4_BIT
+
+
+class FOREGROUND_COLOR:
+ BLACK = 0x0000
+ BLUE = 0x0001
+ GREEN = 0x0002
+ CYAN = 0x0003
+ RED = 0x0004
+ MAGENTA = 0x0005
+ YELLOW = 0x0006
+ GRAY = 0x0007
+ INTENSITY = 0x0008 # Foreground color is intensified.
+
+
+class BACKGROUND_COLOR:
+ BLACK = 0x0000
+ BLUE = 0x0010
+ GREEN = 0x0020
+ CYAN = 0x0030
+ RED = 0x0040
+ MAGENTA = 0x0050
+ YELLOW = 0x0060
+ GRAY = 0x0070
+ INTENSITY = 0x0080 # Background color is intensified.
+
+
+def _create_ansi_color_dict(
+ color_cls: Union[Type[FOREGROUND_COLOR], Type[BACKGROUND_COLOR]]
+) -> Dict[str, int]:
+ "Create a table that maps the 16 named ansi colors to their Windows code."
+ return {
+ "ansidefault": color_cls.BLACK,
+ "ansiblack": color_cls.BLACK,
+ "ansigray": color_cls.GRAY,
+ "ansibrightblack": color_cls.BLACK | color_cls.INTENSITY,
+ "ansiwhite": color_cls.GRAY | color_cls.INTENSITY,
+ # Low intensity.
+ "ansired": color_cls.RED,
+ "ansigreen": color_cls.GREEN,
+ "ansiyellow": color_cls.YELLOW,
+ "ansiblue": color_cls.BLUE,
+ "ansimagenta": color_cls.MAGENTA,
+ "ansicyan": color_cls.CYAN,
+ # High intensity.
+ "ansibrightred": color_cls.RED | color_cls.INTENSITY,
+ "ansibrightgreen": color_cls.GREEN | color_cls.INTENSITY,
+ "ansibrightyellow": color_cls.YELLOW | color_cls.INTENSITY,
+ "ansibrightblue": color_cls.BLUE | color_cls.INTENSITY,
+ "ansibrightmagenta": color_cls.MAGENTA | color_cls.INTENSITY,
+ "ansibrightcyan": color_cls.CYAN | color_cls.INTENSITY,
+ }
+
+
+FG_ANSI_COLORS = _create_ansi_color_dict(FOREGROUND_COLOR)
+BG_ANSI_COLORS = _create_ansi_color_dict(BACKGROUND_COLOR)
+
+assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+
+
+class ColorLookupTable:
+ """
+ Inspired by pygments/formatters/terminal256.py
+ """
+
+ def __init__(self) -> None:
+ self._win32_colors = self._build_color_table()
+
+ # Cache (map color string to foreground and background code).
+ self.best_match: Dict[str, Tuple[int, int]] = {}
+
+ @staticmethod
+ def _build_color_table() -> List[Tuple[int, int, int, int, int]]:
+ """
+ Build an RGB-to-256 color conversion table
+ """
+ FG = FOREGROUND_COLOR
+ BG = BACKGROUND_COLOR
+
+ return [
+ (0x00, 0x00, 0x00, FG.BLACK, BG.BLACK),
+ (0x00, 0x00, 0xAA, FG.BLUE, BG.BLUE),
+ (0x00, 0xAA, 0x00, FG.GREEN, BG.GREEN),
+ (0x00, 0xAA, 0xAA, FG.CYAN, BG.CYAN),
+ (0xAA, 0x00, 0x00, FG.RED, BG.RED),
+ (0xAA, 0x00, 0xAA, FG.MAGENTA, BG.MAGENTA),
+ (0xAA, 0xAA, 0x00, FG.YELLOW, BG.YELLOW),
+ (0x88, 0x88, 0x88, FG.GRAY, BG.GRAY),
+ (0x44, 0x44, 0xFF, FG.BLUE | FG.INTENSITY, BG.BLUE | BG.INTENSITY),
+ (0x44, 0xFF, 0x44, FG.GREEN | FG.INTENSITY, BG.GREEN | BG.INTENSITY),
+ (0x44, 0xFF, 0xFF, FG.CYAN | FG.INTENSITY, BG.CYAN | BG.INTENSITY),
+ (0xFF, 0x44, 0x44, FG.RED | FG.INTENSITY, BG.RED | BG.INTENSITY),
+ (0xFF, 0x44, 0xFF, FG.MAGENTA | FG.INTENSITY, BG.MAGENTA | BG.INTENSITY),
+ (0xFF, 0xFF, 0x44, FG.YELLOW | FG.INTENSITY, BG.YELLOW | BG.INTENSITY),
+ (0x44, 0x44, 0x44, FG.BLACK | FG.INTENSITY, BG.BLACK | BG.INTENSITY),
+ (0xFF, 0xFF, 0xFF, FG.GRAY | FG.INTENSITY, BG.GRAY | BG.INTENSITY),
+ ]
+
+ def _closest_color(self, r: int, g: int, b: int) -> Tuple[int, int]:
+ distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
+ fg_match = 0
+ bg_match = 0
+
+ for r_, g_, b_, fg_, bg_ in self._win32_colors:
+ rd = r - r_
+ gd = g - g_
+ bd = b - b_
+
+ d = rd * rd + gd * gd + bd * bd
+
+ if d < distance:
+ fg_match = fg_
+ bg_match = bg_
+ distance = d
+ return fg_match, bg_match
+
+ def _color_indexes(self, color: str) -> Tuple[int, int]:
+ indexes = self.best_match.get(color, None)
+ if indexes is None:
+ try:
+ rgb = int(str(color), 16)
+ except ValueError:
+ rgb = 0
+
+ r = (rgb >> 16) & 0xFF
+ g = (rgb >> 8) & 0xFF
+ b = rgb & 0xFF
+ indexes = self._closest_color(r, g, b)
+ self.best_match[color] = indexes
+ return indexes
+
+ def lookup_fg_color(self, fg_color: str) -> int:
+ """
+ Return the color for use in the
+ `windll.kernel32.SetConsoleTextAttribute` API call.
+
+ :param fg_color: Foreground as text. E.g. 'ffffff' or 'red'
+ """
+ # Foreground.
+ if fg_color in FG_ANSI_COLORS:
+ return FG_ANSI_COLORS[fg_color]
+ else:
+ return self._color_indexes(fg_color)[0]
+
+ def lookup_bg_color(self, bg_color: str) -> int:
+ """
+ Return the color for use in the
+ `windll.kernel32.SetConsoleTextAttribute` API call.
+
+ :param bg_color: Background as text. E.g. 'ffffff' or 'red'
+ """
+ # Background.
+ if bg_color in BG_ANSI_COLORS:
+ return BG_ANSI_COLORS[bg_color]
+ else:
+ return self._color_indexes(bg_color)[1]
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/windows10.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/windows10.py
index dc4f7cdf44e..933f54a28f2 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/windows10.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/windows10.py
@@ -1,104 +1,104 @@
-from ctypes import byref, windll
-from ctypes.wintypes import DWORD, HANDLE
-from typing import Any, Optional, TextIO
-
-from prompt_toolkit.data_structures import Size
-from prompt_toolkit.utils import is_windows
-from prompt_toolkit.win32_types import STD_OUTPUT_HANDLE
-
-from .base import Output
-from .color_depth import ColorDepth
-from .vt100 import Vt100_Output
-from .win32 import Win32Output
-
-__all__ = [
- "Windows10_Output",
-]
-
-# See: https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms686033(v=vs.85).aspx
-ENABLE_PROCESSED_INPUT = 0x0001
-ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
-
-
-class Windows10_Output:
- """
- Windows 10 output abstraction. This enables and uses vt100 escape sequences.
- """
-
- def __init__(
- self, stdout: TextIO, default_color_depth: Optional[ColorDepth] = None
- ) -> None:
- self.win32_output = Win32Output(stdout, default_color_depth=default_color_depth)
- self.vt100_output = Vt100_Output(
- stdout, lambda: Size(0, 0), default_color_depth=default_color_depth
- )
- self._hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
-
- def flush(self) -> None:
- """
- Write to output stream and flush.
- """
- original_mode = DWORD(0)
-
- # Remember the previous console mode.
- windll.kernel32.GetConsoleMode(self._hconsole, byref(original_mode))
-
- # Enable processing of vt100 sequences.
- windll.kernel32.SetConsoleMode(
- self._hconsole,
- DWORD(ENABLE_PROCESSED_INPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING),
- )
-
- try:
- self.vt100_output.flush()
- finally:
- # Restore console mode.
- windll.kernel32.SetConsoleMode(self._hconsole, original_mode)
-
- @property
- def responds_to_cpr(self) -> bool:
- return False # We don't need this on Windows.
-
- def __getattr__(self, name: str) -> Any:
- if name in (
- "get_size",
- "get_rows_below_cursor_position",
- "enable_mouse_support",
- "disable_mouse_support",
- "scroll_buffer_to_prompt",
- "get_win32_screen_buffer_info",
- "enable_bracketed_paste",
- "disable_bracketed_paste",
- "get_default_color_depth",
- ):
- return getattr(self.win32_output, name)
- else:
- return getattr(self.vt100_output, name)
-
-
-Output.register(Windows10_Output)
-
-
-def is_win_vt100_enabled() -> bool:
- """
- Returns True when we're running Windows and VT100 escape sequences are
- supported.
- """
- if not is_windows():
- return False
-
- hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
-
- # Get original console mode.
- original_mode = DWORD(0)
- windll.kernel32.GetConsoleMode(hconsole, byref(original_mode))
-
- try:
- # Try to enable VT100 sequences.
- result: int = windll.kernel32.SetConsoleMode(
- hconsole, DWORD(ENABLE_PROCESSED_INPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- )
-
- return result == 1
- finally:
- windll.kernel32.SetConsoleMode(hconsole, original_mode)
+from ctypes import byref, windll
+from ctypes.wintypes import DWORD, HANDLE
+from typing import Any, Optional, TextIO
+
+from prompt_toolkit.data_structures import Size
+from prompt_toolkit.utils import is_windows
+from prompt_toolkit.win32_types import STD_OUTPUT_HANDLE
+
+from .base import Output
+from .color_depth import ColorDepth
+from .vt100 import Vt100_Output
+from .win32 import Win32Output
+
+__all__ = [
+ "Windows10_Output",
+]
+
+# See: https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms686033(v=vs.85).aspx
+ENABLE_PROCESSED_INPUT = 0x0001
+ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+
+
+class Windows10_Output:
+ """
+ Windows 10 output abstraction. This enables and uses vt100 escape sequences.
+ """
+
+ def __init__(
+ self, stdout: TextIO, default_color_depth: Optional[ColorDepth] = None
+ ) -> None:
+ self.win32_output = Win32Output(stdout, default_color_depth=default_color_depth)
+ self.vt100_output = Vt100_Output(
+ stdout, lambda: Size(0, 0), default_color_depth=default_color_depth
+ )
+ self._hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
+
+ def flush(self) -> None:
+ """
+ Write to output stream and flush.
+ """
+ original_mode = DWORD(0)
+
+ # Remember the previous console mode.
+ windll.kernel32.GetConsoleMode(self._hconsole, byref(original_mode))
+
+ # Enable processing of vt100 sequences.
+ windll.kernel32.SetConsoleMode(
+ self._hconsole,
+ DWORD(ENABLE_PROCESSED_INPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING),
+ )
+
+ try:
+ self.vt100_output.flush()
+ finally:
+ # Restore console mode.
+ windll.kernel32.SetConsoleMode(self._hconsole, original_mode)
+
+ @property
+ def responds_to_cpr(self) -> bool:
+ return False # We don't need this on Windows.
+
+ def __getattr__(self, name: str) -> Any:
+ if name in (
+ "get_size",
+ "get_rows_below_cursor_position",
+ "enable_mouse_support",
+ "disable_mouse_support",
+ "scroll_buffer_to_prompt",
+ "get_win32_screen_buffer_info",
+ "enable_bracketed_paste",
+ "disable_bracketed_paste",
+ "get_default_color_depth",
+ ):
+ return getattr(self.win32_output, name)
+ else:
+ return getattr(self.vt100_output, name)
+
+
+Output.register(Windows10_Output)
+
+
+def is_win_vt100_enabled() -> bool:
+ """
+ Returns True when we're running Windows and VT100 escape sequences are
+ supported.
+ """
+ if not is_windows():
+ return False
+
+ hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
+
+ # Get original console mode.
+ original_mode = DWORD(0)
+ windll.kernel32.GetConsoleMode(hconsole, byref(original_mode))
+
+ try:
+ # Try to enable VT100 sequences.
+ result: int = windll.kernel32.SetConsoleMode(
+ hconsole, DWORD(ENABLE_PROCESSED_INPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ )
+
+ return result == 1
+ finally:
+ windll.kernel32.SetConsoleMode(hconsole, original_mode)