Qiitaでコードハイライトにファイル名を加える場合、言語の後に:filename
と入力することで、これが表示できます。
```js:index.js
import hoge from 'hoge';
`` `
index.js
import hoge from 'hoge';
marked と Highlight.jsでこれを実現する場合、markedのオプションを少し変更する必要があります。
環境設定
今回は確認をブラウザ上で行いますので、下記index.html
を用意します。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Filename</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/monokai_sublime.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script>
</head>
<body>
<script>
var md = "```js:index.js\nimport hoge from 'hoge';\n```";
var highlight = function(code, lang, callback){
// hljs.highlightの第一引数にはlangを渡すのが適切だが、`js:index.js`という言語は存在しないため、暫定的にハードコーディングで済ます
return hljs.highlight('js',code).value;
}
var renderer = new marked.Renderer;
var html = marked(md,{
highlight: highlight,
renderer: renderer,
});
document.body.innerHTML = html;
</script>
</body>
</html>
ブラウザ上でmd
内のマークダウン文字列が、整形されて表示されることを確認します。
renderer.codeのオーバーライド
marked - Overriding renderer methodsで説明されているように、markedのオプション引数renderer
のプロパティを定義し直すことで、マークダウン文字列のコンパイル内容を変更することができます。
marked-v0.3.5のもともとのコードブロックの処理は、下記のとおりです。
v0.3.5/lib/marked.js#L764-L785
Renderer.prototype.code = function(code, lang, escaped) {
if (this.options.highlight) {
var out = this.options.highlight(code, lang);
if (out != null && out !== code) {
escaped = true;
code = out;
}
}
if (!lang) {
return '<pre><code>'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>';
}
return '<pre><code class="'
+ this.options.langPrefix
+ escape(lang, true)
+ '">'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>\n';
};
さきほどのindex.html
は、既にrenderer
インスタンスをオプション引数に渡しているので、renderer.code
プロパティを定義し直すことで、ファイル名を表示することができます。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/monokai_sublime.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script>
<style>
pre{
background-color: #F7F7F6;
}
pre .filename{
display: inline-block;
padding: 0 .25em;
background: rgba(0,0,0,0.07);
}
pre .filename+ *{
display: block;
}
</style>
</head>
<body>
<script>
var md = "```js:index.js:fuga\nimport hoge from 'hoge';\n```";
var highlight = function(code, lang, callback){
return hljs.highlight(lang,code).value;
}
var renderer = new marked.Renderer;
renderer.code = function(code, fileInfo, escaped) {
var delimiter = ':';
var info = fileInfo.split(delimiter);
var lang = info.shift();
var fileName = info.join(delimiter); // 2つ目以降のdelimiterはファイル名として扱う
var fileTag = '';
if (fileName) {
fileTag = '<code class="filename">'+fileName+'</code>'
}
if (this.options.highlight) {
var out = this.options.highlight(code, lang);
if (out != null && out !== code) {
escaped = true;
code = out;
}
}
if (!lang) {
return '<pre>'+fileTag+'<code>'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>';
}
return '<pre>'+fileTag+'<code class="'
+ this.options.langPrefix
+ escape(lang, true)
+ '">'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>\n';
};
var html = marked(md,{
highlight: highlight,
renderer: renderer,
});
document.body.innerHTML = html;
</script>
</body>
</html>
以上です。