Download the script here: relister.tgz
Source Code follows:
#!/usr/bin/env python #Written by Jarrod Lombardo, #Copylefted under GPL, 2004 (http://www.gnu.org/copyleft/gpl.html) #relister.py Usage documentation #executable input_file output_file #Documentation: #Key stroke Function #q quit, discarding changes #w write and quit #up-arrow move cursor up #down-arrow move cursor down #left-arrow move item up #right-arrow move item down #definitions #input-file: a text file which is a list, separated by '\n' #output-file: a text file which is a list, separated by '\n', # generated by this program import sys, curses, os.path # - - - - - o p e n f i l e s - - - - - def openfiles(argv): """Open the 2 files named in argv[1] and argv[2] or error """ #check if the args are there if (len(argv) != 3): sys.stderr.write("Usage " + argv[0] + " input_file output_file\n") sys.exit(0) #error if the files are the same if (os.path.realpath(argv[1]) == os.path.realpath(argv[2])): sys.stderr.write("Usage " + argv[0] + " input_file output_file\n") sys.stderr.write( "input_file and output_file must be different files.\n") sys.stdout.write( "Please re-run the program with a different output file.\n") sys.exit(0) #prompt if the output_file exists if os.path.isfile(argv[2]): sys.stdout.write("\n" + os.path.basename(argv[2]) + " exists.\n") ynval = raw_input("Would you like to overwrite it (y/n)?") if (ynval[0].upper() != 'Y'): sys.stdout.write( "Please re-run the program with a different output file.\n") sys.exit(0) #actually open the files return file(argv[1]), file(argv[2], 'w') # - - - - - i n i t i a l i z e E v e r y t h i n g - - - - - def initialize(stdscr, itemlist): """Initialize the screen and all of the positions. """ ymax, xmax = stdscr.getmaxyx() #the size of the window stdscr.move(0, 0) #move the the top left corner (it should already #be there (at 0,0), but do it just in case). #Print ymax lines to the screen yoffset = 0 for line in itemlist: if (yoffset <= ymax - 2): #it's really anoying, but the next 2 lines must be #separate for it to work. line = '%.4d ' + line line = line % (yoffset) stdscr.addnstr(yoffset, 0, line, xmax - 1) #move down one line yoffset += 1 else: break #create the cursor (highlight) initial position line = '0000 ' + itemlist[0] stdscr.addnstr(0, 0, line, xmax - 1, curses.A_REVERSE) stdscr.move(0, 0) #refresh the screen stdscr.refresh() return (stdscr, itemlist, 0) # - - - - - c u r d o w n - - - - - def curdown(stdscr, itemlist, listpos): """Move the cursor down one line. """ #if at bottom of list, do nothing if (len(itemlist) - 1 == listpos): return (stdscr, itemlist, listpos) ymax, xmax = stdscr.getmaxyx() ycur, xcur = stdscr.getyx() #if at bottom of screen if (ycur == ymax - 2): #shift all items up one line on the screen stdscr.move(0,0) stdscr.deleteln() #removes the line at 0,0 and moves all #other lines up one #display itemlist[listpos] as A_NORMAL line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur - 1, 0, line1, xmax - 1) #display itemlist[listpos + 1] as A_REVERSE listpos = listpos + 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur, 0, line2, xmax - 1, curses.A_REVERSE) stdscr.move(ycur, 0) #if anywhere else else: line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur, 0, line1, xmax - 1) listpos += 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur + 1, 0, line2, xmax - 1, curses.A_REVERSE) stdscr.move(ycur + 1, 0) return (stdscr, itemlist, listpos) # - - - - - c u r u p - - - - - def curup(stdscr, itemlist, listpos): """Move the cursor up one line. """ #if at top of list, do nothing if (0 == listpos): return (stdscr, itemlist, listpos) ymax, xmax = stdscr.getmaxyx() ycur, xcur = stdscr.getyx() #if at top of screen if (ycur == 0): #shift all items down one line on the screen stdscr.move(0, 0) stdscr.insertln() #inserts a blank line at 0,0 and moves all other #lines down one stdscr.move(ymax-1, 0) stdscr.deleteln() #display itemlist[listpos] as A_NORMAL line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur + 1, 0, line1, xmax - 1, curses.A_NORMAL) #display itemlist[listpos + 1] as A_REVERSE listpos -= 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur, 0, line2, xmax - 1, curses.A_REVERSE) stdscr.move(ycur, 0) #if anywhere else else: line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur, 0, line1, xmax - 1) listpos -= 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur - 1, 0, line2, xmax - 1, curses.A_REVERSE) stdscr.move(ycur - 1, 0) return (stdscr, itemlist, listpos) # - - - - - i t e m u p - - - - - def itemup(stdscr, itemlist, listpos): """Move the current item and cursor up one line. """ #if at top of list, do nothing if (0 == listpos): return (stdscr, itemlist, listpos) ymax, xmax = stdscr.getmaxyx() ycur, xcur = stdscr.getyx() #swap the current item up one position movingitem = itemlist[listpos] itemlist[listpos] = itemlist[listpos - 1] itemlist[listpos - 1] = movingitem #if at top of screen if (ycur == 0): #clean up the top line and shift all items down one line on the screen stdscr.move(1,0) stdscr.deleteln() stdscr.insertln() stdscr.insertln() stdscr.move(ymax-1, 0) stdscr.deleteln() #display itemlist[listpos + 1] as A_NORMAL listpos += 1 line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur + 2, 0, line1, xmax - 1) #display itemlist[listpos] as A_NORMAL listpos -= 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur + 1, 0, line2, xmax - 1) #display itemlist[listpos - 1] as A_REVERSE listpos -= 1 line3 = '%.4d ' + itemlist[listpos] line3 = line3 % listpos stdscr.addnstr(ycur, 0, line3, xmax - 1, curses.A_REVERSE) stdscr.move(ycur, 0) #if anywhere else else: #clean up the 2 lines being swapped stdscr.move(ycur - 1, 0) stdscr.deleteln() stdscr.deleteln() stdscr.insertln() stdscr.insertln() line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur, 0, line1, xmax - 1) listpos -= 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur - 1, 0, line2, xmax - 1, curses.A_REVERSE) stdscr.move(ycur - 1, 0) return (stdscr, itemlist, listpos) # - - - - - i t e m d o w n - - - - - def itemdown(stdscr, itemlist, listpos): """Move the current item and cursor down one line. """ #if at bottom of list, do nothing if (len(itemlist) - 1 == listpos): return (stdscr, itemlist, listpos) ymax, xmax = stdscr.getmaxyx() ycur, xcur = stdscr.getyx() #swap the current item up one position movingitem = itemlist[listpos] itemlist[listpos] = itemlist[listpos + 1] itemlist[listpos + 1] = movingitem #if at bottom of screen if (ycur == ymax - 2): #shift all items up one line on the screen stdscr.move(0,0) stdscr.deleteln() #removes the line at 0,0 and moves all #other lines up one #clean up the 2 lines being swapped stdscr.move(ycur - 1, 0) stdscr.deleteln() stdscr.deleteln() stdscr.insertln() stdscr.insertln() #display itemlist[listpos] as A_NORMAL line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur - 1, 0, line1, xmax - 1) #display itemlist[listpos + 1] as A_REVERSE listpos += 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur, 0, line2, xmax - 1, curses.A_REVERSE) stdscr.move(ycur, 0) #if anywhere else else: #clean up the 2 lines being swapped stdscr.move(ycur, 0) stdscr.deleteln() stdscr.deleteln() stdscr.insertln() stdscr.insertln() line1 = '%.4d ' + itemlist[listpos] line1 = line1 % listpos stdscr.addnstr(ycur, 0, line1, xmax - 1) listpos += 1 line2 = '%.4d ' + itemlist[listpos] line2 = line2 % listpos stdscr.addnstr(ycur + 1, 0, line2, xmax - 1, curses.A_REVERSE) stdscr.move(ycur + 1, 0) return (stdscr, itemlist, listpos) # - - - - - c u r s e s h a n d l e r - - - - - def curseshandler(stdscr, itemlist): """do curses crap, and return the reordered list """ #display itemlist and initialise everything updateneeded = 0 stdscr, itemlist, listpos = initialize(stdscr, itemlist) #wait for a signal while (1): c=stdscr.getch() # Get a keystroke #call whatever function is appropriate if (c == curses.KEY_DOWN): stdscr, itemlist, listpos = curdown(stdscr, itemlist, listpos) updateneeded = 1 elif (c == curses.KEY_UP): stdscr, itemlist, listpos = curup(stdscr, itemlist, listpos) updateneeded = 1 elif (c == curses.KEY_LEFT): stdscr, itemlist, listpos = itemup(stdscr, itemlist, listpos) updateneeded = 1 elif (c == curses.KEY_RIGHT): stdscr, itemlist, listpos = itemdown(stdscr, itemlist, listpos) updateneeded = 1 elif (c == ord('w')): return itemlist elif (c == ord('q')): return None #update the screen if necessary if (updateneeded == 1): #update the screen stdscr.refresh() updateneeded = 0 # - - - - - m a i n - - - - - #Take a input-file and return an output-file #open files cleanly or error infile, outfile = openfiles(sys.argv) #read data from file into a list itemlist = infile.readlines() #curses itemlist = curses.wrapper(curseshandler, itemlist) #write data to file if (itemlist != None): print "\nWriting list to file." outfile.writelines(itemlist) else: print "\nDiscarding changes to list." #close our files infile.close() outfile.close()