1"""
2Interface for an output.
3"""
4
5from __future__ import annotations
6
7from abc import ABCMeta, abstractmethod
8from typing import TextIO
9
10from prompt_toolkit.cursor_shapes import CursorShape
11from prompt_toolkit.data_structures import Size
12from prompt_toolkit.styles import Attrs
13
14from .color_depth import ColorDepth
15
16__all__ = [
17 "Output",
18 "DummyOutput",
19]
20
21
22class Output(metaclass=ABCMeta):
23 """
24 Base class defining the output interface for a
25 :class:`~prompt_toolkit.renderer.Renderer`.
26
27 Actual implementations are
28 :class:`~prompt_toolkit.output.vt100.Vt100_Output` and
29 :class:`~prompt_toolkit.output.win32.Win32Output`.
30 """
31
32 stdout: TextIO | None = None
33
34 @abstractmethod
35 def fileno(self) -> int:
36 "Return the file descriptor to which we can write for the output."
37
38 @abstractmethod
39 def encoding(self) -> str:
40 """
41 Return the encoding for this output, e.g. 'utf-8'.
42 (This is used mainly to know which characters are supported by the
43 output the data, so that the UI can provide alternatives, when
44 required.)
45 """
46
47 @abstractmethod
48 def write(self, data: str) -> None:
49 "Write text (Terminal escape sequences will be removed/escaped.)"
50
51 @abstractmethod
52 def write_raw(self, data: str) -> None:
53 "Write text."
54
55 @abstractmethod
56 def set_title(self, title: str) -> None:
57 "Set terminal title."
58
59 @abstractmethod
60 def clear_title(self) -> None:
61 "Clear title again. (or restore previous title.)"
62
63 @abstractmethod
64 def flush(self) -> None:
65 "Write to output stream and flush."
66
67 @abstractmethod
68 def erase_screen(self) -> None:
69 """
70 Erases the screen with the background color and moves the cursor to
71 home.
72 """
73
74 @abstractmethod
75 def enter_alternate_screen(self) -> None:
76 "Go to the alternate screen buffer. (For full screen applications)."
77
78 @abstractmethod
79 def quit_alternate_screen(self) -> None:
80 "Leave the alternate screen buffer."
81
82 @abstractmethod
83 def enable_mouse_support(self) -> None:
84 "Enable mouse."
85
86 @abstractmethod
87 def disable_mouse_support(self) -> None:
88 "Disable mouse."
89
90 @abstractmethod
91 def erase_end_of_line(self) -> None:
92 """
93 Erases from the current cursor position to the end of the current line.
94 """
95
96 @abstractmethod
97 def erase_down(self) -> None:
98 """
99 Erases the screen from the current line down to the bottom of the
100 screen.
101 """
102
103 @abstractmethod
104 def reset_attributes(self) -> None:
105 "Reset color and styling attributes."
106
107 @abstractmethod
108 def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
109 "Set new color and styling attributes."
110
111 @abstractmethod
112 def disable_autowrap(self) -> None:
113 "Disable auto line wrapping."
114
115 @abstractmethod
116 def enable_autowrap(self) -> None:
117 "Enable auto line wrapping."
118
119 @abstractmethod
120 def cursor_goto(self, row: int = 0, column: int = 0) -> None:
121 "Move cursor position."
122
123 @abstractmethod
124 def cursor_up(self, amount: int) -> None:
125 "Move cursor `amount` place up."
126
127 @abstractmethod
128 def cursor_down(self, amount: int) -> None:
129 "Move cursor `amount` place down."
130
131 @abstractmethod
132 def cursor_forward(self, amount: int) -> None:
133 "Move cursor `amount` place forward."
134
135 @abstractmethod
136 def cursor_backward(self, amount: int) -> None:
137 "Move cursor `amount` place backward."
138
139 @abstractmethod
140 def hide_cursor(self) -> None:
141 "Hide cursor."
142
143 @abstractmethod
144 def show_cursor(self) -> None:
145 "Show cursor."
146
147 @abstractmethod
148 def set_cursor_shape(self, cursor_shape: CursorShape) -> None:
149 "Set cursor shape to block, beam or underline."
150
151 @abstractmethod
152 def reset_cursor_shape(self) -> None:
153 "Reset cursor shape."
154
155 def ask_for_cpr(self) -> None:
156 """
157 Asks for a cursor position report (CPR).
158 (VT100 only.)
159 """
160
161 @property
162 def responds_to_cpr(self) -> bool:
163 """
164 `True` if the `Application` can expect to receive a CPR response after
165 calling `ask_for_cpr` (this will come back through the corresponding
166 `Input`).
167
168 This is used to determine the amount of available rows we have below
169 the cursor position. In the first place, we have this so that the drop
170 down autocompletion menus are sized according to the available space.
171
172 On Windows, we don't need this, there we have
173 `get_rows_below_cursor_position`.
174 """
175 return False
176
177 @abstractmethod
178 def get_size(self) -> Size:
179 "Return the size of the output window."
180
181 def bell(self) -> None:
182 "Sound bell."
183
184 def enable_bracketed_paste(self) -> None:
185 "For vt100 only."
186
187 def disable_bracketed_paste(self) -> None:
188 "For vt100 only."
189
190 def reset_cursor_key_mode(self) -> None:
191 """
192 For vt100 only.
193 Put the terminal in normal cursor mode (instead of application mode).
194
195 See: https://vt100.net/docs/vt100-ug/chapter3.html
196 """
197
198 def scroll_buffer_to_prompt(self) -> None:
199 "For Win32 only."
200
201 def get_rows_below_cursor_position(self) -> int:
202 "For Windows only."
203 raise NotImplementedError
204
205 @abstractmethod
206 def get_default_color_depth(self) -> ColorDepth:
207 """
208 Get default color depth for this output.
209
210 This value will be used if no color depth was explicitly passed to the
211 `Application`.
212
213 .. note::
214
215 If the `$PROMPT_TOOLKIT_COLOR_DEPTH` environment variable has been
216 set, then `outputs.defaults.create_output` will pass this value to
217 the implementation as the default_color_depth, which is returned
218 here. (This is not used when the output corresponds to a
219 prompt_toolkit SSH/Telnet session.)
220 """
221
222
223class DummyOutput(Output):
224 """
225 For testing. An output class that doesn't render anything.
226 """
227
228 def fileno(self) -> int:
229 "There is no sensible default for fileno()."
230 raise NotImplementedError
231
232 def encoding(self) -> str:
233 return "utf-8"
234
235 def write(self, data: str) -> None:
236 pass
237
238 def write_raw(self, data: str) -> None:
239 pass
240
241 def set_title(self, title: str) -> None:
242 pass
243
244 def clear_title(self) -> None:
245 pass
246
247 def flush(self) -> None:
248 pass
249
250 def erase_screen(self) -> None:
251 pass
252
253 def enter_alternate_screen(self) -> None:
254 pass
255
256 def quit_alternate_screen(self) -> None:
257 pass
258
259 def enable_mouse_support(self) -> None:
260 pass
261
262 def disable_mouse_support(self) -> None:
263 pass
264
265 def erase_end_of_line(self) -> None:
266 pass
267
268 def erase_down(self) -> None:
269 pass
270
271 def reset_attributes(self) -> None:
272 pass
273
274 def set_attributes(self, attrs: Attrs, color_depth: ColorDepth) -> None:
275 pass
276
277 def disable_autowrap(self) -> None:
278 pass
279
280 def enable_autowrap(self) -> None:
281 pass
282
283 def cursor_goto(self, row: int = 0, column: int = 0) -> None:
284 pass
285
286 def cursor_up(self, amount: int) -> None:
287 pass
288
289 def cursor_down(self, amount: int) -> None:
290 pass
291
292 def cursor_forward(self, amount: int) -> None:
293 pass
294
295 def cursor_backward(self, amount: int) -> None:
296 pass
297
298 def hide_cursor(self) -> None:
299 pass
300
301 def show_cursor(self) -> None:
302 pass
303
304 def set_cursor_shape(self, cursor_shape: CursorShape) -> None:
305 pass
306
307 def reset_cursor_shape(self) -> None:
308 pass
309
310 def ask_for_cpr(self) -> None:
311 pass
312
313 def bell(self) -> None:
314 pass
315
316 def enable_bracketed_paste(self) -> None:
317 pass
318
319 def disable_bracketed_paste(self) -> None:
320 pass
321
322 def scroll_buffer_to_prompt(self) -> None:
323 pass
324
325 def get_size(self) -> Size:
326 return Size(rows=40, columns=80)
327
328 def get_rows_below_cursor_position(self) -> int:
329 return 40
330
331 def get_default_color_depth(self) -> ColorDepth:
332 return ColorDepth.DEPTH_1_BIT