4
\$\begingroup\$

This program converts glob files' tabs to spaces. There is a special case to ignore content inside triple back ticks.

Example usage is ./tab_2_spaces.py *.md

Main Concern: Can I write the while loop better?

#!/usr/bin/env python3
"""
This program is used to convert markdown file's tab indentations to 2 spaces.
"""

import argparse
from pathlib import Path
import os
import io
import itertools
from multiprocessing import Pool

_TAB_2_SPACE = "  "


def fix_indent(filename):
    with io.open(filename, mode="r", encoding="utf-8") as h:
        text = h.read()

    lines = text.splitlines(True)
    c = len(lines)
    i = 0

    # Replace tab to spaces
    while i < c:
        line = lines[i]

        if line.startswith("```"):
            i += 1
            while i < c:
                if lines[i].startswith("```"):
                    break
                i += 1
            else:
                continue
            break
        elif line.startswith("\t"):
            lines[i] = line.replace("\t", _TAB_2_SPACE)

        i += 1

    with io.open(filename, mode="w", encoding="utf-8") as h:
        h.write("".join(lines))


def main():
    parser = argparse.ArgumentParser(description="Fix indent")
    parser.add_argument(
        "files", metavar="N", type=str, nargs="+", help="List of files to scan"
    )

    args = parser.parse_args()
    all_files = tuple(
        itertools.chain(
            *[
                (filename for filename in Path().glob("**/" + file_))
                for file_ in args.files
            ]
        )
    )

    with Pool(2) as process_pool:
        process_pool.map(fix_indent, all_files)


if __name__ == "__main__":
    main()
\$\endgroup\$
2
\$\begingroup\$

A lot of the code in your while loop can be replaced with a for loop using enumerate() and a toggled boolean.

You should be able to replace your code from c = len(lines) (line 21) down through your entire while loop with:


skip = False
for index, line in enumerate(lines):
    if line.startswith("```"):
        skip = not skip
    else:
        if not skip:
            if line.startswith("\t"):
                lines[index] = line.replace("\t", _TAB_2_SPACE)

I can't test this right now, so please let me know if you run in to any problems with this implementation.

\$\endgroup\$
  • \$\begingroup\$ You can merge else and if to an elif 🤔and next if with an and. \$\endgroup\$ – bhathiya-perera Sep 10 at 10:00
  • 2
    \$\begingroup\$ elif not skip and line.startswith("\t"): \$\endgroup\$ – bhathiya-perera Sep 10 at 10:03
  • \$\begingroup\$ @bhathiya-perera I felt that my implementation was easier to read so I chose not to condense it, but you are correct. \$\endgroup\$ – Confettimaker Sep 10 at 17:14
  • 1
    \$\begingroup\$ Indeed. It's far better than the Java like Python I've written above. :) \$\endgroup\$ – bhathiya-perera Sep 10 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.