How can I get (and set) the current bash cursor position when using readline python?

I have a python script that controls the stdin, stdout and stderr of any application and allows you to correctly insert readline. Think of any application that has many console outputs, but also accepts commands from stdin.

Anyway, 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 processing stdout, I call print_line (). This runs through everything the user can print, prints a line, and then restores the user input text. All this happens without the user noticing something.

The problem occurs when the cursor is not at the end of any input that the user enters. 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 problem, 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: try and visualize what I wrote:

The terminal is as follows:

 ---------------------------------------------- | | | | | <scolling command output here> | | | | <scolling command output here> | | | |: <user inputted text here> | ---------------------------------------------- 

Thus, the output text constantly scrolls as new magazines arrive. At the same time, the user is currently editing and writing a new command, which will be inserted after clicking. This way it looks like a python console, but output is always added.

+8
python bash readline
source share
1 answer

Can I offer Python curses ?

Here are the basic instructions.

The curses module provides an interface to the curses library, the de facto standard for portable processing of additional terminals.

While curses is most commonly used in Unix environments, versions are available for DOS, OS / 2, and possibly other systems. This extension is designed to match the ncurses APIs, the open source curses library hosted on Linux, and the BSD Unix variants.


As an alternative

I found Terminal Controller here: Using terminfo for portable color output and cursor control . It looks more portable than the sitename suggested (MacOS is mentioned in the comments, albeit with changes).

Here is a usage example showing 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 
+4
source share

All Articles