1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qiitaのmarkdownでコードブロックをピンクに染める

Last updated at Posted at 2025-03-02

下記の記事において,筆者がコメントで使ったテクニックの種明かしをします。

記事本文であれば「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 となります。

コード本体

次がコード本体です。コード本体は titleend 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 ではコードブロックのシンタクスハイライトに RubyRouge を使っている3ので同じ技術を使いました。Ruby および Rouge のインストールについては筆者の過去記事4を参照下さい。

json5.rb
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.txttitleend title の間に貼り付ければ出来上がりです。

Ruby スクリプトの実行
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;
}

上記のコードを PlantUMLtitleend 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 記法を気にすることなく自由に記述できます。逆に言うと色を変更することができませんが。

titleend title の中には下記のように記述します。

<code>
//------------------------------
// Hello, World
//------------------------------
#include <stdio.h>
#include <stdlib.h>
int main() {
  printf("Hello, World\n");
  return 0;
}
</code>

こうすると <code></code> の内容がそのまま出力されます。

最後に一言

PlantUML によるコードブロック(風)はシンタクスハイライトを付けて綺麗に見せてはいますが,残念ながらテキストをコピーできません。単なるビットマップ画像を張り付けたのと変わらず,読者にとってはコードの再利用性が低くなっています。用法用量にはご注意ください。

  1. MathJax で利用可能な TeX コマンド(非公式)

  2. QiitaのmarkdownでSVGを使って作図する - Qiita

  3. Qiitaでシンタックスハイライト可能な言語一覧 - Qiita

  4. Qiitaでバッチファイルの謎なシンタクスハイライトを直したい - Qiita

  5. List of tokens - rouge-ruby/rouge

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?