#!/usr/bin/env python # -*- coding: iso-8859-1 -*- #******************************************************************************\ #* $Source$ #* $Id: docutils-movesec 2965 2005-02-12 05:20:29Z blais $ #* #* Copyright (C) 2003, Martin Blais #* #* This program is free software; you can redistribute it and/or modify #* it under the terms of the GNU General Public License as published by #* the Free Software Foundation; either version 2 of the License, or #* (at your option) any later version. #* #* This program is distributed in the hope that it will be useful, #* but WITHOUT ANY WARRANTY; without even the implied warranty of #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #* GNU General Public License for more details. #* #* You should have received a copy of the GNU General Public License #* along with this program; if not, write to the Free Software #* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #* #*****************************************************************************/ """docutils-movesec [] Move docutils section underlines one level up or down. This program can be used to change the level of your sections within a restructured text file. 'newchar' is the character to use for the replacing the bottom-level (or top-level if --down) section underlines. Note: the whitespace characters that appear after the section underlines are preserved. Note2: this might screw up transition markers. """ __version__ = "$Revision: 2965 $" __author__ = "Martin Blais " #=============================================================================== # EXTERNAL DECLARATIONS #=============================================================================== import sys, re #=============================================================================== # LOCAL DECLARATIONS #=============================================================================== # regular expression to get lines with no whitespace in front and a single word. secre = re.compile('^([^\s]+)\s*$') #------------------------------------------------------------------------------- # def getlines( fn ): """Opens the given file and detects the section lines. Return the line numbers.""" if fn == '-': f = sys.stdin else: try: f = open(fn, 'r') except IOError, e: raise SystemExit("Error: opening file '%s':\n%s" % (fn, str(e))) filelines = f.readlines() minthres = 3 seclines = [] lc = -1 for l in filelines: lc += 1 mo = secre.match(l) if not mo: continue l = mo.group(1) if len(l) < minthres: continue c = l[0] skip = 0 for cc in l[1:]: if c != cc: skip = 1 break if not skip: seclines.append(lc) return seclines, filelines #------------------------------------------------------------------------------- # def compute_order( seclines, filelines ): """Compute ordering characters.""" secorder = [] prevord = -1 for sl in seclines: l = filelines[sl] try: prevord = secorder.index(l[0]) except ValueError: if prevord != len(secorder) - 1: raise SystemExit(\ "Error: sections are not consistent at line '%d'" % (sl+1)) prevord = len(secorder) secorder.append(l[0]) return secorder #=============================================================================== # MAIN #=============================================================================== #------------------------------------------------------------------------------- # def main(): debug = False import optparse parser = optparse.OptionParser(__doc__) parser.add_option('-u', '--up', action="store_true", dest="direction", default=True, help="specify move sections up (default)") parser.add_option('-d', '--down', action="store_false", dest="direction", help="specify move sections down") opts, args = parser.parse_args() if len(args) != 2: raise SystemExit('Error: please a new character and a single filename.') newchar, fn = args seclines, filelines = getlines(fn) secorder = compute_order(seclines, filelines) # create new output order. if opts.direction: # up neworder = [newchar] + secorder[:-1] else: # down neworder = secorder[1:] + [newchar] # compute a mapping of old to new omap = {} for i in xrange(len(secorder)): omap[ secorder[i] ] = neworder[i] if debug: for sl in seclines: l = filelines[sl] print secorder.index(l[0]), l, from pprint import pprint print secorder print neworder pprint(omap) # perform replacement of desired line, preserve original whitespace. for sl in seclines: l = filelines[sl] nc = len(l.strip()) filelines[sl] = omap[ l[0] ] * nc + l[nc:] # output. for l in filelines: sys.stdout.write(l) if __name__ == '__main__': main()