Skip to content

Instantly share code, notes, and snippets.

@mojavelinux
Last active March 22, 2019 21:32
Show Gist options
  • Save mojavelinux/3b09d0e4159356330471122d58a3079b to your computer and use it in GitHub Desktop.
Save mojavelinux/3b09d0e4159356330471122d58a3079b to your computer and use it in GitHub Desktop.
Prototype of the Rouge syntax highighter integration for Asciidoctor. Now bundled with Asciidoctor. See https://github.com/asciidoctor/asciidoctor/blob/master/lib/asciidoctor/syntax_highlighter/rouge.rb
class RougeSyntaxHighlighter < Asciidoctor::SyntaxHighlighter::Base
register_for 'rouge'
def initialize *args
super
@requires_stylesheet = nil
@style = nil
end
def highlight?
library_available?
end
def highlight node, source, lang, opts
lexer = (::Rouge::Lexer.find lang) || ::Rouge::Lexer::PlainText
lexer_opts = {}
lexer_opts[:start_inline] = true if lexer.tag == 'php' && !(node.option? 'mixed')
style = @style = opts[:style]
style = @style = DEFAULT_STYLE unless style_available? style
if opts[:css_mode] == :class
@requires_stylesheet = true
formatter = ::Rouge::Formatters::HTML.new style
else
node.set_option 'inline-css'
formatter = ::Rouge::Formatters::HTMLInline.new style
end
if opts[:line_numbers]
formatter = ::Rouge::Formatters::HTMLTable.new formatter, code_class: 'code', gutter_class: 'linenos', start_line: opts[:start_line_number]
if opts[:callouts] && (highlighted = (formatter.format lexer.lex source, lexer_opts).gsub PreRx, '\1')
return [highlighted, (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil]
end
end
formatter.format lexer.lex source, lexer_opts
end
def format node, lang, opts
content = super
if (node.option? 'inline-css') && (pre_style_attr_val = block_style @style)
content.sub %r/<pre[^>]*/, %(\\& style="#{pre_style_attr_val}")
else
content
end
end
def docinfo? location
@requires_stylesheet && location == :footer
end
def docinfo location, doc, opts
if opts[:linkcss]
%(<link rel="stylesheet" href="#{doc.normalize_web_path (stylesheet_basename @style), (doc.attr 'stylesdir', ''), false}"#{opts[:self_closing_tag_slash]}>)
else
%(<style>
#{read_stylesheet @style}
</style>)
end
end
def write_stylesheet? doc
@requires_stylesheet
end
def write_stylesheet doc, to_dir
::File.write (::File.join to_dir, (stylesheet_basename @style)), (read_stylesheet @style)
end
module Loader
private
def library_available?
(@@library_status ||= load_library) == :loaded
end
def load_library
(defined? ::Rouge::Lexer) ? :loaded : (Asciidoctor::Helpers.require_library 'rouge', true, :warn).nil? ? :unavailable : :loaded
end
end
module Styles
include Loader
def read_stylesheet style
if library_available?
@@stylesheet_cache[style ||= DEFAULT_STYLE] ||= (::Rouge::Theme.find style).render scope: BASE_SELECTOR
else
'/* Rouge CSS disabled because Rouge is not available. */'
end
end
def stylesheet_basename style
%(rouge-#{style || DEFAULT_STYLE}.css)
end
private
def block_style style
@@block_style_cache[style ||= DEFAULT_STYLE] ||= begin
base_style = (theme = ::Rouge::Theme.find style).base_style
style = []
{ fg: 'color', bg: 'background-color' }.each do |mode, property_name|
(val = base_style[mode]) && (style << %(#{property_name}: #{theme.palette val}))
end
style.empty? ? nil : (style.join ';')
end
end
def style_available? style
(::Rouge::Theme.find style) ? true : nil
end
@@block_style_cache = {}
@@stylesheet_cache = {}
DEFAULT_STYLE = 'github'
BASE_SELECTOR = '.listingblock .rouge'
private_constant :BASE_SELECTOR
end
include Loader, Styles # adds methods to instance
CodeCellStartTagCs = '<td class="code">'
PreRx = %r(<pre\b[^>]*?>(.*?)</pre>)m
private_constant :CodeCellStartTagCs, :PreRx
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment