Introduction to Coding with SASS via Including ANSI Output in HTML
This assumes you already have a firm grasp of CSS. A passing familiarity with SCSS may also be helpful.
Converting ANSI to HTML
While there are several utilities claiming the ability to convert ANSI to HTML, the only one I've found does the job correctly in all cases is ansi2html, a Python command line tool using IO redirection.
For example, the following outputs a list of the contents of the current directory in color, pipes it to ansi2html
, and writes the result to output.html
.
ls --color=always | ansi2html > output.html
This is usually all you need since the necessary CSS is included in the generated HTML. However I wanted to insert the pre
portion of this HTML into markdown. Therefore I needed to generate all possible CSS myself.
Generating CSS for All Possible Styles with SCSS
The CSS resulting from the SCSS detailed below is all we need to make sure the output of ansi2html can be used directly, without the styling potion, and still present correctly on the web.
Regular CSS
Due to text-based user interfaces (TUIs), terminals all default to a line height of one, so we do so as well.
.ansi2html-content {
color: #1E1C1A;
line-height: 1;
}
Terminals generally support basic formatting via Select Graphic Rendition (SGR). We do our best to translate this into CSS.
.ansi1 { font-weight: bold; }
.ansi2 { font-weight: lighter; }
.ansi3 { font-style: italic; }
.ansi4 { text-decoration: underline;; }
.ansi5 { text-decoration: blink; }
.ansi6 { text-decoration: blink; }
.ansi8 { visibility: hidden; }
.ansi9 { text-decoration: line-through; }
Variables and Lists
Variables in SCSS are names prepended with a dollar sign, which are assigned a value just like regular CSS properties.
In the following case we're assigning the variable $colors
a list of hex color values.
To access
Old terminals could only support 8 colors. While modern terminal emulators support 256 colors, they have 16 base colors in eight pairs of regular and bright.
$colors:
#1E1C1A #962A1C #406D00 #916518 #20419A #883067 #2D746E #CECCCA
#4E4C4A #C85C4E #729F32 #C3974A #5273CD #BA6299 #5FA6A0 #EEECEA;
The set which I'm using above corresponds to the following.
Mixins and Interpolation
Mixins in SCSS are functions which generate SCSS. They're defined using the syntax below, beginning @mixin
.
Interpolation in SCSS allows the use of variables in selectors and property names using the syntax #{}
.
The color-classes
mixin is taking a value $n
and appending it to our class names and assigning those our $color
value. It's used to build all of our text and background colors, as well as their inverses.
@mixin color-classes($n, $color) {
.ansi3#{$n}, .inv4#{$n} { color: $color; }
.ansi4#{$n}, .inv3#{$n} { background-color: $color; }
}
If you don't need to support inverse styles, removing those classes reduces the final CSS from 21.2KB to 15.6KB (when sent over the wire).
For Loops, Using Mixins, and Math
A for
loop in SCSS iterates across a range. If using # to #
, as below, not including the last number, while using # through #
includes the last number.
Mixins are used via the @include
syntax.
The +
is used both as addition and string concatenation.
And list.nth
(or just nth
) is used to access the value at the given position in an array.
We generate color classes for our 16 base colors twice, once for the original codes used for 8 colors, and once for the codes used by 256 color terminals. This is done by looping through integers from 0 to 15 passing the correct code suffix and color to the color-classes
mixin and including the generated SCSS.
@for $i from 0 to length($colors) {
@include color-classes($i, nth($colors, $i + 1));
@include color-classes("8-"+$i, nth($colors, $i + 1));
}
To generate all 256 colors, we need to generate 216 colors along the red, green, blue spectrum. This is done by looping through from 0 to 6 for each primary color carefully building the correct index and color.
@for $r from 0 to 6 {
@for $g from 0 to 6 {
@for $b from 0 to 6 {
$index: 16 + ($r * 36) + ($g * 6) + $b;
$color: rgb($r * 51, $g * 51, $b * 51);
@include color-classes("8-"+$index, $color);
}
}
}
To generate the 24 grayscale colors of our 256 color palette we again loop carefully building the correct shade and index.
@for $i from 0 to 24 {
$shade: ($i * 10) + 8;
$grey: rgb($shade, $shade, $shade);
@include color-classes("8-"+($i + 232), $grey);
}
Additional SCSS Features
There is more to programming with SCSS which I didn't happen to need for the above project.
If
In SCSS, if else is done two ways.
Via a built in function if(boolean_expression, if_true, if_false)
which returns the result of evaluating the correct argument. The other argument is not evaluated at all.
Via an @if
, @else if
, @else
set of directives for returning styles.
Maps, Each, and While
In SCSS, a map is an ordered associative array with a set of basic functions for manipulation.
In addition to @for
there are two other looping mechanisms, @while
and @each
.
Just as in most languages, the while loop is used @while boolean_expression {
, looping until it is false.
Meanwhile, @each
allows iteration over lists and maps. SCSS's @each
also supports multiple assignment. For lists this means given a list of lists @each
will give you the corresponding values from each sub-list each iteration. For maps this means you are given both the key and value each iteration.
Functions
Except that they return a value functions are very similar to mixins. They're defined using @function
and return a value using @return
.