Example #1
0
    def test_record(self):
        # Use pipes in lieu of stdin and stdout
        fd_in_read, fd_in_write = os.pipe()
        fd_out_read, fd_out_write = os.pipe()

        lines = 24
        columns = 80

        pid = os.fork()
        if pid == 0:
            # Child process
            for line in commands:
                os.write(fd_in_write, line.encode('utf-8'))
                time.sleep(0.060)
            os._exit(0)

        # Parent process
        with term.TerminalMode(fd_in_read):
            for _ in term.record(['sh'], columns, lines, fd_in_read,
                                 fd_out_write):
                pass

        os.waitpid(pid, 0)
        for fd in fd_in_read, fd_in_write, fd_out_read, fd_out_write:
            os.close(fd)
Example #2
0
    def test_record(self):
        # Use pipes in lieu of stdin and stdout
        fd_in_read, fd_in_write = os.pipe()
        fd_out_read, fd_out_write = os.pipe()

        lines = 24
        columns = 80
        theme = AsciiCastTheme('#000000', '#111111', ':'.join(['#123456'] * 8))

        pid = os.fork()
        if pid == 0:
            # Child process
            for line in commands:
                os.write(fd_in_write, line.encode('utf-8'))
                time.sleep(0.060)
            os._exit(0)

        # Parent process
        with term.TerminalMode(fd_in_read):
            for _ in term.record(columns, lines, theme, fd_in_read,
                                 fd_out_write):
                pass

        os.waitpid(pid, 0)
        for fd in fd_in_read, fd_in_write, fd_out_read, fd_out_write:
            os.close(fd)
Example #3
0
def record_subcommand(geometry, input_fileno, output_fileno, cast_filename):
    """Save a terminal session as an asciicast recording"""
    import termtosvg.term as term
    logger.info('Recording started, enter "exit" command or Control-D to end')
    if geometry is None:
        columns, lines = term.get_terminal_size(output_fileno)
    else:
        columns, lines = geometry
    with term.TerminalMode(input_fileno):
        records = term.record(columns, lines, input_fileno, output_fileno)
        with open(cast_filename, 'w') as cast_file:
            for record in records:
                print(record.to_json_line(), file=cast_file)
    logger.info('Recording ended, cast file is {}'.format(cast_filename))
Example #4
0
def record_render_subcommand(template, geometry, input_fileno, output_fileno,
                             svg_filename):
    """Record and render the animation on the fly"""
    import termtosvg.term as term

    logger.info('Recording started, enter "exit" command or Control-D to end')
    if geometry is None:
        columns, lines = term.get_terminal_size(output_fileno)
    else:
        columns, lines = geometry
    with term.TerminalMode(input_fileno):
        asciicast_records = term.record(columns, lines, input_fileno,
                                        output_fileno)
        replayed_records = term.replay(
            records=asciicast_records,
            from_pyte_char=anim.CharacterCell.from_pyte)
        anim.render_animation(records=replayed_records,
                              filename=svg_filename,
                              template=template)
    logger.info('Recording ended, SVG animation is {}'.format(svg_filename))
Example #5
0
def main(args=None, input_fileno=None, output_fileno=None):
    # type: (List, Union[int, None], Union[int, None]) -> None
    if args is None:
        args = sys.argv
    if input_fileno is None:
        input_fileno = sys.stdin.fileno()
    if output_fileno is None:
        output_fileno = sys.stdout.fileno()

    console_handler = logging.StreamHandler(sys.stderr)
    console_handler.setLevel(logging.INFO)
    console_formatter = logging.Formatter('%(message)s')
    console_handler.setFormatter(console_formatter)
    logger.handlers = [console_handler]
    logger.setLevel(logging.INFO)

    configuration = config.init_read_conf()
    available_themes = config.CaseInsensitiveDict(**configuration)
    del available_themes['global']

    command, args = parse(args[1:], available_themes)

    if args.verbose:
        _, log_filename = tempfile.mkstemp(prefix='termtosvg_', suffix='.log')
        file_handler = logging.FileHandler(filename=log_filename, mode='w')
        file_handler.setLevel(logging.DEBUG)
        file_formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        file_handler.setFormatter(file_formatter)
        logger.handlers.append(file_handler)
        logger.info('Logging to {}'.format(log_filename))

    if command == 'record':
        logger.info(
            'Recording started, enter "exit" command or Control-D to end')
        if args.output_file is None:
            _, cast_filename = tempfile.mkstemp(prefix='termtosvg_',
                                                suffix='.cast')
        else:
            cast_filename = args.output_file

        columns, lines = term.get_terminal_size(output_fileno)
        with term.TerminalMode(input_fileno):
            records = term.record(columns, lines, input_fileno, output_fileno)
            with open(cast_filename, 'w') as cast_file:
                for record in records:
                    print(record.to_json_line(), file=cast_file)

        logger.info('Recording ended, cast file is {}'.format(cast_filename))
    elif command == 'render':
        logger.info('Rendering started')
        if args.output_file is None:
            _, svg_filename = tempfile.mkstemp(prefix='termtosvg_',
                                               suffix='.svg')
        else:
            svg_filename = args.output_file

        if args.font is None:
            font = configuration['GLOBAL']['font']
        else:
            font = args.font

        fallback_theme_name = configuration['GLOBAL']['theme']
        fallback_theme = configuration[fallback_theme_name]
        cli_theme = configuration.get(args.theme)

        records = asciicast.read_records(args.input_file)
        replayed_records = term.replay(
            records=records,
            from_pyte_char=anim.CharacterCell.from_pyte,
            override_theme=cli_theme,
            fallback_theme=fallback_theme)
        anim.render_animation(replayed_records, svg_filename, font)

        logger.info(
            'Rendering ended, SVG animation is {}'.format(svg_filename))
    else:
        # No command passed: record and render on the fly
        logger.info(
            'Recording started, enter "exit" command or Control-D to end')
        if args.output_file is None:
            _, svg_filename = tempfile.mkstemp(prefix='termtosvg_',
                                               suffix='.svg')
        else:
            svg_filename = args.output_file

        columns, lines = term.get_terminal_size(output_fileno)

        if args.font is None:
            font = configuration['GLOBAL']['font']
        else:
            font = args.font

        fallback_theme_name = configuration['GLOBAL']['theme']
        fallback_theme = configuration[fallback_theme_name]
        cli_theme = configuration.get(args.theme)
        with term.TerminalMode(input_fileno):
            records = term.record(columns, lines, input_fileno, output_fileno)
            replayed_records = term.replay(
                records=records,
                from_pyte_char=anim.CharacterCell.from_pyte,
                override_theme=cli_theme,
                fallback_theme=fallback_theme)
            anim.render_animation(replayed_records, svg_filename, font)

        logger.info(
            'Recording ended, SVG animation is {}'.format(svg_filename))

    for handler in logger.handlers:
        handler.close()
Example #6
0
def main(args=None, input_fileno=None, output_fileno=None):
    # type: (List, Union[int, None], Union[int, None]) -> None
    if args is None:
        args = sys.argv
    if input_fileno is None:
        input_fileno = sys.stdin.fileno()
    if output_fileno is None:
        output_fileno = sys.stdout.fileno()

    command, args = parse(args[1:])

    logger = logging.getLogger('termtosvg')
    logger.setLevel(logging.INFO)

    console_handler = logging.StreamHandler(sys.stderr)
    console_handler.setLevel(logging.INFO)
    console_formatter = logging.Formatter('%(message)s')
    console_handler.setFormatter(console_formatter)
    logger.handlers = [console_handler]

    if args.verbose:
        file_handler = logging.FileHandler(filename=LOG_FILENAME, mode='w')
        file_handler.setLevel(logging.DEBUG)
        file_formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        file_handler.setFormatter(file_formatter)
        logger.handlers.append(file_handler)
        logger.info('Logging to {}'.format(LOG_FILENAME))

    fallback_theme_name = 'solarized-dark'
    xresources_str = term.default_themes()[fallback_theme_name]
    fallback_theme = asciicast.AsciiCastTheme.from_xresources(xresources_str)

    if command == 'record':
        logger.info(
            'Recording started, enter "exit" command or Control-D to end')
        if args.output_file is None:
            _, cast_filename = tempfile.mkstemp(prefix='termtosvg_',
                                                suffix='.cast')
        else:
            cast_filename = args.output_file

        columns, lines, theme = term.get_configuration(output_fileno)
        with term.TerminalMode(input_fileno):
            records = term.record(columns, lines, theme, input_fileno,
                                  output_fileno)
            with open(cast_filename, 'w') as cast_file:
                for record in records:
                    print(record.to_json_line(), file=cast_file)

        logger.info('Recording ended, cast file is {}'.format(cast_filename))
    elif command == 'render':

        def rec_gen():
            with open(args.input_file, 'r') as cast_file:
                for line in cast_file:
                    yield asciicast.AsciiCastRecord.from_json_line(line)

        logger.info('Rendering started')
        if args.output_file is None:
            _, svg_filename = tempfile.mkstemp(prefix='termtosvg_',
                                               suffix='.svg')
        else:
            svg_filename = args.output_file

        if args.theme is None:
            theme = fallback_theme
        else:
            xresources_str = term.default_themes()[args.theme]
            theme = asciicast.AsciiCastTheme.from_xresources(xresources_str)

        replayed_records = term.replay(rec_gen(), anim.CharacterCell.from_pyte,
                                       theme)
        anim.render_animation(replayed_records, svg_filename)

        logger.info(
            'Rendering ended, SVG animation is {}'.format(svg_filename))
    else:
        # No command passed: record and render on the fly
        logger.info(
            'Recording started, enter "exit" command or Control-D to end')
        if args.output_file is None:
            _, svg_filename = tempfile.mkstemp(prefix='termtosvg_',
                                               suffix='.svg')
        else:
            svg_filename = args.output_file

        columns, lines, system_theme = term.get_configuration(output_fileno)

        if args.theme is None:
            if system_theme is None:
                theme = fallback_theme
            else:
                theme = system_theme
        else:
            xresources_str = term.default_themes()[args.theme]
            theme = asciicast.AsciiCastTheme.from_xresources(xresources_str)

        with term.TerminalMode(input_fileno):
            records = term.record(columns, lines, theme, input_fileno,
                                  output_fileno)
            replayed_records = term.replay(records,
                                           anim.CharacterCell.from_pyte, theme)
            anim.render_animation(replayed_records, svg_filename)

        logger.info(
            'Recording ended, SVG animation is {}'.format(svg_filename))

    for handler in logger.handlers:
        handler.close()