💾 Archived View for mozz.us › markdown › render_vt100.py captured on 2024-08-25 at 02:07:11.

View Raw

More Information

⬅️ Previous capture (2020-09-24)

-=-=-=-=-=-=-

#!/usr/bin/env python3
"""
Convert a JSON-encoded Gemini AST into VT-100 styled text.
"""
import textwrap


A_BOLD = '\u001b[1m'
A_UNDERLINE = '\u001b[4m'
A_REVERSED = '\u001b[7m'

BLACK = '\u001b[30m'
RED = '\u001b[31m'
GREEN = '\u001b[32m'
YELLOW = '\u001b[33m'
BLUE = '\u001b[34m'
MAGENTA = '\u001b[35m'
CYAN = '\u001b[36m'
WHITE = '\u001b[37m'

RESET = '\u001b[0m'


def render_vt100(ast, width):

    body = []
    link_count = 0

    def wrap(text, initial_indent, subsequent_indent):
        """Shorthand method for text wrapping to the page width"""
        return '\n'.join(textwrap.wrap(
            text,
            width,
            initial_indent=initial_indent,
            subsequent_indent=subsequent_indent,
        ))

    for name, value in ast:

        if name == 'Horizontal Rule':
            body.append('─' * width)

        elif name == 'Title':
            body.append('')
            title = value.upper().center(width)[:width]
            body.append(A_UNDERLINE + A_BOLD + title + RESET)

        elif name == 'Heading':
            heading = value.upper()[:width]
            body.append(A_BOLD + heading + RESET)

        elif name == 'Sub-Heading':
            subheading = value[:width]
            body.append(A_BOLD + subheading + RESET)

        elif name == 'Paragraph':
            body.append(wrap(value, '', ''))

        elif name == 'Preformatted':
            lines = value.splitlines(keepends=False)
            text_block = [wrap(line, '> ', '') for line in lines]
            body.append(BLUE + '\n'.join(text_block) + RESET)

        elif name == 'Ordered List':
            items = enumerate(value, start=1)
            text_block = [wrap(item, f'{i}. ', '  ') for i, item in items]
            body.append(GREEN + '\n'.join(text_block) + RESET)

        elif name == 'Unordered List':
            text_block = [wrap(item, '• ', '  ') for item in value]
            body.append(YELLOW + '\n'.join(text_block) + RESET)

        elif name == 'Link':
            link = wrap(value[1], f'[{link_count}] ', '  ')
            body.append(CYAN + link + RESET)
            link_count += 1

        else:
            raise ValueError(f'Unrecognized node name `{name}`')

    return '\n\n'.join(body)


def main():
    import argparse
    import sys
    import json

    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('infile', type=argparse.FileType('r'), default=sys.stdin)
    parser.add_argument('--width', type=int, default=50)
    args = parser.parse_args()

    ast = json.load(args.infile)
    text = render_vt100(ast, args.width)
    sys.stdout.write(text)


if __name__ == '__main__':
    main()