Skip to content

Commit e62cdea

Browse files
checkpoint getting stdout working correctly
--HG-- branch : scroll-frontend
1 parent 6479ae9 commit e62cdea

File tree

2 files changed

+51
-49
lines changed

2 files changed

+51
-49
lines changed

bpython/scrollfrontend/coderunner.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def __init__(self, interp=None, stuff_a_refresh_request=lambda:None):
1616
self.stuff_a_refresh_request = stuff_a_refresh_request
1717
self.code_is_waiting = False
1818

19+
@property
20+
def running(self):
21+
return self.source and self.code_thread
22+
1923
def load_code(self, source):
2024
self.source = source
2125
self.code_thread = None
@@ -27,7 +31,7 @@ def run_code(self, input=None):
2731
if source code is incomplete, returns "unfinished"
2832
"""
2933
if self.code_thread is None:
30-
assert self.source
34+
assert self.source is not None
3135
self.code_thread = threading.Thread(target=self._blocking_run_code, name='codethread')
3236
self.code_thread.daemon = True
3337
self.code_thread.start()
@@ -38,6 +42,9 @@ def run_code(self, input=None):
3842

3943
request = self.requests_from_code_thread.get()
4044
if request[0] == 'done':
45+
self.source = None
46+
self.code_thread = None
47+
self.code_is_waiting = False
4148
return 'unfinished' if request[1] else 'done'
4249
else:
4350
method, args, kwargs = request

bpython/scrollfrontend/repl.py

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)