Skip to content

Instantly share code, notes, and snippets.

@jcarlosroldan
Created October 27, 2021 19:41
Show Gist options
  • Save jcarlosroldan/c7e65ec9cae879c3bd73db762b551c26 to your computer and use it in GitHub Desktop.
Save jcarlosroldan/c7e65ec9cae879c3bd73db762b551c26 to your computer and use it in GitHub Desktop.
Convert the files in a directory from space-indented to tab indented detecting the indentation level automatically
''' TABBER: Because spaces suck
This script will recursively convert all files in its directory from space indented to tab indented.
It will detect the number of spaces used for indentation and transform them into tabbed files.
Usage:
1. Copy the directory you want to convert and put this file inside. If you're brave enough, skip the
copying part.
2. Review the EXTENSIONS and IGNORE_FILES values.
3. Run it.
4. Review the errors if any, and run it again.
'''
from math import gcd
from os import listdir
from os.path import isdir, join
from re import findall, match
EXTENSIONS = 'txt', 'json', 'js', 'yaml', 'vue', 'editorconfig', 'md', 'gitignore'
IGNORE_FILES = 'node_modules', '.vscode', '.git', 'package-lock.json'
def tabulate(base='.'):
for file in listdir(base):
if file in IGNORE_FILES: continue
path = join(base, file)
if isdir(path):
tabulate(path)
elif any(path.endswith(ext) for ext in EXTENSIONS):
with open(path, 'r', encoding='utf-8') as fp:
content = fp.read()
space_starts = findall(r'\n( +)[^\s]', content)
tab_starts = findall(r'\n(\t+)[^\s]', content)
if len(space_starts) and len(tab_starts):
print('%s\n\tSkipped due to mixed spaces and tabs' % path)
continue
if not len(space_starts): continue
space_starts = list({len(s) for s in space_starts if s is not None})
tab_size = space_starts[0]
for length in space_starts[1:]:
tab_size = gcd(length, tab_size)
if tab_size == 1:
print('%s\n\tSkipped due to inconsistent spacing of lengths: %s' % (path, ', '.join(sorted(space_starts))))
res = ''
previous_indentation = -1
for n, line in enumerate(content.split('\n')):
if not len(line):
res += '\n'
continue
indentation = match(r'^ +', line)
indentation = len(indentation.group()) // tab_size if indentation is not None else 0
if abs(previous_indentation - indentation) > 1:
print('%s\n\tSkipped due to inconsistent line indentation on line %d' % (path, n))
break
res += indentation * '\t' + line.lstrip(' ') + '\n'
previous_indentation = indentation
else:
with open(path, 'w', encoding='utf-8') as fp:
fp.write(res.rstrip())
if __name__ == '__main__':
tabulate()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment