ActionText Highlighting with Rouge

03.30.2024

I wrote this module to process and format code blocks within a given text input that can be output through ActionText, utilizing the Rouge library for syntax highlighting.

# frozen_string_literal: true

module ActionText
  module RougeExtension
    def transform_text(text)
      parsed_text = parse_html_fragment(text)
      process_code_blocks(parsed_text)

      parsed_text.to_html.html_safe
    end

    private

    def format_code_block(content, lexer)
      formatter = Rouge::Formatters::HTML.new
      formatter.format(lexer.lex(content))
    end

    def get_lexer(language)
      Rouge::Lexer.find(language.downcase) || Rouge::Lexers::PlainText
    end

    def get_first_line(block)
      block.text.strip.lines.first.strip
    end

    def parse_html_fragment(text)
      Nokogiri::HTML.fragment(text)
    end

    def process_code_blocks(parsed_text)
      parsed_text.css("pre").each do |block|
        first_line = get_first_line(block)
        lexer = get_lexer(first_line)
        content = block.content.lines.drop(1).join
        formatted_code = format_code_block(content, lexer)

        block.content = formatted_code
        block.inner_html = formatted_code
      end
    end
  end
end

It can be used by including the module and modifying the ActionText content partial.

# app/helpers/application_helper.rb

# frozen_string_literal: true

module ApplicationHelper
  extend ActiveSupport::Concern

  include ActionText::RougeExtension
end

<%# app/views/layouts/action_text/contents/_content.html.erb %>

<div class="trix-content">
  <%= transform_text(yield) %>
</div>


Back to logs