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)
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)
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))
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))
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()
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()