This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
# -*- coding: utf-8 -*- #
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Rouge
|
||||
class TexThemeRenderer
|
||||
def initialize(theme, opts={})
|
||||
@theme = theme
|
||||
@prefix = opts.fetch(:prefix) { 'RG' }
|
||||
end
|
||||
|
||||
# Our general strategy is this:
|
||||
#
|
||||
# * First, define the \RG{tokname}{content} command, which will
|
||||
# expand into \RG@tok@tokname{content}. We use \csname...\endcsname
|
||||
# to interpolate into a command.
|
||||
#
|
||||
# * Define the default RG* environment, which will enclose the whole
|
||||
# thing. By default this will simply set \ttfamily (select monospace font)
|
||||
# but it can be overridden with \renewcommand by the user to be
|
||||
# any other formatting.
|
||||
#
|
||||
# * Define all the colors using xcolors \definecolor command. First we define
|
||||
# every palette color with a name such as RG@palette@themneame@colorname.
|
||||
# Then we find all foreground and background colors that have literal html
|
||||
# colors embedded in them and define them with names such as
|
||||
# RG@palette@themename@000000. While html allows three-letter colors such
|
||||
# as #FFF, xcolor requires all six characters to be present, so we make sure
|
||||
# to normalize that as well as the case convention in #inline_name.
|
||||
#
|
||||
# * Define the token commands RG@tok@xx. These will take the content as the
|
||||
# argument and format it according to the theme, referring to the color
|
||||
# in the palette.
|
||||
def render(&b)
|
||||
yield <<'END'.gsub('RG', @prefix)
|
||||
\makeatletter
|
||||
\def\RG#1#2{\csname RG@tok@#1\endcsname{#2}}%
|
||||
\newenvironment{RG*}{\ttfamily}{\relax}%
|
||||
END
|
||||
|
||||
base = @theme.class.base_style
|
||||
yield "\\definecolor{#{@prefix}@fgcolor}{HTML}{#{inline_name(base.fg || '#000000')}}"
|
||||
yield "\\definecolor{#{@prefix}@bgcolor}{HTML}{#{inline_name(base.bg || '#FFFFFF')}}"
|
||||
|
||||
render_palette(@theme.palette, &b)
|
||||
|
||||
@theme.styles.each do |tok, style|
|
||||
render_inline_pallete(style, &b)
|
||||
end
|
||||
|
||||
Token.each_token do |tok|
|
||||
style = @theme.class.get_own_style(tok)
|
||||
style ? render_style(tok, style, &b) : render_blank(tok, &b)
|
||||
end
|
||||
yield '\makeatother'
|
||||
end
|
||||
|
||||
def render_palette(palette, &b)
|
||||
palette.each do |name, color|
|
||||
hex = inline_name(color)
|
||||
|
||||
yield "\\definecolor{#{palette_name(name)}}{HTML}{#{hex}}%"
|
||||
end
|
||||
end
|
||||
|
||||
def render_inline_pallete(style, &b)
|
||||
gen_inline(style[:fg], &b)
|
||||
gen_inline(style[:bg], &b)
|
||||
end
|
||||
|
||||
def inline_name(color)
|
||||
color =~ /^#(\h+)/ or return nil
|
||||
|
||||
# xcolor does not support 3-character HTML colors,
|
||||
# so we convert them here
|
||||
case $1.size
|
||||
when 6
|
||||
$1
|
||||
when 3
|
||||
# duplicate every character: abc -> aabbcc
|
||||
$1.gsub(/\h/, '\0\0')
|
||||
else
|
||||
raise "invalid HTML color: #{$1}"
|
||||
end.upcase
|
||||
end
|
||||
|
||||
def gen_inline(name, &b)
|
||||
# detect inline colors
|
||||
hex = inline_name(name)
|
||||
return unless hex
|
||||
|
||||
@gen_inline ||= {}
|
||||
@gen_inline[hex] ||= begin
|
||||
yield "\\definecolor{#{palette_name(hex)}}{HTML}{#{hex}}%"
|
||||
end
|
||||
end
|
||||
|
||||
def camelize(name)
|
||||
name.gsub(/_(.)/) { $1.upcase }
|
||||
end
|
||||
|
||||
def palette_name(name)
|
||||
name = inline_name(name) || name.to_s
|
||||
|
||||
"#{@prefix}@palette@#{camelize(@theme.name)}@#{camelize(name.to_s)}"
|
||||
end
|
||||
|
||||
def token_name(tok)
|
||||
"\\csname #@prefix@tok@#{tok.shortname}\\endcsname"
|
||||
end
|
||||
|
||||
def render_blank(tok, &b)
|
||||
"\\expandafter\\def#{token_name(tok)}#1{#1}"
|
||||
end
|
||||
|
||||
def render_style(tok, style, &b)
|
||||
out = String.new('')
|
||||
out << "\\expandafter\\def#{token_name(tok)}#1{"
|
||||
out << "\\fboxsep=0pt\\colorbox{#{palette_name(style[:bg])}}{" if style[:bg]
|
||||
out << '\\textbf{' if style[:bold]
|
||||
out << '\\textit{' if style[:italic]
|
||||
out << "\\textcolor{#{palette_name(style[:fg])}}{" if style[:fg]
|
||||
out << "#1"
|
||||
# close the right number of curlies
|
||||
out << "}" if style[:bold]
|
||||
out << "}" if style[:italic]
|
||||
out << "}" if style[:fg]
|
||||
out << "}" if style[:bg]
|
||||
out << "}%"
|
||||
yield out
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user