Spaces:
Sleeping
Sleeping
from __future__ import annotations | |
from abc import ABC, abstractmethod | |
from enum import Enum | |
from typing import TYPE_CHECKING, Any, Callable, Union | |
from prompt_toolkit.enums import EditingMode | |
from prompt_toolkit.key_binding.vi_state import InputMode | |
if TYPE_CHECKING: | |
from .application import Application | |
__all__ = [ | |
"CursorShape", | |
"CursorShapeConfig", | |
"SimpleCursorShapeConfig", | |
"ModalCursorShapeConfig", | |
"DynamicCursorShapeConfig", | |
"to_cursor_shape_config", | |
] | |
class CursorShape(Enum): | |
# Default value that should tell the output implementation to never send | |
# cursor shape escape sequences. This is the default right now, because | |
# before this `CursorShape` functionality was introduced into | |
# prompt_toolkit itself, people had workarounds to send cursor shapes | |
# escapes into the terminal, by monkey patching some of prompt_toolkit's | |
# internals. We don't want the default prompt_toolkit implementation to | |
# interfere with that. E.g., IPython patches the `ViState.input_mode` | |
# property. See: https://github.com/ipython/ipython/pull/13501/files | |
_NEVER_CHANGE = "_NEVER_CHANGE" | |
BLOCK = "BLOCK" | |
BEAM = "BEAM" | |
UNDERLINE = "UNDERLINE" | |
BLINKING_BLOCK = "BLINKING_BLOCK" | |
BLINKING_BEAM = "BLINKING_BEAM" | |
BLINKING_UNDERLINE = "BLINKING_UNDERLINE" | |
class CursorShapeConfig(ABC): | |
def get_cursor_shape(self, application: Application[Any]) -> CursorShape: | |
""" | |
Return the cursor shape to be used in the current state. | |
""" | |
AnyCursorShapeConfig = Union[CursorShape, CursorShapeConfig, None] | |
class SimpleCursorShapeConfig(CursorShapeConfig): | |
""" | |
Always show the given cursor shape. | |
""" | |
def __init__(self, cursor_shape: CursorShape = CursorShape._NEVER_CHANGE) -> None: | |
self.cursor_shape = cursor_shape | |
def get_cursor_shape(self, application: Application[Any]) -> CursorShape: | |
return self.cursor_shape | |
class ModalCursorShapeConfig(CursorShapeConfig): | |
""" | |
Show cursor shape according to the current input mode. | |
""" | |
def get_cursor_shape(self, application: Application[Any]) -> CursorShape: | |
if application.editing_mode == EditingMode.VI: | |
if application.vi_state.input_mode == InputMode.INSERT: | |
return CursorShape.BEAM | |
if application.vi_state.input_mode == InputMode.REPLACE: | |
return CursorShape.UNDERLINE | |
# Default | |
return CursorShape.BLOCK | |
class DynamicCursorShapeConfig(CursorShapeConfig): | |
def __init__( | |
self, get_cursor_shape_config: Callable[[], AnyCursorShapeConfig] | |
) -> None: | |
self.get_cursor_shape_config = get_cursor_shape_config | |
def get_cursor_shape(self, application: Application[Any]) -> CursorShape: | |
return to_cursor_shape_config(self.get_cursor_shape_config()).get_cursor_shape( | |
application | |
) | |
def to_cursor_shape_config(value: AnyCursorShapeConfig) -> CursorShapeConfig: | |
""" | |
Take a `CursorShape` instance or `CursorShapeConfig` and turn it into a | |
`CursorShapeConfig`. | |
""" | |
if value is None: | |
return SimpleCursorShapeConfig() | |
if isinstance(value, CursorShape): | |
return SimpleCursorShapeConfig(value) | |
return value | |