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 レンダリングを強化する試み

Last updated at Posted at 2025-08-02

概要

GitBucket は、GitHub のようにネットワーク上で Git リポジトリを共有できる Web サービスです。

  • Apache-2.0 ライセンスで配布されている。
  • Scala で開発されており、Java 17 実行環境があれば、起動可能。
  • お試しであれば、内臓のH2データベースエンジンが利用できる。
    • 実運用には、PostgreSQL や MariaDB などのリレーショナルデータベースサーバーの利用を推奨
  • 非常に簡単にセルフホストが可能です。

今回は、GitBucket 標準のマークダウンレンダリング機能を置き換える試みです。

成果を yasumichi/gitbucket-markdown-enhanced: GitBucket Markdown Enhanced Plugin に公開しています。

Scala の利用経験が浅いので色々、ご教示いただけますと幸いです。

これまでの GitBucket プラグインへの関わり

gitbucket-drawio-plugin を導入しましたが、4年開発が止まっているせいか、うまく動作しなかったので改修しました。

目標は Visual Studio Code の Markdown Preview Enhanced

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

実現できない機能もあるかと思いますが、できるだけ、近づけたいと考えます。

本家の gitbucket.core.view.Markdown の拡張を考えたが挫折

本家の gitbucket/src/main/scala/gitbucket/core/view/Markdown.scala を派生して強化するか、このクラスが利用している markedj を直接修正するか考えましたが、挫折しました。

flexmark-java との出会い

大してリサーチした訳ではないですが、Java の markdown ライブラリを探していた際に最近の commit もあって拡張機能が豊富な flexmark-java を見つけました。

flexmark-java を Scala から利用するためには、build.sbt に以下の行を加えます。

libraryDependencies += "com.vladsch.flexmark" % "flexmark-all" % "0.64.8"

gitbucket.core.plugin.Renderer の拡張

Renderer を開発するには、gitbucket.core.plugin.Renderer から派生したクラスで render メソッドをオーバーライドします。

素の flexmark-java を使う場合は、以下のようになります。

class MarkdownEnhancedRenderer extends Renderer {
  def render(request: RenderRequest): Html = {
    import request._
    Html(toHtml(fileContent)(context))
  }

  def shutdown(): Unit = {
  }

  def toHtml(content: String)(implicit context: Context): String = {
    val options = new MutableDataSet();
    
    val parser = Parser.builder(options).build()
    val renderer = HtmlRenderer.builder(options).build()

    val document = parser.parse(content)
    renderer.render(document)
  }
}

gitbucket.core.plugin.Plugin の拡張

gitbucket.core.plugin.Plugin を継承し、前項で作成した renderer を initialize メソッドで登録します。

class Plugin extends gitbucket.core.plugin.Plugin {
  override val pluginId: String = "gitbucket-markdown-enhanced"
  override val pluginName: String = "GitBucket Markdown Enhanced Plugin"
  override val description: String = "Rendering markdown files."
  override val versions: List[Version] = List(
    new Version("0.1.0")
  )

  private[this] var renderer: Option[MarkdownEnhancedRenderer] = None

  override def initialize(registry: PluginRegistry, context: ServletContext, settings: SystemSettingsService.SystemSettings): Unit = {
    val test = Try{ new MarkdownEnhancedRenderer() }
    val mer = test.get
    registry.addRenderer("md", mer)
    renderer = Option(mer)
    super.initialize(registry, context, settings)
  }

  override def shutdown(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Unit = {
    renderer.foreach(r => r.shutdown())
  }

}

flexmark-java の拡張機能を利用

拡張機能のコレクションを生成し、オプション Parser.EXTENSIONS にセットします。

    val extension: Seq[Extension] = Seq(
      AnchorLinkExtension.create(),
      EmojiExtension.create(),
      FootnoteExtension.create(),
      GitLabExtension.create(),
      StrikethroughExtension.create(),
      TablesExtension.create(),
      TaskListExtension.create(),
      TocExtension.create()
    )
   options.set(Parser.EXTENSIONS, extension.asJava)

この際、Scala のコレクションを Java のコレクションに変換する asJava メソッドを使用するため、以下の import 文を追加する必要がありました。

import collection.JavaConverters._

AnchorLinkExtension

AnchorLinkExtension

タイトルアンカーをリンクにする機能です。

GitBucket 本家とリンクの表示が異なるので同じようにできないか、調査中です。

EmojiExtension

EmojiExtension

flexmark-java/flexmark-ext-emoji/src/main/resources/EmojiReference.txt at master · vsch/flexmark-java で定義されている絵文字のショートカットが使えるようです。(設定次第で増やせるのか未確認)

:grinning: のような記述で :grinning: のような絵文字に変換されます。

FootnoteExtension

FootnoteExtension

脚注を有効にする拡張機能です。

GitLabExtension

GitLabExtension

GitLab Flavoured Markdown を利用できるようにする拡張機能です。

特に以下の機能サポートを利用できるようになります。

  • 数式を描画する katex
  • ダイアグラムを描画する mermaid

ただし、これらを利用する場合、以下の CSS と JavaScript の追加が必要です。

<link rel="stylesheet" href="katex.min.css">
<script src="katex.min.js"></script>
<script src="mermaid.min.js"></script>
<script>
    (function () {
      document.addEventListener("DOMContentLoaded", function () {
        var mathElems = document.getElementsByClassName("katex");
        var elems = [];
        for (const i in mathElems) {
            if (mathElems.hasOwnProperty(i)) elems.push(mathElems[i]);
        }

        elems.forEach(elem => {
            katex.render(elem.textContent, elem, { throwOnError: false, displayMode: elem.nodeName !== 'SPAN', });
        });
    });
})();

これを出力するため、 gitbucket.core.plugin.Plugin の javaScripts メソッドをオーバーライドします。

  override def javaScripts(registry: PluginRegistry, context: ServletContext, settings: SystemSettingsService.SystemSettings): Seq[(String, String)] = {
    val jsPath = settings.baseUrl.getOrElse(context.getContextPath) + "/plugin-assets/gme"
    Seq(".*" -> s"""
      |</script>
      |<link rel='stylesheet' href='$jsPath/katex.min.css'>
      |<script src="${jsPath}/katex.min.js">
      |</script>
      |<script src="${jsPath}/mermaid.min.js">
      |</script>
      |<script>
      |(function () {
      |  document.addEventListener("DOMContentLoaded", function () {
      |    var mathElems = document.getElementsByClassName("katex");
      |    var elems = [];
      |    for (const i in mathElems) {
      |      if (mathElems.hasOwnProperty(i)) elems.push(mathElems[i]);
      |    }
      |    elems.forEach(elem => {
      |      katex.render(elem.textContent, elem, { throwOnError: false, displayMode: elem.nodeName !== 'SPAN', });
      |    });
      |  });
      |})();
      |""".stripMargin)
  }

StrikethroughExtension

StrikethroughExtension

打消し線を有効にする拡張機能です。

TablesExtension

TablesExtension

表の出力を制御する拡張機能です。

TaskListExtension

TaskListExtension

GitBucket 本家の機能でも実現されていますが、GitHub 風のタスクリストを扱うための拡張機能です。

TocExtension

TocExtension

目次(Table of contents) を出力できる拡張です。

[TOC]

上記の記述がある部分を目次に変換します。 levels でどの階層までを目次に出力するか、制御できます。

参考文献

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?