Basj
Basj

Reputation: 46423

Terminal with each line after another + some fixed text as well

I'd like to have both:

It nearly works, until ~ Blah 250, when the look is destroyed! Why?


(source: gget.it)

from sys import stdout
import time

ESC = "\x1b"
CSI = ESC+"["

def movePos(row, col):
    stdout.write("%s%d;%dH" % (CSI, row, col))
  
stdout.write("%s2J" % CSI)      # CLEAR SCREEN

for i in range(1,1000):
    movePos(i+1,60)
    print time.strftime('%H:%M:%S', time.gmtime())
    movePos(i+5,60)
    print 'Bonjour'

    movePos(24+i,0)
    print "Blah %i" % i
    time.sleep(0.01)

With an ANSI terminal, how to have both normal terminal behaviour (one new line for each print) + fixed position display?

Note: On Windows, I use ansicon.exe to have ANSI support in Windows cmd.exe.

Upvotes: 0

Views: 862

Answers (2)

Basj
Basj

Reputation: 46423

Here is a solution:


(source: gget.it)

The code is (check here for latest version):

"""
zeroterm is a light weight terminal allowing both:
* lines written one after another (normal terminal/console behaviour)
* fixed position text

Note: Requires an ANSI terminal. For Windows 7, please download https://github.com/downloads/adoxa/ansicon/ansi160.zip and run ansicon.exe -i to install it.
"""

from sys import stdout
import time

class zeroterm:
    def __init__(self, nrow=24, ncol=50):      # nrow, ncol determines the size of the scrolling (=normal terminal behaviour) part of the screen
        stdout.write("\x1b[2J")                # clear screen
        self.nrow = nrow
        self.ncol = ncol
        self.buf = []

    def write(self, s, x=None, y=None):        # if no x,y specified, normal console behaviour
        if x is not None and y is not None:    # if x,y specified, fixed text position
            self.movepos(x,y)
            print s
        else:
            if len(self.buf) < self.nrow:
                self.buf.append(s)
            else:
                self.buf[:-1] = self.buf[1:]
                self.buf[-1] = s

            for i, r in enumerate(self.buf):
                self.movepos(i+1,0)
                print r[:self.ncol].ljust(self.ncol)

    def movepos(self, row, col):
        stdout.write("\x1b[%d;%dH" % (row, col))


if __name__ == '__main__':
    # An exemple
    t = zeroterm()
    t.write('zeroterm', 1, 60)

    for i in range(1000):
        t.write(time.strftime("%H:%M:%S"), 3, 60)
        t.write("Hello %i" % i)
        time.sleep(0.1)

Upvotes: 1

Thomas Dickey
Thomas Dickey

Reputation: 54505

From the given picture: ansicon appears to be allocating a console buffer to do its work; that has a limited size (due to the Windows console, which limits the buffer size to 64 kilobytes). Once your script reaches the end of the buffer and tries to move the cursor past the end, ansicon forces the whole buffer to scroll up. That makes the style of update change.

If your calls to movePos were bounded within ansicon's workspace, you would get more consistent results.

Regarding the "multiple lines" for "Bonjour", this chunk

movePos(i+1,60)
print time.strftime('%H:%M:%S', time.gmtime())
movePos(i+5,60)
print 'Bonjour'

is printing the date on one line, and then moving forward 4 lines, printing "Bonjour" on the same column. It seems that there's enough space (10 columns) on the same line to do this:

movePos(i+1,60)
print time.strftime('%H:%M:%S', time.gmtime())
movePos(i+1,70)
print 'Bonjour'

which would at least make the text on the right look consistent. The scrolling from movePos will cause some double-spacing at times though.

Upvotes: 0

Related Questions