Script+Shiki for beautiful terminal snippets
8 April 2025
·
3 min read
Today I learn how you can keep the colors of the output of your terminal applications, when pasting then into your code blocks in Markdown. This is not about syntax highlight for a language like Python, but rather about the output of terminal applications.
You will go from this:
$ npm exec astro check
16:03:12 [content] Syncing content
16:03:12 [content] Synced content
16:03:12 [types] Generated 177ms
16:03:12 [check] Getting diagnostics for Astro files in /var/home/ayats/Documents/neohome...
Result (39 files):
- 0 errors
- 0 warnings
- 0 hints
To this:
$ npm exec astro check
16:06:02 [content] Syncing content
16:06:02 [content] Synced content
16:06:02 [types] Generated 183ms
16:06:02 [check] Getting diagnostics for Astro files in /var/home/ayats/Documents/neohome...
Result (39 files):
- 0 errors
- 0 warnings
- 0 hints
ANSI control sequences
Terminal colors are generated with escape sequences. Simply put, if you (a program) wants to make some text red, you have to send a special sequence of characters to the terminal to indicate that the following text is red. This sequence is interpreted by the terminal, and removed from the actual text.
For the terminal, every sequence starts with the 28th ascii character, that is a char
with value 27
(0x1B
hex) which is commonly
known as ESC
. This character doesn’t have a representation, so if I paste it here: , you may see either nothing or something similar to the fallback
Unicode character U+241B
␛
.
You’ve probably seen it written in other ways, like \x1b
or \e
. These are easier shorthands that use regular ASCII characters to
represent the ␛
, which is cumbersome to write and not printable.
Following it, you will find the character [
, some function arguments and the function to call. You can find a longer explanation here: https://notes.burke.libbey.me/ansi-escape-codes. For color, we care about the m
instruction.
Knowing this, to set the foreground color we simply send the instruction to the terminal and then reset it:
␛[31m(This is some red text)␛[0m
$ printf "\e[31m(This is some red text)\e[0m"
(This is some red text)
The important bit is that we cant to preserve this information. There are many tools to do this, but the one I’ve found is script
.
- Run
script
. - Inside the shell, you any commands you want colored output of.
- Exit
script
. - You will have a
typescript
file with all the raw ANSI escape sequences for the command logs.
$ script
Script started, output log file is 'typescript'.
$ printf "\e[31mHello\e[0m"
Hello
$ exit
ShikiJS
Now that we have a typescript
file with all our raw escape sequences that mark color, we need to give it to a syntax highlighter that supports it.
I’m using the highlighter Shiki, which is the default for Astro, and other projects like Slidev. Discord’s syntax highlight has support for ANSI.
Simply, mark your code blocks with the ansi
language, and paste your raw escape sequences:
```ansi
$ printf "\e[31mHello\e[0m"
␛[31mHello␛[0m
```
Will be rendered as:
$ printf "\e[31mHello\e[0m"
Hello
Closing thoughts
That’s all! I hope this helped you beautify your own blog or documentation site!