module CodeRay
module Encoders
# Outputs code highlighted for a color terminal.
#
# Note: This encoder is in beta. It currently doesn't use the Styles.
#
# Alias: +term+
#
# == Authors & License
#
# By Rob Aldred (http://robaldred.co.uk)
#
# Based on idea by Nathan Weizenbaum (http://nex-3.com)
#
# MIT License (http://www.opensource.org/licenses/mit-license.php)
class Terminal < Encoder
register_for :terminal
TOKEN_COLORS = {
:annotation => '35',
:attribute_name => '33',
:attribute_value => '31',
:binary => '1;35',
:char => {
:self => '36', :delimiter => '34'
},
:class => '1;35',
:class_variable => '36',
:color => '32',
:comment => '37',
:complex => '34',
:constant => ['34', '4'],
:decoration => '35',
:definition => '1;32',
:directive => ['32', '4'],
:doc => '46',
:doctype => '1;30',
:doc_string => ['31', '4'],
:entity => '33',
:error => ['1;33', '41'],
:exception => '1;31',
:float => '1;35',
:function => '1;34',
:global_variable => '42',
:hex => '1;36',
:include => '33',
:integer => '1;34',
:key => '35',
:label => '1;15',
:local_variable => '33',
:octal => '1;35',
:operator_name => '1;29',
:predefined_constant => '1;36',
:predefined_type => '1;30',
:predefined => ['4', '1;34'],
:preprocessor => '36',
:pseudo_class => '34',
:regexp => {
:self => '31',
:content => '31',
:delimiter => '1;29',
:modifier => '35',
:function => '1;29'
},
:reserved => '1;31',
:shell => {
:self => '42',
:content => '1;29',
:delimiter => '37',
},
:string => {
:self => '32',
:modifier => '1;32',
:escape => '1;36',
:delimiter => '1;32',
},
:symbol => '1;32',
:tag => '34',
:type => '1;34',
:value => '36',
:variable => '34',
:insert => '42',
:delete => '41',
:change => '44',
:head => '45'
}
TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved]
TOKEN_COLORS[:method] = TOKEN_COLORS[:function]
TOKEN_COLORS[:imaginary] = TOKEN_COLORS[:complex]
TOKEN_COLORS[:begin_group] = TOKEN_COLORS[:end_group] =
TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter]
protected
def setup(options)
super
@opened = []
@subcolors = nil
end
public
def text_token text, kind
if color = (@subcolors || TOKEN_COLORS)[kind]
if Hash === color
if color[:self]
color = color[:self]
else
@out << text
return
end
end
@out << ansi_colorize(color)
@out << text.gsub("\n", ansi_clear + "\n" + ansi_colorize(color))
@out << ansi_clear
@out << ansi_colorize(@subcolors[:self]) if @subcolors && @subcolors[:self]
else
@out << text
end
end
def begin_group kind
@opened << kind
@out << open_token(kind)
end
alias begin_line begin_group
def end_group kind
if @opened.empty?
# nothing to close
else
@opened.pop
@out << ansi_clear
@out << open_token(@opened.last)
end
end
def end_line kind
if @opened.empty?
# nothing to close
else
@opened.pop
# whole lines to be highlighted,
# eg. added/modified/deleted lines in a diff
@out << "\t" * 100 + ansi_clear
@out << open_token(@opened.last)
end
end
private
def open_token kind
if color = TOKEN_COLORS[kind]
if Hash === color
@subcolors = color
ansi_colorize(color[:self]) if color[:self]
else
@subcolors = {}
ansi_colorize(color)
end
else
@subcolors = nil
''
end
end
def ansi_colorize(color)
Array(color).map { |c| "\e[#{c}m" }.join
end
def ansi_clear
ansi_colorize(0)
end
end
end
end