【VSCode】コードをHTMLやPDFに変換する拡張機能

CodeToHTML拡張機能のロゴ

今回は、Visual Studio Codeで書いたソースコードをハイライトされた状態で、HTML、PDFおよび画像に変換し、エクスポートすることのできる拡張機能を作ったので、紹介します。

概要

私はウェブサイトを運営しているため、書いたソースコードを記事に記載することが多々あります。

今までは、prism.jsやhighlight.jsなどのシンタックスハイライトを行うライブラリを使って、ソースコードを記載していましたが、あくまでシンタックスハイライトのみであり、Semantic Highlight(良い日本語がないため英語で記載)を行うことができません。

そこで、VSCode上のソースコードをそのままHTMLやPDFに変換し、出力することができる拡張機能を作成しました。

Note

Syntax Highlight(シンタックスハイライト)とは、プログラムのソースコードを色分けして表示することで、プログラムの構造を視覚的に理解しやすくするための技術です。

しかしながら、あくまで正規表現を使って特定の文字列を色分けするだけであり、Semantic Highlightのように、ソースコードの本質を理解して色分けすることはできません。

Semantic Highlightは、プログラムのソースコードを解析し、変数や関数などの意味を理解して色分けする技術であり、VSCodeでは、言語サーバープロトコル(LSP)を用いて、コードに関する追加の情報を提供し、単純なシンタックスハイライトを超えた機能を実現しています。

機能

この拡張機能には、以下の機能があります。

  • エディタ上のソースコードをHTMLに変換し、出力する機能
  • エディタ上のソースコードをPDFに変換し、出力する機能
  • エディタ上のソースコードを画像に変換し、出力する機能

インストール

VSCodeの拡張機能タブから、CodeToHTMLと検索し、インストールしてください。

または、Visual Studio Marketplaceからインストールすることもできます。

ソースコードは、GitHubにて公開しています。

使い方

今回は以下のソースコードを変換してみます。

class Person {
  constructor(name = "Anonymous") {
    this.name = name;
  }
  introduce() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const person = new Person();
person.introduce(); // Hello, my name is Anonymous
VSCodeのコマンドパレットで [CodeToHTML] Code to HTML を選択している画面
  • 変換したいソースコードを開きます。
  • Ctrl + Shift + Pを押しコマンドパレットを開きます。
  • コマンドパレットにCodeToHTMLと入力し、[CodeToHTML] Code to HTMLを選択します。
  • Webviewが開き、HTMLコードが表示されます。

コードをHTMLに変換する

Code To HTMLのWebview画面。Structure・Text Wrap・Max Lengthの設定と、DownloadとCopyのボタン、変換対象コードのプレビューが表示されている

デフォルトでCode To HTMLが選択されているため、お好みで設定を変更して、Downloadを選択すると、HTMLファイルがダウンロードされます。

Copyでクリップボードにコピーすることもできます。

それぞれの設定は以下の通りです。

  • Structure: ソースコードの構造を変更します。
    • html > body > div — htmlおよびbodyタグに囲われたdivベースの構造(改行はbrタグ)
    • html > body > pre — htmlおよびbodyタグに囲われたpreベースの構造
    • html > body > pre > code — htmlおよびbodyタグに囲われたpre > codeベースの構造
    • div — divタグのみで囲まれた構造(改行はbrタグ)
    • pre — preタグのみで囲まれた構造
    • pre > code — pre > codeタグのみで囲まれた構造
  • Text Wrap: ソースコードの折り返しを変更します。
    • None — 折り返しなし
    • Normal — 通常の折り返し(折り返しが先頭から始まる)
    • Smart — インデントに合わせた折り返し(その行の先頭に空白がある場合、折り返しにも空白が入る)
  • Max Length: 折り返しする最大文字数を変更します。

html > body > divの変換結果は以下の通りです。

html > body > div構造で変換されたHTMLソースコード。行ごとのdivと色指定つきのspanで構成されている

エクスポートされたHTML(選択可)

class Person {
  constructor(name = "Anonymous") {
    this.name = name;
  }
  introduce() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const person = new Person();
person.introduce(); // Hello, my name is Anonymous

コードをPDFに変換する

Code To PDFのWebview画面。Font・Text Wrap・Max Lengthの設定とDownloadボタンが表示されている

Code To PDFを選択し、Downloadを選択すると、PDFファイルがダウンロードされます。

それぞれの設定は以下の通りです。

  • Font(.ttf): フォントを変更します。
  • Text Wrap: ソースコードの折り返しを変更します。(詳しくはHTMLの説明を参照)
  • Max Length: 折り返しする最大文字数を変更します。(詳しくはHTMLの説明を参照)

フォントは、デフォルトでcourierが選択されていますが、日本語を出力できません。

そのため、英語と日本語の両方を出力できるフォントを選択してください。

FontForgeなどのツールを使って、VSCode標準のフォントであるConsolasと日本語フォントを組み合わせたフォントを作成することもできますし、元から英語と日本語の両方を出力できるプログラミング向けのフォント(例えばPlemolJPなど)を使うこともできます。

コードを画像に変換する

Code To ImageのWebview画面。Image Type・Text Wrap・Max Lengthの設定とDownloadボタンが表示されている

Code To Imageを選択し、Downloadを選択すると、画像ファイルがダウンロードされます。

それぞれの設定は以下の通りです。

  • Image Type: 画像の形式を変更します。
    • png
    • jpeg
    • svg
  • Text Wrap: ソースコードの折り返しを変更します。(詳しくはHTMLの説明を参照)
  • Max Length: 折り返しする最大文字数を変更します。(詳しくはHTMLの説明を参照)

まとめ

今回は、VSCodeのエディタ上のソースコードをHTMLやPDFに変換し、出力することができる拡張機能について紹介しました。

制作の経緯と動作原理についても記載しましたので、もしご興味があれば、ご覧いただければ幸いです。

制作の経緯

初期の案では、VSCodeのエディタ上のトークン化されたソースコードから、それぞれのトークンの色を取得し、HTMLに変換することを考えていました。

しかし、VSCodeのAPIには、トークン化されたソースコードを取得するためのAPIがなく、トークンの色を取得するためのAPIもありませんでした。(GitHubのVSCodeリポジトリには、この件に関連するIssueが複数立っていました)

例えば、Developer: Inspect Editor Tokens and Scopesというコマンドがあります。

Inspect Editor Tokens and Scopesの表示。トークンの言語・色・semantic token type・textmate scopesの情報が並んでいる

このコマンドを実行すると、GUI上にそのトークンのTextMateおよびSemantic Highlightの情報が表示されますが、これを取得するためのAPIは見当たりませんでした。

仕方がないので、自分でトークン化し、色を取得するためのプログラムを実装することにしたのですが、残念ながら、トークン化しTextMateのルールに従って色を取得するまではできたものの、結局シンタックスハイライトのみしか行えず、Semantic Highlightはできませんでした。

参考: https://github.com/microsoft/vscode-textmate

余談

ちなみに、これをブラウザ上でも動かせるmonaco-textmateというライブラリを見つけました。

これを使って、ブラウザ上でSyntax Highlightを任意で行うことができるようなので、prism.jsやhighlight.jsの代わりに使えるライブラリを作ることを一瞬考えましたが、手間が大きいため見送りました。誰かが作ってくれることを期待しています。

その後、言語サーバープロトコルの勉強を始めようかと思ったのですが、さすがに私には難しすぎたので、あきらめかけていたところ、VSCodeにハイライトされた状態のソースコードをリッチテキスト形式でクリップボードにコピーするコマンドがあることに気がつきました。

参考: https://stackoverflow.com/questions/35660927/how-to-copy-formatted-code-to-clipboard-in-vs-code

しかし、これがまた厄介で、存在するのはクリップボード上のリッチテキストなので、rtfファイルからHTMLに変換するライブラリが使えず、なかなかうまくいきませんでした。

無理かと思いつつ、Stack Overflowを眺めていると、なんとDataTransfer.getData()およびDataTransfer.setData()にて、text/plainだけでなく、text/htmlを指定することで、クリップボードに格納されたリッチテキストのHTML表現を取得できるという情報を得ました。

Mozillaのリファレンスにも記載がなかったため、半信半疑でしたが、実際に試してみると、コピーしたコードのHTML表現を取得することができ、これにより、VSCodeのエディタ上のソースコードをHTMLに変換することができるようになりました。

あとは、HTMLをPDFや画像に変換するライブラリを使い(うまく動かなかったのでHTMLのパースの処理は書くことになりましたが)、拡張機能が完成しました。

いろいろ躓くところがありましたが、ひとまず完成してよかったです。

余談ですが、VSCodeの拡張機能の公開は、ブラウザの拡張機能の公開よりもはるかに簡単で、公開するための審査もないため、誰でも簡単に公開することができます。

もし興味があれば、ぜひVSCodeの拡張機能を作ってみてください。

ここまでお読みいただき、ありがとうございました。