Skip to content

Commit 2cb18da

Browse files
Merge branch 'fix-inconsistent-history'
Conflicts: bpython/curtsiesfrontend/repl.py bpython/test/test_curtsies_repl.py
2 parents 3fa21ab + 6469adf commit 2cb18da

File tree

6 files changed

+455
-52
lines changed

6 files changed

+455
-52
lines changed

bpython/config.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ def loadini(struct, configfile):
8989
},
9090
'curtsies': {
9191
'list_above' : False,
92-
'fill_terminal' : False,
9392
'right_arrow_completion' : True,
9493
}})
9594
if not config.read(config_path):
@@ -157,7 +156,6 @@ def loadini(struct, configfile):
157156
struct.save_append_py = config.getboolean('general', 'save_append_py')
158157

159158
struct.curtsies_list_above = config.getboolean('curtsies', 'list_above')
160-
struct.curtsies_fill_terminal = config.getboolean('curtsies', 'fill_terminal')
161159
struct.curtsies_right_arrow_completion = config.getboolean('curtsies', 'right_arrow_completion')
162160

163161
color_scheme_name = config.get('general', 'color_scheme')

bpython/curtsies.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ def main(args=None, locals_=None, banner=None):
3131
]))
3232
if options.log:
3333
handler = logging.FileHandler(filename='bpython.log')
34-
logging.getLogger('curtsies').setLevel(logging.DEBUG)
34+
logging.getLogger('curtsies').setLevel(logging.WARNING)
3535
logging.getLogger('curtsies').addHandler(handler)
3636
logging.getLogger('curtsies').propagate = False
37-
logging.getLogger('bpython').setLevel(logging.DEBUG)
37+
logging.getLogger('bpython').setLevel(logging.WARNING)
3838
logging.getLogger('bpython').addHandler(handler)
3939
logging.getLogger('bpython').propagate = False
4040
else:

bpython/curtsiesfrontend/repl.py

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@
5151

5252
logger = logging.getLogger(__name__)
5353

54-
HELP_MESSAGE = """
54+
INCONSISTENT_HISTORY_MSG = u"#<---History inconsistent with output shown--->"
55+
CONTIGUITY_BROKEN_MSG = u"#<---History contiguity broken by rewind--->"
56+
HELP_MESSAGE = u"""
5557
Thanks for using bpython!
5658
5759
See http://bpython-interpreter.org/ for info, http://docs.bpython-interpreter.org/ for docs, and https://github.com/bpython/bpython for source.
@@ -270,12 +272,7 @@ def smarter_request_reload(desc):
270272
self.get_term_hw = get_term_hw
271273
self.get_cursor_vertical_diff = get_cursor_vertical_diff
272274

273-
self.status_bar = StatusBar(
274-
(_(" <%s> Rewind <%s> Save <%s> Pastebin <%s> Editor")
275-
% (config.undo_key, config.save_key, config.pastebin_key, config.external_editor_key)
276-
if config.curtsies_fill_terminal else ''),
277-
refresh_request=self.request_refresh
278-
)
275+
self.status_bar = StatusBar('', refresh_request=self.request_refresh)
279276
self.edit_keys = edit_keys.mapping_with_config(config, key_dispatch)
280277
logger.debug("starting parent init")
281278
super(Repl, self).__init__(interp, config)
@@ -308,6 +305,8 @@ def smarter_request_reload(desc):
308305
self.stdin = FakeStdin(self.coderunner, self, self.edit_keys)
309306

310307
self.request_paint_to_clear_screen = False # next paint should clear screen
308+
self.inconsistent_history = False # offscreen command yields different result from history
309+
self.history_already_messed_up = False # history error message displayed
311310
self.last_events = [None] * 50 # some commands act differently based on the prev event
312311
# this list doesn't include instances of event.Event,
313312
# only keypress-type events (no refresh screen events etc.)
@@ -1011,41 +1010,72 @@ def paint(self, about_to_exit=False, user_quit=False):
10111010
self.clean_up_current_line_for_exit() # exception to not changing state!
10121011

10131012
width, min_height = self.width, self.height
1014-
show_status_bar = bool(self.status_bar.should_show_message) or (self.config.curtsies_fill_terminal or self.status_bar.has_focus)
1013+
show_status_bar = bool(self.status_bar.should_show_message) or self.status_bar.has_focus
10151014
if show_status_bar:
1016-
min_height -= 1
1015+
min_height -= 1 # because we're going to tack the status bar on at the end,
1016+
# shoot for an array one less than the height of the screen
10171017

10181018
current_line_start_row = len(self.lines_for_display) - max(0, self.scroll_offset)
1019+
#TODO how is the situation of self.scroll_offset < 0 possible?
10191020
#current_line_start_row = len(self.lines_for_display) - self.scroll_offset
10201021
if self.request_paint_to_clear_screen: # or show_status_bar and about_to_exit ?
10211022
self.request_paint_to_clear_screen = False
1022-
if self.config.curtsies_fill_terminal: #TODO clean up this logic - really necessary check?
1023-
arr = FSArray(self.height - 1 + current_line_start_row, width)
1024-
else:
1025-
arr = FSArray(self.height + current_line_start_row, width)
1023+
arr = FSArray(min_height + current_line_start_row, width)
10261024
else:
10271025
arr = FSArray(0, width)
10281026
#TODO test case of current line filling up the whole screen (there aren't enough rows to show it)
10291027

1030-
if current_line_start_row < 0: #if current line trying to be drawn off the top of the screen
1031-
logger.debug('#<---History contiguity broken by rewind--->')
1032-
msg = "#<---History contiguity broken by rewind--->"
1033-
arr[0, 0:min(len(msg), width)] = [msg[:width]]
1034-
1028+
def move_screen_up(current_line_start_row):
10351029
# move screen back up a screen minus a line
10361030
while current_line_start_row < 0:
1031+
logger.debug('scroll_offset was %s, current_line_start_row was %s', self.scroll_offset, current_line_start_row)
10371032
self.scroll_offset = self.scroll_offset - self.height
10381033
current_line_start_row = len(self.lines_for_display) - max(-1, self.scroll_offset)
1034+
logger.debug('scroll_offset changed to %s, current_line_start_row changed to %s', self.scroll_offset, current_line_start_row)
1035+
return current_line_start_row
1036+
1037+
if self.inconsistent_history == True and not self.history_already_messed_up:
1038+
logger.debug(INCONSISTENT_HISTORY_MSG)
1039+
self.history_already_messed_up = True
1040+
msg = INCONSISTENT_HISTORY_MSG
1041+
arr[0, 0:min(len(msg), width)] = [msg[:width]]
1042+
current_line_start_row += 1 # for the message
1043+
self.scroll_offset -= 1 # to make up for the scroll we're going to receive
1044+
# after we render scrolls down a line
1045+
1046+
current_line_start_row = move_screen_up(current_line_start_row)
1047+
logger.debug('current_line_start_row: %r', current_line_start_row)
1048+
1049+
history = paint.paint_history(max(0, current_line_start_row - 1), width, self.lines_for_display)
1050+
arr[1:history.height+1,:history.width] = history
1051+
1052+
if arr.height <= min_height:
1053+
arr[min_height, 0] = ' ' # force scroll down to hide broken history message
1054+
1055+
elif current_line_start_row < 0: #if current line trying to be drawn off the top of the screen
1056+
logger.debug(CONTIGUITY_BROKEN_MSG)
1057+
msg = CONTIGUITY_BROKEN_MSG
1058+
arr[0, 0:min(len(msg), width)] = [msg[:width]]
1059+
1060+
current_line_start_row = move_screen_up(current_line_start_row)
10391061

10401062
history = paint.paint_history(max(0, current_line_start_row - 1), width, self.lines_for_display)
10411063
arr[1:history.height+1,:history.width] = history
10421064

10431065
if arr.height <= min_height:
10441066
arr[min_height, 0] = ' ' # force scroll down to hide broken history message
1067+
10451068
else:
1069+
assert current_line_start_row >= 0
1070+
logger.debug("no history issues. start %i",current_line_start_row)
10461071
history = paint.paint_history(current_line_start_row, width, self.lines_for_display)
10471072
arr[:history.height,:history.width] = history
10481073

1074+
1075+
1076+
1077+
self.inconsistent_history = False
1078+
10491079
current_line = paint.paint_current_line(min_height, width, self.current_cursor_line)
10501080
if user_quit: # quit() or exit() in interp
10511081
current_line_start_row = current_line_start_row - current_line.height
@@ -1072,7 +1102,7 @@ def paint(self, about_to_exit=False, user_quit=False):
10721102
assert cursor_column >= 0, (cursor_column, len(self.current_cursor_line), len(self.current_line), self.cursor_offset)
10731103
cursor_row += current_line_start_row
10741104

1075-
if self.list_win_visible:
1105+
if self.list_win_visible and not self.coderunner.running:
10761106
logger.debug('infobox display code running')
10771107
visible_space_above = history.height
10781108
visible_space_below = min_height - current_line_end_row - 1
@@ -1095,23 +1125,11 @@ def paint(self, about_to_exit=False, user_quit=False):
10951125

10961126
logger.debug('about to exit: %r', about_to_exit)
10971127
if show_status_bar:
1098-
if self.config.curtsies_fill_terminal:
1099-
if about_to_exit:
1100-
arr[max(arr.height, min_height), :] = FSArray(1, width)
1101-
else:
1102-
arr[max(arr.height, min_height), :] = paint.paint_statusbar(1, width, self.status_bar.current_line, self.config)
1103-
1104-
if self.presentation_mode:
1105-
rows = arr.height
1106-
columns = arr.width
1107-
last_key_box = paint.paint_last_events(rows, columns, [events.pp_event(x) for x in self.last_events if x])
1108-
arr[arr.height-last_key_box.height:arr.height, arr.width-last_key_box.width:arr.width] = last_key_box
1128+
statusbar_row = min_height if arr.height == min_height else arr.height
1129+
if about_to_exit:
1130+
arr[statusbar_row, :] = FSArray(1, width)
11091131
else:
1110-
statusbar_row = min_height + 1 if arr.height == min_height else arr.height
1111-
if about_to_exit:
1112-
arr[statusbar_row, :] = FSArray(1, width)
1113-
else:
1114-
arr[statusbar_row, :] = paint.paint_statusbar(1, width, self.status_bar.current_line, self.config)
1132+
arr[statusbar_row, :] = paint.paint_statusbar(1, width, self.status_bar.current_line, self.config)
11151133

11161134
if self.config.color_scheme['background'] not in ('d', 'D'):
11171135
for r in range(arr.height):
@@ -1240,6 +1258,7 @@ def reevaluate(self, insert_into_history=False):
12401258
"""bpython.Repl.undo calls this"""
12411259
if self.watcher: self.watcher.reset()
12421260
old_logical_lines = self.history
1261+
old_display_lines = self.display_lines
12431262
self.history = []
12441263
self.display_lines = []
12451264

@@ -1263,6 +1282,16 @@ def reevaluate(self, insert_into_history=False):
12631282
sys.stdin = self.stdin
12641283
self.reevaluating = False
12651284

1285+
num_lines_onscreen = len(self.lines_for_display) - max(0, self.scroll_offset)
1286+
display_lines_offscreen = self.display_lines[:len(self.display_lines) - num_lines_onscreen]
1287+
old_display_lines_offscreen = old_display_lines[:len(self.display_lines) - num_lines_onscreen]
1288+
logger.debug('old_display_lines_offscreen %s', '|'.join([str(x) for x in old_display_lines_offscreen]))
1289+
logger.debug(' display_lines_offscreen %s', '|'.join([str(x) for x in display_lines_offscreen]))
1290+
if old_display_lines_offscreen[:len(display_lines_offscreen)] != display_lines_offscreen and not self.history_already_messed_up:
1291+
#self.scroll_offset = self.scroll_offset + (len(old_display_lines)-len(self.display_lines))
1292+
self.inconsistent_history = True
1293+
logger.debug('after rewind, self.inconsistent_history is %r', self.inconsistent_history)
1294+
12661295
self.cursor_offset = 0
12671296
self.current_line = ''
12681297

0 commit comments

Comments
 (0)