lib/playbook/markdown/helper.rb



# frozen_string_literal: true

require "redcarpet"
require "rouge"
require "rouge/plugins/redcarpet"
require "action_view"

module Playbook
  module Markdown
    module Helper
      def self.call(template, _source)
        markdown(template.source)
      end

      def render_markdown(text)
        # rubocop:disable Security/Eval
        eval(Playbook::Markdown::Helper.markdown(text))
        # rubocop:enable Security/Eval
      end

      def self.markdown(text)
        options = {
          filter_html: false,
          hard_wrap: true,
          link_attributes: { rel: "nofollow", target: "_blank" },
          space_after_headers: true,
          fenced_code_blocks: true,
          no_styles: false,
          safe_links_only: true,
        }

        extensions = {
          lax_spacing: true,
          no_intra_emphasis: true,
          autolink: true,
          superscript: true,
          fenced_code_blocks: true,
          tables: true,
          disable_indented_code_blocks: false,
          strikethrough: true,
          underline: true,
          highlight: true,
          footnotes: true,
          with_toc_data: true,
        }

        renderer = HTMLBlockCode.new(options)
        # toc_renderer = Redcarpet::Render::HTML_TOC.new(with_toc_data: true)
        # @TOC = Redcarpet::Markdown.new(toc_renderer)
        # puts "TOC: #{@TOC.inspect}"
        markdown = Redcarpet::Markdown.new(renderer, extensions)
        "#{markdown.render(text).inspect}.html_safe;"
      end

      def rouge(text, language)
        formatter = Rouge::Formatters::HTML.new(scope: ".highlight")
        lexer = Rouge::Lexer.find(language)
        formatter.format(lexer.lex(text))
      end

      class HTML < Redcarpet::Render::HTML
        include Rouge::Plugins::Redcarpet
      end

      def rouge_markdown(text)
        render_options = {
          filter_html: true,
          hard_wrap: true,
          link_attributes: { rel: "nofollow" },
        }
        renderer = HTML.new(render_options)

        extensions = {
          autolink: true,
          fenced_code_blocks: true,
          lax_spacing: true,
          no_intra_emphasis: true,
          strikethrough: true,
          superscript: true,
        }
        markdown = Redcarpet::Markdown.new(renderer, extensions)
        markdown.render(text)
      end
    end

    class HTMLWithPants < Redcarpet::Render::HTML
      include Redcarpet::Render::SmartyPants
    end

    class HTML < Redcarpet::Render::HTML
      include Rouge::Plugins::Redcarpet
    end

    class HTMLBlockCode < Redcarpet::Render::HTML
      include ActionView::Helpers::AssetTagHelper

      # def block_code(code, language)
      #   "\n.nf\n#{normal_text(rouge(code, language))}\n.fi\n"
      # end

      def table(header, body)
        "<table class='pb_table table-sm table-responsive-collapse table-card table-collapse-sm'>" \
          "<thead>#{header}</thead>" \
          "<tbody>#{body}</tbody>" \
        "</table>"
      end

      def header(title, level)
        @headers ||= []
        permalink = title.gsub(/\W+/, "-")
        if @headers.include?(permalink)
          permalink += "_1"
          loop do
            break unless @headers.include?(permalink)

            permalink.gsub!(/_(\d+)$/, "_#{Regexp.last_match(1).to_i + 1}")
          end
        end
        @headers << permalink
        permalink_markup = %(<a name="#{permalink}" class="markdown-header-anchor" )
        permalink_markup += %(href="##{permalink}"><span class="far fa-link markdown-header-anchor-icon"></span></a>)
        %(\n<h#{level} id="#{permalink}">#{title} #{permalink_markup}</h#{level}>\n)
      end

      def image(link, title, alt_text)
        return nil if link.nil?

        %(<a href="#{link}" target="_blank">#{image_tag(link, title: title, alt: alt_text, class: 'imageloader lazyload')}</a>)
      end
    end
  end
end