kramdown 1.2.0 → 1.3.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.
- checksums.yaml +4 -4
- data/CONTRIBUTERS +5 -1
- data/README.md +5 -1
- data/Rakefile +5 -3
- data/VERSION +1 -1
- data/benchmark/generate_data.rb +1 -1
- data/doc/default.template +2 -2
- data/doc/index.page +3 -4
- data/doc/news.feed +1 -1
- data/doc/quickref.page +4 -4
- data/doc/sidebar.template +7 -8
- data/doc/syntax.page +10 -3
- data/doc/tests.page +1 -1
- data/lib/kramdown/converter.rb +1 -0
- data/lib/kramdown/converter/base.rb +57 -9
- data/lib/kramdown/converter/kramdown.rb +4 -2
- data/lib/kramdown/converter/pdf.rb +638 -0
- data/lib/kramdown/document.rb +1 -1
- data/lib/kramdown/element.rb +4 -0
- data/lib/kramdown/options.rb +44 -8
- data/lib/kramdown/parser/base.rb +4 -2
- data/lib/kramdown/parser/gfm.rb +25 -18
- data/lib/kramdown/parser/html.rb +2 -2
- data/lib/kramdown/parser/kramdown.rb +24 -2
- data/lib/kramdown/parser/kramdown/abbreviation.rb +3 -2
- data/lib/kramdown/parser/kramdown/autolink.rb +2 -1
- data/lib/kramdown/parser/kramdown/blockquote.rb +2 -1
- data/lib/kramdown/parser/kramdown/codeblock.rb +4 -2
- data/lib/kramdown/parser/kramdown/codespan.rb +2 -1
- data/lib/kramdown/parser/kramdown/emphasis.rb +2 -1
- data/lib/kramdown/parser/kramdown/extensions.rb +5 -4
- data/lib/kramdown/parser/kramdown/footnote.rb +6 -4
- data/lib/kramdown/parser/kramdown/header.rb +4 -2
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +2 -1
- data/lib/kramdown/parser/kramdown/html_entity.rb +4 -2
- data/lib/kramdown/parser/kramdown/link.rb +3 -2
- data/lib/kramdown/parser/kramdown/list.rb +9 -5
- data/lib/kramdown/parser/kramdown/math.rb +5 -3
- data/lib/kramdown/parser/kramdown/paragraph.rb +2 -1
- data/lib/kramdown/parser/kramdown/table.rb +5 -3
- data/lib/kramdown/parser/kramdown/typographic_symbol.rb +10 -5
- data/lib/kramdown/utils.rb +1 -0
- data/lib/kramdown/utils/string_scanner.rb +52 -0
- data/lib/kramdown/version.rb +1 -1
- data/man/man1/kramdown.1 +41 -6
- data/test/test_files.rb +2 -2
- data/test/test_location.rb +158 -0
- data/test/test_string_scanner_kramdown.rb +22 -0
- data/test/testcases/block/04_header/with_auto_id_stripping.html +1 -0
- data/test/testcases/block/04_header/with_auto_id_stripping.options +1 -0
- data/test/testcases/block/04_header/with_auto_id_stripping.text +1 -0
- data/test/testcases/span/math/normal.html +2 -1
- data/test/testcases/span/math/normal.text +2 -1
- data/test/testcases_gfm/hard_line_breaks_off.html +2 -0
- data/test/testcases_gfm/hard_line_breaks_off.options +1 -0
- data/test/testcases_gfm/hard_line_breaks_off.text +2 -0
- metadata +27 -3
data/lib/kramdown/document.rb
CHANGED
data/lib/kramdown/element.rb
CHANGED
@@ -16,6 +16,9 @@ module Kramdown
|
|
16
16
|
#
|
17
17
|
# Following is a description of all supported element types.
|
18
18
|
#
|
19
|
+
# Note that the option :location may contain the start line number of an element in the source
|
20
|
+
# document.
|
21
|
+
#
|
19
22
|
# == Structural Elements
|
20
23
|
#
|
21
24
|
# === :root
|
@@ -459,6 +462,7 @@ module Kramdown
|
|
459
462
|
#
|
460
463
|
# The option :type can be set to an array of strings to define for which converters the raw string
|
461
464
|
# is valid.
|
465
|
+
#
|
462
466
|
class Element
|
463
467
|
|
464
468
|
# A symbol representing the element type. For example, :p or :blockquote.
|
data/lib/kramdown/options.rb
CHANGED
@@ -79,8 +79,7 @@ module Kramdown
|
|
79
79
|
temp = defaults
|
80
80
|
hash.each do |k,v|
|
81
81
|
k = k.to_sym
|
82
|
-
|
83
|
-
temp[k] = parse(k, v)
|
82
|
+
@options.has_key?(k) ? temp[k] = parse(k, v) : temp[k] = v
|
84
83
|
end
|
85
84
|
temp
|
86
85
|
end
|
@@ -147,6 +146,7 @@ module Kramdown
|
|
147
146
|
|
148
147
|
define(:template, String, '', <<EOF)
|
149
148
|
The name of an ERB template file that should be used to wrap the output
|
149
|
+
or the ERB template itself.
|
150
150
|
|
151
151
|
This is used to wrap the output in an environment so that the output can
|
152
152
|
be used as a stand-alone document. For example, an HTML template would
|
@@ -155,10 +155,13 @@ valid HTML file. If no template is specified, the output will be just
|
|
155
155
|
the converted text.
|
156
156
|
|
157
157
|
When resolving the template file, the given template name is used first.
|
158
|
-
If such a file is not found, the converter extension
|
159
|
-
file still cannot be found, the
|
160
|
-
template name that is provided by
|
161
|
-
extension).
|
158
|
+
If such a file is not found, the converter extension (the same as the
|
159
|
+
converter name) is appended. If the file still cannot be found, the
|
160
|
+
templates name is interpreted as a template name that is provided by
|
161
|
+
kramdown (without the converter extension). If the file is still not
|
162
|
+
found, the template name is checked if it starts with 'string://' and if
|
163
|
+
it does, this prefix is removed and the rest is used as template
|
164
|
+
content.
|
162
165
|
|
163
166
|
kramdown provides a default template named 'document' for each converter.
|
164
167
|
|
@@ -174,10 +177,24 @@ generated if no ID is explicitly specified.
|
|
174
177
|
|
175
178
|
Default: true
|
176
179
|
Used by: HTML/Latex converter
|
180
|
+
EOF
|
181
|
+
|
182
|
+
define(:auto_id_stripping, Boolean, false, <<EOF)
|
183
|
+
Strip all formatting from header text for automatic ID generation
|
184
|
+
|
185
|
+
If this option is `true`, only the text elements of a header are used
|
186
|
+
for generating the ID later (in contrast to just using the raw header
|
187
|
+
text line).
|
188
|
+
|
189
|
+
This option will be removed in version 2.0 because this will be the
|
190
|
+
default then.
|
191
|
+
|
192
|
+
Default: false
|
193
|
+
Used by: kramdown parser
|
177
194
|
EOF
|
178
195
|
|
179
196
|
define(:auto_id_prefix, String, '', <<EOF)
|
180
|
-
Prefix used for automatically generated
|
197
|
+
Prefix used for automatically generated header IDs
|
181
198
|
|
182
199
|
This option can be used to set a prefix for the automatically generated
|
183
200
|
header IDs so that there is no conflict when rendering multiple kramdown
|
@@ -321,12 +338,21 @@ The tab width used in highlighted code
|
|
321
338
|
Used by: HTML converter
|
322
339
|
EOF
|
323
340
|
|
324
|
-
define(:coderay_bold_every,
|
341
|
+
define(:coderay_bold_every, Object, 10, <<EOF) do |val|
|
325
342
|
Defines how often a line number should be made bold
|
326
343
|
|
344
|
+
Can either be an integer or false (to turn off bold line numbers
|
345
|
+
completely).
|
346
|
+
|
327
347
|
Default: 10
|
328
348
|
Used by: HTML converter
|
329
349
|
EOF
|
350
|
+
if val == false || val.to_s == 'false'
|
351
|
+
false
|
352
|
+
else
|
353
|
+
Integer(val.to_s) rescue raise Kramdown::Error, "Invalid value for option 'coderay_bold_every'"
|
354
|
+
end
|
355
|
+
end
|
330
356
|
|
331
357
|
define(:coderay_css, Symbol, :style, <<EOF)
|
332
358
|
Defines how the highlighted code gets styled
|
@@ -456,6 +482,16 @@ level 1 will be used. If c+n is greater than 6, level 6 will be used.
|
|
456
482
|
|
457
483
|
Default: 0
|
458
484
|
Used by: HTML converter, Kramdown converter, Latex converter
|
485
|
+
EOF
|
486
|
+
|
487
|
+
define(:hard_wrap, Boolean, true, <<EOF)
|
488
|
+
Interprets line breaks literally
|
489
|
+
|
490
|
+
Insert HTML `<br />` tags inside paragraphs where the original Markdown
|
491
|
+
document had newlines (by default, Markdown ignores these newlines).
|
492
|
+
|
493
|
+
Default: true
|
494
|
+
Used by: GFM parser
|
459
495
|
EOF
|
460
496
|
|
461
497
|
end
|
data/lib/kramdown/parser/base.rb
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
#++
|
8
8
|
#
|
9
9
|
|
10
|
+
require 'kramdown/utils/string_scanner'
|
11
|
+
|
10
12
|
module Kramdown
|
11
13
|
|
12
14
|
module Parser
|
@@ -14,7 +16,7 @@ module Kramdown
|
|
14
16
|
# == \Base class for parsers
|
15
17
|
#
|
16
18
|
# This class serves as base class for parsers. It provides common methods that can/should be
|
17
|
-
# used by all parsers, especially by those using StringScanner for parsing.
|
19
|
+
# used by all parsers, especially by those using StringScanner(Kramdown) for parsing.
|
18
20
|
#
|
19
21
|
# A parser object is used as a throw-away object, i.e. it is only used for storing the needed
|
20
22
|
# state information during parsing. Therefore one can't instantiate a parser object directly but
|
@@ -49,7 +51,7 @@ module Kramdown
|
|
49
51
|
def initialize(source, options)
|
50
52
|
@source = source
|
51
53
|
@options = Kramdown::Options.merge(options)
|
52
|
-
@root = Element.new(:root, nil, nil, :encoding => (source.encoding rescue nil))
|
54
|
+
@root = Element.new(:root, nil, nil, :encoding => (source.encoding rescue nil), :location => 1)
|
53
55
|
@warnings = []
|
54
56
|
@text_type = :text
|
55
57
|
end
|
data/lib/kramdown/parser/gfm.rb
CHANGED
@@ -8,33 +8,40 @@ module Kramdown
|
|
8
8
|
|
9
9
|
def initialize(source, options)
|
10
10
|
super
|
11
|
+
@span_parsers.delete(:line_break)
|
11
12
|
i = @block_parsers.index(:codeblock_fenced)
|
12
13
|
@block_parsers.delete(:codeblock_fenced)
|
13
14
|
@block_parsers.insert(i, :codeblock_fenced_gfm)
|
14
15
|
end
|
15
16
|
|
17
|
+
def parse
|
18
|
+
super
|
19
|
+
add_hard_line_breaks(@root) if @options[:hard_wrap]
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_hard_line_breaks(element)
|
23
|
+
element.children.map! do |child|
|
24
|
+
if child.type == :text && child.value =~ /\n/
|
25
|
+
children = []
|
26
|
+
lines = child.value.split(/\n(?=.)/)
|
27
|
+
lines.each_with_index do |line, index|
|
28
|
+
children << Element.new(:text, (index > 0 ? "\n#{line}" : line))
|
29
|
+
children << Element.new(:br) if index < lines.size - 1
|
30
|
+
end
|
31
|
+
children
|
32
|
+
elsif child.type == :html_element
|
33
|
+
child
|
34
|
+
else
|
35
|
+
add_hard_line_breaks(child)
|
36
|
+
child
|
37
|
+
end
|
38
|
+
end.flatten!
|
39
|
+
end
|
40
|
+
|
16
41
|
FENCED_CODEBLOCK_MATCH = /^(([~`]){3,})\s*?(\w+)?\s*?\n(.*?)^\1\2*\s*?\n/m
|
17
42
|
|
18
43
|
define_parser(:codeblock_fenced_gfm, /^[~`]{3,}/, nil, 'parse_codeblock_fenced')
|
19
44
|
|
20
|
-
def parse_paragraph
|
21
|
-
result = @src.scan(PARAGRAPH_MATCH)
|
22
|
-
while !@src.match?(self.class::PARAGRAPH_END)
|
23
|
-
result << @src.scan(PARAGRAPH_MATCH)
|
24
|
-
end
|
25
|
-
result.chomp!
|
26
|
-
unless @tree.children.last && @tree.children.last.type == :p
|
27
|
-
@tree.children << new_block_el(:p)
|
28
|
-
end
|
29
|
-
lines = result.lstrip.split(/\n/)
|
30
|
-
lines.each_with_index do |line, index|
|
31
|
-
@tree.children.last.children << Element.new(@text_type, line) << Element.new(:br) << Element.new(@text_type, "\n")
|
32
|
-
end
|
33
|
-
@tree.children.last.children.pop # added one \n too many
|
34
|
-
@tree.children.last.children.pop # added one :br too many
|
35
|
-
true
|
36
|
-
end
|
37
|
-
|
38
45
|
end
|
39
46
|
end
|
40
47
|
end
|
data/lib/kramdown/parser/html.rb
CHANGED
@@ -243,7 +243,7 @@ module Kramdown
|
|
243
243
|
# entities in entity elements.
|
244
244
|
def process_text(raw, preserve = false)
|
245
245
|
raw.gsub!(/\s+/, ' ') unless preserve
|
246
|
-
src = StringScanner.new(raw)
|
246
|
+
src = Kramdown::Utils::StringScanner.new(raw)
|
247
247
|
result = []
|
248
248
|
while !src.eos?
|
249
249
|
if tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/)
|
@@ -533,7 +533,7 @@ module Kramdown
|
|
533
533
|
# Parse the source string provided on initialization as HTML document.
|
534
534
|
def parse
|
535
535
|
@stack, @tree = [], @root
|
536
|
-
@src = StringScanner.new(adapt_source(source))
|
536
|
+
@src = Kramdown::Utils::StringScanner.new(adapt_source(source))
|
537
537
|
|
538
538
|
while true
|
539
539
|
if result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/)
|
@@ -118,7 +118,8 @@ module Kramdown
|
|
118
118
|
# Parse all block-level elements in +text+ into the element +el+.
|
119
119
|
def parse_blocks(el, text = nil)
|
120
120
|
@stack.push([@tree, @src, @block_ial])
|
121
|
-
@tree, @
|
121
|
+
@tree, @block_ial = el, nil
|
122
|
+
@src = (text.nil? ? @src : ::Kramdown::Utils::StringScanner.new(text, el.options[:location]))
|
122
123
|
|
123
124
|
status = catch(:stop_block_parsing) do
|
124
125
|
while !@src.eos?
|
@@ -148,7 +149,8 @@ module Kramdown
|
|
148
149
|
element.children.map! do |child|
|
149
150
|
if child.type == :raw_text
|
150
151
|
last_blank = nil
|
151
|
-
reset_env(:src => StringScanner.new(child.value
|
152
|
+
reset_env(:src => ::Kramdown::Utils::StringScanner.new(child.value, element.options[:location]),
|
153
|
+
:text_type => :text)
|
152
154
|
parse_spans(child)
|
153
155
|
child.children
|
154
156
|
elsif child.type == :eob
|
@@ -165,6 +167,7 @@ module Kramdown
|
|
165
167
|
last_blank = nil
|
166
168
|
update_tree(child)
|
167
169
|
update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial]
|
170
|
+
update_raw_header_text(child) if child.type == :header
|
168
171
|
child
|
169
172
|
end
|
170
173
|
end.flatten!
|
@@ -253,6 +256,25 @@ module Kramdown
|
|
253
256
|
end
|
254
257
|
end
|
255
258
|
|
259
|
+
# Update the raw header text for automatic ID generation.
|
260
|
+
def update_raw_header_text(header)
|
261
|
+
# DEPRECATED: option auto_id_stripping will be removed in 2.0 because then this will be the
|
262
|
+
# default behaviour
|
263
|
+
return unless @options[:auto_id_stripping]
|
264
|
+
raw_text = ''
|
265
|
+
|
266
|
+
append_text = lambda do |child|
|
267
|
+
if child.type == :text
|
268
|
+
raw_text << child.value
|
269
|
+
else
|
270
|
+
child.children.each {|c| append_text.call(c)}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
append_text.call(header)
|
275
|
+
header.options[:raw_text] = raw_text
|
276
|
+
end
|
277
|
+
|
256
278
|
# Create a new block-level element, taking care of applying a preceding block IAL if it
|
257
279
|
# exists. This method should always be used for creating a block-level element!
|
258
280
|
def new_block_el(*args)
|
@@ -15,10 +15,11 @@ module Kramdown
|
|
15
15
|
|
16
16
|
# Parse the link definition at the current location.
|
17
17
|
def parse_abbrev_definition
|
18
|
+
start_line_number = @src.current_line_number
|
18
19
|
@src.pos += @src.matched_size
|
19
20
|
abbrev_id, abbrev_text = @src[1], @src[2]
|
20
21
|
abbrev_text.strip!
|
21
|
-
warning("Duplicate abbreviation ID '#{abbrev_id}' - overwriting") if @root.options[:abbrev_defs][abbrev_id]
|
22
|
+
warning("Duplicate abbreviation ID '#{abbrev_id}' on line #{start_line_number} - overwriting") if @root.options[:abbrev_defs][abbrev_id]
|
22
23
|
@root.options[:abbrev_defs][abbrev_id] = abbrev_text
|
23
24
|
@tree.children << Element.new(:eob, :abbrev_def)
|
24
25
|
true
|
@@ -37,7 +38,7 @@ module Kramdown
|
|
37
38
|
if child.type == :text
|
38
39
|
if child.value =~ regexps.first
|
39
40
|
result = []
|
40
|
-
strscan = StringScanner.new(child.value)
|
41
|
+
strscan = Kramdown::Utils::StringScanner.new(child.value)
|
41
42
|
while temp = strscan.scan_until(regexps.last)
|
42
43
|
abbr = strscan.scan(regexps.first) # begin of line case of abbr with \W char as first one
|
43
44
|
if abbr.nil?
|
@@ -23,9 +23,10 @@ module Kramdown
|
|
23
23
|
|
24
24
|
# Parse the autolink at the current location.
|
25
25
|
def parse_autolink
|
26
|
+
start_line_number = @src.current_line_number
|
26
27
|
@src.pos += @src.matched_size
|
27
28
|
href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1])
|
28
|
-
el = Element.new(:a, nil, {'href' => href})
|
29
|
+
el = Element.new(:a, nil, {'href' => href}, :location => start_line_number)
|
29
30
|
add_text(@src[1].sub(/^mailto:/, ''), el)
|
30
31
|
@tree.children << el
|
31
32
|
end
|
@@ -19,13 +19,14 @@ module Kramdown
|
|
19
19
|
|
20
20
|
# Parse the blockquote at the current location.
|
21
21
|
def parse_blockquote
|
22
|
+
start_line_number = @src.current_line_number
|
22
23
|
result = @src.scan(PARAGRAPH_MATCH)
|
23
24
|
while !@src.match?(self.class::LAZY_END)
|
24
25
|
result << @src.scan(PARAGRAPH_MATCH)
|
25
26
|
end
|
26
27
|
result.gsub!(BLOCKQUOTE_START, '')
|
27
28
|
|
28
|
-
el = new_block_el(:blockquote)
|
29
|
+
el = new_block_el(:blockquote, nil, nil, :location => start_line_number)
|
29
30
|
@tree.children << el
|
30
31
|
parse_blocks(el, result)
|
31
32
|
true
|
@@ -21,10 +21,11 @@ module Kramdown
|
|
21
21
|
|
22
22
|
# Parse the indented codeblock at the current location.
|
23
23
|
def parse_codeblock
|
24
|
+
start_line_number = @src.current_line_number
|
24
25
|
data = @src.scan(self.class::CODEBLOCK_MATCH)
|
25
26
|
data.gsub!(/\n( {0,3}\S)/, ' \\1')
|
26
27
|
data.gsub!(INDENT, '')
|
27
|
-
@tree.children << new_block_el(:codeblock, data)
|
28
|
+
@tree.children << new_block_el(:codeblock, data, nil, :location => start_line_number)
|
28
29
|
true
|
29
30
|
end
|
30
31
|
define_parser(:codeblock, CODEBLOCK_START)
|
@@ -36,8 +37,9 @@ module Kramdown
|
|
36
37
|
# Parse the fenced codeblock at the current location.
|
37
38
|
def parse_codeblock_fenced
|
38
39
|
if @src.check(self.class::FENCED_CODEBLOCK_MATCH)
|
40
|
+
start_line_number = @src.current_line_number
|
39
41
|
@src.pos += @src.matched_size
|
40
|
-
el = new_block_el(:codeblock, @src[4])
|
42
|
+
el = new_block_el(:codeblock, @src[4], nil, :location => start_line_number)
|
41
43
|
lang = @src[3].to_s.strip
|
42
44
|
el.attr['class'] = "language-#{lang}" unless lang.empty?
|
43
45
|
@tree.children << el
|
@@ -15,6 +15,7 @@ module Kramdown
|
|
15
15
|
|
16
16
|
# Parse the codespan at the current scanner location.
|
17
17
|
def parse_codespan
|
18
|
+
start_line_number = @src.current_line_number
|
18
19
|
result = @src.scan(CODESPAN_DELIMITER)
|
19
20
|
simple = (result.length == 1)
|
20
21
|
reset_pos = @src.pos
|
@@ -30,7 +31,7 @@ module Kramdown
|
|
30
31
|
text = text[1..-1] if text[0..0] == ' '
|
31
32
|
text = text[0..-2] if text[-1..-1] == ' '
|
32
33
|
end
|
33
|
-
@tree.children << Element.new(:codespan, text)
|
34
|
+
@tree.children << Element.new(:codespan, text, nil, :location => start_line_number)
|
34
35
|
else
|
35
36
|
@src.pos = reset_pos
|
36
37
|
add_text(result)
|
@@ -15,6 +15,7 @@ module Kramdown
|
|
15
15
|
|
16
16
|
# Parse the emphasis at the current location.
|
17
17
|
def parse_emphasis
|
18
|
+
start_line_number = @src.current_line_number
|
18
19
|
result = @src.scan(EMPHASIS_START)
|
19
20
|
element = (result.length == 2 ? :strong : :em)
|
20
21
|
type = result[0..0]
|
@@ -27,7 +28,7 @@ module Kramdown
|
|
27
28
|
end
|
28
29
|
|
29
30
|
sub_parse = lambda do |delim, elem|
|
30
|
-
el = Element.new(elem)
|
31
|
+
el = Element.new(elem, nil, nil, :location => start_line_number)
|
31
32
|
stop_re = /#{Regexp.escape(delim)}/
|
32
33
|
found = parse_spans(el, stop_re) do
|
33
34
|
(@src.pre_match[-1, 1] !~ /\s/) &&
|
@@ -16,7 +16,7 @@ module Kramdown
|
|
16
16
|
# Parse the string +str+ and extract all attributes and add all found attributes to the hash
|
17
17
|
# +opts+.
|
18
18
|
def parse_attribute_list(str, opts)
|
19
|
-
return if str.strip.empty?
|
19
|
+
return if str.strip.empty? || str.strip == ':'
|
20
20
|
attrs = str.scan(ALD_TYPE_ANY)
|
21
21
|
attrs.each do |key, sep, val, ref, id_and_or_class, _, _|
|
22
22
|
if ref
|
@@ -55,6 +55,7 @@ module Kramdown
|
|
55
55
|
# or :span depending whether we parse a block or span extension tag.
|
56
56
|
def parse_extension_start_tag(type)
|
57
57
|
orig_pos = @src.pos
|
58
|
+
start_line_number = @src.current_line_number
|
58
59
|
@src.pos += @src.matched_size
|
59
60
|
|
60
61
|
error_block = lambda do |msg|
|
@@ -66,7 +67,7 @@ module Kramdown
|
|
66
67
|
|
67
68
|
if @src[4] || @src.matched == '{:/}'
|
68
69
|
name = (@src[4] ? "for '#{@src[4]}' " : '')
|
69
|
-
return error_block.call("Invalid extension stop tag #{name}found - ignoring it")
|
70
|
+
return error_block.call("Invalid extension stop tag #{name} found on line #{start_line_number} - ignoring it")
|
70
71
|
end
|
71
72
|
|
72
73
|
ext = @src[1]
|
@@ -80,12 +81,12 @@ module Kramdown
|
|
80
81
|
body = result.sub!(stop_re, '')
|
81
82
|
body.chomp! if type == :block
|
82
83
|
else
|
83
|
-
return error_block.call("No stop tag for extension '#{ext}' found - ignoring it")
|
84
|
+
return error_block.call("No stop tag for extension '#{ext}' found on line #{start_line_number} - ignoring it")
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
87
88
|
if !handle_extension(ext, opts, body, type)
|
88
|
-
error_block.call("Invalid extension with name '#{ext}' specified - ignoring it")
|
89
|
+
error_block.call("Invalid extension with name '#{ext}' specified on line #{start_line_number} - ignoring it")
|
89
90
|
else
|
90
91
|
true
|
91
92
|
end
|
@@ -19,13 +19,14 @@ module Kramdown
|
|
19
19
|
|
20
20
|
# Parse the foot note definition at the current location.
|
21
21
|
def parse_footnote_definition
|
22
|
+
start_line_number = @src.current_line_number
|
22
23
|
@src.pos += @src.matched_size
|
23
24
|
|
24
|
-
el = Element.new(:footnote_def)
|
25
|
+
el = Element.new(:footnote_def, nil, nil, :location => start_line_number)
|
25
26
|
parse_blocks(el, @src[2].gsub(INDENT, ''))
|
26
27
|
warning("Duplicate footnote name '#{@src[1]}' - overwriting") if @footnotes[@src[1]]
|
27
28
|
(@footnotes[@src[1]] = {})[:content] = el
|
28
|
-
@tree.children << Element.new(:eob, :footnote_def)
|
29
|
+
@tree.children << Element.new(:eob, :footnote_def, nil, :location => start_line_number)
|
29
30
|
true
|
30
31
|
end
|
31
32
|
define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START)
|
@@ -35,15 +36,16 @@ module Kramdown
|
|
35
36
|
|
36
37
|
# Parse the footnote marker at the current location.
|
37
38
|
def parse_footnote_marker
|
39
|
+
start_line_number = @src.current_line_number
|
38
40
|
@src.pos += @src.matched_size
|
39
41
|
fn_def = @footnotes[@src[1]]
|
40
42
|
if fn_def
|
41
43
|
fn_def[:marker] ||= []
|
42
|
-
fn_def[:marker].push(Element.new(:footnote, fn_def[:content], nil, :name => @src[1]))
|
44
|
+
fn_def[:marker].push(Element.new(:footnote, fn_def[:content], nil, :name => @src[1], :location => start_line_number))
|
43
45
|
fn_def[:stack] = [@stack.map {|s| s.first}, @tree, fn_def[:marker]].flatten.compact
|
44
46
|
@tree.children << fn_def[:marker].last
|
45
47
|
else
|
46
|
-
warning("Footnote definition for '#{@src[1]}' not found")
|
48
|
+
warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}")
|
47
49
|
add_text(@src.matched)
|
48
50
|
end
|
49
51
|
end
|