Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/prompt_toolkit/cursor_shapes.py: 59%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

49 statements  

1from __future__ import annotations 

2 

3from abc import ABC, abstractmethod 

4from enum import Enum 

5from typing import TYPE_CHECKING, Any, Callable, Union 

6 

7from prompt_toolkit.enums import EditingMode 

8from prompt_toolkit.key_binding.vi_state import InputMode 

9 

10if TYPE_CHECKING: 

11 from .application import Application 

12 

13__all__ = [ 

14 "CursorShape", 

15 "CursorShapeConfig", 

16 "SimpleCursorShapeConfig", 

17 "ModalCursorShapeConfig", 

18 "DynamicCursorShapeConfig", 

19 "to_cursor_shape_config", 

20] 

21 

22 

23class CursorShape(Enum): 

24 # Default value that should tell the output implementation to never send 

25 # cursor shape escape sequences. This is the default right now, because 

26 # before this `CursorShape` functionality was introduced into 

27 # prompt_toolkit itself, people had workarounds to send cursor shapes 

28 # escapes into the terminal, by monkey patching some of prompt_toolkit's 

29 # internals. We don't want the default prompt_toolkit implementation to 

30 # interfere with that. E.g., IPython patches the `ViState.input_mode` 

31 # property. See: https://github.com/ipython/ipython/pull/13501/files 

32 _NEVER_CHANGE = "_NEVER_CHANGE" 

33 

34 BLOCK = "BLOCK" 

35 BEAM = "BEAM" 

36 UNDERLINE = "UNDERLINE" 

37 BLINKING_BLOCK = "BLINKING_BLOCK" 

38 BLINKING_BEAM = "BLINKING_BEAM" 

39 BLINKING_UNDERLINE = "BLINKING_UNDERLINE" 

40 

41 

42class CursorShapeConfig(ABC): 

43 @abstractmethod 

44 def get_cursor_shape(self, application: Application[Any]) -> CursorShape: 

45 """ 

46 Return the cursor shape to be used in the current state. 

47 """ 

48 

49 

50AnyCursorShapeConfig = Union[CursorShape, CursorShapeConfig, None] 

51 

52 

53class SimpleCursorShapeConfig(CursorShapeConfig): 

54 """ 

55 Always show the given cursor shape. 

56 """ 

57 

58 def __init__(self, cursor_shape: CursorShape = CursorShape._NEVER_CHANGE) -> None: 

59 self.cursor_shape = cursor_shape 

60 

61 def get_cursor_shape(self, application: Application[Any]) -> CursorShape: 

62 return self.cursor_shape 

63 

64 

65class ModalCursorShapeConfig(CursorShapeConfig): 

66 """ 

67 Show cursor shape according to the current input mode. 

68 """ 

69 

70 def get_cursor_shape(self, application: Application[Any]) -> CursorShape: 

71 if application.editing_mode == EditingMode.VI: 

72 if application.vi_state.input_mode in { 

73 InputMode.NAVIGATION, 

74 }: 

75 return CursorShape.BLOCK 

76 if application.vi_state.input_mode in { 

77 InputMode.INSERT, 

78 InputMode.INSERT_MULTIPLE, 

79 }: 

80 return CursorShape.BEAM 

81 if application.vi_state.input_mode in { 

82 InputMode.REPLACE, 

83 InputMode.REPLACE_SINGLE, 

84 }: 

85 return CursorShape.UNDERLINE 

86 elif application.editing_mode == EditingMode.EMACS: 

87 # like vi's INSERT 

88 return CursorShape.BEAM 

89 

90 # Default 

91 return CursorShape.BLOCK 

92 

93 

94class DynamicCursorShapeConfig(CursorShapeConfig): 

95 def __init__( 

96 self, get_cursor_shape_config: Callable[[], AnyCursorShapeConfig] 

97 ) -> None: 

98 self.get_cursor_shape_config = get_cursor_shape_config 

99 

100 def get_cursor_shape(self, application: Application[Any]) -> CursorShape: 

101 return to_cursor_shape_config(self.get_cursor_shape_config()).get_cursor_shape( 

102 application 

103 ) 

104 

105 

106def to_cursor_shape_config(value: AnyCursorShapeConfig) -> CursorShapeConfig: 

107 """ 

108 Take a `CursorShape` instance or `CursorShapeConfig` and turn it into a 

109 `CursorShapeConfig`. 

110 """ 

111 if value is None: 

112 return SimpleCursorShapeConfig() 

113 

114 if isinstance(value, CursorShape): 

115 return SimpleCursorShapeConfig(value) 

116 

117 return value