@@ -93,13 +93,13 @@ async def kbd_intr_task(exec_task, s):
9393
9494
9595# REPL task. Invoke this with an optional mutable globals dict.
96- async def task (g = None , prompt = "--> " ):
96+ async def task (g = None , prompt = "--> " , s_in = sys . stdin , s_out = sys . stdout ):
9797 print ("Starting asyncio REPL..." )
9898 if g is None :
9999 g = __import__ ("__main__" ).__dict__
100100 try :
101101 micropython .kbd_intr (- 1 )
102- s = asyncio .StreamReader (sys . stdin )
102+ s = asyncio .StreamReader (s_in )
103103 # clear = True
104104 hist = [None ] * _HISTORY_LIMIT
105105 hist_i = 0 # Index of most recent entry.
@@ -108,7 +108,7 @@ async def task(g=None, prompt="--> "):
108108 t = 0 # timestamp of most recent character.
109109 while True :
110110 hist_b = 0 # How far back in the history are we currently.
111- sys . stdout .write (prompt )
111+ s_out .write (prompt )
112112 cmd : str = ""
113113 paste = False
114114 curs = 0 # cursor offset from end of cmd buffer
@@ -122,7 +122,7 @@ async def task(g=None, prompt="--> "):
122122 if c == 0x0A :
123123 # LF
124124 if paste :
125- sys . stdout .write (b )
125+ s_out .write (b )
126126 cmd += b
127127 continue
128128 # If the previous character was also LF, and was less
@@ -132,9 +132,9 @@ async def task(g=None, prompt="--> "):
132132 continue
133133 if curs :
134134 # move cursor to end of the line
135- sys . stdout .write ("\x1b [{}C" .format (curs ))
135+ s_out .write ("\x1b [{}C" .format (curs ))
136136 curs = 0
137- sys . stdout .write ("\n " )
137+ s_out .write ("\n " )
138138 if cmd :
139139 # Push current command.
140140 hist [hist_i ] = cmd
@@ -144,46 +144,46 @@ async def task(g=None, prompt="--> "):
144144
145145 result = await execute (cmd , g , s )
146146 if result is not None :
147- sys . stdout .write (repr (result ))
148- sys . stdout .write ("\n " )
147+ s_out .write (repr (result ))
148+ s_out .write ("\n " )
149149 break
150150 elif c == 0x08 or c == 0x7F :
151151 # Backspace.
152152 if cmd :
153153 if curs :
154154 cmd = "" .join ((cmd [: - curs - 1 ], cmd [- curs :]))
155- sys . stdout .write (
155+ s_out .write (
156156 "\x08 \x1b [K"
157157 ) # move cursor back, erase to end of line
158- sys . stdout .write (cmd [- curs :]) # redraw line
159- sys . stdout .write ("\x1b [{}D" .format (curs )) # reset cursor location
158+ s_out .write (cmd [- curs :]) # redraw line
159+ s_out .write ("\x1b [{}D" .format (curs )) # reset cursor location
160160 else :
161161 cmd = cmd [:- 1 ]
162- sys . stdout .write ("\x08 \x08 " )
162+ s_out .write ("\x08 \x08 " )
163163 elif c == CHAR_CTRL_A :
164- await raw_repl (s , g )
164+ await raw_repl (s_in , s_out , g )
165165 break
166166 elif c == CHAR_CTRL_B :
167167 continue
168168 elif c == CHAR_CTRL_C :
169169 if paste :
170170 break
171- sys . stdout .write ("\n " )
171+ s_out .write ("\n " )
172172 break
173173 elif c == CHAR_CTRL_D :
174174 if paste :
175175 result = await execute (cmd , g , s )
176176 if result is not None :
177- sys . stdout .write (repr (result ))
178- sys . stdout .write ("\n " )
177+ s_out .write (repr (result ))
178+ s_out .write ("\n " )
179179 break
180180
181- sys . stdout .write ("\n " )
181+ s_out .write ("\n " )
182182 # Shutdown asyncio.
183183 asyncio .new_event_loop ()
184184 return
185185 elif c == CHAR_CTRL_E :
186- sys . stdout .write ("paste mode; Ctrl-C to cancel, Ctrl-D to finish\n ===\n " )
186+ s_out .write ("paste mode; Ctrl-C to cancel, Ctrl-D to finish\n ===\n " )
187187 paste = True
188188 elif c == 0x1B :
189189 # Start of escape sequence.
@@ -193,66 +193,66 @@ async def task(g=None, prompt="--> "):
193193 hist [(hist_i - hist_b ) % _HISTORY_LIMIT ] = cmd
194194 # Clear current command.
195195 b = "\x08 " * len (cmd )
196- sys . stdout .write (b )
197- sys . stdout .write (" " * len (cmd ))
198- sys . stdout .write (b )
196+ s_out .write (b )
197+ s_out .write (" " * len (cmd ))
198+ s_out .write (b )
199199 # Go backwards or forwards in the history.
200200 if key == "[A" :
201201 hist_b = min (hist_n , hist_b + 1 )
202202 else :
203203 hist_b = max (0 , hist_b - 1 )
204204 # Update current command.
205205 cmd = hist [(hist_i - hist_b ) % _HISTORY_LIMIT ]
206- sys . stdout .write (cmd )
206+ s_out .write (cmd )
207207 elif key == "[D" : # left
208208 if curs < len (cmd ) - 1 :
209209 curs += 1
210- sys . stdout .write ("\x1b " )
211- sys . stdout .write (key )
210+ s_out .write ("\x1b " )
211+ s_out .write (key )
212212 elif key == "[C" : # right
213213 if curs :
214214 curs -= 1
215- sys . stdout .write ("\x1b " )
216- sys . stdout .write (key )
215+ s_out .write ("\x1b " )
216+ s_out .write (key )
217217 elif key == "[H" : # home
218218 pcurs = curs
219219 curs = len (cmd )
220- sys . stdout .write ("\x1b [{}D" .format (curs - pcurs )) # move cursor left
220+ s_out .write ("\x1b [{}D" .format (curs - pcurs )) # move cursor left
221221 elif key == "[F" : # end
222222 pcurs = curs
223223 curs = 0
224- sys . stdout .write ("\x1b [{}C" .format (pcurs )) # move cursor right
224+ s_out .write ("\x1b [{}C" .format (pcurs )) # move cursor right
225225 else :
226- # sys.stdout .write("\\x")
227- # sys.stdout .write(hex(c))
226+ # s_out .write("\\x")
227+ # s_out .write(hex(c))
228228 pass
229229 else :
230230 if curs :
231231 # inserting into middle of line
232232 cmd = "" .join ((cmd [:- curs ], b , cmd [- curs :]))
233- sys . stdout .write (cmd [- curs - 1 :]) # redraw line to end
234- sys . stdout .write ("\x1b [{}D" .format (curs )) # reset cursor location
233+ s_out .write (cmd [- curs - 1 :]) # redraw line to end
234+ s_out .write ("\x1b [{}D" .format (curs )) # reset cursor location
235235 else :
236- sys . stdout .write (b )
236+ s_out .write (b )
237237 cmd += b
238238 finally :
239239 micropython .kbd_intr (3 )
240240
241241
242- async def raw_paste (s , g , window = 512 ):
243- sys . stdout .write ("R\x01 " ) # supported
244- sys . stdout .write (bytearray ([window & 0xFF , window >> 8 , 0x01 ]).decode ())
242+ def raw_paste (s_in , s_out , window = 512 ):
243+ s_out .write ("R\x01 " ) # supported
244+ s_out .write (bytearray ([window & 0xFF , window >> 8 , 0x01 ]).decode ())
245245 eof = False
246246 idx = 0
247247 buff = bytearray (window )
248248 file = b""
249249 while not eof :
250250 for idx in range (window ):
251- b = await s .read (1 )
251+ b = s_in .read (1 )
252252 c = ord (b )
253253 if c == CHAR_CTRL_C or c == CHAR_CTRL_D :
254254 # end of file
255- sys . stdout .write (chr (CHAR_CTRL_D ))
255+ s_out .write (chr (CHAR_CTRL_D ))
256256 if c == CHAR_CTRL_C :
257257 raise KeyboardInterrupt
258258 file += buff [:idx ]
@@ -262,46 +262,51 @@ async def raw_paste(s, g, window=512):
262262
263263 if not eof :
264264 file += buff
265- sys . stdout .write ("\x01 " ) # indicate window available to host
265+ s_out .write ("\x01 " ) # indicate window available to host
266266
267267 return file
268268
269269
270- async def raw_repl (s : asyncio .StreamReader , g : dict ):
270+ async def raw_repl (s_in : io .IOBase , s_out : io .IOBase , g : dict ):
271+ """
272+ This function is blocking to prevent other
273+ async tasks from writing to the stdio stream and
274+ breaking the raw repl session.
275+ """
271276 heading = "raw REPL; CTRL-B to exit\n "
272277 line = ""
273- sys . stdout .write (heading )
278+ s_out .write (heading )
274279
275280 while True :
276281 line = ""
277- sys . stdout .write (">" )
282+ s_out .write (">" )
278283 while True :
279- b = await s .read (1 )
284+ b = s_in .read (1 )
280285 c = ord (b )
281286 if c == CHAR_CTRL_A :
282287 rline = line
283288 line = ""
284289
285290 if len (rline ) == 2 and ord (rline [0 ]) == CHAR_CTRL_E :
286291 if rline [1 ] == "A" :
287- line = await raw_paste (s , g )
292+ line = raw_paste (s_in , s_out )
288293 break
289294 else :
290295 # reset raw REPL
291- sys . stdout .write (heading )
292- sys . stdout .write (">" )
296+ s_out .write (heading )
297+ s_out .write (">" )
293298 continue
294299 elif c == CHAR_CTRL_B :
295300 # exit raw REPL
296- sys . stdout .write ("\n " )
301+ s_out .write ("\n " )
297302 return 0
298303 elif c == CHAR_CTRL_C :
299304 # clear line
300305 line = ""
301306 elif c == CHAR_CTRL_D :
302307 # entry finished
303308 # indicate reception of command
304- sys . stdout .write ("OK" )
309+ s_out .write ("OK" )
305310 break
306311 else :
307312 # let through any other raw 8-bit value
@@ -310,16 +315,16 @@ async def raw_repl(s: asyncio.StreamReader, g: dict):
310315 if len (line ) == 0 :
311316 # Normally used to trigger soft-reset but stay in raw mode.
312317 # Fake it for aiorepl / mpremote.
313- sys . stdout .write ("Ignored: soft reboot\n " )
314- sys . stdout .write (heading )
318+ s_out .write ("Ignored: soft reboot\n " )
319+ s_out .write (heading )
315320
316321 try :
317322 result = exec (line , g )
318323 if result is not None :
319- sys . stdout .write (repr (result ))
320- sys . stdout .write (chr (CHAR_CTRL_D ))
324+ s_out .write (repr (result ))
325+ s_out .write (chr (CHAR_CTRL_D ))
321326 except Exception as ex :
322327 print (line )
323- sys . stdout .write (chr (CHAR_CTRL_D ))
324- sys .print_exception (ex , sys . stdout )
325- sys . stdout .write (chr (CHAR_CTRL_D ))
328+ s_out .write (chr (CHAR_CTRL_D ))
329+ sys .print_exception (ex , s_out )
330+ s_out .write (chr (CHAR_CTRL_D ))
0 commit comments