| 172 | |
| 173 | |
| 174 | class Reindenter: |
| 175 | |
| 176 | def __init__(self, f): |
| 177 | self.find_stmt = 1 # next token begins a fresh stmt? |
| 178 | self.level = 0 # current indent level |
| 179 | |
| 180 | # Raw file lines. |
| 181 | self.raw = f.readlines() |
| 182 | |
| 183 | # File lines, rstripped & tab-expanded. Dummy at start is so |
| 184 | # that we can use tokenize's 1-based line numbering easily. |
| 185 | # Note that a line is all-blank iff it's "\n". |
| 186 | self.lines = [_rstrip(line).expandtabs() + "\n" |
| 187 | for line in self.raw] |
| 188 | self.lines.insert(0, None) |
| 189 | self.index = 1 # index into self.lines of next line |
| 190 | |
| 191 | # List of (lineno, indentlevel) pairs, one for each stmt and |
| 192 | # comment line. indentlevel is -1 for comment lines, as a |
| 193 | # signal that tokenize doesn't know what to do about them; |
| 194 | # indeed, they're our headache! |
| 195 | self.stats = [] |
| 196 | |
| 197 | # Save the newlines found in the file so they can be used to |
| 198 | # create output without mutating the newlines. |
| 199 | self.newlines = f.newlines |
| 200 | |
| 201 | def run(self): |
| 202 | tokens = tokenize.generate_tokens(self.getline) |
| 203 | for _token in tokens: |
| 204 | self.tokeneater(*_token) |
| 205 | # Remove trailing empty lines. |
| 206 | lines = self.lines |
| 207 | while lines and lines[-1] == "\n": |
| 208 | lines.pop() |
| 209 | # Sentinel. |
| 210 | stats = self.stats |
| 211 | stats.append((len(lines), 0)) |
| 212 | # Map count of leading spaces to # we want. |
| 213 | have2want = {} |
| 214 | # Program after transformation. |
| 215 | after = self.after = [] |
| 216 | # Copy over initial empty lines -- there's nothing to do until |
| 217 | # we see a line with *something* on it. |
| 218 | i = stats[0][0] |
| 219 | after.extend(lines[1:i]) |
| 220 | for i in range(len(stats) - 1): |
| 221 | thisstmt, thislevel = stats[i] |
| 222 | nextstmt = stats[i + 1][0] |
| 223 | have = getlspace(lines[thisstmt]) |
| 224 | want = thislevel * 4 |
| 225 | if want < 0: |
| 226 | # A comment line. |
| 227 | if have: |
| 228 | # An indented comment line. If we saw the same |
| 229 | # indentation before, reuse what it most recently |
| 230 | # mapped to. |
| 231 | want = have2want.get(have, -1) |