|
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): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_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): |
|
@abstractmethod |
|
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 in { |
|
InputMode.NAVIGATION, |
|
}: |
|
return CursorShape.BLOCK |
|
if application.vi_state.input_mode in { |
|
InputMode.INSERT, |
|
InputMode.INSERT_MULTIPLE, |
|
}: |
|
return CursorShape.BEAM |
|
if application.vi_state.input_mode in { |
|
InputMode.REPLACE, |
|
InputMode.REPLACE_SINGLE, |
|
}: |
|
return CursorShape.UNDERLINE |
|
elif application.editing_mode == EditingMode.EMACS: |
|
|
|
return CursorShape.BEAM |
|
|
|
|
|
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 |
|
|