@@ -60,7 +60,7 @@ def __init__(self, coderunner, repl):
6060 def process_event (self , e ):
6161 assert self .has_focus
6262 if e in rl_char_sequences :
63- self .cursor_offset_in_line , self .current_line = rl_char_sequences [e ](self .cursor_offset_in_line , self ._current_line )
63+ self .cursor_offset_in_line , self .current_line = rl_char_sequences [e ](self .cursor_offset_in_line , self .current_line )
6464 #TODO EOF on ctrl-d
6565 else : # add normal character
6666 logging .debug ('adding normal char %r to current line' , e )
@@ -127,6 +127,7 @@ def __init__(self, locals_=None, config=None, stuff_a_refresh_request=None):
127127 # interact is called to interact with the status bar,
128128 # so we're just using the same object
129129 self ._current_line = '' # line currently being edited, without '>>> '
130+ self .current_output_line = '' # current line of output - stdout and stdin go here
130131 self .display_lines = [] # lines separated whenever logical line
131132 # length goes over what the terminal width
132133 # was at the time of original output
@@ -142,6 +143,7 @@ def __init__(self, locals_=None, config=None, stuff_a_refresh_request=None):
142143
143144 self .coderunner = CodeRunner (self .interp , stuff_a_refresh_request )
144145 self .stdout = FakeOutput (self .coderunner , self .send_to_stdout )
146+ self .stderr = FakeOutput (self .coderunner , self .send_to_stderr )
145147 self .stdin = FakeStdin (self .coderunner , self )
146148
147149 self .paste_mode = False
@@ -158,14 +160,12 @@ def __enter__(self):
158160 self .orig_stderr = sys .stderr
159161 self .orig_stdin = sys .stdin
160162 sys .stdout = self .stdout
161- sys .stderr = StringIO ()
163+ sys .stderr = self . stderr
162164 sys .stdin = self .stdin
163165 return self
164166
165167 def __exit__ (self , * args ):
166- sys .stderr .seek (0 )
167- s = sys .stderr .read ()
168- self .orig_stderr .write (s )
168+ sys .stdin = self .orig_stdin
169169 sys .stdout = self .orig_stdout
170170 sys .stderr = self .orig_stderr
171171
@@ -191,7 +191,7 @@ def process_event(self, e):
191191
192192 logging .debug ("processing event %r" , e )
193193 if isinstance (e , events .RefreshRequestEvent ):
194- self .run_runsource_part_2_when_finished ()
194+ self .finish_command_if_done ()
195195 return
196196 self .last_events .append (e )
197197 self .last_events .pop (0 )
@@ -286,7 +286,21 @@ def on_enter(self, insert_into_history=True):
286286 self .push (self ._current_line , insert_into_history = insert_into_history )
287287
288288 def send_to_stdout (self , output ):
289- self .display_lines .extend (sum ([paint .display_linize (line , self .width ) for line in output .split ('\n ' )], []))
289+ lines = output .split ('\n ' )
290+ logging .debug ('display_lines: %r' , self .display_lines )
291+ if len (lines ) and lines [0 ]:
292+ self .current_output_line += lines [0 ]
293+ if len (lines ) > 1 :
294+ self .display_lines .extend (paint .display_linize (self .current_output_line , self .width ))
295+ self .display_lines .extend (sum ([paint .display_linize (line , self .width ) for line in lines [1 :- 1 ]], []))
296+ self .current_output_line = lines [- 1 ]
297+ logging .debug ('display_lines: %r' , self .display_lines )
298+
299+ def send_to_stderr (self , error ):
300+ self .send_to_stdout (error )
301+ #self.display_lines.extend([func_for_letter(self.config.color_scheme['error'])(line)
302+ # for line in sum([paint.display_linize(line, self.width)
303+ # for line in error.split('\n')], [])])
290304
291305 def send_to_stdin (self , line ):
292306 self .display_lines = self .display_lines [:len (self .display_lines ) - self .stdin .old_num_lines ]
@@ -372,22 +386,12 @@ def update_completion(self, tab=False):
372386 self .list_win_visible = BpythonRepl .complete (self , tab )
373387
374388 def push (self , line , insert_into_history = True ):
375- """Push a line of code onto the buffer, run the buffer
389+ """Push a line of code onto the buffer, start running the buffer
376390
377391 If the interpreter successfully runs the code, clear the buffer
378392 """
379393 if insert_into_history :
380394 self .insert_into_history (line )
381- self .runsource (line )
382-
383- def runsource (self , line ):
384- """Push a line of code on to the buffer, run the buffer, clean up
385-
386- Makes requests for input and announces being done as necessary via threadsafe queue
387- sends messages:
388- * request for readline
389- * (stdoutput, error, done?, amount_to_indent_next_line)
390- """
391395 self .buffer .append (line )
392396 indent = len (re .match (r'[ ]*' , line ).group ())
393397
@@ -397,10 +401,8 @@ def runsource(self, line):
397401 indent = max (0 , indent - self .config .tab_length )
398402 elif line and ':' not in line and line .strip ().startswith (('return' , 'pass' , 'raise' , 'yield' )):
399403 indent = max (0 , indent - self .config .tab_length )
400- err_spot = sys .stderr .tell ()
401404 logging .debug ('running %r in interpreter' , self .buffer )
402405 self .coderunner .load_code ('\n ' .join (self .buffer ))
403- self .saved_err_spot = err_spot
404406 self .saved_indent = indent
405407 self .saved_line = line
406408
@@ -419,39 +421,23 @@ def runsource(self, line):
419421 self .display_lines .extend (self .display_buffer_lines )
420422 self .display_buffer = []
421423 self .buffer = []
424+ self .cursor_offset_in_line = 0
422425
423- self .run_runsource_part_2_when_finished ()
426+ self .finish_command_if_done ()
424427
425- def run_runsource_part_2_when_finished (self ):
428+ def finish_command_if_done (self ):
426429 r = self .coderunner .run_code ()
427430 if r :
428431 unfinished = r == 'unfinished'
429- self .runsource_part_2 (self .saved_line , self .saved_err_spot , unfinished , self .saved_indent )
432+ err = True #TODO implement this properly - via interp.write_error I suppose
433+ self .finish_command (self .saved_line , unfinished , self .saved_indent , err )
430434
431- def runsource_part_2 (self , line , err_spot , unfinished , indent ):
432- sys .stderr .seek (err_spot )
433- err = sys .stderr .read ()
435+ def finish_command (self , line , unfinished , indent , err ):
434436
435- # easier debugging: save only errors that aren't from this interpreter
436- oldstderr = sys .stderr
437- sys .stderr = StringIO ()
438- oldstderr .seek (0 )
439- sys .stderr .write (oldstderr .read (err_spot ))
437+ done = not unfinished
440438
441- if unfinished and not err :
442- logging .debug ('unfinished - line added to buffer' )
443- output , error , done = None , None , False
444- else :
445- if err :
446- indent = 0
447- logging .debug ('sending output info' )
448- output , error , done = None , err [:- 1 ], True
449- logging .debug ('sent output info' )
450-
451- if error :
452- self .display_lines .extend ([func_for_letter (self .config .color_scheme ['error' ])(line )
453- for line in sum ([paint .display_linize (line , self .width )
454- for line in error .split ('\n ' )], [])])
439+ if err :
440+ indent = 0
455441 self ._current_line = ' ' * indent
456442 self .cursor_offset_in_line = len (self ._current_line )
457443 self .done = done
@@ -532,6 +518,14 @@ def display_line_with_prompt(self):
532518 if self .done else
533519 func_for_letter (self .config .color_scheme ['prompt_more' ])(self .ps2 )) + self .current_line_formatted
534520
521+ @property
522+ def current_cursor_line (self ):
523+
524+ if self .coderunner .running :
525+ return self .current_output_line
526+ else :
527+ return self .display_line_with_prompt
528+
535529 def paint (self , about_to_exit = False ):
536530 """Returns an array of min_height or more rows and width columns, plus cursor position
537531
@@ -576,17 +570,17 @@ def paint(self, about_to_exit=False):
576570 history = paint .paint_history (current_line_start_row , width , self .lines_for_display )
577571 arr [:history .height ,:history .width ] = history
578572
579- current_line = paint .paint_current_line (min_height , width , self .display_line_with_prompt )
573+ current_line = paint .paint_current_line (min_height , width , self .current_cursor_line )
580574 arr [current_line_start_row :current_line_start_row + current_line .height ,
581575 0 :current_line .width ] = current_line
582576
583577 if current_line .height > min_height :
584578 return arr , (0 , 0 ) # short circuit, no room for infobox
585579
586- lines = paint .display_linize (self .display_line_with_prompt + 'X' , width )
580+ lines = paint .display_linize (self .current_cursor_line + 'X' , width )
587581 # extra character for space for the cursor
588582 cursor_row = current_line_start_row + len (lines ) - 1
589- cursor_column = (self .cursor_offset_in_line + len (self .display_line_with_prompt ) - len (self ._current_line )) % width
583+ cursor_column = (self .cursor_offset_in_line + len (self .current_cursor_line ) - len (self ._current_line )) % width
590584
591585 if self .list_win_visible :
592586 #infobox not properly expanding window! try reduce( docs about halfway down a 80x24 terminal
@@ -630,6 +624,7 @@ def paint(self, about_to_exit=False):
630624 for r in range (arr .height ):
631625 arr [r ] = fmtstr (arr [r ], bg = color_for_letter (self .config .color_scheme ['background' ]))
632626 logging .debug ('returning arr of size %r' , arr .shape )
627+ logging .debug ('cursor pos: %r' , (cursor_row , cursor_column ))
633628 return arr , (cursor_row , cursor_column )
634629
635630 ## Debugging shims
0 commit comments