Oh, hey there!
If you are like me, you find a certain satisfaction using a well crafted CLI or terminal tool...
Especially when they use colour or redraw the terminal.
"how do we make on of those?" You are asking yourself? (hopefully) -- This must be your lucky day because this
is the subject of this video! > ANSI Sequence <
This article is a transcript of a Youtube video I made.
An ANSI sequence is a standard signaling to control everything from the cursor position, to styling to colours.
In other words, it's a sequence of characters that makes commands to the terminal.
don't change no matter what language or runtime you are using.
I will run this script that will simply redirect raw input from my keyboard to the terminal's output.
deno run --unstable echo.js
I can start typing anything...
Now, I will type the first ANSI sequence to render all incoming input red.
ESC + [ + 3 + 1 + m
If I want to render the text in blue, I just need to type in a new sequence with the appropriate number for blue, 34.
ESC + [ + 3 + 4 + m
Now everything is blue ~~
I can also set the background color.
ESC + [ + 4 + 3 + m
It's like IKEA
Next, I can just reset the colors.
ESC + [ + 0 + m
Back to basics.
Within the boundary of my terminal I can move the cursor.
ESC + [ + H
I'm typing here!
ESC + [ + 2 + 0 + ; + 2 + 0 + H
Now, I'm typing here.
If I move my cursor back to the top-left corner, I can clear the rest of the screen, giving me a blank slate...
ESC + [ + 0 + H + ESC + [ + J
I did promise you some drawing, let me type away.
ESC[45m ESC[2;2H space space space ESC[2;6H space space space ESC[3;3H space space space space space ESC[4;5H space
Oh, look... a heart! Which reminds me that if you're following me, I love you!
Before we go any further, I think it's important to mention that not all terminal client can interpret ANSI sequence, so you might
want to test yours before getting too excited. That being said, it probably does...
If you want to confirm, go to your terminal and type
echo $TERM... If the value contains one of those words, you're good to go...
It'll probably say "xterm" though...
xterm rxvt eterm screen tmux vt100 vt102 vt220 vt320 ansi scoansi cygwin linux konsole bvterm
Now if you're running PowerShell, I think that it supports ANSI sequences, but the feature is turned off by default...
While we're on the terminal, another thing you might want to play with is a command called
tput -- the command is useful when you need to query
the state and features of your terminal.
The commands that might interest you are the followings.
To output the number of columns
To output the number of rows/ or lines
And, finally to output the number of colours
So now we know that my terminal has 80 columns, 25 rows and is capable of displaying 256 colours. Awesome!
\x1b ~ which is the hexadecimal number for the Escape key.
So we can do something like this:
console.log("\x1b[31mSomething went wrong.\x1b[0m");
And, this works for all sort of sequences...
console.log("\x1b[H\x1b[J\x1b[36mAh! so clean\x1b[0m");
It's already obvious that using ANSI sequences this way can become very noisy. So let's wrap the commands we want to use into function.
For this demo, I will use TypedArray instead of strings. If you are not quite familiar with TypedArray, I wrote an article explaining all about it. I'll wait.
At any rate, here's a refresher: A Typed Array is an array that can only hold a specific amount of bit per item.
When dealing with character, it's typical to use an unsigned 8 bits integers. If you don't know why, again, read the article.
I'll explain this one briefly, you can see the final result here: https://github.com/sebastienfilion/i-y/blob/main/fundamentals/ANSI/generate.js
And get yourself a copy of the artwork here: https://raw.githubusercontent.com/sebastienfilion/i-y/main/fundamentals/ANSI/logo.js
You can also watch the video to get more explanations and the time-lapse.
First I create a few utility functions like this one to facilitate the process:
const clear = () => new Uint8Array([ 27, 91, 72, 27, 91, 74 ]);
The function returns a TypedArray of the following character
\x1b being the hexadecimal number for the "escape" key.
Once I have all of my utility functions ready, all returning a TypedArray, I create a buffer of 1KB.
const xs = new Uint8Array(1024);
Then I reduce all of the commands into the buffer:
[ clear(), inverse(), fill(10) ] .reduce( (i, ys) => xs.set(ys, i) || i + ys.byteLength, 0 );
To finally display my art running:
await Deno.write(Deno.stdout.rid, xs);
ANSI sequence are a powerful way to make any CLI or terminal tool interactive and engaging.
I suggest that you look up the Wikipedia page to get a reference for all the various sequence and their effects.
If you're curious and want to learn more about TypedArray, Readable/Writable-Streams and ANSI sequence, you should subscribe to this channel.
I will use these concepts in an incoming video series.
Otherwise, don't forget to hit the "like" button, share or leave a comment if you've learned something.
Okay bye now...