Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@getty104

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

コードのシンタックスハイライトを行う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以外でも、全ての言語のシンタックスを拡張した別のシンタックスを追加したい時などで、同じ方法が使えると思います。
誰かの参考になれば幸いです。

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
getty104
Rubyを書いています。最近はElixirに興味があります。設計が好きです。Qiitaの開発とプロダクトマネジメントをしています。
increments
「エンジニアを最高に幸せにする」ために Qiita、Qiita Team、Qiita Jobs を開発・運営しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?