Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Lexer#with and Lexer.lookup_fancy #1565

Merged
merged 4 commits into from
Sep 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions lib/rouge/lexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,15 @@ def find(name)
registry[name.to_s]
end

# Find a lexer, with fancy shiny features.
#
# * The string you pass can include CGI-style options
#
# Lexer.find_fancy('erb?parent=tex')
#
# * You can pass the special name 'guess' so we guess for you,
# and you can pass a second argument of the code to guess by
#
# Lexer.find_fancy('guess', "#!/bin/bash\necho Hello, world")
# Same as ::find_fancy, except instead of returning an instantiated
# lexer, returns a pair of [lexer_class, options], so that you can
# modify or provide additional options to the lexer.
#
# 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.
#
def find_fancy(str, code=nil, additional_options={})

# Please note: the lexer class might be nil!
def lookup_fancy(str, code=nil, default_options={})
if str && !str.include?('?') && str != 'guess'
lexer_class = find(str)
return lexer_class && lexer_class.new(additional_options)
return [lexer_class, default_options]
end

name, opts = str ? str.split('?', 2) : [nil, '']
Expand All @@ -75,7 +62,7 @@ def find_fancy(str, code=nil, additional_options={})
[ k.to_s, val ]
end

opts = additional_options.merge(Hash[opts])
opts = default_options.merge(Hash[opts])

lexer_class = case name
when 'guess', nil
Expand All @@ -84,6 +71,29 @@ def find_fancy(str, code=nil, additional_options={})
self.find(name)
end

[lexer_class, opts]
end

# Find a lexer, with fancy shiny features.
#
# * The string you pass can include CGI-style options
#
# Lexer.find_fancy('erb?parent=tex')
#
# * You can pass the special name 'guess' so we guess for you,
# and you can pass a second argument of the code to guess by
#
# 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.
#
def find_fancy(str, code=nil, default_options={})
lexer_class, opts = lookup_fancy(str, code, default_options)

lexer_class && lexer_class.new(opts)
end

Expand Down Expand Up @@ -317,6 +327,14 @@ def initialize(opts={})
@debug = Lexer.debug_enabled? && bool_option('debug')
end

# Returns a new lexer with the given options set. Useful for e.g. setting
# debug flags post hoc, or providing global overrides for certain options
def with(opts={})
new_options = @options.dup
opts.each { |k, v| new_options[k.to_s] = v }
self.class.new(new_options)
end

def as_bool(val)
case val
when nil, false, 0, '0', 'false', 'off'
Expand Down
12 changes: 12 additions & 0 deletions spec/lexer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,16 @@ def initialize(*)
assert_equal false, option_lexer.new({bool_opt: 'false'}).instance_variable_get(:@bool_opt)
assert_equal false, option_lexer.new({bool_opt: 'off'}).instance_variable_get(:@bool_opt)
end

it 'extends options with #with' do
php = Rouge::Lexers::PHP.new

assert { php.instance_variable_get(:@start_inline) == :guess }

inline_php = php.with(start_inline: true)
assert { inline_php.is_a?(Rouge::Lexers::PHP) }
assert { inline_php != php }
assert { php.instance_variable_get(:@start_inline) == :guess }
assert { inline_php.instance_variable_get(:@start_inline) == true }
end
end