1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Formatters
class Tex < Formatter
tag 'tex'
# A map of TeX escape characters.
# Newlines are handled specially by using #token_lines
# spaces are preserved as long as they aren't at the beginning
# of a line. see #tag_first for our initial-space strategy
ESCAPE = {
'&' => '\&',
'%' => '\%',
'$' => '\$',
'#' => '\#',
'_' => '\_',
'{' => '\{',
'}' => '\}',
'~' => '{\textasciitilde}',
'^' => '{\textasciicircum}',
'|' => '{\textbar}',
'\\' => '{\textbackslash}',
'`' => '{\textasciigrave}',
"'" => "'{}",
'"' => '"{}',
"\t" => '{\tab}',
}
ESCAPE_REGEX = /[#{ESCAPE.keys.map(&Regexp.method(:escape)).join}]/om
def initialize(opts={})
@prefix = opts.fetch(:prefix) { 'RG' }
end
def escape_tex(str)
str.gsub(ESCAPE_REGEX, ESCAPE)
end
def stream(tokens, &b)
# surround the output with \begin{RG*}...\end{RG*}
yield "\\begin{#{@prefix}*}%\n"
# we strip the newline off the last line to avoid
# an extra line being rendered. we do this by yielding
# the \newline tag *before* every line group except
# the first.
first = true
token_lines tokens do |line|
if first
first = false
else
yield "\\newline%\n"
end
render_line(line, &b)
end
yield "%\n\\end{#{@prefix}*}%\n"
end
def render_line(line, &b)
line.each do |(tok, val)|
hphantom_tag(tok, val, &b)
end
end
# Special handling for leading spaces, since they may be gobbled
# by a previous command. We replace all initial spaces with
# \hphantom{xxxx}, which renders an empty space equal to the size
# of the x's.
def hphantom_tag(tok, val)
leading = nil
val.sub!(/^[ ]+/) { leading = $&.size; '' }
yield "\\hphantom{#{'x' * leading}}" if leading
yield tag(tok, val) unless val.empty?
end
def tag(tok, val)
if escape?(tok)
val
elsif tok == Token::Tokens::Text
escape_tex(val)
else
"\\#@prefix{#{tok.shortname}}{#{escape_tex(val)}}"
end
end
end
end
end
|