0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitBucket Markdown Enhanced Plugin でシンタックスハイライトを有効にする

Last updated at Posted at 2025-12-09

概要

GitBucket用のプラグイン GitBucket Markdown Enhanced Pluginを開発しています。

GitBucket Markdown Enhanced Plugin は、GitBucket 標準のマークダウンレンダリングエンジンを置き換えるプラグインです。

目標は、Visual Studio CodeMarkdown Preview Enhanced 向けの markdown ファイルを軽易に Web で共有できる環境です。

今回は、GitBucket の標準機能に搭載されているシンタックスハイライトを有効にします。

前回の記事

flexmark-java のコードハイライトに対する立場を検索してみた

度々、Issue が投稿されるようだが、代表的な issue を挙げます。

Is the library support code highlight? · Issue #183 · vsch/flexmark-java

No, this library cannot highlight your code (jet?). But you could use something like prism.js if your app is for web.

flexmark-java としては、シンタックスハイライトを行えないが、prism.js のようなものを使えば実現できるよと。

GitBucket では、シンタックスハイライトに highlight.js を使用しており、マークダウンレンダラーを差し替えても highlight.js に関連するスクリプトが読み込まれるようになっています。

クライアント負荷やリポジトリビューアーのファイルビューとの整合を考えると prism.js を使うよりも既存機能を使った方が良さそうです。

生成されるコードブロックの違い

GitBucket では、シンタックスハイライトに highlight.js を使用しており、マークダウンレンダラーを差し替えても highlight.js

比較に使ったマークダウンは、次のとおりです。


```scala
  private def renderFencedCodeBlock(
      node: FencedCodeBlock,
      context: NodeRendererContext,
      html: HtmlWriter
  ): Unit = {
    val htmlOptions: HtmlRendererOptions = context.getHtmlOptions()
    val language: BasedSequence =
      node.getInfoDelimitedByAny(htmlOptions.languageDelimiterSet)
    val info: String = node.getInfo().toString()

    logger.debug("FencedCodeBlock getInfo: " + node.getInfo().toString())

    if (language.equals("plantuml") || language.equals("puml")) {
      renderPlantUML(html, node)
    } else if (language.equals("wavedrom")) {
      renderWaveDrom(html, node)
    } else if (language.equals("dot") || language.equals("viz")) {
      renderDot(html, node, info)
    } else {
      context.delegateRender()
    }
  }
```

このマークダウンを元に GitBucket の標準機能が生成する HTML と GitBucket Markdown Enhanced Plugin が生成する HTML を比較してみます。

標準

          <pre class="prettyprint lang-scala">  private def renderFencedCodeBlock(
      node: FencedCodeBlock,
      context: NodeRendererContext,
      html: HtmlWriter
  ): Unit = {
    val htmlOptions: HtmlRendererOptions = context.getHtmlOptions()
    val language: BasedSequence =
      node.getInfoDelimitedByAny(htmlOptions.languageDelimiterSet)
    val info: String = node.getInfo().toString()

    logger.debug("FencedCodeBlock getInfo: " + node.getInfo().toString())

    if (language.equals("plantuml") || language.equals("puml")) {
      renderPlantUML(html, node)
    } else if (language.equals("wavedrom")) {
      renderWaveDrom(html, node)
    } else if (language.equals("dot") || language.equals("viz")) {
      renderDot(html, node, info)
    } else {
      context.delegateRender()
    }
  }</pre>

GitBucket Markdown Enhanced Plugin

<pre><code class="language-scala">  private def renderFencedCodeBlock(
      node: FencedCodeBlock,
      context: NodeRendererContext,
      html: HtmlWriter
  ): Unit = {
    val htmlOptions: HtmlRendererOptions = context.getHtmlOptions()
    val language: BasedSequence =
      node.getInfoDelimitedByAny(htmlOptions.languageDelimiterSet)
    val info: String = node.getInfo().toString()

    logger.debug("FencedCodeBlock getInfo: " + node.getInfo().toString())

    if (language.equals("plantuml") || language.equals("puml")) {
      renderPlantUML(html, node)
    } else if (language.equals("wavedrom")) {
      renderWaveDrom(html, node)
    } else if (language.equals("dot") || language.equals("viz")) {
      renderDot(html, node, info)
    } else {
      context.delegateRender()
    }
  }
</code></pre>

違い

  • 標準機能では prettyprint というクラスと pre 要素に直接コードが記述されている。
    • pre 要素に prettyprint というクラスとプログラミング言語を表すクラス lang-言語名 というクラスが指定されている。
  • GitBucket Markdown Enhanced Plugin では、pre 要素の子として code 要素がある。
    • pre 要素ではなく code 要素にクラスとプログラミング言語を表す language-言語名 というクラスが指定されている。

GitBucket Markdown Enhanced Plugin 側で標準機能に合わせた出力に修正していくことにします。

修正ソース

src\main\scala\io\github\yasumichi\gme\MarkdownEnhancedNodeRenderer.scala(修正前)

今まで GitBucket Markdown Enhanced Plugin で独自の拡張を行う言語名以外は、flexmark-java の既存のレンダラーに委譲していましたが、そこも独自実装することにします。

ただ、独自で処理しない mermaid は、他のレンダラー(GitLabExtension)に委譲するようにしています。

  private def renderFencedCodeBlock(
      node: FencedCodeBlock,
      context: NodeRendererContext,
      html: HtmlWriter
  ): Unit = {
    val htmlOptions: HtmlRendererOptions = context.getHtmlOptions()
    val language: BasedSequence =
      node.getInfoDelimitedByAny(htmlOptions.languageDelimiterSet)
    val info: String = node.getInfo().toString()

    logger.debug("FencedCodeBlock getInfo: " + node.getInfo().toString())

    if (language.equals("plantuml") || language.equals("puml")) {
      renderPlantUML(html, node)
    } else if (language.equals("wavedrom")) {
      renderWaveDrom(html, node)
    } else if (language.equals("dot") || language.equals("viz")) {
      renderDot(html, node, info)
    } else if (language.equals("mermaid")) {
      context.delegateRender()
    } else {
      renderPrittyPrint(html, node, context, language.toString())
    }
  }

最後の else 節で呼び出している renderPrittyPrint メソッドは、次のとおりです。

  private def renderPrittyPrint(
      html: HtmlWriter,
      node: FencedCodeBlock,
      context: NodeRendererContext,
      language: String
  ): Unit = {
    html
      .withAttr()
      .attr("class", s"prettyprint lang-${language}")
      .tag("pre")
    html.rawIndentedPre(node.getContentChars().toString())
    html.tag("/pre")
  }

html.rawIndentedPre(node.getContentChars().toString()) にたどり着くまでが苦労しました。

これまで使用してきた HtmlWriter クラス1appendtext などのメソッドでは、行頭のインデントが削除されてしまうのです。

スクリーンショット

ここまでの修正でスクリーンショットのとおり、GitBucket 標準のシンタックスハイライトが適用されるようになりました。

image.png

入手先

Releases · yasumichi/gitbucket-markdown-enhanced から、最新バージョンを入手できます。

  1. 正確には基本クラス HtmlAppendableBase

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?