Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pagination with the python cmd module

I'm prototyping a Python app with the cmd module.

Some messages to the user will be quite long and I'd like to paginate them. The first 10 (or a configurable number) lines of the message would appear, and pressing the SPACE bar would display the next page, until the end of the message.

I don't want to reinvent something here, is there a simple mean to implement this feature?

like image 632
Gra Avatar asked Feb 06 '09 16:02

Gra


3 Answers

The simple thing would just be to pipe your script through "less" or a similar command at runtime.

Here's a simple method that does approximately what you want, though:

def print_and_wait(some_long_message):
    lines = some_long_message.split('\n')
    i=0
    while i < len(lines):
        print '\n'.join(lines[i:i+10])
        raw_input("press enter to read more...")
        i += 10

You could also look into using curses.

like image 107
Yoni Samlan Avatar answered Nov 15 '22 15:11

Yoni Samlan


As Yoni said above the right way to do this is to provide a print method that pages automatically inside your running cmd instance. The constructor of Cmd takes stdin and stdout arguments. So simple provide an object that works like stdout and supports your paging print method.

class PagingStdOut(object):
    def write(self, buffer, lines_before_pause=40):
        # do magic paging here...
like image 21
Trey Stout Avatar answered Nov 15 '22 15:11

Trey Stout


I had the same question. There is a pager built in to the pydoc module. I incorporated it thusly (which I find hackish and unsatisfying... I'm open to better ideas though).

I like the idea that it would autopage if there are more than x results and paging is on, which is possible to implement, but not done here.

import cmd
from pydoc import pager
from cStringIO import StringIO
import sys

PAGER = True
class Commander(cmd.Cmd):
    prompt = "> "
    def do_pager(self,line):
        global PAGER
        line = line + " 1"
        tokens = line.lower().split()
        if tokens[0] in ("on","true","t", "1"):
            PAGER = True
            print "# setting PAGER True"
        elif tokens[0] in ("off","false","f","0"):
            PAGER = False
            print "# setting PAGER False"
        else:
            print "# can't set pager:  don't know -> %s" % tokens[0]

    def do_demo(self,line):
        results = dict(a=1,b=2,c=3)
        self.format_commandline_results(results)

    def format_commandline_results(self,results):
        if PAGER:
            ofh = StringIO()
        else:
            ofh = sys.stdout

        for (k,v) in sorted(results.items()):
            print >> ofh, "%s -> %s" % (k,v)

        if PAGER:
            ofh.seek(0)
            pager(ofh.read())

        return None

    def do_EOF(self,line):
        print "",
        return True

if __name__ == "__main__":
    Commander().cmdloop("# try: \n> pager off \n> demo \n> pager on \n> demo \n\n")
like image 29
Gregg Lind Avatar answered Nov 15 '22 15:11

Gregg Lind