Class: Abqari::SyntaxHighlighter
- Inherits:
-
Object
- Object
- Abqari::SyntaxHighlighter
- Defined in:
- lib/abqari/syntax_highlighter.rb
Defined Under Namespace
Classes: Stylesheet
Constant Summary collapse
- DEFAULT_THEME =
'github'- COMMONMARKER_BLOCK =
CommonMarker 1.x emits two shapes depending on whether
render.unsafeis true (it is, in our config — so authors can use raw HTML in markdown). With unsafe, the lang lives on<code class="language-X">and<pre>carries an inlinestyle=. Without unsafe, lang lived on<pre lang="X">. Both shapes also wrap tokens in inline-style<span>tags from commonmarker's bundled highlighter — which we strip and re-render with Rouge for theme-aware output. %r{<pre lang="(?<lang>[^"]+)"[^>]*>\s*<code>(?<code>.*?)</code>\s*</pre>}m.freeze
- PLAIN_BLOCK =
Permissive: any attributes on
, optional language class on
. %r{<pre[^>]*>\s*<code(?:\s+class="language-(?<lang>[^"]+)")?>(?<code>.*?)</code>\s*</pre>}m.freeze
- SPAN_TAGS =
%r{</?span[^>]*>}.freeze
Class Method Summary collapse
Class Method Details
.highlight(lang, code) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/abqari/syntax_highlighter.rb', line 37 def self.highlight(lang, code) # Strip any inline <span> tags from commonmarker's pre-highlighting, # then decode HTML entities back to source. raw = CGI.unescapeHTML(code.gsub(SPAN_TAGS, '')) lexer = (lang && Rouge::Lexer.find(lang)) || Rouge::Lexers::PlainText formatter = Rouge::Formatters::HTML.new highlighted = formatter.format(lexer.lex(raw)) lang_class = lang ? %( class="language-#{lang}") : '' %(<div class="highlight"><pre class="highlight"><code#{lang_class}>#{highlighted}</code></pre></div>) end |
.process(html) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/abqari/syntax_highlighter.rb', line 22 def self.process(html) html = html.gsub(COMMONMARKER_BLOCK) { highlight(Regexp.last_match[:lang], Regexp.last_match[:code]) } html.gsub(PLAIN_BLOCK) do m = Regexp.last_match # Skip blocks the first pass already produced — they carry # `class="highlight"` on the <pre>. Re-running `highlight` on them # would strip the Rouge `<span>`s (losing the highlighting) and # unescape entities a second time (`&amp;` → `&` → `&`). pre_tag = m[0][/\A<pre[^>]*>/] next m[0] if pre_tag&.include?('highlight') highlight(m[:lang], m[:code]) end end |