Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some characters stick to my colorized prompt in Python cmd

I am using Python 2's cmd module to make a command line for a program. Everything works nicely as long as I don't add color to my prompt.

Working code:

from cmd import Cmd

class App(Cmd):

    def __init__(self):
        Cmd.__init__(self)
        self.prompt = "PG ["+ (str('username'), 'green') +"@"+ str('hostname') +"]: "

    def do_exit(self, line):
        '''
        '''
        return True

App().cmdloop()

When I change my code as below, if I enter a long command or try to search in the command history, some characters stick to my prompt.

Problem code:

from cmd import Cmd

class App(Cmd):

    def __init__(self):
        Cmd.__init__(self)
        self.prompt = "PG ["+ self.colorize(str('username'), 'green') +"@"+ str('hostname') +"]: "

    colorcodes =    {'green':{True:'\x1b[32m',False:'\x1b[39m'}}


    def colorize(self, val, color):
        return self.colorcodes[color][True] + val + self.colorcodes[color][False]

    def do_exit(self, line):
        '''
        '''
        return True

App().cmdloop()

You can see this problem in asciicasts. The problem also exists with the cmd2 module.

like image 364
RaminNietzsche Avatar asked Apr 09 '17 07:04

RaminNietzsche


1 Answers

Just add markers to your color codes:

    colorcodes =    {'green':{True:'\x01\x1b[32m\x02',False:'\x01\x1b[39m\x02'}}
                                  # ^^^^        ^^^^         ^^^^        ^^^^

In your asciicast, you have problems when you leave i-search mode and the prompt is re-printed. That is because Python doesn't know that the escape characters don't actually take up space on the screen. Putting \x01 before each escape sequence, and \x02 after each escape sequence, tells Python to assume those characters take up no space, and so the prompt will be correctly reprinted.

This is the same solution as in this answer, which had the corresponding problem in a different context. There is an open issue to mention this in the Python readline documentation, but I don't see that it has yet been done.

I tested the above colorcodes values with Python 2.7.12 on Cygwin, running in mintty. In the prompt, username printed green and everything else printed the default (light gray). I used the standard system cmd module, not cmd2 (which you linked).

like image 75
cxw Avatar answered Nov 19 '22 06:11

cxw