def pause_scroll_for_user_input(self): # TODO: mark last paused line, set it up so such lines get # marked with a plus when still in the buffer, to help your # eye track the scroll. self.flush() if not buf_empty(self.textBuf): term_width, term_height = term.get_size() if term_width - self.env.hdr.screen_width_units > 0: term.home_cursor() term.cursor_down(term_height - 1) # we reserve a one unit right margin for this status char term.cursor_right(self.env.hdr.screen_width_units) term.write_char_with_color('+', self.env.fg_color, self.env.bg_color) term.getch_or_esc_seq() self.update_seen_lines()
def scroll(self, count_lines=True): env = self.env if not self.seenBuf[self.textBuf[env.top_window_height]]: if not buf_empty(self.textBuf[env.top_window_height:]): self.pause_scroll_for_user_input() old_line = self.textBuf.pop(env.top_window_height) term.home_cursor() self.overwrite_line_with(old_line) term.scroll_down() new_line = self.make_screen_line() self.textBuf.append(new_line) self.seenBuf[new_line] = False self.haveNotScrolled = False self.slow_scroll_effect()
def scroll_top_line_only(self): env = self.env old_line = self.textBuf[env.top_window_height] # avoid some moderately rare shifting text glitches (when possible) if self.haveNotScrolled and line_empty(old_line): return if not self.seenBuf[old_line] and not line_empty(old_line): self.pause_scroll_for_user_input() term.home_cursor() self.overwrite_line_with(old_line) term.scroll_down() new_line = self.make_screen_line() self.textBuf[env.top_window_height] = new_line self.seenBuf[new_line] = False self.haveNotScrolled = False
def first_draw(self): env = self.env for i in range(env.hdr.screen_height_units - 1): write_char('\n', env.fg_color, env.bg_color, env.text_style) term.fill_to_eol_with_bg_color() term.home_cursor()
def get_line_of_input(self, prompt='', prefilled=''): env = self.env for c in prompt: self.write_unwrapped( [ScreenChar(c, env.fg_color, env.bg_color, env.text_style)]) self.flush() self.update_seen_lines() row, col = env.cursor[env.current_window] term.home_cursor() term.cursor_down(row) term.cursor_right(col) term.set_color(env.fg_color, env.bg_color) if line_empty(self.textBuf[row][col:]): term.fill_to_eol_with_bg_color() term.show_cursor() col = max( 0, col - len(prefilled) ) # TODO: prefilled is a seldom-used old and crusty feature, but make unicode safe env.cursor[env.current_window] = row, col class CursorLine(object): def __init__(self, cursor_start, chars): self.cursor = cursor_start self.chars = chars def backspace(self): if self.cursor == 0: return self.left() self.delete_char() def delete_char(self): del self.chars[self.cursor:self.cursor + 1] self.refresh_rest_of_line(is_delete=True) def refresh_rest_of_line(self, is_delete=False): rest = self.chars[self.cursor:] term.puts(''.join(rest)) to_back_up = len(rest) if is_delete: term.puts(' ') to_back_up += 1 if to_back_up: term.cursor_left(to_back_up) def left(self): if self.cursor > 0: self.cursor -= 1 term.cursor_left() def right(self): if self.cursor < len(self.chars): self.cursor += 1 term.cursor_right() def home(self): while self.cursor > 0: self.left() def end(self): while self.cursor != len(self.chars): self.right() def kill_left(self): while self.chars[:self.cursor]: self.backspace() def kill_right(self): while self.chars[self.cursor:]: self.delete_char() def insert(self, c): self.chars.insert(self.cursor, c) term.puts(c) self.cursor += 1 self.refresh_rest_of_line() cursor_start = len(prefilled) cursor_line = CursorLine(cursor_start, [c for c in prefilled]) max_input_len = 120 # 120 char limit seen on gargoyle c = term.getch_or_esc_seq() while c != '\n' and c != '\r': if c == '\b' or c == '\x7f': cursor_line.backspace() # normal edit keys and a bit of readline flavor # left arrow or C-b elif c == '\x1b[D' or c == '\x02': cursor_line.left() # right arrow or C-f elif c == '\x1b[C' or c == '\x06': cursor_line.right() # home or C-a elif c == '\x1b[H' or c == '\x01': cursor_line.home() # end or C-e elif c == '\x1b[F' or c == '\x05': cursor_line.end() # delete or C-d elif c == '\x1b[3~' or c == '\x04': cursor_line.delete_char() # C-u, kill left of cursor elif c == '\x15': cursor_line.kill_left() # C-u, kill right of cursor elif c == '\x0b': cursor_line.kill_right() else: if is_valid_inline_char(c) and len( cursor_line.chars) < max_input_len: if c == '\t': if len(cursor_line.chars) + 4 <= max_input_len: for i in range(4): cursor_line.insert(' ') else: cursor_line.insert(c) c = term.getch_or_esc_seq() term.hide_cursor() term.flush() for c in cursor_line.chars: self.write_unwrapped( [ScreenChar(c, env.fg_color, env.bg_color, env.text_style)]) self.new_line_via_spaces(env.fg_color, env.bg_color, env.text_style) term.home_cursor() return ''.join(cursor_line.chars)