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?
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.
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...
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 in ("on","true","t", "1"): PAGER = True print "# setting PAGER True" elif tokens in ("off","false","f","0"): PAGER = False print "# setting PAGER False" else: print "# can't set pager: don't know -> %s" % tokens 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")
Paging subroutines can be found in the genutils.py file of IPython (see page, or page_dumb for a simpler one). The code is a little complicated, but that's probably unavoidable if you are trying to be portable to systems including Windows and the various kinds of terminal emulators.