kramdown 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of kramdown might be problematic. Click here for more details.
- data/CONTRIBUTERS +1 -1
- data/ChangeLog +532 -0
- data/README +22 -12
- data/Rakefile +9 -8
- data/VERSION +1 -1
- data/benchmark/benchmark.sh +61 -0
- data/benchmark/generate_data.rb +57 -55
- data/benchmark/testing.sh +1 -1
- data/benchmark/timing.sh +3 -3
- data/bin/kramdown +1 -2
- data/data/kramdown/document.html +2 -2
- data/data/kramdown/document.latex +2 -2
- data/doc/default.scss.css +6 -1
- data/doc/default.template +1 -1
- data/doc/documentation.page +1 -1
- data/doc/index.page +9 -7
- data/doc/installation.page +2 -3
- data/doc/links.markdown +1 -1
- data/doc/quickref.page +19 -19
- data/doc/syntax.page +117 -98
- data/doc/tests.page +8 -7
- data/lib/kramdown/compatibility.rb +2 -1
- data/lib/kramdown/converter.rb +5 -7
- data/lib/kramdown/converter/base.rb +87 -32
- data/lib/kramdown/converter/html.rb +134 -122
- data/lib/kramdown/converter/kramdown.rb +24 -25
- data/lib/kramdown/converter/latex.rb +65 -55
- data/lib/kramdown/document.rb +487 -42
- data/lib/kramdown/error.rb +3 -0
- data/lib/kramdown/options.rb +83 -28
- data/lib/kramdown/parser.rb +5 -5
- data/lib/kramdown/parser/base.rb +55 -13
- data/lib/kramdown/parser/html.rb +83 -71
- data/lib/kramdown/parser/kramdown.rb +73 -54
- data/lib/kramdown/parser/kramdown/abbreviation.rb +17 -12
- data/lib/kramdown/parser/kramdown/autolink.rb +2 -3
- data/lib/kramdown/parser/kramdown/blank_line.rb +1 -1
- data/lib/kramdown/parser/kramdown/block_boundary.rb +2 -2
- data/lib/kramdown/parser/kramdown/blockquote.rb +2 -2
- data/lib/kramdown/parser/kramdown/codeblock.rb +5 -2
- data/lib/kramdown/parser/kramdown/codespan.rb +1 -2
- data/lib/kramdown/parser/kramdown/emphasis.rb +1 -1
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +1 -1
- data/lib/kramdown/parser/kramdown/extensions.rb +204 -0
- data/lib/kramdown/parser/kramdown/footnote.rb +7 -7
- data/lib/kramdown/parser/kramdown/header.rb +4 -2
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +1 -1
- data/lib/kramdown/parser/kramdown/html.rb +39 -45
- data/lib/kramdown/parser/kramdown/link.rb +19 -29
- data/lib/kramdown/parser/kramdown/list.rb +13 -13
- data/lib/kramdown/parser/kramdown/math.rb +1 -1
- data/lib/kramdown/parser/kramdown/paragraph.rb +5 -4
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +1 -1
- data/lib/kramdown/parser/kramdown/table.rb +51 -12
- data/lib/kramdown/parser/markdown.rb +69 -0
- data/lib/kramdown/utils.rb +2 -2
- data/lib/kramdown/utils/entities.rb +10 -1
- data/lib/kramdown/utils/html.rb +22 -11
- data/lib/kramdown/utils/ordered_hash.rb +44 -40
- data/lib/kramdown/version.rb +1 -1
- data/man/man1/kramdown.1 +31 -4
- data/test/testcases/block/08_list/item_ial.html +1 -1
- data/test/testcases/block/11_ial/nested.html +11 -0
- data/test/testcases/block/11_ial/nested.text +15 -0
- data/test/testcases/block/13_definition_list/item_ial.html +1 -1
- data/test/testcases/block/14_table/escaping.html +52 -0
- data/test/testcases/block/14_table/escaping.text +19 -0
- data/test/testcases/block/14_table/simple.html.19 +139 -0
- data/test/testcases/block/14_table/simple.text +1 -1
- data/test/testcases/block/15_math/normal.html +13 -13
- data/test/testcases/block/16_toc/{no_toc_depth.html → no_toc.html} +0 -0
- data/test/testcases/block/16_toc/{no_toc_depth.options → no_toc.options} +0 -0
- data/test/testcases/block/16_toc/{no_toc_depth.text → no_toc.text} +0 -0
- data/test/testcases/block/16_toc/{toc_depth_2.html → toc_levels.html} +4 -4
- data/test/testcases/block/16_toc/toc_levels.options +1 -0
- data/test/testcases/block/16_toc/{toc_depth_2.text → toc_levels.text} +0 -0
- data/test/testcases/span/escaped_chars/normal.html +4 -0
- data/test/testcases/span/escaped_chars/normal.text +4 -0
- data/test/testcases/span/ial/simple.html +1 -1
- data/test/testcases/span/math/normal.html +2 -2
- metadata +20 -25
- data/benchmark/historic-jruby-1.4.0.dat +0 -7
- data/benchmark/historic-ruby-1.8.6.dat +0 -7
- data/benchmark/historic-ruby-1.8.7.dat +0 -7
- data/benchmark/historic-ruby-1.9.1p243.dat +0 -7
- data/benchmark/historic-ruby-1.9.2dev.dat +0 -7
- data/benchmark/static-jruby-1.4.0.dat +0 -7
- data/benchmark/static-ruby-1.8.6.dat +0 -7
- data/benchmark/static-ruby-1.8.7.dat +0 -7
- data/benchmark/static-ruby-1.9.1p243.dat +0 -7
- data/benchmark/static-ruby-1.9.2dev.dat +0 -7
- data/lib/kramdown/parser/kramdown/attribute_list.rb +0 -111
- data/lib/kramdown/parser/kramdown/extension.rb +0 -116
- data/test/testcases/block/16_toc/toc_depth_2.options +0 -1
@@ -26,14 +26,14 @@ module Kramdown
|
|
26
26
|
|
27
27
|
module Converter
|
28
28
|
|
29
|
-
# Converts
|
29
|
+
# Converts an element tree to the kramdown format.
|
30
30
|
class Kramdown < Base
|
31
31
|
|
32
32
|
# :stopdoc:
|
33
33
|
|
34
|
-
include ::Kramdown::Utils::
|
34
|
+
include ::Kramdown::Utils::Html
|
35
35
|
|
36
|
-
def initialize(
|
36
|
+
def initialize(root, options)
|
37
37
|
super
|
38
38
|
@linkrefs = []
|
39
39
|
@footnotes = []
|
@@ -45,12 +45,12 @@ module Kramdown
|
|
45
45
|
res = send("convert_#{el.type}", el, opts)
|
46
46
|
if el.type != :html_element && el.type != :li && el.type != :dd && (ial = ial_for_element(el))
|
47
47
|
res << ial
|
48
|
-
res << "\n\n" if
|
48
|
+
res << "\n\n" if Element.category(el) == :block
|
49
49
|
elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] &&
|
50
50
|
([el.type, :codeblock].include?(opts[:next].type) ||
|
51
51
|
(opts[:next].type == :blank && opts[:nnext] && [el.type, :codeblock].include?(opts[:nnext].type)))
|
52
52
|
res << "^\n\n"
|
53
|
-
elsif
|
53
|
+
elsif Element.category(el) == :block && ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
|
54
54
|
(el.type != :p || !el.options[:transparent])
|
55
55
|
res << "\n"
|
56
56
|
end
|
@@ -77,7 +77,7 @@ module Kramdown
|
|
77
77
|
""
|
78
78
|
end
|
79
79
|
|
80
|
-
ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{"'])|^[ ]{0,3}(:)/
|
80
|
+
ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{"'|])|^[ ]{0,3}(:)/
|
81
81
|
|
82
82
|
def convert_text(el, opts)
|
83
83
|
if opts[:raw_text]
|
@@ -90,10 +90,9 @@ module Kramdown
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def convert_p(el, opts)
|
93
|
-
w = @
|
93
|
+
w = @options[:line_width] - opts[:indent].to_s.to_i
|
94
94
|
first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
|
95
|
-
first.gsub!(/^(?:(
|
96
|
-
first.gsub!(/\|/, '\\|')
|
95
|
+
first.gsub!(/^(?:(#|>)|(\d+)\.|([+-]\s))/) { $1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\."} if first
|
97
96
|
second.gsub!(/^([=-]+\s*?)$/, "\\\1") if second
|
98
97
|
[first, second, *rest].compact.join("\n") + "\n"
|
99
98
|
end
|
@@ -132,7 +131,7 @@ module Kramdown
|
|
132
131
|
["#{opts[:index] + 1}.".ljust(4), 4]
|
133
132
|
end
|
134
133
|
if ial = ial_for_element(el)
|
135
|
-
sym
|
134
|
+
sym << ial << " "
|
136
135
|
end
|
137
136
|
|
138
137
|
opts[:indent] += width
|
@@ -156,7 +155,7 @@ module Kramdown
|
|
156
155
|
def convert_dd(el, opts)
|
157
156
|
sym, width = ": ", (el.children.first.type == :codeblock ? 4 : 2)
|
158
157
|
if ial = ial_for_element(el)
|
159
|
-
sym
|
158
|
+
sym << ial << " "
|
160
159
|
end
|
161
160
|
|
162
161
|
opts[:indent] += width
|
@@ -166,7 +165,7 @@ module Kramdown
|
|
166
165
|
last = last.map {|l| " "*width + l}.join("\n")
|
167
166
|
text = first + (last.empty? ? "" : "\n") + last + newlines
|
168
167
|
text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd
|
169
|
-
text
|
168
|
+
text << "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt
|
170
169
|
if el.children.first.type == :p && !el.children.first.options[:transparent]
|
171
170
|
"\n#{sym}#{text}"
|
172
171
|
elsif el.children.first.type == :codeblock
|
@@ -184,19 +183,19 @@ module Kramdown
|
|
184
183
|
|
185
184
|
def convert_html_element(el, opts)
|
186
185
|
markdown_attr = el.options[:category] == :block && el.children.any? do |c|
|
187
|
-
c.type != :html_element && (c.type != :p || !c.options[:transparent]) &&
|
186
|
+
c.type != :html_element && (c.type != :p || !c.options[:transparent]) && Element.category(c) == :block
|
188
187
|
end
|
189
188
|
opts[:force_raw_text] = true if %w{script pre code}.include?(el.value)
|
190
189
|
opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || (el.options[:category] != :span && !markdown_attr)
|
191
190
|
opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text]
|
192
191
|
res = inner(el, opts)
|
193
192
|
if el.options[:category] == :span
|
194
|
-
"<#{el.value}#{html_attributes(el)}" << (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
|
193
|
+
"<#{el.value}#{html_attributes(el.attr)}" << (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
|
195
194
|
else
|
196
195
|
output = ''
|
197
|
-
output << "<#{el.value}#{html_attributes(el)}"
|
196
|
+
output << "<#{el.value}#{html_attributes(el.attr)}"
|
198
197
|
output << " markdown=\"1\"" if markdown_attr
|
199
|
-
if !res.empty? && el.options[:
|
198
|
+
if !res.empty? && el.options[:content_model] != :block
|
200
199
|
output << ">#{res}</#{el.value}>"
|
201
200
|
elsif !res.empty?
|
202
201
|
output << ">\n#{res}" << "</#{el.value}>"
|
@@ -205,20 +204,19 @@ module Kramdown
|
|
205
204
|
else
|
206
205
|
output << " />"
|
207
206
|
end
|
208
|
-
output << "\n" if @stack.last.type != :html_element || @stack.last.options[:
|
207
|
+
output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
|
209
208
|
output
|
210
209
|
end
|
211
210
|
end
|
212
211
|
|
213
212
|
def convert_xml_comment(el, opts)
|
214
|
-
if el.options[:category] == :block && (@stack.last.type != :html_element || @stack.last.options[:
|
213
|
+
if el.options[:category] == :block && (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw)
|
215
214
|
el.value + "\n"
|
216
215
|
else
|
217
216
|
el.value
|
218
217
|
end
|
219
218
|
end
|
220
219
|
alias :convert_xml_pi :convert_xml_comment
|
221
|
-
alias :convert_html_doctype :convert_xml_comment
|
222
220
|
|
223
221
|
def convert_table(el, opts)
|
224
222
|
opts[:alignment] = el.options[:alignment]
|
@@ -257,9 +255,8 @@ module Kramdown
|
|
257
255
|
end
|
258
256
|
|
259
257
|
def convert_td(el, opts)
|
260
|
-
inner(el, opts)
|
258
|
+
inner(el, opts)
|
261
259
|
end
|
262
|
-
alias :convert_th :convert_td
|
263
260
|
|
264
261
|
def convert_comment(el, opts)
|
265
262
|
if el.options[:category] == :block
|
@@ -310,7 +307,7 @@ module Kramdown
|
|
310
307
|
end
|
311
308
|
|
312
309
|
def convert_footnote(el, opts)
|
313
|
-
@footnotes << [el.options[:name],
|
310
|
+
@footnotes << [el.options[:name], el.value]
|
314
311
|
"[^#{el.options[:name]}]"
|
315
312
|
end
|
316
313
|
|
@@ -381,15 +378,15 @@ module Kramdown
|
|
381
378
|
res = ''
|
382
379
|
@footnotes.each do |name, data|
|
383
380
|
res << "[^#{name}]:\n"
|
384
|
-
res << inner(data
|
381
|
+
res << inner(data).chomp.split(/\n/).map {|l| " #{l}"}.join("\n") + "\n\n"
|
385
382
|
end
|
386
383
|
res
|
387
384
|
end
|
388
385
|
|
389
386
|
def create_abbrev_defs
|
390
|
-
return '' unless @
|
387
|
+
return '' unless @root.options[:abbrev_defs]
|
391
388
|
res = ''
|
392
|
-
@
|
389
|
+
@root.options[:abbrev_defs].each do |name, text|
|
393
390
|
res << "*[#{name}]: #{text}\n"
|
394
391
|
end
|
395
392
|
res
|
@@ -415,6 +412,8 @@ module Kramdown
|
|
415
412
|
res.strip.empty? ? nil : "{:#{res}}"
|
416
413
|
end
|
417
414
|
|
415
|
+
# :startdoc:
|
416
|
+
|
418
417
|
end
|
419
418
|
|
420
419
|
end
|
@@ -26,24 +26,37 @@ module Kramdown
|
|
26
26
|
|
27
27
|
module Converter
|
28
28
|
|
29
|
-
# Converts
|
30
|
-
#
|
29
|
+
# Converts an element tree to LaTeX.
|
30
|
+
#
|
31
|
+
# This converter uses ideas from other Markdown-to-LaTeX converters like Pandoc and Maruku.
|
32
|
+
#
|
33
|
+
# You can customize this converter by sub-classing it and overriding the <tt>convert_NAME</tt>
|
34
|
+
# methods. Each such method takes the following parameters:
|
35
|
+
#
|
36
|
+
# [+el+] The element of type +NAME+ to be converted.
|
37
|
+
#
|
38
|
+
# [+opts+] A hash containing processing options that are passed down from parent elements. The
|
39
|
+
# key <tt>:parent</tt> is always set and contains the parent element as value.
|
40
|
+
#
|
41
|
+
# The return value of such a method has to be a string containing the element +el+ formatted
|
42
|
+
# correctly as LaTeX markup.
|
31
43
|
class Latex < Base
|
32
44
|
|
33
|
-
#
|
34
|
-
|
35
|
-
# Initialize the LaTeX converter with the given Kramdown document +doc+.
|
36
|
-
def initialize(doc)
|
45
|
+
# Initialize the LaTeX converter with the +root+ element and the conversion +options+.
|
46
|
+
def initialize(root, options)
|
37
47
|
super
|
38
48
|
#TODO: set the footnote counter at the beginning of the document
|
39
|
-
@
|
40
|
-
@
|
49
|
+
@options[:footnote_nr]
|
50
|
+
@data[:packages] = Set.new
|
41
51
|
end
|
42
52
|
|
53
|
+
# Dispatch the conversion of the element +el+ to a <tt>convert_TYPE</tt> method using the
|
54
|
+
# +type+ of the element.
|
43
55
|
def convert(el, opts = {})
|
44
56
|
send("convert_#{el.type}", el, opts)
|
45
57
|
end
|
46
58
|
|
59
|
+
# Return the converted content of the children of +el+ as a string.
|
47
60
|
def inner(el, opts)
|
48
61
|
result = ''
|
49
62
|
options = opts.dup.merge(:parent => el)
|
@@ -75,6 +88,8 @@ module Kramdown
|
|
75
88
|
end
|
76
89
|
end
|
77
90
|
|
91
|
+
# Helper method used by +convert_p+ to convert a paragraph that only contains a single
|
92
|
+
# <tt>:img</tt> element.
|
78
93
|
def convert_standalone_image(el, opts, img)
|
79
94
|
attrs = attribute_list(el)
|
80
95
|
"\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n\\caption{#{escape(el.children.first.attr['alt'])}}\n\\end{figure}#{attrs}\n"
|
@@ -85,37 +100,23 @@ module Kramdown
|
|
85
100
|
lang = el.attr['lang']
|
86
101
|
if show_whitespace || lang
|
87
102
|
result = "\\lstset{showspaces=%s,showtabs=%s}\n" % (show_whitespace ? ['true', 'true'] : ['false', 'false'])
|
88
|
-
result
|
89
|
-
result
|
103
|
+
result << "\\lstset{language=#{lang}}\n" if lang
|
104
|
+
result << "\\lstset{basicstyle=\\ttfamily\\footnotesize}\\lstset{columns=fixed,frame=tlbr}\n"
|
90
105
|
attrs = attribute_list(el)
|
91
|
-
"
|
106
|
+
result << "\\begin{lstlisting}#{attrs}\n#{el.value}\n\\end{lstlisting}#{attrs}\n"
|
92
107
|
else
|
93
108
|
"\\begin{verbatim}#{el.value}\\end{verbatim}\n"
|
94
109
|
end
|
95
110
|
end
|
96
111
|
|
97
|
-
def latex_environment(type, el, text)
|
98
|
-
attrs = attribute_list(el)
|
99
|
-
"\\begin{#{type}}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n"
|
100
|
-
end
|
101
|
-
|
102
112
|
def convert_blockquote(el, opts)
|
103
113
|
latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts))
|
104
114
|
end
|
105
115
|
|
106
|
-
HEADER_TYPES = {
|
107
|
-
1 => 'section',
|
108
|
-
2 => 'subsection',
|
109
|
-
3 => 'subsubsection',
|
110
|
-
4 => 'paragraph',
|
111
|
-
5 => 'subparagraph',
|
112
|
-
6 => 'subparagraph'
|
113
|
-
}
|
114
116
|
def convert_header(el, opts)
|
115
|
-
type =
|
117
|
+
type = @options[:latex_headers][el.options[:level] - 1]
|
116
118
|
if ((id = el.attr['id']) ||
|
117
|
-
(@
|
118
|
-
(@doc.options[:toc_depth] <= 0 || el.options[:level] <= @doc.options[:toc_depth])
|
119
|
+
(@options[:auto_ids] && (id = generate_id(el.options[:raw_text])))) && in_toc?(el)
|
119
120
|
"\\hypertarget{#{id}}{}\\#{type}{#{inner(el, opts)}}\\label{#{id}}\n\n"
|
120
121
|
else
|
121
122
|
"\\#{type}*{#{inner(el, opts)}}\n\n"
|
@@ -128,8 +129,8 @@ module Kramdown
|
|
128
129
|
end
|
129
130
|
|
130
131
|
def convert_ul(el, opts)
|
131
|
-
if !@
|
132
|
-
@
|
132
|
+
if !@data[:has_toc] && (el.options[:ial][:refs].include?('toc') rescue nil)
|
133
|
+
@data[:has_toc] = true
|
133
134
|
'\tableofcontents'
|
134
135
|
else
|
135
136
|
latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts))
|
@@ -159,7 +160,7 @@ module Kramdown
|
|
159
160
|
elsif el.value == 'b'
|
160
161
|
"\\emph{#{inner(el, opts)}}"
|
161
162
|
else
|
162
|
-
|
163
|
+
warning("Can't convert HTML element")
|
163
164
|
''
|
164
165
|
end
|
165
166
|
end
|
@@ -169,12 +170,11 @@ module Kramdown
|
|
169
170
|
end
|
170
171
|
|
171
172
|
def convert_xml_pi(el, opts)
|
172
|
-
|
173
|
+
warning("Can't convert XML PI")
|
173
174
|
''
|
174
175
|
end
|
175
|
-
alias :convert_html_doctype :convert_xml_pi
|
176
176
|
|
177
|
-
TABLE_ALIGNMENT_CHAR = {:default => 'l', :left => 'l', :center => 'c', :right => 'r'}
|
177
|
+
TABLE_ALIGNMENT_CHAR = {:default => 'l', :left => 'l', :center => 'c', :right => 'r'} # :nodoc:
|
178
178
|
|
179
179
|
def convert_table(el, opts)
|
180
180
|
align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a]}.join('|')
|
@@ -201,7 +201,6 @@ module Kramdown
|
|
201
201
|
def convert_td(el, opts)
|
202
202
|
inner(el, opts)
|
203
203
|
end
|
204
|
-
alias :convert_th :convert_td
|
205
204
|
|
206
205
|
def convert_comment(el, opts)
|
207
206
|
el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") + "\n"
|
@@ -209,7 +208,7 @@ module Kramdown
|
|
209
208
|
|
210
209
|
def convert_br(el, opts)
|
211
210
|
res = "\\newline"
|
212
|
-
res
|
211
|
+
res << "\n" if (c = opts[:parent].children[opts[:index]+1]) && (c.type != :text || c.value !~ /^\s*\n/)
|
213
212
|
res
|
214
213
|
end
|
215
214
|
|
@@ -224,13 +223,13 @@ module Kramdown
|
|
224
223
|
|
225
224
|
def convert_img(el, opts)
|
226
225
|
if el.attr['src'] =~ /^(https?|ftps?):\/\//
|
227
|
-
|
226
|
+
warning("Cannot include non-local image")
|
228
227
|
''
|
229
228
|
elsif !el.options.attr['src'].empty?
|
230
|
-
@
|
229
|
+
@data[:packages] << 'graphicx'
|
231
230
|
"\\includegraphics{#{el.attr['src']}}"
|
232
231
|
else
|
233
|
-
|
232
|
+
warning("Cannot include image with empty path")
|
234
233
|
''
|
235
234
|
end
|
236
235
|
end
|
@@ -240,8 +239,8 @@ module Kramdown
|
|
240
239
|
end
|
241
240
|
|
242
241
|
def convert_footnote(el, opts)
|
243
|
-
@
|
244
|
-
"\\footnote{#{inner(
|
242
|
+
@data[:packages] << 'fancyvrb'
|
243
|
+
"\\footnote{#{inner(el.value, opts).rstrip}}"
|
245
244
|
end
|
246
245
|
|
247
246
|
def convert_raw(el, opts)
|
@@ -504,16 +503,16 @@ module Kramdown
|
|
504
503
|
253 => ['\\\'y'],
|
505
504
|
254 => ['\thorn', 'wasysym'],
|
506
505
|
255 => ['\"y'],
|
507
|
-
}
|
506
|
+
} # :nodoc:
|
508
507
|
ENTITY_CONV_TABLE.each {|k,v| ENTITY_CONV_TABLE[k] = v.unshift(v.shift + '{}')}
|
509
508
|
|
510
509
|
def convert_entity(el, opts)
|
511
510
|
text, package = ENTITY_CONV_TABLE[el.value.code_point]
|
512
511
|
if text
|
513
|
-
@
|
512
|
+
@data[:packages] << package if package
|
514
513
|
text
|
515
514
|
else
|
516
|
-
|
515
|
+
warning("Couldn't find entity in substitution table!")
|
517
516
|
''
|
518
517
|
end
|
519
518
|
end
|
@@ -522,20 +521,20 @@ module Kramdown
|
|
522
521
|
:mdash => '---', :ndash => '--', :hellip => '\ldots{}',
|
523
522
|
:laquo_space => '\guillemotleft{}~', :raquo_space => '~\guillemotright{}',
|
524
523
|
:laquo => '\guillemotleft{}', :raquo => '\guillemotright{}'
|
525
|
-
}
|
524
|
+
} # :nodoc:
|
526
525
|
def convert_typographic_sym(el, opts)
|
527
526
|
TYPOGRAPHIC_SYMS[el.value]
|
528
527
|
end
|
529
528
|
|
530
|
-
SMART_QUOTE_SYMS = {:lsquo => '`', :rsquo => '\'', :ldquo => '``', :rdquo => '\'\''}
|
529
|
+
SMART_QUOTE_SYMS = {:lsquo => '`', :rsquo => '\'', :ldquo => '``', :rdquo => '\'\''} # :nodoc:
|
531
530
|
def convert_smart_quote(el, opts)
|
532
531
|
res = SMART_QUOTE_SYMS[el.value]
|
533
|
-
res
|
532
|
+
res << "{}" if (nel = opts[:parent].children[opts[:index]+1]) && nel.type == :smart_quote
|
534
533
|
res
|
535
534
|
end
|
536
535
|
|
537
536
|
def convert_math(el, opts)
|
538
|
-
@
|
537
|
+
@data[:packages] += %w[amssymb amsmath amsthm amsfonts]
|
539
538
|
if el.options[:category] == :block
|
540
539
|
if el.value =~ /\A\s*\\begin\{/
|
541
540
|
el.value
|
@@ -551,6 +550,22 @@ module Kramdown
|
|
551
550
|
el.value
|
552
551
|
end
|
553
552
|
|
553
|
+
# Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to
|
554
|
+
# the method #attribute_list -- the resulting string is appended to both the <tt>\\begin</tt>
|
555
|
+
# and the <tt>\\end</tt> lines of the LaTeX environment for easier post-processing of LaTeX
|
556
|
+
# environments.
|
557
|
+
def latex_environment(type, el, text)
|
558
|
+
attrs = attribute_list(el)
|
559
|
+
"\\begin{#{type}}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n"
|
560
|
+
end
|
561
|
+
|
562
|
+
# Return a LaTeX comment containing all attributes as <tt>key="value"</tt> pairs.
|
563
|
+
def attribute_list(el)
|
564
|
+
attrs = el.attr.map {|k,v| v.nil? ? '' : " #{k}=\"#{v.to_s}\""}.compact.sort.join('')
|
565
|
+
attrs = " % #{attrs}" if !attrs.empty?
|
566
|
+
attrs
|
567
|
+
end
|
568
|
+
|
554
569
|
ESCAPE_MAP = {
|
555
570
|
"^" => "\\^{}",
|
556
571
|
"\\" => "\\textbackslash{}",
|
@@ -558,19 +573,14 @@ module Kramdown
|
|
558
573
|
"|" => "\\textbar{}",
|
559
574
|
"<" => "\\textless{}",
|
560
575
|
">" => "\\textgreater{}"
|
561
|
-
}.merge(Hash[*("{}$%&_#".scan(/./).map {|c| [c, "\\#{c}"]}.flatten)])
|
562
|
-
ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k,v| k})
|
576
|
+
}.merge(Hash[*("{}$%&_#".scan(/./).map {|c| [c, "\\#{c}"]}.flatten)]) # :nodoc:
|
577
|
+
ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k,v| k}) # :nodoc:
|
563
578
|
|
579
|
+
# Escape the special LaTeX characters in the string +str+.
|
564
580
|
def escape(str)
|
565
581
|
str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m]}
|
566
582
|
end
|
567
583
|
|
568
|
-
def attribute_list(el)
|
569
|
-
attrs = el.attr.map {|k,v| v.nil? ? '' : " #{k}=\"#{v.to_s}\""}.compact.sort.join('')
|
570
|
-
attrs = " % #{attrs}" if !attrs.empty?
|
571
|
-
attrs
|
572
|
-
end
|
573
|
-
|
574
584
|
end
|
575
585
|
|
576
586
|
end
|
data/lib/kramdown/document.rb
CHANGED
@@ -52,32 +52,24 @@ module Kramdown
|
|
52
52
|
# doc = Kramdown::Document.new('This *is* some kramdown text')
|
53
53
|
# puts doc.to_html
|
54
54
|
#
|
55
|
-
# The #to_html method is a shortcut for using the Converter::Html class.
|
55
|
+
# The #to_html method is a shortcut for using the Converter::Html class. See #method_missing for
|
56
|
+
# more information.
|
56
57
|
#
|
57
|
-
# The second argument to the
|
58
|
-
# used parser and the converter. See
|
58
|
+
# The second argument to the ::new method is an options hash for customizing the behaviour of the
|
59
|
+
# used parser and the converter. See ::new for more information!
|
59
60
|
class Document
|
60
61
|
|
61
|
-
# The
|
62
|
-
# called.
|
63
|
-
attr_accessor :
|
62
|
+
# The root Element of the element tree. It is immediately available after the ::new method has
|
63
|
+
# been called.
|
64
|
+
attr_accessor :root
|
64
65
|
|
65
|
-
# The options hash which holds the options for parsing/converting the Kramdown document.
|
66
|
-
# possible that these values get changed during the parsing phase.
|
66
|
+
# The options hash which holds the options for parsing/converting the Kramdown document.
|
67
67
|
attr_reader :options
|
68
68
|
|
69
69
|
# An array of warning messages. It is filled with warnings during the parsing phase (i.e. in
|
70
|
-
#
|
70
|
+
# ::new) and the conversion phase.
|
71
71
|
attr_reader :warnings
|
72
72
|
|
73
|
-
# Holds needed parse information which is dependent on the used parser, like ALDs, link
|
74
|
-
# definitions and so on. This information may be used by converters afterwards.
|
75
|
-
attr_reader :parse_infos
|
76
|
-
|
77
|
-
# Holds conversion information which is dependent on the used converter. A converter clears this
|
78
|
-
# variable before doing the conversion.
|
79
|
-
attr_reader :conversion_infos
|
80
|
-
|
81
73
|
|
82
74
|
# Create a new Kramdown document from the string +source+ and use the provided +options+. The
|
83
75
|
# options that can be used are defined in the Options module.
|
@@ -87,18 +79,14 @@ module Kramdown
|
|
87
79
|
# select the kramdown parser, one would set the <tt>:input</tt> key to +Kramdown+. If this key
|
88
80
|
# is not set, it defaults to +Kramdown+.
|
89
81
|
#
|
90
|
-
# The +source+ is immediately parsed by the selected parser so that the
|
82
|
+
# The +source+ is immediately parsed by the selected parser so that the root element is
|
91
83
|
# immediately available and the output can be generated.
|
92
84
|
def initialize(source, options = {})
|
93
|
-
@options = Options.merge(options)
|
94
|
-
@warnings = []
|
95
|
-
@parse_infos = {}
|
96
|
-
@parse_infos[:encoding] = source.encoding if RUBY_VERSION >= '1.9'
|
97
|
-
@conversion_infos = {}
|
85
|
+
@options = Options.merge(options).freeze
|
98
86
|
parser = (options[:input] || 'kramdown').to_s
|
99
87
|
parser = parser[0..0].upcase + parser[1..-1]
|
100
88
|
if Parser.const_defined?(parser)
|
101
|
-
@
|
89
|
+
@root, @warnings = Parser.const_get(parser).parse(source, @options)
|
102
90
|
else
|
103
91
|
raise Kramdown::Error.new("kramdown has no parser to handle the specified input format: #{options[:input]}")
|
104
92
|
end
|
@@ -109,24 +97,468 @@ module Kramdown
|
|
109
97
|
#
|
110
98
|
# For example, +to_html+ would instantiate the Kramdown::Converter::Html class.
|
111
99
|
def method_missing(id, *attr, &block)
|
112
|
-
if id.to_s =~ /^to_(\w+)$/
|
113
|
-
Converter.const_get(
|
100
|
+
if id.to_s =~ /^to_(\w+)$/ && (name = $1[0..0].upcase + $1[1..-1]) && Converter.const_defined?(name)
|
101
|
+
output, warnings = Converter.const_get(name).convert(@root, @options)
|
102
|
+
@warnings.concat(warnings)
|
103
|
+
output
|
114
104
|
else
|
115
105
|
super
|
116
106
|
end
|
117
107
|
end
|
118
108
|
|
119
109
|
def inspect #:nodoc:
|
120
|
-
"<KD:Document: options=#{@options.inspect}
|
110
|
+
"<KD:Document: options=#{@options.inspect} root=#{@root.inspect} warnings=#{@warnings.inspect}>"
|
121
111
|
end
|
122
112
|
|
123
113
|
end
|
124
114
|
|
125
115
|
|
126
|
-
# Represents all elements in the
|
116
|
+
# Represents all elements in the element tree.
|
127
117
|
#
|
128
|
-
# kramdown only uses this one class for representing all available elements in
|
118
|
+
# kramdown only uses this one class for representing all available elements in an element tree
|
129
119
|
# (paragraphs, headers, emphasis, ...). The type of element can be set via the #type accessor.
|
120
|
+
#
|
121
|
+
# Following is a description of all supported element types.
|
122
|
+
#
|
123
|
+
# == Structural Elements
|
124
|
+
#
|
125
|
+
# === :root
|
126
|
+
#
|
127
|
+
# [Category] None
|
128
|
+
# [Usage context] As the root element of a document
|
129
|
+
# [Content model] Block-level elements
|
130
|
+
#
|
131
|
+
# Represents the root of a kramdown document.
|
132
|
+
#
|
133
|
+
# The root element contains the following option keys:
|
134
|
+
#
|
135
|
+
# <tt>:encoding</tt>:: When running on Ruby 1.9 this key has to be set to the encoding used for
|
136
|
+
# the text parts of the kramdown document.
|
137
|
+
#
|
138
|
+
# <tt>:abbrev_defs</tt>:: This key may be used to store the mapping of abbreviation to
|
139
|
+
# abbreviation definition.
|
140
|
+
#
|
141
|
+
#
|
142
|
+
# === :blank
|
143
|
+
#
|
144
|
+
# [Category] Block-level element
|
145
|
+
# [Usage context] Where block-level elements are expected
|
146
|
+
# [Content model] Empty
|
147
|
+
#
|
148
|
+
# Represents one or more blank lines. It is not allowed to have two or more consecutive blank
|
149
|
+
# elements.
|
150
|
+
#
|
151
|
+
# The +value+ field may contain the original content of the blank lines.
|
152
|
+
#
|
153
|
+
#
|
154
|
+
# === :p
|
155
|
+
#
|
156
|
+
# [Category] Block-level element
|
157
|
+
# [Usage context] Where block-level elements are expected
|
158
|
+
# [Content model] Span-level elements
|
159
|
+
#
|
160
|
+
# Represents a paragraph.
|
161
|
+
#
|
162
|
+
# If the option <tt>:transparent</tt> is +true+, this element just represents a block of text.
|
163
|
+
# I.e. this element just functions as a container for span-level elements.
|
164
|
+
#
|
165
|
+
#
|
166
|
+
# === :header
|
167
|
+
#
|
168
|
+
# [Category] Block-level element
|
169
|
+
# [Usage context] Where block-level elements are expected
|
170
|
+
# [Content model] Span-level elements
|
171
|
+
#
|
172
|
+
# Represents a header.
|
173
|
+
#
|
174
|
+
# The option <tt>:level</tt> specifies the header level and has to contain a number between 1 and
|
175
|
+
# \6. The option <tt>:raw_text</tt> has to contain the raw header text.
|
176
|
+
#
|
177
|
+
#
|
178
|
+
# === :blockquote
|
179
|
+
#
|
180
|
+
# [Category] Block-level element
|
181
|
+
# [Usage context] Where block-level elements are expected
|
182
|
+
# [Content model] Block-level elements
|
183
|
+
#
|
184
|
+
# Represents a blockquote.
|
185
|
+
#
|
186
|
+
#
|
187
|
+
# === :codeblock
|
188
|
+
#
|
189
|
+
# [Category] Block-level element
|
190
|
+
# [Usage context] Where block-level elements are expected
|
191
|
+
# [Content model] Empty
|
192
|
+
#
|
193
|
+
# Represents a code block, i.e. a block of text that should be used as-is.
|
194
|
+
#
|
195
|
+
# The +value+ field has to contain the content of the code block.
|
196
|
+
#
|
197
|
+
#
|
198
|
+
# === :ul
|
199
|
+
#
|
200
|
+
# [Category] Block-level element
|
201
|
+
# [Usage context] Where block-level elements are expected
|
202
|
+
# [Content model] One or more :li elements
|
203
|
+
#
|
204
|
+
# Represents an unordered list.
|
205
|
+
#
|
206
|
+
#
|
207
|
+
# === :ol
|
208
|
+
#
|
209
|
+
# [Category] Block-level element
|
210
|
+
# [Usage context] Where block-level elements are expected
|
211
|
+
# [Content model] One or more :li elements
|
212
|
+
#
|
213
|
+
# Represents an ordered list.
|
214
|
+
#
|
215
|
+
#
|
216
|
+
# === :li
|
217
|
+
#
|
218
|
+
# [Category] None
|
219
|
+
# [Usage context] Inside :ol and :ul elements
|
220
|
+
# [Content model] Block-level elements
|
221
|
+
#
|
222
|
+
# Represents a list item of an ordered or unordered list.
|
223
|
+
#
|
224
|
+
#
|
225
|
+
# === :dl
|
226
|
+
#
|
227
|
+
# [Category] Block-level element
|
228
|
+
# [Usage context] Where block-level elements are expected
|
229
|
+
# [Content model] One or more groups each consisting of one or more :dt elements followed by one
|
230
|
+
# or more :dd elements.
|
231
|
+
#
|
232
|
+
# Represents a definition list which contains groups consisting of terms and definitions for them.
|
233
|
+
#
|
234
|
+
#
|
235
|
+
# === :dt
|
236
|
+
#
|
237
|
+
# [Category] None
|
238
|
+
# [Usage context] Before :dt or :dd elements inside a :dl elment
|
239
|
+
# [Content model] Span-level elements
|
240
|
+
#
|
241
|
+
# Represents the term part of a term-definition group in a definition list.
|
242
|
+
#
|
243
|
+
#
|
244
|
+
# === :dd
|
245
|
+
#
|
246
|
+
# [Category] None
|
247
|
+
# [Usage context] After :dt or :dd elements inside a :dl elment
|
248
|
+
# [Content model] Block-level elements
|
249
|
+
#
|
250
|
+
# Represents the definition part of a term-definition group in a definition list.
|
251
|
+
#
|
252
|
+
#
|
253
|
+
# === :hr
|
254
|
+
#
|
255
|
+
# [Category] Block-level element
|
256
|
+
# [Usage context] Where block-level elements are expected
|
257
|
+
# [Content model] None
|
258
|
+
#
|
259
|
+
# Represents a horizontal line.
|
260
|
+
#
|
261
|
+
#
|
262
|
+
# === :table
|
263
|
+
#
|
264
|
+
# [Category] Block-level element
|
265
|
+
# [Usage context] Where block-level elements are expected
|
266
|
+
# [Content model] Zero or one :thead elements, one or more :tbody elements, zero or one :tfoot
|
267
|
+
# elements
|
268
|
+
#
|
269
|
+
# Represents a table. Each table row (i.e. :tr element) of the table has to contain the same
|
270
|
+
# number of :td elements.
|
271
|
+
#
|
272
|
+
# The option <tt>:alignment</tt> has to be an array containing the alignment values, exactly one
|
273
|
+
# for each column of the table. The possible alignment values are <tt>:left</tt>,
|
274
|
+
# <tt>:center</tt>, <tt>:right</tt> and <tt>:default</tt>.
|
275
|
+
#
|
276
|
+
#
|
277
|
+
# === :thead
|
278
|
+
#
|
279
|
+
# [Category] None
|
280
|
+
# [Usage context] As first element inside a :table element
|
281
|
+
# [Content model] One or more :tr elements
|
282
|
+
#
|
283
|
+
# Represents the table header.
|
284
|
+
#
|
285
|
+
#
|
286
|
+
# === :tbody
|
287
|
+
#
|
288
|
+
# [Category] None
|
289
|
+
# [Usage context] After a :thead element but before a :tfoot element inside a :table element
|
290
|
+
# [Content model] One or more :tr elements
|
291
|
+
#
|
292
|
+
# Represents a table body.
|
293
|
+
#
|
294
|
+
#
|
295
|
+
# === :tfoot
|
296
|
+
#
|
297
|
+
# [Category] None
|
298
|
+
# [Usage context] As last element inside a :table element
|
299
|
+
# [Content model] One or more :tr elements
|
300
|
+
#
|
301
|
+
# Represents the table footer.
|
302
|
+
#
|
303
|
+
#
|
304
|
+
# === :tr
|
305
|
+
#
|
306
|
+
# [Category] None
|
307
|
+
# [Usage context] Inside :thead, :tbody and :tfoot elements
|
308
|
+
# [Content model] One or more :td elements
|
309
|
+
#
|
310
|
+
# Represents a table row.
|
311
|
+
#
|
312
|
+
#
|
313
|
+
# === :td
|
314
|
+
#
|
315
|
+
# [Category] None
|
316
|
+
# [Usage context] Inside :tr elements
|
317
|
+
# [Content model] As child of :thead/:tr span-level elements, as child of :tbody/:tr and
|
318
|
+
# :tfoot/:tr block-level elements
|
319
|
+
#
|
320
|
+
# Represents a table cell.
|
321
|
+
#
|
322
|
+
#
|
323
|
+
# === :math
|
324
|
+
#
|
325
|
+
# [Category] Block/span-level element
|
326
|
+
# [Usage context] Where block/span-level elements are expected
|
327
|
+
# [Content model] None
|
328
|
+
#
|
329
|
+
# Represents mathematical text that is written in LaTeX.
|
330
|
+
#
|
331
|
+
# The +value+ field has to contain the actual mathematical text.
|
332
|
+
#
|
333
|
+
# The option <tt>:category</tt> has to be set to either <tt>:span</tt> or <tt>:block</tt>
|
334
|
+
# depending on the context where the element is used.
|
335
|
+
#
|
336
|
+
#
|
337
|
+
# == Text Markup Elements
|
338
|
+
#
|
339
|
+
# === :text
|
340
|
+
#
|
341
|
+
# [Category] Span-level element
|
342
|
+
# [Usage context] Where span-level elements are expected
|
343
|
+
# [Content model] None
|
344
|
+
#
|
345
|
+
# Represents text.
|
346
|
+
#
|
347
|
+
# The +value+ field has to contain the text itself.
|
348
|
+
#
|
349
|
+
#
|
350
|
+
# === :br
|
351
|
+
#
|
352
|
+
# [Category] Span-level element
|
353
|
+
# [Usage context] Where span-level elements are expected
|
354
|
+
# [Content model] None
|
355
|
+
#
|
356
|
+
# Represents a hard line break.
|
357
|
+
#
|
358
|
+
#
|
359
|
+
# === :a
|
360
|
+
#
|
361
|
+
# [Category] Span-level element
|
362
|
+
# [Usage context] Where span-level elements are expected
|
363
|
+
# [Content model] Span-level elements
|
364
|
+
#
|
365
|
+
# Represents a link to an URL.
|
366
|
+
#
|
367
|
+
# The attribute +href+ has to be set to the URL to which the link points. The attribute +title+
|
368
|
+
# optionally contains the title of the link.
|
369
|
+
#
|
370
|
+
#
|
371
|
+
# === :img
|
372
|
+
#
|
373
|
+
# [Category] Span-level element
|
374
|
+
# [Usage context] Where span-level elements are expected
|
375
|
+
# [Content model] None
|
376
|
+
#
|
377
|
+
# Represents an image.
|
378
|
+
#
|
379
|
+
# The attribute +src+ has to be set to the URL of the image. The attribute +alt+ has to contain a
|
380
|
+
# text description of the image. The attribute +title+ optionally contains the title of the image.
|
381
|
+
#
|
382
|
+
#
|
383
|
+
# === :codespan
|
384
|
+
#
|
385
|
+
# [Category] Span-level element
|
386
|
+
# [Usage context] Where span-level elements are expected
|
387
|
+
# [Content model] None
|
388
|
+
#
|
389
|
+
# Represents verbatim text.
|
390
|
+
#
|
391
|
+
# The +value+ field has to contain the content of the code span.
|
392
|
+
#
|
393
|
+
#
|
394
|
+
# === :footnote
|
395
|
+
#
|
396
|
+
# [Category] Span-level element
|
397
|
+
# [Usage context] Where span-level elements are expected
|
398
|
+
# [Content model] None
|
399
|
+
#
|
400
|
+
# Represents a footnote marker.
|
401
|
+
#
|
402
|
+
# The +value+ field has to contain an element whose children are the content of the footnote. The
|
403
|
+
# option <tt>:name</tt> has to contain a valid and unique footnote name. A valid footnote name
|
404
|
+
# consists of a word character or a digit and then optionally followed by other word characters,
|
405
|
+
# digits or dashes.
|
406
|
+
#
|
407
|
+
#
|
408
|
+
# === :em
|
409
|
+
#
|
410
|
+
# [Category] Span-level element
|
411
|
+
# [Usage context] Where span-level elements are expected
|
412
|
+
# [Content model] Span-level elements
|
413
|
+
#
|
414
|
+
# Represents emphasis of its contents.
|
415
|
+
#
|
416
|
+
#
|
417
|
+
# === :strong
|
418
|
+
#
|
419
|
+
# [Category] Span-level element
|
420
|
+
# [Usage context] Where span-level elements are expected
|
421
|
+
# [Content model] Span-level elements
|
422
|
+
#
|
423
|
+
# Represents strong importance for its contents.
|
424
|
+
#
|
425
|
+
#
|
426
|
+
# === :entity
|
427
|
+
#
|
428
|
+
# [Category] Span-level element
|
429
|
+
# [Usage context] Where span-level elements are expected
|
430
|
+
# [Content model] None
|
431
|
+
#
|
432
|
+
# Represents an HTML entity.
|
433
|
+
#
|
434
|
+
# The +value+ field has to contain an instance of Kramdown::Utils::Entities::Entity. The option
|
435
|
+
# <tt>:original</tt> can be used to store the original representation of the entity.
|
436
|
+
#
|
437
|
+
#
|
438
|
+
# === :typographic_sym
|
439
|
+
#
|
440
|
+
# [Category] Span-level element
|
441
|
+
# [Usage context] Where span-level elements are expected
|
442
|
+
# [Content model] None
|
443
|
+
#
|
444
|
+
# Represents a typographic symbol.
|
445
|
+
#
|
446
|
+
# The +value+ field needs to contain a Symbol representing the specific typographic symbol from
|
447
|
+
# the following list:
|
448
|
+
#
|
449
|
+
# <tt>:mdash</tt>:: An mdash character (---)
|
450
|
+
# <tt>:ndash</tt>:: An ndash character (--)
|
451
|
+
# <tt>:hellip</tt>:: An ellipsis (...)
|
452
|
+
# <tt>:laquo</tt>:: A left guillemet (<<)
|
453
|
+
# <tt>:raquo</tt>:: A right guillemet (>>)
|
454
|
+
# <tt>:laquo_space</tt>:: A left guillemet with a space (<< )
|
455
|
+
# <tt>:raquo_space</tt>:: A right guillemet with a space ( >>)
|
456
|
+
#
|
457
|
+
#
|
458
|
+
# === :smart_quote
|
459
|
+
#
|
460
|
+
# [Category] Span-level element
|
461
|
+
# [Usage context] Where span-level elements are expected
|
462
|
+
# [Content model] None
|
463
|
+
#
|
464
|
+
# Represents a quotation character.
|
465
|
+
#
|
466
|
+
# The +value+ field needs to contain a Symbol representing the specific quotation character:
|
467
|
+
#
|
468
|
+
# <tt>:lsquo</tt>:: Left single quote
|
469
|
+
# <tt>:rsquo</tt>:: Right single quote
|
470
|
+
# <tt>:ldquo</tt>:: Left double quote
|
471
|
+
# <tt>:rdquo</tt>:: Right double quote
|
472
|
+
#
|
473
|
+
#
|
474
|
+
# === :abbreviation
|
475
|
+
#
|
476
|
+
# [Category] Span-level element
|
477
|
+
# [Usage context] Where span-level elements are expected
|
478
|
+
# [Content model] None
|
479
|
+
#
|
480
|
+
# Represents a text part that is an abbreviation.
|
481
|
+
#
|
482
|
+
# The +value+ field has to contain the text part that is the abbreviation. The definition of the
|
483
|
+
# abbreviation is stored in the <tt>:root</tt> element of the document.
|
484
|
+
#
|
485
|
+
#
|
486
|
+
# == Other Elements
|
487
|
+
#
|
488
|
+
# === :html_element
|
489
|
+
#
|
490
|
+
# [Category] Block/span-level element
|
491
|
+
# [Usage context] Where block/span-level elements or raw HTML elements are expected
|
492
|
+
# [Content model] Depends on the element
|
493
|
+
#
|
494
|
+
# Represents an HTML element.
|
495
|
+
#
|
496
|
+
# The +value+ field has to contain the name of the HTML element the element is representing.
|
497
|
+
#
|
498
|
+
# The option <tt>:category</tt> has to be set to either <tt>:span</tt> or <tt>:block</tt>
|
499
|
+
# depending on the whether the element is a block-level or a span-level element. The option
|
500
|
+
# <tt>:content_model</tt> has to be set to the content model for the element (either
|
501
|
+
# <tt>:block</tt> if it contains block-level elements, <tt>:span</tt> if it contains span-level
|
502
|
+
# elements or <tt>:raw</tt> if it contains raw content).
|
503
|
+
#
|
504
|
+
#
|
505
|
+
# === :xml_comment
|
506
|
+
#
|
507
|
+
# [Category] Block/span-level element
|
508
|
+
# [Usage context] Where block/span-level elements are expected or in raw HTML elements
|
509
|
+
# [Content model] None
|
510
|
+
#
|
511
|
+
# Represents an XML/HTML comment.
|
512
|
+
#
|
513
|
+
# The +value+ field has to contain the whole XML/HTML comment including the delimiters.
|
514
|
+
#
|
515
|
+
# The option <tt>:category</tt> has to be set to either <tt>:span</tt> or <tt>:block</tt>
|
516
|
+
# depending on the context where the element is used.
|
517
|
+
#
|
518
|
+
#
|
519
|
+
# === :xml_pi
|
520
|
+
#
|
521
|
+
# [Category] Block/span-level element
|
522
|
+
# [Usage context] Where block/span-level elements are expected or in raw HTML elements
|
523
|
+
# [Content model] None
|
524
|
+
#
|
525
|
+
# Represents an XML/HTML processing instruction.
|
526
|
+
#
|
527
|
+
# The +value+ field has to contain the whole XML/HTML processing instruction including the
|
528
|
+
# delimiters.
|
529
|
+
#
|
530
|
+
# The option <tt>:category</tt> has to be set to either <tt>:span</tt> or <tt>:block</tt>
|
531
|
+
# depending on the context where the element is used.
|
532
|
+
#
|
533
|
+
#
|
534
|
+
# === :comment
|
535
|
+
#
|
536
|
+
# [Category] Block/span-level element
|
537
|
+
# [Usage context] Where block/span-level elements are expected
|
538
|
+
# [Content model] None
|
539
|
+
#
|
540
|
+
# Represents a comment.
|
541
|
+
#
|
542
|
+
# The +value+ field has to contain the comment.
|
543
|
+
#
|
544
|
+
# The option <tt>:category</tt> has to be set to either <tt>:span</tt> or <tt>:block</tt>
|
545
|
+
# depending on the context where the element is used.
|
546
|
+
#
|
547
|
+
#
|
548
|
+
# === :raw
|
549
|
+
#
|
550
|
+
# [Category] Block/span-level element
|
551
|
+
# [Usage context] Where block/span-level elements are expected
|
552
|
+
# [Content model] None
|
553
|
+
#
|
554
|
+
# Represents a raw string that should not be modified. For example, the element could contain some
|
555
|
+
# HTML code that should be output as-is without modification and escaping.
|
556
|
+
#
|
557
|
+
# The +value+ field has to contain the actual raw text.
|
558
|
+
#
|
559
|
+
# The option <tt>:category</tt> has to be set to either <tt>:span</tt> or <tt>:block</tt>
|
560
|
+
# depending on the context where the element is used. The option <tt>:type</tt> can be set to an
|
561
|
+
# array of strings to define for which converters the raw string is valid.
|
130
562
|
class Element
|
131
563
|
|
132
564
|
# A symbol representing the element type. For example, <tt>:p</tt> or <tt>:blockquote</tt>.
|
@@ -136,32 +568,45 @@ module Kramdown
|
|
136
568
|
# Many elements don't use this field.
|
137
569
|
attr_accessor :value
|
138
570
|
|
139
|
-
# The attributes of the element. Uses an Utils::OrderedHash to retain the insertion order.
|
140
|
-
attr_reader :attr
|
141
|
-
|
142
|
-
# The options hash for the element. It is used for storing arbitray options as well as the
|
143
|
-
# following special contents:
|
144
|
-
#
|
145
|
-
# - Category of the element, either <tt>:block</tt> or <tt>:span</tt>, under the
|
146
|
-
# <tt>:category</tt> key. If this key is absent, it can be assumed that the element is in the
|
147
|
-
# <tt>:span</tt> category.
|
148
|
-
attr_accessor :options
|
149
|
-
|
150
571
|
# The child elements of this element.
|
151
572
|
attr_accessor :children
|
152
573
|
|
153
574
|
|
154
575
|
# Create a new Element object of type +type+. The optional parameters +value+, +attr+ and
|
155
576
|
# +options+ can also be set in this constructor for convenience.
|
156
|
-
def initialize(type, value = nil, attr = nil, options =
|
157
|
-
@type, @value, @attr, @options = type, value, Utils::OrderedHash.new(attr), options
|
577
|
+
def initialize(type, value = nil, attr = nil, options = nil)
|
578
|
+
@type, @value, @attr, @options = type, value, (Utils::OrderedHash.new.merge!(attr) if attr), options
|
158
579
|
@children = []
|
159
580
|
end
|
160
581
|
|
582
|
+
# The attributes of the element. Uses an Utils::OrderedHash to retain the insertion order.
|
583
|
+
def attr
|
584
|
+
@attr ||= Utils::OrderedHash.new
|
585
|
+
end
|
586
|
+
|
587
|
+
# The options hash for the element. It is used for storing arbitray options.
|
588
|
+
def options
|
589
|
+
@options ||= {}
|
590
|
+
end
|
591
|
+
|
161
592
|
def inspect #:nodoc:
|
162
593
|
"<kd:#{@type}#{@value.nil? ? '' : ' ' + @value.inspect} #{@attr.inspect}#{options.empty? ? '' : ' ' + @options.inspect}#{@children.empty? ? '' : ' ' + @children.inspect}>"
|
163
594
|
end
|
164
595
|
|
596
|
+
CATEGORY = {} # :nodoc:
|
597
|
+
[:blank, :p, :header, :blockquote, :codeblock, :ul, :ol, :dl, :table, :hr].each {|b| CATEGORY[b] = :block}
|
598
|
+
[:text, :a, :br, :img, :codespan, :footnote, :em, :strong, :entity, :typographic_sym,
|
599
|
+
:smart_quote, :abbreviation].each {|b| CATEGORY[b] = :span}
|
600
|
+
|
601
|
+
# Return the category of +el+ which can be <tt>:block</tt>, <tt>:span</tt> or +nil+.
|
602
|
+
#
|
603
|
+
# Most elements have a fixed category, however, some elements can either appear in a block-level
|
604
|
+
# or a span-level context. These elements need to have the option <tt>:category</tt> correctly
|
605
|
+
# set.
|
606
|
+
def self.category(el)
|
607
|
+
CATEGORY[el.type] || el.options[:category]
|
608
|
+
end
|
609
|
+
|
165
610
|
end
|
166
611
|
|
167
612
|
end
|