TL;DR

Paste code from VS Code into your blog: https://github.com/slang25/html-copy-vscode

The problem

When I started this blog I did some investigation into how I should render fragments of code. I eventually landed on Prism, which works great as I can just write code in my markdown like this:

```fsharp
let square x = x*x
```

However a couple of things bothered me with this approach:

  • There is a burden on the readers browser to download Prism, and parse the code, I would like this to be done ahead of time.
  • I have to find formatters for all the languages I might use, they aren't perfect and have mixed results. I'd like to use something more robust which understands the syntax and semantics more completely.

So looking for something better, I wanted to use VS Code, as nothing looks better to me when I'm viewing code, and it supports many themes, and more importantly to me, many languages.

As a side note, I also investigate using Monaco, which is the editor engine that powers VS Code and can be ran in a browser. I could use the monaco.editor.colorizeElement method (see here for example), however the overhead of loading Monaco wasn't ideal, and I really wanted to do the work ahead of time. There is potential to wrap this up in a cli tool that would act as a pre-processor to parse markdown code snippets and output the fully stylized markup in order to automate everything, but that's for another day.

I decided I could do everything with a simple manual workflow with VS Code.

The workflow

Onetime Step

Install the html-copy-vscode command line tool:

dotnet tool install -g HtmlCopyVSCode

Step 1

Copy some code from VS Code.

Step 2

Run the tool:

html-copy-vscode -c vscode

(-c is optionally used to remove the root style and add your own class)

Step 3

Paste the code into your blog. It will look something like this (formatted for readability):

<div class="vscode" style="white-space: pre;">
<div>
<span style="color: #569cd6;">let</span>
<span style="color: #d4d4d4;"> </span>
<span style="color: #9cdcfe;">square x</span>
<span style="color: #d4d4d4;"> </span>
<span style="color: #569cd6;">=</span>
<span style="color: #d4d4d4;"> x</span>
<span style="color: #569cd6;">*</span>
<span style="color: #d4d4d4;">x</span>
</div>
</div>

For me, I use Ghost, which accepts Markdown. Markdown can contain regular HTML markup, so I can just paste it in anywhere.

Now for the finishing touches, I add rounded edges, background, a drop shadow and some layout:

.vscode
{
color: #d4d4d4;
background-color: #1e1e1e;
font-family: 'Fira Code', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-weight: 500;
font-size: 16px;
line-height: 1.5em;
white-space: pre;
padding: 1em;
margin: .5em 0 2em;
box-shadow: rgba(0, 0, 0, 0.65) 0px 10px 20px;
border-radius: .5em;
overflow: auto;
}

And the snippets in this post are the results. Have a little look yourself with your browser dev tools.

How does it work?

When copy in VS Code, the work is mostly done for you, the default copy action in VS Code is the same as the command Copy With Syntax Highlighting. Windows (and macOS as I understand) stores the contents in multiple formats, starting with the most descriptive down to the least, so for highlighted code it's HTML (CF_HTML), then plain text (CF_TEXT).

When you paste somewhere, it will try to use the most descriptive format it can support, so if we paste into an email you might get the formatted HTML, but into a text editor you might get the plain text fallback.

There are command line tools you can run to get the contents of the HTML format and return them as plaintext, for example on Windows:

Get-Clipboard -TextFormatType Html | Set-Clipboard

However, there is a know bug with this where the characters get garbled, so I wrote this dotnet global tool to fill the gap, the interesting code is here.

For macOS you can run this:

osascript -e 'the clipboard as «class HTML»' | perl -ne 'print chr foreach unpack("C*",pack("H*",substr($_,11,-3)))'

Downsides

The only thing I'm not completely happy with, is I can no longer retrospectively re-theme the code. If I were to use the Monaco colorizeElement approach mentioned above, I would have classes in the markup, so I could swap themes in and out, and the markup would have been slightly more concise. Overall I am happy with this approach.

While writing this post, Maxime Mangel has built a npm package to programmatically harness the VS Code code highlighting called Code-Lightner.

I hope this is useful for people who want to embed code into their blog, want it to look good, and want to keep the frontend clean and simple.