RaminNietzsche
RaminNietzsche

Reputation: 2791

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.

Upvotes: 10

Views: 717

Answers (1)

cxw
cxw

Reputation: 17051

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).

Upvotes: 11

Related Questions