/lib/PEG_GrammarExplorer/PEG_GrammarExplorer/PegSamples/python_2_5_2/input/simple_tabview.py
Python | 234 lines | 199 code | 7 blank | 28 comment | 8 complexity | 74e27ba9020bfffeed9c6e6194fc9551 MD5 | raw file
- #!/usr/local/bin/python
- # tabview.py -- View a tab-delimited file in a spreadsheet-like display.
- # Contributed by A.M. Kuchling <amk@amk.ca>
- #
- # The tab-delimited file is displayed on screen. The highlighted
- # position is shown in the top-left corner of the screen; below it are
- # shown the contents of that cell.
- #
- # Movement keys are:
- # Cursor keys: Move the highlighted cell, scrolling if required.
- # Q or q : Quit
- # TAB : Page right a screen
- # Home : Move to the start of this line
- # End : Move to the end of this line
- # PgUp/PgDn : Move a page up or down
- # Insert : Memorize this position
- # Delete : Return to memorized position (if any)
- #
- # TODO :
- # A 'G' for Goto: enter a cell like AA260 and move there
- # A key to re-read the tab-delimited file
- #
- # Possible projects:
- # Allow editing of cells, and then saving the modified data
- # Add formula evaluation, and you've got a simple spreadsheet
- # program. (Actually, you should allow displaying both via curses and
- # via a Tk widget.)
- #
- import curses, re, string
- def yx2str(y,x):
- "Convert a coordinate pair like 1,26 to AA2"
- if x<26: s=chr(65+x)
- else:
- x=x-26
- s=chr(65+ (x/26) ) + chr(65+ (x%26) )
- s=s+str(y+1)
- return s
- coord_pat = re.compile('^(?P<x>[a-zA-Z]{1,2})(?P<y>\d+)$')
- def str2yx(s):
- "Convert a string like A1 to a coordinate pair like 0,0"
- match = coord_pat.match(s)
- if not match: return None
- y,x = match.group('y', 'x')
- x = string.upper(x)
- if len(x)==1: x=ord(x)-65
- else:
- x= (ord(x[0])-65)*26 + ord(x[1])-65 + 26
- return string.atoi(y)-1, x
- assert yx2str(0,0) == 'A1'
- assert yx2str(1,26) == 'AA2'
- assert str2yx('AA2') == (1,26)
- assert str2yx('B2') == (1,1)
-
- class TabFile:
- def __init__(self, scr, filename, column_width=20):
- self.scr=scr ; self.filename = filename
- self.column_width = column_width
- f=open(filename, 'r')
- self.data = []
- while (1):
- L=f.readline()
- if L=="": break
- self.data.append( string.split(L, '\t') )
- # if len(self.data)>6: break # XXX
- self.x, self.y = 0,0
- self.win_x, self.win_y = 0,0
- self.max_y, self.max_x = self.scr.getmaxyx()
- self.num_columns = int(self.max_x/self.column_width)
- self.scr.clear()
- self.display()
- def move_to_end(self):
- """Move the highlighted location to the end of the current line."""
- # This is a method because I didn't want to have the code to
- # handle the End key be aware of the internals of the TabFile object.
- yp=self.y+self.win_y ; xp=self.x+self.win_x
- if len(self.data)<=yp: end=0
- else: end=len(self.data[yp])-1
-
- # If the end column is on-screen, just change the
- # .x value appropriately.
- if self.win_x <= end < self.win_x + self.num_columns:
- self.x = end - self.win_x
- else:
- if end<self.num_columns:
- self.win_x = 0 ; self.x = end
- else:
- self.x = self.num_columns-1
- self.win_x = end-self.x
-
-
- def display(self):
- """Refresh the current display"""
-
- self.scr.addstr(0,0,
- yx2str(self.y + self.win_y, self.x+self.win_x)+' ',
- curses.A_REVERSE)
- for y in range(0, self.max_y-3):
- self.scr.move(y+2,0) ; self.scr.clrtoeol()
- for x in range(0, int(self.max_x / self.column_width) ):
- self.scr.attrset(curses.A_NORMAL)
- yp=y+self.win_y ; xp=x+self.win_x
- if len(self.data)<=yp: s=""
- elif len(self.data[yp])<=xp: s=""
- else: s=self.data[yp][xp]
- s = string.ljust(s, 15)[0:15]
- if x==self.x and y==self.y: self.scr.attrset(curses.A_STANDOUT)
- self.scr.addstr(y+2, x*self.column_width, s)
- yp=self.y+self.win_y ; xp=self.x+self.win_x
- if len(self.data)<=yp: s=""
- elif len(self.data[yp])<=xp: s=""
- else: s=self.data[yp][xp]
- self.scr.move(1,0) ; self.scr.clrtoeol()
- self.scr.addstr(s[0:self.max_x])
- self.scr.refresh()
- def main(stdscr):
- import string, curses, sys
- if len(sys.argv)==1:
- print 'Usage: tabview.py <filename>'
- return
- filename=sys.argv[1]
- # Clear the screen and display the menu of keys
- stdscr.clear()
- file = TabFile(stdscr, filename)
-
- # Main loop:
- while (1):
- stdscr.move(file.y+2, file.x*file.column_width) # Move the cursor
- c=stdscr.getch() # Get a keystroke
- if 0<c<256:
- c=chr(c)
- # Q or q exits
- if c in 'Qq': break
- # Tab pages one screen to the right
- elif c=='\t':
- file.win_x = file.win_x + file.num_columns
- file.display()
- else: pass # Ignore incorrect keys
- # Cursor keys
- elif c==curses.key_up:
- if file.y == 0:
- if file.win_y>0: file.win_y = file.win_y - 1
- else: file.y=file.y-1
- file.display()
- elif c==curses.key_down:
- if file.y < file.max_y-3 -1: file.y=file.y+1
- else: file.win_y = file.win_y+1
- file.display()
- elif c==curses.key_left:
- if file.x == 0:
- if file.win_x>0: file.win_x = file.win_x - 1
- else: file.x=file.x-1
- file.display()
- elif c==curses.key_right:
- if file.x < int(file.max_x/file.column_width)-1: file.x=file.x+1
- else: file.win_x = file.win_x+1
- file.display()
- # Home key moves to the start of this line
- elif c==curses.key_home:
- file.win_x = file.x = 0
- file.display()
- # End key moves to the end of this line
- elif c==curses.key_end:
- file.move_to_end()
- file.display()
- # PageUp moves up a page
- elif c==curses.key_ppage:
- file.win_y = file.win_y - (file.max_y - 2)
- if file.win_y<0: file.win_y = 0
- file.display()
- # PageDn moves down a page
- elif c==curses.key_npage:
- file.win_y = file.win_y + (file.max_y - 2)
- if file.win_y<0: file.win_y = 0
- file.display()
-
- # Insert memorizes the current position
- elif c==curses.key_ic:
- file.save_y, file.save_x = file.y + file.win_y, file.x + file.win_x
- # Delete restores a saved position
- elif c==curses.key_dc:
- if hasattr(file, 'save_y'):
- file.x = file.y = 0
- file.win_y, file.win_x = file.save_y, file.save_x
- file.display()
- else:
- stdscr.addstr(0,50, curses.keyname(c)+ ' pressed')
- stdscr.refresh()
- pass # Ignore incorrect keys
- if __name__=='__main__':
- import curses, traceback
- try:
- # Initialize curses
- stdscr=curses.initscr()
- # Turn off echoing of keys, and enter cbreak mode,
- # where no buffering is performed on keyboard input
- curses.noecho() ; curses.cbreak()
- # In keypad mode, escape sequences for special keys
- # (like the cursor keys) will be interpreted and
- # a special value like curses.key_left will be returned
- stdscr.keypad(1)
- main(stdscr) # Enter the main loop
- # Set everything back to normal
- stdscr.keypad(0)
- curses.echo() ; curses.nocbreak()
- curses.endwin() # Terminate curses
- except:
- # In the event of an error, restore the terminal
- # to a sane state.
- stdscr.keypad(0)
- curses.echo() ; curses.nocbreak()
- curses.endwin()
- traceback.print_exc() # Print the exception