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!