Jack Jansen | b5ec5e4 | 2000-11-29 10:02:22 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | import tokenize |
| 4 | import string |
| 5 | |
| 6 | TABSONLY = 'TABSONLY' |
| 7 | SPACESONLY = 'SPACESONLY' |
| 8 | MIXED = 'MIXED' |
| 9 | |
| 10 | class PyText: |
| 11 | def __init__(self, fnm, optdict): |
| 12 | self.optdict = optdict |
| 13 | self.fnm = fnm |
| 14 | self.txt = open(self.fnm, 'r').readlines() |
| 15 | self.indents = [(0, 0, )] |
| 16 | self.lnndx = 0 |
| 17 | self.indentndx = 0 |
| 18 | def getline(self): |
| 19 | if self.lnndx < len(self.txt): |
| 20 | txt = self.txt[self.lnndx] |
| 21 | self.lnndx = self.lnndx + 1 |
| 22 | else: |
| 23 | txt = '' |
| 24 | return txt |
| 25 | def tokeneater(self, type, token, start, end, line): |
| 26 | if type == tokenize.INDENT: |
| 27 | (lvl, s) = self.indents[-1] |
| 28 | self.indents[-1] = (lvl, s, start[0]-1) |
| 29 | self.indents.append((lvl+1, start[0]-1,)) |
| 30 | elif type == tokenize.DEDENT: |
| 31 | (lvl, s) = self.indents[-1] |
| 32 | self.indents[-1] = (lvl, s, start[0]-1) |
| 33 | self.indents.append((lvl-1, start[0]-1,)) |
| 34 | elif type == tokenize.ENDMARKER: |
| 35 | (lvl, s) = self.indents[-1] |
| 36 | self.indents[-1] = (lvl, s, len(self.txt)) |
| 37 | def split(self, ln): |
| 38 | content = string.lstrip(ln) |
| 39 | if not content: |
| 40 | return ('', '\n') |
| 41 | lead = ln[:len(ln) - len(content)] |
| 42 | lead = string.expandtabs(lead) |
| 43 | return (lead, content) |
| 44 | |
| 45 | def process(self): |
| 46 | style = self.optdict.get('style', TABSONLY) |
| 47 | indent = string.atoi(self.optdict.get('indent', '4')) |
| 48 | tabsz = string.atoi(self.optdict.get('tabs', '8')) |
| 49 | print 'file %s -> style %s, tabsize %d, indent %d' % (self.fnm, style, tabsz, indent) |
| 50 | tokenize.tokenize(self.getline, self.tokeneater) |
| 51 | #import pprint |
| 52 | #pprint.pprint(self.indents) |
| 53 | new = [] |
| 54 | for (lvl, s, e) in self.indents: |
| 55 | if s >= len(self.txt): |
| 56 | break |
| 57 | if s == e: |
| 58 | continue |
| 59 | oldlead, content = self.split(self.txt[s]) |
| 60 | #print "oldlead", len(oldlead), `oldlead` |
| 61 | if style == TABSONLY: |
| 62 | newlead = '\t'*lvl |
| 63 | elif style == SPACESONLY: |
| 64 | newlead = ' '*(indent*lvl) |
| 65 | else: |
| 66 | sz = indent*lvl |
| 67 | t,spcs = divmod(sz, tabsz) |
| 68 | newlead = '\t'*t + ' '*spcs |
| 69 | new.append(newlead + content) |
| 70 | for ln in self.txt[s+1:e]: |
| 71 | lead, content = self.split(ln) |
| 72 | #print "lead:", len(lead) |
| 73 | new.append(newlead + lead[len(oldlead):] + content) |
| 74 | self.save(new) |
| 75 | #print "---", self.fnm |
| 76 | #for ln in new: |
| 77 | # print ln, |
| 78 | #print |
| 79 | |
| 80 | def save(self, txt): |
| 81 | bakname = os.path.splitext(self.fnm)[0]+'.bak' |
| 82 | print "backing up", self.fnm, "to", bakname |
| 83 | #print os.getcwd() |
| 84 | try: |
| 85 | os.rename(self.fnm, bakname) |
| 86 | except os.error: |
| 87 | os.remove(bakname) |
| 88 | os.rename(self.fnm, bakname) |
| 89 | open(self.fnm, 'w').writelines(txt) |
| 90 | |
| 91 | def test(): |
| 92 | tc = PyText('test1.py') |
| 93 | tc.process() |
| 94 | tc = PyText('test1.py') |
| 95 | tc.process(style=TABSONLY) |
| 96 | tc = PyText('test1.py') |
| 97 | tc.process(style=MIXED, indent=4, tabs=8) |
| 98 | tc = PyText('test1.py') |
| 99 | tc.process(style=MIXED, indent=2, tabs=8) |
| 100 | |
| 101 | def cleanfile(fnm, d): |
| 102 | if os.path.isdir(fnm) and not os.path.islink(fnm): |
| 103 | names = os.listdir(fnm) |
| 104 | for name in names: |
| 105 | fullnm = os.path.join(fnm, name) |
| 106 | if (os.path.isdir(fullnm) and not os.path.islink(fullnm)) or \ |
| 107 | os.path.normcase(fullnm[-3:]) == ".py": |
| 108 | cleanfile(fullnm, d) |
| 109 | return |
| 110 | tc = PyText(fnm, d) |
| 111 | tc.process() |
| 112 | |
| 113 | usage="""\ |
| 114 | %s [options] [path...] |
| 115 | options |
| 116 | -T : reformat to TABS ONLY |
| 117 | -S : reformat to SPACES ONLY ( -i option is important) |
| 118 | -M : reformat to MIXED SPACES / TABS ( -t and -i options important) |
| 119 | -t<n> : tab is worth <n> characters |
| 120 | -i<n> : indents should be <n> characters |
| 121 | -h : print this text |
| 122 | path is file or directory |
| 123 | """ |
| 124 | if __name__ == '__main__': |
| 125 | import sys, getopt, os |
| 126 | opts, args = getopt.getopt(sys.argv[1:], "TSMht:i:") |
| 127 | d = {} |
| 128 | print `opts` |
| 129 | for opt in opts: |
| 130 | if opt[0] == '-T': |
| 131 | d['style'] = TABSONLY |
| 132 | elif opt[0] == '-S': |
| 133 | d['style'] = SPACESONLY |
| 134 | elif opt[0] == '-M': |
| 135 | d['style'] = MIXED |
| 136 | elif opt[0] == '-t': |
| 137 | d['tabs'] = opt[1] |
| 138 | elif opt[0] == '-i': |
| 139 | d['indent'] = opt[1] |
| 140 | elif opt[0] == '-h': |
| 141 | print usage % sys.argv[0] |
| 142 | sys.exit(0) |
| 143 | if not args: |
| 144 | print usage % sys.argv[0] |
| 145 | for arg in args: |
| 146 | cleanfile(arg, d) |
| 147 | |
| 148 | |
| 149 | |
| 150 | |
| 151 | |
| 152 | |
| 153 | |
| 154 | |
| 155 | |
| 156 | |
| 157 | |
| 158 | |
| 159 | |
| 160 | |