Skip to content

Instantly share code, notes, and snippets.

@SJShaw
Created August 1, 2023 11:15
Show Gist options
  • Save SJShaw/4830f6b1a0dd0b779713a617f7c84819 to your computer and use it in GitHub Desktop.
Save SJShaw/4830f6b1a0dd0b779713a617f7c84819 to your computer and use it in GitHub Desktop.
Convert a file using simple whitespace (1 char per level) indents to a numbered system
#!/usr/bin/env python
import argparse
class Item:
def __init__(self, name, depth):
self.name = name
self.depth = depth
self.children = []
def add_child(self, item):
self.children.append(item)
def __iter__(self):
for child in self.children:
yield child
def __str__(self):
return f"Item({self.name}, {[child.name for child in self]})"
def __repr__(self):
return str(self)
def parse(iterator) -> list[Item]:
root = Item("", 0)
stack = [root]
current = root
reuse = None
depth = 1
while True:
if reuse:
line = reuse
reuse = None
else:
line = next(iterator, None)
if line is None:
return root.children
stripped = line.strip()
# skip blank lines or comments
if not stripped or stripped.startswith("#"):
continue
assert line
diff = len(line) - len(stripped)
if diff == depth:
current.add_child(Item(stripped, depth))
assert current.children
continue
if diff == depth + 1:
current = current.children[-1]
stack.append(current)
depth += 1
reuse = line
continue
if diff < depth:
reuse = line
while stack and stack[-1].depth != diff:
depth -= 1
stack.pop()
depth = diff
# and one more, since we're looking for the stack to be at
# the parent of the current item
stack.pop()
current = stack[-1]
continue
raise ValueError(f"bad format with diff {diff}: {line}")
return root.children
def display(values, depths: list[int] = None):
if depths is None:
depths = []
for i, item in enumerate(values):
i += 1 # make it 1-indexed
trace = depths + [str(i)]
if item.depth == 1:
print()
print(f"{'.'.join(trace)} {item.name}")
if item.children:
display(item.children, trace)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("input", type=argparse.FileType("r"),
help="The indented file to convert")
args = parser.parse_args()
lines = args.input.readlines()
display(parse(iter(lines)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment