RedCloth 3.0.4 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of RedCloth might be problematic. Click here for more details.
- data/CHANGELOG +17 -0
- data/COPYING +18 -0
- data/README +156 -0
- data/Rakefile +238 -0
- data/bin/redcloth +27 -2
- data/ext/redcloth_scan/extconf.rb +9 -0
- data/ext/redcloth_scan/redcloth.h +149 -0
- data/ext/redcloth_scan/redcloth_attributes.c +650 -0
- data/ext/redcloth_scan/redcloth_attributes.rl +78 -0
- data/ext/redcloth_scan/redcloth_common.rl +113 -0
- data/ext/redcloth_scan/redcloth_inline.c +5102 -0
- data/ext/redcloth_scan/redcloth_inline.rl +282 -0
- data/ext/redcloth_scan/redcloth_scan.c +9300 -0
- data/ext/redcloth_scan/redcloth_scan.rl +523 -0
- data/extras/mingw-rbconfig.rb +176 -0
- data/extras/ragel_profiler.rb +73 -0
- data/lib/redcloth.rb +22 -1128
- data/lib/redcloth/formatters/base.rb +50 -0
- data/lib/redcloth/formatters/html.rb +342 -0
- data/lib/redcloth/formatters/latex.rb +227 -0
- data/lib/redcloth/formatters/latex_entities.yml +2414 -0
- data/lib/redcloth/textile_doc.rb +105 -0
- data/lib/redcloth/version.rb +18 -0
- data/test/basic.yml +794 -0
- data/test/code.yml +195 -0
- data/test/definitions.yml +71 -0
- data/test/extra_whitespace.yml +64 -0
- data/test/filter_html.yml +177 -0
- data/test/filter_pba.yml +12 -0
- data/test/helper.rb +108 -0
- data/test/html.yml +271 -0
- data/test/images.yml +202 -0
- data/{tests → test}/instiki.yml +14 -15
- data/test/links.yml +214 -0
- data/test/lists.yml +283 -0
- data/test/poignant.yml +89 -0
- data/test/sanitize_html.yml +42 -0
- data/test/table.yml +267 -0
- data/test/test_custom_tags.rb +46 -0
- data/test/test_extensions.rb +31 -0
- data/test/test_formatters.rb +15 -0
- data/test/test_parser.rb +68 -0
- data/test/test_restrictions.rb +41 -0
- data/test/textism.yml +480 -0
- data/test/threshold.yml +772 -0
- data/test/validate_fixtures.rb +73 -0
- metadata +94 -60
- data/doc/CHANGELOG +0 -160
- data/doc/COPYING +0 -25
- data/doc/README +0 -106
- data/doc/REFERENCE +0 -216
- data/doc/make.rb +0 -359
- data/run-tests.rb +0 -28
- data/setup.rb +0 -1376
- data/tests/code.yml +0 -105
- data/tests/hard_breaks.yml +0 -26
- data/tests/images.yml +0 -171
- data/tests/links.yml +0 -155
- data/tests/lists.yml +0 -77
- data/tests/markdown.yml +0 -218
- data/tests/poignant.yml +0 -64
- data/tests/table.yml +0 -198
- data/tests/textism.yml +0 -406
@@ -0,0 +1,50 @@
|
|
1
|
+
module RedCloth::Formatters
|
2
|
+
module Base
|
3
|
+
|
4
|
+
def pba(opts)
|
5
|
+
opts.delete(:style) if filter_styles
|
6
|
+
opts.delete(:class) if filter_classes
|
7
|
+
opts.delete(:id) if filter_ids
|
8
|
+
|
9
|
+
atts = ''
|
10
|
+
opts[:"text-align"] = opts.delete(:align)
|
11
|
+
opts[:style] += ';' if opts[:style] && (opts[:style][-1..-1] != ';')
|
12
|
+
[:float, :"text-align", :"vertical-align"].each do |a|
|
13
|
+
opts[:style] = "#{a}:#{opts[a]};#{opts[:style]}" if opts[a]
|
14
|
+
end
|
15
|
+
[:"padding-right", :"padding-left"].each do |a|
|
16
|
+
opts[:style] = "#{a}:#{opts[a]}em;#{opts[:style]}" if opts[a]
|
17
|
+
end
|
18
|
+
[:style, :class, :lang, :id, :colspan, :rowspan, :title, :start, :align].each do |a|
|
19
|
+
atts << " #{a}=\"#{ opts[a] }\"" if opts[a]
|
20
|
+
end
|
21
|
+
atts
|
22
|
+
end
|
23
|
+
|
24
|
+
def ignore(opts)
|
25
|
+
opts[:text]
|
26
|
+
end
|
27
|
+
alias_method :notextile, :ignore
|
28
|
+
|
29
|
+
def redcloth_version(opts)
|
30
|
+
p(:text => "#{opts[:prefix]}#{RedCloth::VERSION::STRING}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def inline_redcloth_version(opts)
|
34
|
+
RedCloth::VERSION::STRING
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(method, opts)
|
38
|
+
opts[:text] || ""
|
39
|
+
end
|
40
|
+
|
41
|
+
def before_transform(text)
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def after_transform(text)
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
module RedCloth::Formatters::HTML
|
2
|
+
include RedCloth::Formatters::Base
|
3
|
+
|
4
|
+
# escapement for regular HTML (not in PRE tag)
|
5
|
+
def escape(text)
|
6
|
+
html_esc(text)
|
7
|
+
end
|
8
|
+
|
9
|
+
# escapement for HTML in a PRE tag
|
10
|
+
def escape_pre(text)
|
11
|
+
html_esc(text, :html_escape_preformatted)
|
12
|
+
end
|
13
|
+
|
14
|
+
def after_transform(text)
|
15
|
+
text.chomp!
|
16
|
+
end
|
17
|
+
|
18
|
+
[:h1, :h2, :h3, :h4, :h5, :h6, :p, :pre, :div].each do |m|
|
19
|
+
define_method(m) do |opts|
|
20
|
+
"<#{m}#{pba(opts)}>#{opts[:text]}</#{m}>\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
[:strong, :code, :em, :i, :b, :ins, :sup, :sub, :span, :cite].each do |m|
|
25
|
+
define_method(m) do |opts|
|
26
|
+
opts[:block] = true
|
27
|
+
"<#{m}#{pba(opts)}>#{opts[:text]}</#{m}>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def acronym(opts)
|
32
|
+
opts[:block] = true
|
33
|
+
"<acronym#{pba(opts)}>#{caps(:text => opts[:text])}</acronym>"
|
34
|
+
end
|
35
|
+
|
36
|
+
def caps(opts)
|
37
|
+
if no_span_caps
|
38
|
+
opts[:text]
|
39
|
+
else
|
40
|
+
opts[:class] = 'caps'
|
41
|
+
span(opts)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def del(opts)
|
46
|
+
opts[:block] = true
|
47
|
+
"<del#{pba(opts)}>#{opts[:text]}</del>"
|
48
|
+
end
|
49
|
+
|
50
|
+
def del_phrase(opts)
|
51
|
+
" #{del(opts)}"
|
52
|
+
end
|
53
|
+
|
54
|
+
[:ol, :ul].each do |m|
|
55
|
+
define_method("#{m}_open") do |opts|
|
56
|
+
opts[:block] = true
|
57
|
+
"#{"\n" if opts[:nest] > 1}#{"\t" * (opts[:nest] - 1)}<#{m}#{pba(opts)}>\n"
|
58
|
+
end
|
59
|
+
define_method("#{m}_close") do |opts|
|
60
|
+
"#{li_close}#{"\t" * (opts[:nest] - 1)}</#{m}>#{"\n" if opts[:nest] <= 1}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def li_open(opts)
|
65
|
+
"#{li_close unless opts.delete(:first)}#{"\t" * opts[:nest]}<li#{pba(opts)}>#{opts[:text]}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def li_close(opts=nil)
|
69
|
+
"</li>\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
def dl_open(opts)
|
73
|
+
opts[:block] = true
|
74
|
+
"<dl#{pba(opts)}>\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
def dl_close(opts=nil)
|
78
|
+
"</dl>\n"
|
79
|
+
end
|
80
|
+
|
81
|
+
[:dt, :dd].each do |m|
|
82
|
+
define_method(m) do |opts|
|
83
|
+
"\t<#{m}#{pba(opts)}>#{opts[:text]}</#{m}>\n"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def td(opts)
|
88
|
+
tdtype = opts[:th] ? 'th' : 'td'
|
89
|
+
"\t\t<#{tdtype}#{pba(opts)}>#{opts[:text]}</#{tdtype}>\n"
|
90
|
+
end
|
91
|
+
|
92
|
+
def tr_open(opts)
|
93
|
+
"\t<tr#{pba(opts)}>\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
def tr_close(opts)
|
97
|
+
"\t</tr>\n"
|
98
|
+
end
|
99
|
+
|
100
|
+
def table_open(opts)
|
101
|
+
"<table#{pba(opts)}>\n"
|
102
|
+
end
|
103
|
+
|
104
|
+
def table_close(opts)
|
105
|
+
"</table>\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
def bc_open(opts)
|
109
|
+
opts[:block] = true
|
110
|
+
"<pre#{pba(opts)}>"
|
111
|
+
end
|
112
|
+
|
113
|
+
def bc_close(opts)
|
114
|
+
"</pre>\n"
|
115
|
+
end
|
116
|
+
|
117
|
+
def bq_open(opts)
|
118
|
+
opts[:block] = true
|
119
|
+
cite = opts[:cite] ? " cite=\"#{ opts[:cite] }\"" : ''
|
120
|
+
"<blockquote#{cite}#{pba(opts)}>\n"
|
121
|
+
end
|
122
|
+
|
123
|
+
def bq_close(opts)
|
124
|
+
"</blockquote>\n"
|
125
|
+
end
|
126
|
+
|
127
|
+
LINK_TEXT_WITH_TITLE_RE = /
|
128
|
+
([^"]+?) # $text
|
129
|
+
\s?
|
130
|
+
\(([^)]+?)\) # $title
|
131
|
+
$
|
132
|
+
/x
|
133
|
+
def link(opts)
|
134
|
+
if opts[:name] =~ LINK_TEXT_WITH_TITLE_RE
|
135
|
+
md = LINK_TEXT_WITH_TITLE_RE.match(opts[:name])
|
136
|
+
opts[:name] = md[1]
|
137
|
+
opts[:title] = md[2]
|
138
|
+
end
|
139
|
+
"<a href=\"#{opts[:href].gsub(/&/, '&')}\"#{pba(opts)}>#{opts[:name]}</a>"
|
140
|
+
end
|
141
|
+
|
142
|
+
def image(opts)
|
143
|
+
opts.delete(:align)
|
144
|
+
opts[:alt] = opts[:title]
|
145
|
+
img = "<img src=\"#{urlesc opts[:src]}\"#{pba(opts)} alt=\"#{opts[:alt]}\" />"
|
146
|
+
img = "<a href=\"#{urlesc opts[:href]}\">#{img}</a>" if opts[:href]
|
147
|
+
img
|
148
|
+
end
|
149
|
+
|
150
|
+
def footno(opts)
|
151
|
+
opts[:id] ||= opts[:text]
|
152
|
+
%Q{<sup class="footnote"><a href=\"#fn#{opts[:id]}\">#{opts[:text]}</a></sup>}
|
153
|
+
end
|
154
|
+
|
155
|
+
def fn(opts)
|
156
|
+
no = opts[:id]
|
157
|
+
opts[:id] = "fn#{no}"
|
158
|
+
opts[:class] = ["footnote", opts[:class]].compact.join(" ")
|
159
|
+
"<p#{pba(opts)}><sup>#{no}</sup> #{opts[:text]}</p>\n"
|
160
|
+
end
|
161
|
+
|
162
|
+
def snip(opts)
|
163
|
+
"<pre#{pba(opts)}><code>#{opts[:text]}</code></pre>\n"
|
164
|
+
end
|
165
|
+
|
166
|
+
def quote1(opts)
|
167
|
+
"‘#{opts[:text]}’"
|
168
|
+
end
|
169
|
+
|
170
|
+
def quote2(opts)
|
171
|
+
"“#{opts[:text]}”"
|
172
|
+
end
|
173
|
+
|
174
|
+
def ellipsis(opts)
|
175
|
+
"#{opts[:text]}…"
|
176
|
+
end
|
177
|
+
|
178
|
+
def emdash(opts)
|
179
|
+
"—"
|
180
|
+
end
|
181
|
+
|
182
|
+
def endash(opts)
|
183
|
+
" – "
|
184
|
+
end
|
185
|
+
|
186
|
+
def arrow(opts)
|
187
|
+
"→"
|
188
|
+
end
|
189
|
+
|
190
|
+
def dim(opts)
|
191
|
+
space = opts[:space] ? " " : ''
|
192
|
+
"#{opts[:text]}#{space}×#{space}"
|
193
|
+
end
|
194
|
+
|
195
|
+
def trademark(opts)
|
196
|
+
"™"
|
197
|
+
end
|
198
|
+
|
199
|
+
def registered(opts)
|
200
|
+
"®"
|
201
|
+
end
|
202
|
+
|
203
|
+
def copyright(opts)
|
204
|
+
"©"
|
205
|
+
end
|
206
|
+
|
207
|
+
def entity(opts)
|
208
|
+
"&#{opts[:text]};"
|
209
|
+
end
|
210
|
+
|
211
|
+
def urlesc(txt)
|
212
|
+
txt.gsub(/&/, '&')
|
213
|
+
end
|
214
|
+
|
215
|
+
def amp(opts)
|
216
|
+
"&"
|
217
|
+
end
|
218
|
+
|
219
|
+
def gt(opts)
|
220
|
+
">"
|
221
|
+
end
|
222
|
+
|
223
|
+
def lt(opts)
|
224
|
+
"<"
|
225
|
+
end
|
226
|
+
|
227
|
+
def br(opts)
|
228
|
+
if hard_breaks == false
|
229
|
+
"\n"
|
230
|
+
else
|
231
|
+
"<br />\n"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def quot(opts)
|
236
|
+
"""
|
237
|
+
end
|
238
|
+
|
239
|
+
def squot(opts)
|
240
|
+
"’"
|
241
|
+
end
|
242
|
+
|
243
|
+
def html(opts)
|
244
|
+
"#{opts[:text]}\n"
|
245
|
+
end
|
246
|
+
|
247
|
+
def html_block(opts)
|
248
|
+
inline_html(:text => "#{opts[:indent_before_start]}#{opts[:start_tag]}#{opts[:indent_after_start]}") +
|
249
|
+
"#{opts[:text]}" +
|
250
|
+
inline_html(:text => "#{opts[:indent_before_end]}#{opts[:end_tag]}#{opts[:indent_after_end]}")
|
251
|
+
end
|
252
|
+
|
253
|
+
def notextile(opts)
|
254
|
+
if filter_html
|
255
|
+
html_esc(opts[:text], :html_escape_preformatted)
|
256
|
+
else
|
257
|
+
opts[:text]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def inline_html(opts)
|
262
|
+
if filter_html
|
263
|
+
html_esc(opts[:text], :html_escape_preformatted)
|
264
|
+
else
|
265
|
+
"#{opts[:text]}" # nil-safe
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def ignored_line(opts)
|
270
|
+
opts[:text] + "\n"
|
271
|
+
end
|
272
|
+
|
273
|
+
def before_transform(text)
|
274
|
+
clean_html(text) if sanitize_html
|
275
|
+
end
|
276
|
+
|
277
|
+
# HTML cleansing stuff
|
278
|
+
BASIC_TAGS = {
|
279
|
+
'a' => ['href', 'title'],
|
280
|
+
'img' => ['src', 'alt', 'title'],
|
281
|
+
'br' => [],
|
282
|
+
'i' => nil,
|
283
|
+
'u' => nil,
|
284
|
+
'b' => nil,
|
285
|
+
'pre' => nil,
|
286
|
+
'kbd' => nil,
|
287
|
+
'code' => ['lang'],
|
288
|
+
'cite' => nil,
|
289
|
+
'strong' => nil,
|
290
|
+
'em' => nil,
|
291
|
+
'ins' => nil,
|
292
|
+
'sup' => nil,
|
293
|
+
'sub' => nil,
|
294
|
+
'del' => nil,
|
295
|
+
'table' => nil,
|
296
|
+
'tr' => nil,
|
297
|
+
'td' => ['colspan', 'rowspan'],
|
298
|
+
'th' => nil,
|
299
|
+
'ol' => ['start'],
|
300
|
+
'ul' => nil,
|
301
|
+
'li' => nil,
|
302
|
+
'p' => nil,
|
303
|
+
'h1' => nil,
|
304
|
+
'h2' => nil,
|
305
|
+
'h3' => nil,
|
306
|
+
'h4' => nil,
|
307
|
+
'h5' => nil,
|
308
|
+
'h6' => nil,
|
309
|
+
'blockquote' => ['cite'],
|
310
|
+
'notextile' => nil
|
311
|
+
}
|
312
|
+
|
313
|
+
# Clean unauthorized tags.
|
314
|
+
def clean_html( text, allowed_tags = BASIC_TAGS )
|
315
|
+
text.gsub!( /<!\[CDATA\[/, '' )
|
316
|
+
text.gsub!( /<(\/*)([A-Za-z]\w*)([^>]*?)(\s?\/?)>/ ) do |m|
|
317
|
+
raw = $~
|
318
|
+
tag = raw[2].downcase
|
319
|
+
if allowed_tags.has_key? tag
|
320
|
+
pcs = [tag]
|
321
|
+
allowed_tags[tag].each do |prop|
|
322
|
+
['"', "'", ''].each do |q|
|
323
|
+
q2 = ( q != '' ? q : '\s' )
|
324
|
+
if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i
|
325
|
+
attrv = $1
|
326
|
+
next if (prop == 'src' or prop == 'href') and not attrv =~ %r{^(http|https|ftp):}
|
327
|
+
pcs << "#{prop}=\"#{attrv.gsub('"', '\\"')}\""
|
328
|
+
break
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end if allowed_tags[tag]
|
332
|
+
"<#{raw[1]}#{pcs.join " "}#{raw[4]}>"
|
333
|
+
else # Unauthorized tag
|
334
|
+
if block_given?
|
335
|
+
yield m
|
336
|
+
else
|
337
|
+
''
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module RedCloth::Formatters::LATEX
|
4
|
+
include RedCloth::Formatters::Base
|
5
|
+
|
6
|
+
ENTITIES = YAML::load(File.read(File.dirname(__FILE__)+'/latex_entities.yml'))
|
7
|
+
|
8
|
+
def escape(text)
|
9
|
+
latex_esc(text)
|
10
|
+
end
|
11
|
+
|
12
|
+
def escape_pre(text)
|
13
|
+
text
|
14
|
+
end
|
15
|
+
|
16
|
+
# headers
|
17
|
+
{ :h1 => 'section*',
|
18
|
+
:h2 => 'subsection*',
|
19
|
+
:h3 => 'subsubsection*',
|
20
|
+
:h4 => 'textbf',
|
21
|
+
:h5 => 'textbf',
|
22
|
+
:h6 => 'textbf',
|
23
|
+
}.each do |m,tag|
|
24
|
+
define_method(m) do |opts|
|
25
|
+
"\\#{tag}{#{opts[:text]}}\n\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# commands
|
30
|
+
{ :strong => 'textbf',
|
31
|
+
:em => 'emph',
|
32
|
+
:i => 'emph',
|
33
|
+
:b => 'textbf',
|
34
|
+
:ins => 'underline',
|
35
|
+
:del => 'sout',
|
36
|
+
:acronym => 'MakeUppercase',
|
37
|
+
:caps => 'MakeUppercase',
|
38
|
+
}.each do |m,tag|
|
39
|
+
define_method(m) do |opts|
|
40
|
+
"\\#{tag}{#{opts[:text]}}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
{ :sup => '\ensuremath{^\textrm{#1}}',
|
45
|
+
:sub => '\ensuremath{_\textrm{#1}}',
|
46
|
+
}.each do |m, expr|
|
47
|
+
define_method(m) do |opts|
|
48
|
+
expr.sub('#1', opts[:text])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# environments
|
53
|
+
{ :pre => 'verbatim',
|
54
|
+
:code => 'verbatim',
|
55
|
+
:cite => 'quote',
|
56
|
+
}.each do |m, env|
|
57
|
+
define_method(m) do |opts|
|
58
|
+
begin_chunk(env) + opts[:text] + end_chunk(env)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# ignore (or find a good solution later)
|
63
|
+
[ :span,
|
64
|
+
:div,
|
65
|
+
].each do |m|
|
66
|
+
define_method(m) do |opts|
|
67
|
+
opts[:text].to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def del_phrase(opts)
|
72
|
+
" #{del(opts)}"
|
73
|
+
end
|
74
|
+
|
75
|
+
{ :ol => 'enumerate',
|
76
|
+
:ul => 'itemize',
|
77
|
+
}.each do |m, env|
|
78
|
+
define_method("#{m}_open") do |opts|
|
79
|
+
opts[:block] = true
|
80
|
+
"\\begin{#{env}}\n"
|
81
|
+
end
|
82
|
+
define_method("#{m}_close") do |opts|
|
83
|
+
"#{li_close}\\end{#{env}}\n\n"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def li_open(opts)
|
88
|
+
"#{li_close unless opts.delete(:first)}\t\\item #{opts[:text]}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def li_close(opts=nil)
|
92
|
+
"\n"
|
93
|
+
end
|
94
|
+
|
95
|
+
def p(opts)
|
96
|
+
opts[:text] + "\n\n"
|
97
|
+
end
|
98
|
+
|
99
|
+
def td(opts)
|
100
|
+
"\t\t\t#{opts[:text]} &\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
def tr_open(opts)
|
104
|
+
"\t\t"
|
105
|
+
end
|
106
|
+
|
107
|
+
def tr_close(opts)
|
108
|
+
"\t\t\\\\\n"
|
109
|
+
end
|
110
|
+
|
111
|
+
# FIXME: we need to know the column count before opening tabular context.
|
112
|
+
def table_open(opts)
|
113
|
+
"\\begin{align*}\n"
|
114
|
+
end
|
115
|
+
|
116
|
+
def table_close(opts)
|
117
|
+
"\t\\end{align*}\n"
|
118
|
+
end
|
119
|
+
|
120
|
+
def bc_open(opts)
|
121
|
+
opts[:block] = true
|
122
|
+
begin_chunk("verbatim") + "\n"
|
123
|
+
end
|
124
|
+
|
125
|
+
def bc_close(opts)
|
126
|
+
end_chunk("verbatim") + "\n"
|
127
|
+
end
|
128
|
+
|
129
|
+
def bq_open(opts)
|
130
|
+
opts[:block] = true
|
131
|
+
"\\begin{quotation}\n"
|
132
|
+
end
|
133
|
+
|
134
|
+
def bq_close(opts)
|
135
|
+
"\\end{quotation}\n\n"
|
136
|
+
end
|
137
|
+
|
138
|
+
def link(opts)
|
139
|
+
"\\href{#{opts[:href]}}{#{opts[:name]}}"
|
140
|
+
end
|
141
|
+
|
142
|
+
# FIXME: use includegraphics with security verification
|
143
|
+
def image(opts)
|
144
|
+
""
|
145
|
+
end
|
146
|
+
|
147
|
+
def footno(opts)
|
148
|
+
# TODO: insert a placeholder until we know the footnote content.
|
149
|
+
# For this to work, we need some kind of post-processing...
|
150
|
+
"\\footnotemark[#{opts[:text]}]"
|
151
|
+
end
|
152
|
+
|
153
|
+
def fn(opts)
|
154
|
+
"\\footnotetext[#{opts[:id]}]{#{opts[:text]}}"
|
155
|
+
end
|
156
|
+
|
157
|
+
def snip(opts)
|
158
|
+
"\\begin{verbatim}#{opts[:text]}\\end{verbatim}"
|
159
|
+
end
|
160
|
+
|
161
|
+
def quote1(opts)
|
162
|
+
"`#{opts[:text]}'"
|
163
|
+
end
|
164
|
+
|
165
|
+
def quote2(opts)
|
166
|
+
"``#{opts[:text]}\""
|
167
|
+
end
|
168
|
+
|
169
|
+
def ellipsis(opts)
|
170
|
+
"#{opts[:text]}\\ldots{}"
|
171
|
+
end
|
172
|
+
|
173
|
+
def emdash(opts)
|
174
|
+
"---"
|
175
|
+
end
|
176
|
+
|
177
|
+
def endash(opts)
|
178
|
+
"--"
|
179
|
+
end
|
180
|
+
|
181
|
+
def arrow(opts)
|
182
|
+
"\\rightarrow{}"
|
183
|
+
end
|
184
|
+
|
185
|
+
def trademark(opts)
|
186
|
+
"\\texttrademark{}"
|
187
|
+
end
|
188
|
+
|
189
|
+
def registered(opts)
|
190
|
+
"\\textregistered{}"
|
191
|
+
end
|
192
|
+
|
193
|
+
def copyright(opts)
|
194
|
+
"\\copyright{}"
|
195
|
+
end
|
196
|
+
|
197
|
+
# TODO: what do we do with (unknown) unicode entities ?
|
198
|
+
#
|
199
|
+
def entity(opts)
|
200
|
+
text = opts[:text][0..0] == '#' ? opts[:text][1..-1] : opts[:text]
|
201
|
+
ENTITIES[text]
|
202
|
+
end
|
203
|
+
|
204
|
+
def dim(opts)
|
205
|
+
space = opts[:space] ? " " : ''
|
206
|
+
"#{opts[:text]}#{space}\\texttimes{}#{space}"
|
207
|
+
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
def begin_chunk(type)
|
212
|
+
chunk_counter[type] += 1
|
213
|
+
return "\\begin{#{type}}" if 1 == chunk_counter[type]
|
214
|
+
''
|
215
|
+
end
|
216
|
+
|
217
|
+
def end_chunk(type)
|
218
|
+
chunk_counter[type] -= 1
|
219
|
+
raise RuntimeError, "Bad latex #{type} nesting detected" if chunk_counter[type] < 0 # This should never need to happen
|
220
|
+
return "\\end{#{type}}" if 0 == chunk_counter[type]
|
221
|
+
''
|
222
|
+
end
|
223
|
+
|
224
|
+
def chunk_counter
|
225
|
+
@chunk_counter ||= Hash.new 0
|
226
|
+
end
|
227
|
+
end
|