LoginSignup
1
1

More than 3 years have passed since last update.

Tips: RougeにDiffシンタックスとと各言語のシンタックスを一緒にかけるLexerを追加する

Posted at

コードのシンタックスハイライトを行うgemとして、Rougeが有名だと思います。
RougeにはDiffのシンタックスはありますが、Diffと各言語のシンタックスを同時に適用することができないので、それを実現するためのTipsを紹介します。

実は実現する方法はRouge内のIssueで議論されていました。これを使って作ってみます。

まずは1つのLexerに対してDiffの指定も行えるようにしてみます。

rubyの場合(Rouge
module Rouge
  module Lexers
    class DiffRuby < Ruby
      prepend :root do
        rule(/^\+.*$\n?/, Generic::Inserted)
        rule(/^-+.*$\n?/, Generic::Deleted)
        rule(/^!.*$\n?/, Generic::Strong)
        rule(/^@.*$\n?/, Generic::Subheading)
        rule(/^([Ii]ndex|diff).*$\n?/, Generic::Heading)
        rule(/^=.*$\n?/, Generic::Heading)
      end
    end
  end
end

これだけでRubyのシンタックスでDiffの指定も行えるようになります。
しかし、このままではRouge全ての言語に対してカスタムLexerを作成する必要があります。愚直にかくとかなり大変そうです。
そこで、以下のようなモンキーパッチを作成してみました。

(::Rouge::Lexer.all - [::Rouge::Lexers::Diff]).each do |lexer|
  next unless lexer.ancestors.include?(::Rouge::RegexLexer) # RegexLexerを継承していないと構文の追加が行えないのでスキップ
  klass_name = "Diff#{lexer.name.demodulize}"

  ::Rouge::Lexers.const_set(klass_name, Class.new(lexer) do |_klass| # クラスを生成する
    title "Diff of #{lexer.title}"
    tag klass_name.underscore

    prepend :root do
      rule(/^\+.*$\n?/, Generic::Inserted)
      rule(/^-+.*$\n?/, Generic::Deleted)
      rule(/^!.*$\n?/, Generic::Strong)
      rule(/^@.*$\n?/, Generic::Subheading)
      rule(/^([Ii]ndex|diff).*$\n?/, Generic::Heading)
      rule(/^=.*$\n?/, Generic::Heading)
    end
  end)
end

これをRailsであればinitializerなどで実行すれば、Diffを適用したカスタムLexerを全ての言語に対して生成することができます。

Diff以外でも、全ての言語のシンタックスを拡張した別のシンタックスを追加したい時などで、同じ方法が使えると思います。
誰かの参考になれば幸いです。

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