Skip to content

Commit

Permalink
Handle Guesser::Ambiguous in Markdown context (#1349)
Browse files Browse the repository at this point in the history
If more than one lexer is selected when guessing the language of
provided code, `Lexer.find_fancy` will throw a `Guesser::Ambiguous`
error. When lexing in the context of Markdown, this commit causes Rouge
to instead select the first of the candidates.
  • Loading branch information
johnfairh authored and pyrmont committed Oct 13, 2019
1 parent abbf5fa commit 8ffc50b
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 2 deletions.
3 changes: 3 additions & 0 deletions lib/rouge/lexer.rb
Expand Up @@ -49,6 +49,9 @@ def find(name)
#
# Lexer.find_fancy('guess', "#!/bin/bash\necho Hello, world")
#
# If the code matches more than one lexer then Guesser::Ambiguous
# is raised.
#
# This is used in the Redcarpet plugin as well as Rouge's own
# markdown lexer for highlighting internal code blocks.
#
Expand Down
8 changes: 7 additions & 1 deletion lib/rouge/lexers/markdown.rb
Expand Up @@ -34,7 +34,13 @@ def html

rule %r/^([ \t]*)(```|~~~)([^\n]*\n)((.*?)(\2))?/m do |m|
name = m[3].strip
sublexer = Lexer.find_fancy(name.empty? ? "guess" : name, m[5], @options)
sublexer =
begin
Lexer.find_fancy(name.empty? ? "guess" : name, m[5], @options)
rescue Guesser::Ambiguous => e
e.alternatives.first.new(@options)
end

sublexer ||= PlainText.new(@options.merge(:token => Str::Backtick))
sublexer.reset!

Expand Down
8 changes: 7 additions & 1 deletion lib/rouge/plugins/redcarpet.rb
Expand Up @@ -9,7 +9,13 @@ module Rouge
module Plugins
module Redcarpet
def block_code(code, language)
lexer = Lexer.find_fancy(language, code) || Lexers::PlainText
lexer =
begin
Lexer.find_fancy(language, code)
rescue Guesser::Ambiguous => e
e.alternatives.first
end
lexer ||= Lexers::PlainText

# XXX HACK: Redcarpet strips hard tabs out of code blocks,
# so we assume you're not using leading spaces that aren't tabs,
Expand Down
8 changes: 8 additions & 0 deletions spec/lexers/markdown_spec.rb
Expand Up @@ -39,6 +39,14 @@
assert_has_token("Comment.Single","```\n#!/usr/bin/env ruby\n```\n")
end

it 'picks a sub-lexer when the code-block-content is ambiguous' do
source = "Index: ): Awaitable<\n"
assert_raises Rouge::Guesser::Ambiguous do
Rouge::Lexer.find_fancy(nil, source)
end
assert_no_errors "```\n#{source}```\n"
end

it 'recognizes backticks instead of code block if inside string' do
assert_has_token("Literal.String.Backtick","\nx```ruby\nfoo\n```\n")
deny_has_token("Name.Label","\nx```ruby\nfoo\n```\n")
Expand Down
10 changes: 10 additions & 0 deletions spec/plugins/redcarpet_spec.rb
Expand Up @@ -42,6 +42,16 @@
assert { result.include?(%(<pre class="highlight ruby"><code>)) }
end

it 'chooses when a guess is ambiguous' do
result = markdown.render <<-mkd
``` guess
Index: ): Awaitable<
```
mkd

assert { result.include?(%(<pre class="highlight)) }
end

it 'passes options' do
result = markdown.render <<-mkd
``` shell?k=v
Expand Down

0 comments on commit 8ffc50b

Please sign in to comment.