Rendering ANSI Escape Sequences to Rich HTML: Introducing fromansi

 ╔═══╗╔═══╗╔═══╗╔═╗╔═╗╔═══╗╔═╗─╔╗╔═══╗╔══╗
 ║╔══╝║╔═╗║║╔═╗║║║╚╝║║║╔═╗║║║╚╗║║║╔═╗║╚╣╠╝
 ║╚══╗║╚═╝║║║─║║║╔╗╔╗║║║─║║║╔╗╚╝║║╚══╗─║║─
 ║╔══╝║╔╗╔╝║║─║║║║║║║║║╚═╝║║║╚╗║║╚══╗║─║║─
 ║║───║║║╚╗║╚═╝║║║║║║║║╔═╗║║║─║║║╚═╝║╔╣╠╗
 ╚╝───╚╝╚═╝╚═══╝╚╝╚╝╚╝╚╝─╚╝╚╝─╚═╝╚═══╝╚══╝

Introduction

Terminal applications often produce stunning output with colors, styles, and effects using ANSI escape sequences. However, when you copy-paste this into a blog, documentation, or email, all the formatting is lost. fromansi solves this: a Rust CLI tool that parses ANSI sequences and renders them as fully-styled HTML.

Why Another Terminal Capture Tool?

There is an awesome list of terminal recorders that can capture a terminal session. However, I wanted something simple that just captures the output of a single command.

There is also this script (which is what I was using initially), but it doesn't support 24-bit colors.

I tried ansi2html, but I had a few issues with the generated CSS. It requires two classes to exist on the containing element and I wasn't sure why or how they worked. I just figured that this should be a simple task where you put a foreground color and background color on something and it "just works", since CSS supports both of these easily.

After fiddling with both of these solutions and not getting exactly what I wanted (24-bit color support + simple additive CSS styles), I decided that it would make sense to make my own tool.

Primary Features

fromansi has the following features:

  • Colors: Standard 16-color palette, 256-color extended, truecolor (24-bit RGB) for foreground and background.
  • Styles: Bold, italic, underline, strikethrough, blink, dim, hidden.
  • CLI Modes:
    • html: Output HTML fragment or standalone page.
    • css: Generate CSS for use in an HTML page.
    • rex: Convert RexPaint (.xp) files to ANSI.

The tool uses stdin and stdout which makes it easy to integrate into existing workflows.

HTML Rendering

fromansi generates a foreground and background class for all possible primary and indexed colors. This allows one CSS file to be loaded and re-used for any number of ANSI outputs. Additionally, if the input data uses 24-bit true color (extended) mode, then an extra CSS class will be generated for each specific color. fromansi checks all the colors prior to HTML+CSS generation and tries to use indexed colors if possible.

The generated HTML uses CSS additively in order to color the elements:

<span class="fg1 bold blink">X</span>

Reverse mode is also supported, but it is applied when the HTML file is generated by swapping the foreground and background.

RexPaint Integration

RexPaint is a popular ASCII art tool, and fromansi supports it natively. All we need to do is cat a .xp file to fromansi, and then pipe the output back into fromansi again to generate HTML:

cat art.xp | fromansi rex | fromansi html

Currently there is no write support for RexPaint files, but I'm thinking it would be fun to add support for that soon!

Conclusion

Now I'm happy with my terminal capture experience. fromansi makes it easy to get compiler output and paste it directly into my blog. It's open source and available at GitHub .



Comments