202 lines
5.9 KiB
Ruby
202 lines
5.9 KiB
Ruby
module CodeRay
|
|
|
|
# This module holds the Encoder class and its subclasses.
|
|
# For example, the HTML encoder is named CodeRay::Encoders::HTML
|
|
# can be found in coderay/encoders/html.
|
|
#
|
|
# Encoders also provides methods and constants for the register
|
|
# mechanism and the [] method that returns the Encoder class
|
|
# belonging to the given format.
|
|
module Encoders
|
|
|
|
extend PluginHost
|
|
plugin_path File.dirname(__FILE__), 'encoders'
|
|
|
|
# = Encoder
|
|
#
|
|
# The Encoder base class. Together with Scanner and
|
|
# Tokens, it forms the highlighting triad.
|
|
#
|
|
# Encoder instances take a Tokens object and do something with it.
|
|
#
|
|
# The most common Encoder is surely the HTML encoder
|
|
# (CodeRay::Encoders::HTML). It highlights the code in a colorful
|
|
# html page.
|
|
# If you want the highlighted code in a div or a span instead,
|
|
# use its subclasses Div and Span.
|
|
class Encoder
|
|
extend Plugin
|
|
plugin_host Encoders
|
|
|
|
class << self
|
|
|
|
# If FILE_EXTENSION isn't defined, this method returns the
|
|
# downcase class name instead.
|
|
def const_missing sym
|
|
if sym == :FILE_EXTENSION
|
|
(defined?(@plugin_id) && @plugin_id || name[/\w+$/].downcase).to_s
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
# The default file extension for output file of this encoder class.
|
|
def file_extension
|
|
self::FILE_EXTENSION
|
|
end
|
|
|
|
end
|
|
|
|
# Subclasses are to store their default options in this constant.
|
|
DEFAULT_OPTIONS = { }
|
|
|
|
# The options you gave the Encoder at creating.
|
|
attr_accessor :options, :scanner
|
|
|
|
# Creates a new Encoder.
|
|
# +options+ is saved and used for all encode operations, as long
|
|
# as you don't overwrite it there by passing additional options.
|
|
#
|
|
# Encoder objects provide three encode methods:
|
|
# - encode simply takes a +code+ string and a +lang+
|
|
# - encode_tokens expects a +tokens+ object instead
|
|
#
|
|
# Each method has an optional +options+ parameter. These are
|
|
# added to the options you passed at creation.
|
|
def initialize options = {}
|
|
@options = self.class::DEFAULT_OPTIONS.merge options
|
|
@@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = false
|
|
end
|
|
|
|
# Encode a Tokens object.
|
|
def encode_tokens tokens, options = {}
|
|
options = @options.merge options
|
|
@scanner = tokens.scanner if tokens.respond_to? :scanner
|
|
setup options
|
|
compile tokens, options
|
|
finish options
|
|
end
|
|
|
|
# Encode the given +code+ using the Scanner for +lang+.
|
|
def encode code, lang, options = {}
|
|
options = @options.merge options
|
|
@scanner = Scanners[lang].new code, CodeRay.get_scanner_options(options).update(:tokens => self)
|
|
setup options
|
|
@scanner.tokenize
|
|
finish options
|
|
end
|
|
|
|
# You can use highlight instead of encode, if that seems
|
|
# more clear to you.
|
|
alias highlight encode
|
|
|
|
# The default file extension for this encoder.
|
|
def file_extension
|
|
self.class.file_extension
|
|
end
|
|
|
|
def << token
|
|
unless @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN
|
|
warn 'Using old Tokens#<< interface.'
|
|
@@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = true
|
|
end
|
|
self.token(*token)
|
|
end
|
|
|
|
# Called with +content+ and +kind+ of the currently scanned token.
|
|
# For simple scanners, it's enougth to implement this method.
|
|
#
|
|
# By default, it calls text_token, begin_group, end_group, begin_line,
|
|
# or end_line, depending on the +content+.
|
|
def token content, kind
|
|
case content
|
|
when String
|
|
text_token content, kind
|
|
when :begin_group
|
|
begin_group kind
|
|
when :end_group
|
|
end_group kind
|
|
when :begin_line
|
|
begin_line kind
|
|
when :end_line
|
|
end_line kind
|
|
else
|
|
raise ArgumentError, 'Unknown token content type: %p, kind = %p' % [content, kind]
|
|
end
|
|
end
|
|
|
|
# Called for each text token ([text, kind]), where text is a String.
|
|
def text_token text, kind
|
|
@out << text
|
|
end
|
|
|
|
# Starts a token group with the given +kind+.
|
|
def begin_group kind
|
|
end
|
|
|
|
# Ends a token group with the given +kind+.
|
|
def end_group kind
|
|
end
|
|
|
|
# Starts a new line token group with the given +kind+.
|
|
def begin_line kind
|
|
end
|
|
|
|
# Ends a new line token group with the given +kind+.
|
|
def end_line kind
|
|
end
|
|
|
|
protected
|
|
|
|
# Called with merged options before encoding starts.
|
|
# Sets @out to an empty string.
|
|
#
|
|
# See the HTML Encoder for an example of option caching.
|
|
def setup options
|
|
@out = get_output(options)
|
|
end
|
|
|
|
def get_output options
|
|
options[:out] || ''
|
|
end
|
|
|
|
# Append data.to_s to the output. Returns the argument.
|
|
def output data
|
|
@out << data.to_s
|
|
data
|
|
end
|
|
|
|
# Called with merged options after encoding starts.
|
|
# The return value is the result of encoding, typically @out.
|
|
def finish options
|
|
@out
|
|
end
|
|
|
|
# Do the encoding.
|
|
#
|
|
# The already created +tokens+ object must be used; it must be a
|
|
# Tokens object.
|
|
def compile tokens, options = {}
|
|
content = nil
|
|
for item in tokens
|
|
if item.is_a? Array
|
|
raise ArgumentError, 'Two-element array tokens are no longer supported.'
|
|
end
|
|
if content
|
|
token content, item
|
|
content = nil
|
|
else
|
|
content = item
|
|
end
|
|
end
|
|
raise 'odd number list for Tokens' if content
|
|
end
|
|
|
|
alias tokens compile
|
|
public :tokens
|
|
|
|
end
|
|
|
|
end
|
|
end
|