def test_paint_lasts_events(self): actual = replpainter.paint_last_events(4, 100, ['a', 'b', 'c'], config=setup_config()) expected = fsarray(["┌─┐", "│c│", "│b│", "└─┘"]) self.assertFSArraysEqualIgnoringFormatting(actual, expected)
def test_paint_lasts_events(self): actual = replpainter.paint_last_events( 4, 100, ["a", "b", "c"], config=setup_config() ) if config.supports_box_chars(): expected = fsarray(["┌─┐", "│c│", "│b│", "└─┘"]) else: expected = fsarray(["+-+", "|c|", "|b|", "+-+"]) self.assertFSArraysEqualIgnoringFormatting(actual, expected)
def test_paint_lasts_events(self): actual = replpainter.paint_last_events(4, 100, ['a', 'b', 'c'], config=setup_config()) if config.supports_box_chars(): expected = fsarray(["┌─┐", "│c│", "│b│", "└─┘"]) else: expected = fsarray(["+-+", "|c|", "|b|", "+-+"]) self.assertFSArraysEqualIgnoringFormatting(actual, expected)
def paint(self, about_to_exit=False, user_quit=False): """Returns an array of min_height or more rows and width columns, plus cursor position Paints the entire screen - ideally the terminal display layer will take a diff and only write to the screen in portions that have changed, but the idea is that we don't need to worry about that here, instead every frame is completely redrawn because less state is cool! """ # The hairiest function in the curtsies - a cleanup would be great. if about_to_exit: self.clean_up_current_line_for_exit() # exception to not changing state! width, min_height = self.width, self.height show_status_bar = bool(self.status_bar._message) or (self.config.curtsies_fill_terminal or self.status_bar.has_focus) if show_status_bar: min_height -= 1 current_line_start_row = len(self.lines_for_display) - max(0, self.scroll_offset) if self.request_paint_to_clear_screen: # or show_status_bar and about_to_exit ? self.request_paint_to_clear_screen = False if self.config.curtsies_fill_terminal: #TODO clean up this logic - really necessary check? arr = FSArray(self.height - 1 + current_line_start_row, width) else: arr = FSArray(self.height + current_line_start_row, width) else: arr = FSArray(0, width) #TODO test case of current line filling up the whole screen (there aren't enough rows to show it) if current_line_start_row < 0: #if current line trying to be drawn off the top of the screen logging.debug('#<---History contiguity broken by rewind--->') msg = "#<---History contiguity broken by rewind--->" arr[0, 0:min(len(msg), width)] = [msg[:width]] # move screen back up a screen minus a line while current_line_start_row < 0: self.scroll_offset = self.scroll_offset - self.height current_line_start_row = len(self.lines_for_display) - max(-1, self.scroll_offset) history = paint.paint_history(max(0, current_line_start_row - 1), width, self.lines_for_display) arr[1:history.height+1,:history.width] = history if arr.height <= min_height: arr[min_height, 0] = ' ' # force scroll down to hide broken history message else: history = paint.paint_history(current_line_start_row, width, self.lines_for_display) arr[:history.height,:history.width] = history current_line = paint.paint_current_line(min_height, width, self.current_cursor_line) if user_quit: # quit() or exit() in interp current_line_start_row = current_line_start_row - current_line.height logging.debug("---current line row slice %r, %r", current_line_start_row, current_line_start_row + current_line.height) logging.debug("---current line col slice %r, %r", 0, current_line.width) arr[current_line_start_row:current_line_start_row + current_line.height, 0:current_line.width] = current_line if current_line.height > min_height: return arr, (0, 0) # short circuit, no room for infobox lines = paint.display_linize(self.current_cursor_line+'X', width) # extra character for space for the cursor current_line_end_row = current_line_start_row + len(lines) - 1 if self.stdin.has_focus: cursor_row, cursor_column = divmod(len(self.current_stdouterr_line) + self.stdin.cursor_offset_in_line, width) assert cursor_column >= 0, cursor_column elif self.coderunner.running: #TODO does this ever happen? cursor_row, cursor_column = divmod(len(self.current_cursor_line) + self.cursor_offset_in_line, width) assert cursor_column >= 0, (cursor_column, len(self.current_cursor_line), len(self._current_line), self.cursor_offset_in_line) else: cursor_row, cursor_column = divmod(len(self.current_cursor_line) - len(self._current_line) + self.cursor_offset_in_line, width) assert cursor_column >= 0, (cursor_column, len(self.current_cursor_line), len(self._current_line), self.cursor_offset_in_line) cursor_row += current_line_start_row if self.list_win_visible: logging.debug('infobox display code running') visible_space_above = history.height visible_space_below = min_height - current_line_end_row - 1 info_max_rows = max(visible_space_above, visible_space_below) infobox = paint.paint_infobox(info_max_rows, int(width * self.config.cli_suggestion_width), self.matches, self.argspec, self.current_word, self.docstring, self.config) if visible_space_above >= infobox.height and self.config.curtsies_list_above: arr[current_line_start_row - infobox.height:current_line_start_row, 0:infobox.width] = infobox else: arr[current_line_end_row + 1:current_line_end_row + 1 + infobox.height, 0:infobox.width] = infobox logging.debug('slamming infobox of shape %r into arr of shape %r', infobox.shape, arr.shape) logging.debug('about to exit: %r', about_to_exit) if show_status_bar: if self.config.curtsies_fill_terminal: if about_to_exit: arr[max(arr.height, min_height), :] = FSArray(1, width) else: arr[max(arr.height, min_height), :] = paint.paint_statusbar(1, width, self.status_bar.current_line, self.config) if self.presentation_mode: rows = arr.height columns = arr.width last_key_box = paint.paint_last_events(rows, columns, [events.pp_event(x) for x in self.last_events if x]) arr[arr.height-last_key_box.height:arr.height, arr.width-last_key_box.width:arr.width] = last_key_box else: statusbar_row = min_height + 1 if arr.height == min_height else arr.height if about_to_exit: arr[statusbar_row, :] = FSArray(1, width) else: arr[statusbar_row, :] = paint.paint_statusbar(1, width, self.status_bar.current_line, self.config) if self.config.color_scheme['background'] not in ('d', 'D'): for r in range(arr.height): arr[r] = fmtstr(arr[r], bg=color_for_letter(self.config.color_scheme['background'])) logging.debug('returning arr of size %r', arr.shape) logging.debug('cursor pos: %r', (cursor_row, cursor_column)) return arr, (cursor_row, cursor_column)