def test_render_scroll_pgup_keystroke(self): """ Test we render properly when stuck to the bottom """ os.environ['TERM'] = 'dumb' app = Logria(None, False, False) # Fake window size: 10 x 100 app.height = 10 app.width = 100 # Set fake previous render app.last_row = app.height - 3 # simulate the last row we can render to app.current_end = 40 # Simulate the last message rendered # Set fake messages app.messages = [str(x) for x in range(100)] # Set positional booleans app.manually_controlled_line = False app.stick_to_top = True app.stick_to_bottom = True # Scroll action resolve_keypress(app, 'KEY_PPAGE') start, end = determine_position(app, app.messages) self.assertEqual(start, 25) self.assertEqual(end, 33) app.stop()
def main(self, stdscr) -> None: """ Main program loop, handles user control and logical flow """ curses.use_default_colors() self.stdscr = stdscr stdscr.keypad(1) height, width = stdscr.getmaxyx() # Get screen size # Save these values self.height = height self.width = width - 1 # Setup Output window output_start_row = 0 # Leave space for top border output_height = height - 3 # Leave space for command line self.last_row = output_height - output_start_row # The last row we can write to # Create the window with these sizes self.outwin = curses.newwin(output_height, width - 1, output_start_row, 0) self.outwin.refresh() # Setup Command line self.build_command_line() # Update the command line status reset_regex_status(self) # Disable cursor: curses.curs_set(0) # If the streams do not exist, create them if not self.streams: setup_streams(self) # Start the main app loop while True: # Update messages from the input stream's queues, track time t_0 = time.perf_counter() new_messages: int = 0 for stream in self.streams: while not stream.stderr.empty(): message = stream.stderr.get() self.stderr_messages.append(message) new_messages += 1 while not stream.stdout.empty(): message = stream.stdout.get() self.stdout_messages.append(message) new_messages += 1 # Prevent this loop from taking up 100% of the CPU dedicated to the main thread by delaying loops t_1 = time.perf_counter() - t_0 # Don't delay if the queue processing took too long time.sleep(max(0, self.poll_rate - t_1)) # Calculate new poll rate if self.smart_poll_rate: self.handle_smart_poll_rate(t_1, new_messages) # Since this is the first run, set the visible stream to the one that has the most messages if self.first_run and (len(self.stdout_messages) > 0 or len(self.stderr_messages) > 0): self.first_run = False # Default to stdout unless stderr has more messages if len(self.stdout_messages) >= len(self.stderr_messages): self.messages = self.stdout_messages else: self.messages = self.stderr_messages try: # Get keypress, raise curses.error if nothing detected keypress = self.command_line.getkey() resolve_keypress(self, keypress) except curses.error: if self.exit_val == -1: return # If we have an active filter/parser, process it/them if self.parser: # This may block if there are a lot of messages process_parser(self) if self.func_handle: # This may block if there are a lot of messages process_matches(self) # Always try to render self.render_text_in_output()