' (HTML): {:s}".format(ln, text)) zones, stack = [], {} for kind, name, ln in markers: if kind == "BEGIN": if name in stack: problems.append(" line {:d}: BEGIN {:s} reopened before its" " END (earlier BEGIN at line {:d})" .format(ln, name, stack[name])) stack[name] = ln else: if name in stack: b = stack.pop(name) if ":" not in name: zones.append((name, b, ln)) else: problems.append(" line {:d}: END {:s} has no matching BEGIN" .format(ln, name)) for name, ln in stack.items(): problems.append(" line {:d}: BEGIN {:s} is never closed by an END" .format(ln, name)) if problems: raise SystemExit("Registry NOT rebuilt \u2014 fix these markers first:\n" + "\n".join(sorted(problems))) zones.sort(key=lambda z: z[1]) # Four-region classification (uses original, pre-shift line numbers \u2014 # a uniform shift below does not change which region a marker is in). def region_of(b): if style_close and b < style_close: return "CSS" if script_open and b < script_open: return "HTML" if script_close and b < script_close: return "JS" return "HTML" counts = {} for n, _, _ in zones: counts[n] = counts.get(n, 0) + 1 labeled = [] for n, b, e in zones: nm = (n + " (" + region_of(b) + ")") if counts[n] > 1 else n labeled.append((nm, b, e)) # Locate the existing ZONE REGISTRY block so we know how many lines it # currently occupies. It always precedes the REBUILDER block, so the # first