I have a python script that takes manages the stdin, stdout, and stderr of any application and allows for readline to be inserted gracefully. Think of any application that has lots of console output, but also accepts commands from stdin.
In any case, my script uses these two functions:
def blank_current_readline():
# Next line said to be reasonably portable for various Unixes
(rows,cols) = struct.unpack('hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ,'1234'))
text_len = len(readline.get_line_buffer())+2
# ANSI escape sequences (All VT100 except ESC[0G)
sys.stdout.write('\x1b[2K') # Clear current line
sys.stdout.write('\x1b[1A\x1b[2K'*(text_len/cols)) # Move cursor up and clear line
sys.stdout.write('\x1b[0G') # Move to start of line
def print_line(line):
global cmd_state
blank_current_readline()
print line,
sys.stdout.write(cmd_state["prompt"] + readline.get_line_buffer())
sys.stdout.flush()
When handling stdout, I call print_line(). This blanks whatever the user might be typing, prints the line, then restores the user's input text. This all happens without the user noticing a thing.
The problem occurs when the cursor is not at the end of whatever input the user is typing. When the cursor is in the middle of the test and a line is printed, the cursor will automatically be placed at the end of the input. To solve this, I want to do something like this in print_line:
def print_line(line):
global cmd_state
cursorPos = getCurrentCursorPos() #Doesn't exist
blank_current_readline()
print line,
sys.stdout.write(cmd_state["prompt"] + readline.get_line_buffer())
sys.stdout.setCurrentCursorPos(cursorPos) #Doesn't exist
sys.stdout.flush()
Edit: To try and visualize what I have written:
The terminal looks like this:
----------------------------------------------
| |
| |
| <scolling command output here> |
| |
| <scolling command output here> |
| |
|: <user inputted text here> |
----------------------------------------------
So the output text is constantly scrolling as new logs are coming through. At the same time, the user is currently editing and writing a new command that will be inserted once the hit enter. So it looks like the python console, but with output always being appended.
Might I suggest Python curses?
Here is the Basic how-to
The curses module provides an interface to the curses library, the de-facto standard for portable advanced terminal handling.
While curses is most widely used in the Unix environment, versions are available for DOS, OS/2, and possibly other systems as well. This extension module is designed to match the API of ncurses, an open-source curses library hosted on Linux and the BSD variants of Unix.
I found Terminal Controller here: Using terminfo for portable color output & cursor control. It looks to be more portable than the sitename would suggest (MacOS mentioned in the comments - though with changes).
Here is a usage example, displaying a progress bar:
class ProgressBar:
"""
A 3-line progress bar, which looks like::
Header
20% [===========----------------------------------]
progress message
The progress bar is colored, if the terminal supports color
output; and adjusts to the width of the terminal.
"""
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
def __init__(self, term, header):
self.term = term
if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
raise ValueError("Terminal isn't capable enough -- you "
"should use a simpler progress dispaly.")
self.width = self.term.COLS or 75
self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width))
self.cleared = 1 #: true if we haven't drawn the bar yet.
self.update(0, '')
def update(self, percent, message):
if self.cleared:
sys.stdout.write(self.header)
self.cleared = 0
n = int((self.width-10)*percent)
sys.stdout.write(
self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
self.term.CLEAR_EOL + message.center(self.width))
def clear(self):
if not self.cleared:
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL)
self.cleared = 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With