下記の記事において,筆者がコメントで使ったテクニックの種明かしをします。
記事本文であれば「Markdown で本文を見る」という機能を使えば Markdown を読めるので,その記事の著者がどんなテクニックを使っているのかリバースエンジニアリングして勉強できるのですが,残念ながら現時点の Qiita の機能ではコメントの Markdown を見ることができないからです。
コードスパンをピンクに染める
まず筆者のコメントで使用しているコードスパン(風)のトリックを明かします。
どうせなら本文に貼り付ける $\bbox[#FFE4E1,2px]{\color{#C71585}{\small\texttt{settings.json}}}$ もピンクに染めたい。
ここは MathJax を使っています。
$\bbox[#FFE4E1,2px]{\color{#C71585}{\small\texttt{settings.json}}}$
ここで背景色 #FFE4E1
は \bbox
,文字色 #C71585
は \color
を用いて指定しています。なお MathJax でも書体を選択できますが,残念ながら本物のコードスパンと完全一致するものはありません。なので最も近いと思われる typewriter typestyle を選びました。
※この辺りは Web ブラウザにも依存するので難しいところです。
書体 | 実際の字体 | MathJax 指定 |
---|---|---|
roman | $\bbox[#f0f0f0,2px]{\small\textrm{settings.json}}$ | \textrm |
bold font | $\bbox[#f0f0f0,2px]{\small\textbf{settings.json}}$ | \textbf |
italic | $\bbox[#f0f0f0,2px]{\small\textit{settings.json}}$ | \textit |
sans serif | $\bbox[#f0f0f0,2px]{\small\textsf{settings.json}}$ | \textsf |
typewriter typestyle | $\bbox[#f0f0f0,2px]{\small\texttt{settings.json}}$ | \texttt |
本物のコードスパン | settings.json |
なお,MathJax の詳しい記法は参考文献1を参考にさせて頂きました。
コードブロックをピンクに染める
コードブロックの全容
次はコードブロック(風)のトリックを明かします。まずは全容を示しましょう。
ここは PlantUML を用いています。これから順に説明しますが,気になる方はここで「Markdown で本文を見る」機能を使って Markdown を直接見てください。
スタイル設定
まずは冒頭のオマジナイです。コードブロックはすべて図のタイトル部分に記載しており,ここではそのタイトル部分のスタイルを設定しています。背景色のミスティローズ #FFE4E1
はここで設定しています。
```plantuml
@startuml
<style>
root {
margin 0
padding 0
}
title {
horizontalAlignment left
roundCorner 16
padding 0 16 16 16
fontStyle normal
fontSize 14
fontName monospaced
backgroundColor #FFE4E1
fontColor #000000
}
</style>
インライン SVG スプライト
次がファイル名である settings.json
の表示部分です。PlantUML の持つインライン SVG スプライトという技術を用いています。インライン SVG スプライトについては筆者の過去記事2を参照下さい。
sprite TITLE <svg width="320" height="24">
<path d="M0 0 v18 a6 6 0 0 0 6 6 h92 a6 6 0 0 0 6 -6 v-18" fill="#FFC0CB" />
<text x="7" y="16" font-size="14" fill="#C71585">settings.json</text>
</svg>
二倍に拡大したものを以下に示します。角の丸めも再現していることが分かります。
なお,このインライン SVG スプライトはコードブロックの横幅の最小値を確保するためにも利用しています。<svg width="320" height="24">
と記述すると 320px となります。
コード本体
次がコード本体です。コード本体は title
~ end title
の中に記述します。まず先頭でインライン SVG スプライトを配置し,その後一行空けてコード本体を記載しています。この際に <color>
タグで色付けを行っています。
title
<$TITLE>
{
<color:#C71585>"workbench.colorTheme"</color>: <color:#FF6347>"Default Light Modern"</color>,
<color:#C71585>"editor.fontFamily"</color>:
<color:#FF6347>"'Rounded M+', 'Noto Sans JP', 'メイリオ', 'MS ゴシック', monospace"</color>,
~中略~
}
end title
@enduml
```
これらのタグ付けを自動的に行うために下記の Ruby スクリプトを作成しました。Qiita ではコードブロックのシンタクスハイライトに Ruby の Rouge を使っている3ので同じ技術を使いました。Ruby および Rouge のインストールについては筆者の過去記事4を参照下さい。
require "rouge"
if ARGV.size == 0 then
puts "usage: json5(.rb) [filename(.json)]"
exit
end
filename = ARGV[0]
if !File.exist?(filename) then
puts "#{filename} is not found."
exit
end
input = File.open(filename, "rt:BOM|utf-8")
source = input.read
lexer = Rouge::Lexers::JSON5.new
html = Rouge::Formatters::HTML.new
text = html.format(lexer.lex(source))
text.gsub!(/<span class="p">(.+?)<\/span>/){$1}
text.gsub!(/<span class="w">(\s+)<\/span>/){$1}
text.gsub!(/<span class="c">/, "<color:#A020F0>")
text.gsub!(/<span class="nl">/, "<color:#C71585>")
text.gsub!(/<span class="s2">/, "<color:#FF6347>")
text.gsub!(/<\/span>/, "</color>"}
puts text
exit
html.format()
は HTML 形式で出力するので,PlantUML の記法に置換します。なお,下記のように色付けを設定しました。クラスの詳細については本家サイト5を参照ください。
クラス | 意味 | 変換色 |
---|---|---|
p | 区切り記号 | 地色 |
w | 空白 | 地色 |
c | コメント |
#A020F0 パープル |
nl | ラベル名 |
#C71585 ミディアムバイオレットレッド |
s2 | 文字列(二重引用符付き) |
#FF6347 トマト |
こうして下記のように Ruby スクリプトを実行して,生成された settings.txt
を title
~ end title
の間に貼り付ければ出来上がりです。
c:\Qiita>json5 settings.json > settings.txt
※変換元の settings.json
の文字コードは UTF-8 形式にしておいて下さい。
注意事項
本技術を汎用的に使おうとすると PlantUML のマークアップ記法(Creole)に注意する必要があります。例えば下記の C ソースコードを例にとります。
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, World\n");
return 0;
}
上記のコードを PlantUML の title
~ end title
内にそのまま貼り付けると下記のようになります。行頭の記号 #
は順序付きリスト(Ordered List)の記号として取り扱われてしまうのです。
これを防ぐためには記号 #
の前にエスケープ記号のチルダ ~
を付けます。
~#include <stdio.h>
~#include <stdlib.h>
int main() {
printf("Hello, World\n");
return 0;
}
こうすると PlantUml でも正しく表記できるようになります。
しかし,次のように記号を連続させた場合が厄介です。
1 -
2 --
3 ---
4 ----
5 -----
6 ------
7 -------
8 --------
9 ---------
10 ----------
Creole では文字列の左右を連続したハイフン --
で囲むと取り消し表現になるので,ハイフンが5文字連続すると等号 =
(あるいは太いハイフン ━
)に見えますが,実はハイフンの上に取り消し記号が重なった形なのです。
今のところ,これらを簡単にエスケープさせる方式が思いつきません。ということで本技術を汎用的に用いるには,まだまだ課題が残っているのですが,たまたま今回の事例では問題なかったので使ってみました。
おまけ
文字色が単色で良いなら,PlantUML のコードブロック <code>
~ </code>
を使うという方法があります。コードブロック内では Creole 記法を気にすることなく自由に記述できます。逆に言うと色を変更することができませんが。
title
~ end title
の中には下記のように記述します。
<code>
//------------------------------
// Hello, World
//------------------------------
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, World\n");
return 0;
}
</code>
こうすると <code>
~ </code>
の内容がそのまま出力されます。
最後に一言
PlantUML によるコードブロック(風)はシンタクスハイライトを付けて綺麗に見せてはいますが,残念ながらテキストをコピーできません。単なるビットマップ画像を張り付けたのと変わらず,読者にとってはコードの再利用性が低くなっています。用法用量にはご注意ください。