1
- # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2
1
# SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries
3
2
#
4
3
# SPDX-License-Identifier: MIT
8
7
9
8
Slimmed down implementation of prompt_toolkit for CircuitPython
10
9
11
-
12
- * Author(s): Scott Shawcroft
13
-
14
- Implementation Notes
15
- --------------------
16
-
17
10
"""
18
11
19
- # imports
12
+ from . history import InMemoryHistory
20
13
21
14
__version__ = "0.0.0+auto.0"
22
15
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Prompt_Toolkit.git"
23
16
24
- from .history import InMemoryHistory
25
-
26
17
27
- def _prompt (message = "" , * , input = None , output = None , history = None ):
18
+ def _prompt (message = "" , * , input_ = None , output = None , history = None ):
19
+ # pylint: disable=too-many-nested-blocks,too-many-branches,too-many-statements
28
20
output .write (message .encode ("utf-8" ))
29
21
commands = []
30
22
control_command = []
31
23
offset = 0
32
24
selected_history_entry = None
33
25
while not commands or commands [- 1 ] != ord ("\r " ):
34
- c = input .read (1 )
35
- print (c , c [0 ])
26
+ char = input_ .read (1 )
27
+ print (char , char [0 ])
36
28
37
29
if control_command :
38
- control_command .append (c [0 ])
39
- print ("control" , control_command )
30
+ control_command .append (char [0 ])
40
31
# Check for unsupported codes. If one is found, add the second character to the
41
32
# plain command and ignore the escape.
42
33
if len (control_command ) == 2 and not control_command [- 1 ] == ord (b"[" ):
@@ -47,8 +38,8 @@ def _prompt(message="", *, input=None, output=None, history=None):
47
38
ord ("0" ) <= control_command [- 1 ] <= ord ("9" )
48
39
):
49
40
echo = False
50
- cc = control_command [- 1 ]
51
- if cc == ord ("A" ) or cc == ord ("B" ):
41
+ control_char = control_command [- 1 ]
42
+ if control_char == ord ("A" ) or control_char == ord ("B" ):
52
43
if history is None :
53
44
control_command = []
54
45
output .write (b"\a " )
@@ -58,7 +49,7 @@ def _prompt(message="", *, input=None, output=None, history=None):
58
49
control_command = []
59
50
output .write (b"\a " )
60
51
continue
61
- if cc == ord ("A" ):
52
+ if control_char == ord ("A" ):
62
53
# up
63
54
if selected_history_entry is None :
64
55
selected_history_entry = 1
@@ -69,49 +60,50 @@ def _prompt(message="", *, input=None, output=None, history=None):
69
60
selected_history_entry = len (strings )
70
61
else :
71
62
# down
72
- print ("down" )
73
63
if selected_history_entry is None :
74
64
output .write (b"\a " )
75
65
else :
76
66
selected_history_entry -= 1
77
67
if selected_history_entry < 1 :
78
68
selected_history_entry = None
79
- # Move the cursor left as much as our current command
80
- for _ in commands :
81
- output .write (b"\b " )
82
- # Set and print the new command
83
- commands = list (strings [- selected_history_entry ].encode ("utf-8" ))
84
- output .write (bytes (commands ))
85
- # Clear the rest of the line
86
- output .write (b"\x1b [K" )
87
- elif cc == ord ("C" ):
69
+ if selected_history_entry is not None :
70
+ # Move the cursor left as much as our current command
71
+ for _ in commands :
72
+ output .write (b"\b " )
73
+ # Set and print the new command
74
+ commands = list (
75
+ strings [- selected_history_entry ].encode ("utf-8" )
76
+ )
77
+ output .write (bytes (commands ))
78
+ # Clear the rest of the line
79
+ output .write (b"\x1b [K" )
80
+ elif control_char == ord ("C" ):
88
81
echo = True
89
82
offset = max (0 , offset - 1 )
90
- elif cc == ord ("D" ):
83
+ elif control_char == ord ("D" ):
91
84
echo = True
92
85
offset += 1
93
86
94
87
if echo :
95
88
b = bytes (control_command )
96
- print ("echo" , b )
97
89
output .write (b )
98
90
control_command = []
99
91
continue
100
- elif c == b"\x1b " :
101
- control_command .append (c [0 ])
92
+ if char == b"\x1b " :
93
+ control_command .append (char [0 ])
102
94
continue
103
- elif offset == 0 or c == b"\r " :
104
- commands .append (c [0 ])
95
+ if offset == 0 or char == b"\r " :
96
+ commands .append (char [0 ])
105
97
else :
106
- commands [- offset ] = c [0 ]
98
+ commands [- offset ] = char [0 ]
107
99
offset -= 1
108
100
109
- if c [- 1 ] == 127 :
101
+ if char [- 1 ] == 127 :
110
102
commands .pop ()
111
103
commands .pop ()
112
104
output .write (b"\b \x1b [K" )
113
105
else :
114
- output .write (c )
106
+ output .write (char )
115
107
116
108
print (commands , not commands )
117
109
output .write (b"\n " )
@@ -125,22 +117,35 @@ def _prompt(message="", *, input=None, output=None, history=None):
125
117
126
118
127
119
def prompt (message = "" , * , input = None , output = None ):
128
- return _prompt (message , input = input , output = output )
120
+ """Prompt the user for input over the ``input`` stream with the given
121
+ ``message`` output on ``output``. Handles control characters for value editing."""
122
+ # "input" and "output" are only on PromptSession in upstream "prompt_toolkit" but we use it for
123
+ # prompts without history.
124
+ # pylint: disable=redefined-builtin
125
+ return _prompt (message , input_ = input , output = output )
129
126
130
127
131
128
class PromptSession :
129
+ """Session for multiple prompts. Stores common arguments to `prompt()` and
130
+ history of commands for user selection."""
131
+
132
132
def __init__ (self , message = "" , * , input = None , output = None , history = None ):
133
+ # "input" and "output" are names used in upstream "prompt_toolkit" so we
134
+ # use them too.
135
+ # pylint: disable=redefined-builtin
133
136
self .message = message
134
137
self ._input = input
135
138
self ._output = output
136
139
137
140
self .history = history if history else InMemoryHistory ()
138
141
139
142
def prompt (self , message = None ) -> str :
143
+ """Prompt the user for input over the session's ``input`` with the given
144
+ message or the default message."""
140
145
message = message if message else self .message
141
146
142
147
decoded = _prompt (
143
- message , input = self ._input , output = self ._output , history = self .history
148
+ message , input_ = self ._input , output = self ._output , history = self .history
144
149
)
145
150
146
151
return decoded
0 commit comments