kramdown 1.4.1 → 1.4.2
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 +1 -1
- data/VERSION +1 -1
- data/data/kramdown/document.latex +2 -0
- data/doc/index.page +2 -2
- data/doc/sidebar.template +2 -2
- data/doc/tests.page +42 -43
- data/lib/kramdown/converter/html.rb +6 -2
- data/lib/kramdown/converter/kramdown.rb +1 -0
- data/lib/kramdown/converter/latex.rb +0 -2
- data/lib/kramdown/parser/base.rb +4 -3
- data/lib/kramdown/parser/gfm.rb +1 -1
- data/lib/kramdown/parser/html.rb +3 -3
- data/lib/kramdown/parser/kramdown.rb +1 -1
- data/lib/kramdown/parser/kramdown/abbreviation.rb +7 -3
- data/lib/kramdown/parser/kramdown/codespan.rb +2 -2
- data/lib/kramdown/parser/kramdown/emphasis.rb +6 -3
- data/lib/kramdown/parser/kramdown/extensions.rb +6 -6
- data/lib/kramdown/parser/kramdown/footnote.rb +1 -1
- data/lib/kramdown/parser/kramdown/header.rb +1 -1
- data/lib/kramdown/parser/kramdown/line_break.rb +1 -1
- data/lib/kramdown/parser/kramdown/link.rb +6 -5
- data/lib/kramdown/parser/kramdown/math.rb +2 -2
- data/lib/kramdown/parser/kramdown/paragraph.rb +1 -1
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +2 -1
- data/lib/kramdown/parser/kramdown/table.rb +4 -3
- data/lib/kramdown/utils/string_scanner.rb +21 -18
- data/lib/kramdown/version.rb +1 -1
- data/test/test_location.rb +34 -0
- data/test/testcases/block/04_header/atx_header.html +2 -0
- data/test/testcases/block/04_header/atx_header.text +1 -0
- data/test/testcases/span/04_footnote/inside_footnote.html +17 -0
- data/test/testcases/span/04_footnote/inside_footnote.text +9 -0
- data/test/testcases_gfm/hard_line_breaks_off.html +2 -2
- data/test/testcases_gfm/hard_line_breaks_off.text +2 -2
- data/test/testcases_gfm/two_para_hard_line_breaks.html +1 -1
- data/test/testcases_gfm/two_para_hard_line_breaks.text +1 -1
- metadata +41 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d76ec0e7087a62788b9eb1d27027b1d4b4a2610e
|
4
|
+
data.tar.gz: 4b6fcefcd89fd851be053d975cdd825e07278c58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c34e8bb6438d78c04d45c4237856530669933add8620ce12e3847729d6a49429b114be6dc00dcefe3ff2b450a4f947bfc36c2854dbb6c43799437f5429efbb8
|
7
|
+
data.tar.gz: 902838d7ee4add0e5dc66e67899b75fd9f44dddfff181eb6c99b20ffebd1af97c920f15bf6a87317c410ffef89f57ba28d9b6e48bbf1bc7de714389833ffee6a
|
data/CONTRIBUTERS
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.4.
|
1
|
+
1.4.2
|
data/doc/index.page
CHANGED
@@ -87,8 +87,8 @@ Markdown implementations because kramdown borrowed many ideas from existing pack
|
|
87
87
|
completely written in Ruby, supports standard Markdown (with some minor modifications) and various
|
88
88
|
extensions that have been made popular by the [PHP Markdown Extra] package and [Maruku].
|
89
89
|
|
90
|
-
It is probably the fastest pure-Ruby Markdown converter available (
|
91
|
-
faster than [Maruku] and about 5x faster than [BlueFeather].
|
90
|
+
It is probably the fastest pure-Ruby Markdown converter available (September 2014), being about 3x
|
91
|
+
faster than [Maruku] and about 4.5x faster than [BlueFeather].
|
92
92
|
|
93
93
|
[PHP Markdown Extra]: http://michelf.com/projects/php-markdown/extra/
|
94
94
|
[Maruku]: http://maruku.rubyforge.org
|
data/doc/sidebar.template
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
<h2>News</h2>
|
2
2
|
|
3
|
-
<p>The latest version of kramdown is <span class="inline-important">1.4.
|
4
|
-
on <span class="inline-important">2014-
|
3
|
+
<p>The latest version of kramdown is <span class="inline-important">1.4.2</span> and it was released
|
4
|
+
on <span class="inline-important">2014-09-16</span></p>
|
5
5
|
|
6
6
|
<p>More <a href="{relocatable: news.html}">news</a>…</p>
|
7
7
|
|
data/doc/tests.page
CHANGED
@@ -33,73 +33,72 @@ kramdown comes with a small benchmark to test how fast it is in regard to four o
|
|
33
33
|
implementations: Maruku, BlueFeather, BlueCloth, RDiscount and Redcarpet. The first two are written
|
34
34
|
using only Ruby, the latter three are written in C and need to be compiled.
|
35
35
|
|
36
|
-
As one can see below, kramdown is currently (
|
37
|
-
than BlueFeather but ~30x slower than
|
36
|
+
As one can see below, kramdown is currently (September 2014) ~3x faster than Maruku, ~4.5x faster
|
37
|
+
than BlueFeather but ~30x slower than RDiscount and ~150x slower than Redcarpet:
|
38
38
|
|
39
39
|
<pre><code>
|
40
|
-
Running tests on 2014-
|
40
|
+
Running tests on 2014-09-16 under ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]
|
41
41
|
|
42
42
|
Test using file mdsyntax.text and 20 runs
|
43
43
|
Rehearsal ----------------------------------------------------
|
44
|
-
kramdown 1.
|
45
|
-
Maruku 0.7.
|
46
|
-
BlueFeather 0.41
|
47
|
-
BlueCloth 2.2.0 0.050000 0.000000 0.050000 ( 0.
|
48
|
-
RDiscount 2.
|
49
|
-
redcarpet 3.
|
50
|
-
------------------------------------------- total:
|
44
|
+
kramdown 1.4.2 0.900000 0.010000 0.910000 ( 0.914992)
|
45
|
+
Maruku 0.7.1 2.360000 0.040000 2.400000 ( 2.403571)
|
46
|
+
BlueFeather 0.41 3.760000 0.010000 3.770000 ( 3.776421)
|
47
|
+
BlueCloth 2.2.0 0.050000 0.000000 0.050000 ( 0.050221)
|
48
|
+
RDiscount 2.1.7 0.020000 0.000000 0.020000 ( 0.024180)
|
49
|
+
redcarpet 3.1.2 0.010000 0.000000 0.010000 ( 0.004579)
|
50
|
+
------------------------------------------- total: 7.160000sec
|
51
51
|
|
52
52
|
user system total real
|
53
|
-
kramdown 1.
|
54
|
-
Maruku 0.7.
|
55
|
-
BlueFeather 0.41
|
56
|
-
BlueCloth 2.2.0 0.
|
57
|
-
RDiscount 2.
|
58
|
-
redcarpet 3.
|
53
|
+
kramdown 1.4.2 0.830000 0.000000 0.830000 ( 0.834144)
|
54
|
+
Maruku 0.7.1 2.250000 0.030000 2.280000 ( 2.286579)
|
55
|
+
BlueFeather 0.41 3.680000 0.010000 3.690000 ( 3.693769)
|
56
|
+
BlueCloth 2.2.0 0.050000 0.000000 0.050000 ( 0.044831)
|
57
|
+
RDiscount 2.1.7 0.020000 0.000000 0.020000 ( 0.022847)
|
58
|
+
redcarpet 3.1.2 0.010000 0.000000 0.010000 ( 0.004601)
|
59
59
|
|
60
60
|
Real time of X divided by real time of kramdown
|
61
|
-
Maruku 2.
|
62
|
-
BlueFeather 4.
|
63
|
-
BlueCloth 0.
|
64
|
-
RDiscount 0.
|
65
|
-
redcarpet 0.
|
61
|
+
Maruku 2.7412
|
62
|
+
BlueFeather 4.4282
|
63
|
+
BlueCloth 0.0537
|
64
|
+
RDiscount 0.0274
|
65
|
+
redcarpet 0.0055
|
66
66
|
|
67
67
|
Test using file mdbasics.text and 20 runs
|
68
68
|
Rehearsal ----------------------------------------------------
|
69
|
-
kramdown 1.
|
70
|
-
Maruku 0.7.
|
71
|
-
BlueFeather 0.41
|
72
|
-
BlueCloth 2.2.0 0.
|
73
|
-
RDiscount 2.
|
74
|
-
redcarpet 3.
|
75
|
-
------------------------------------------- total:
|
69
|
+
kramdown 1.4.2 0.150000 0.000000 0.150000 ( 0.149989)
|
70
|
+
Maruku 0.7.1 0.580000 0.010000 0.590000 ( 0.584910)
|
71
|
+
BlueFeather 0.41 0.780000 0.000000 0.780000 ( 0.788740)
|
72
|
+
BlueCloth 2.2.0 0.020000 0.000000 0.020000 ( 0.014700)
|
73
|
+
RDiscount 2.1.7 0.000000 0.000000 0.000000 ( 0.007692)
|
74
|
+
redcarpet 3.1.2 0.010000 0.000000 0.010000 ( 0.002064)
|
75
|
+
------------------------------------------- total: 1.550000sec
|
76
76
|
|
77
77
|
user system total real
|
78
|
-
kramdown 1.
|
79
|
-
Maruku 0.7.
|
80
|
-
BlueFeather 0.41
|
81
|
-
BlueCloth 2.2.0 0.
|
82
|
-
RDiscount 2.
|
83
|
-
redcarpet 3.
|
78
|
+
kramdown 1.4.2 0.150000 0.000000 0.150000 ( 0.151586)
|
79
|
+
Maruku 0.7.1 0.520000 0.000000 0.520000 ( 0.525707)
|
80
|
+
BlueFeather 0.41 0.770000 0.010000 0.780000 ( 0.763559)
|
81
|
+
BlueCloth 2.2.0 0.020000 0.000000 0.020000 ( 0.015509)
|
82
|
+
RDiscount 2.1.7 0.010000 0.000000 0.010000 ( 0.006545)
|
83
|
+
redcarpet 3.1.2 0.000000 0.000000 0.000000 ( 0.001475)
|
84
84
|
|
85
85
|
Real time of X divided by real time of kramdown
|
86
|
-
Maruku
|
87
|
-
BlueFeather
|
88
|
-
BlueCloth 0.
|
89
|
-
RDiscount 0.
|
90
|
-
redcarpet 0.
|
86
|
+
Maruku 3.468
|
87
|
+
BlueFeather 5.0371
|
88
|
+
BlueCloth 0.1023
|
89
|
+
RDiscount 0.0432
|
90
|
+
redcarpet 0.0097
|
91
91
|
</code></pre>
|
92
92
|
|
93
93
|
And here are some graphs which show the execution times of the various kramdown releases on
|
94
94
|
different Ruby interpreters:
|
95
95
|
|
96
96
|
![ruby 1.8.7p302]({relocatable: img/graph-ruby-1.8.7-302.png})
|
97
|
-
![ruby 1.9.2p320]({relocatable: img/graph-ruby-1.9.2p320-320.png})
|
98
97
|
![ruby 1.9.3p448]({relocatable: img/graph-ruby-1.9.3p448-448.png})
|
99
98
|
![ruby 2.0.0p247]({relocatable: img/graph-ruby-2.0.0p247-247.png})
|
100
|
-
![ruby 2.1.
|
101
|
-
![jruby 1.7.
|
102
|
-
![rubinius 2.
|
99
|
+
![ruby 2.1.2p95]({relocatable: img/graph-ruby-2.1.2p95-95.png})
|
100
|
+
![jruby 1.7.15]({relocatable: img/graph-jruby-1.7.15-392.png})
|
101
|
+
![rubinius 2.2.10]({relocatable: img/graph-rubinius-2.2.10-0.png})
|
103
102
|
|
104
103
|
[Markdown Test Suite]: http://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip
|
105
104
|
[MDTest]: http://www.michelf.com/docs/projets/mdtest-1.0.zip
|
@@ -430,10 +430,11 @@ module Kramdown
|
|
430
430
|
def footnote_content
|
431
431
|
ol = Element.new(:ol)
|
432
432
|
ol.attr['start'] = @footnote_start if @footnote_start != 1
|
433
|
-
|
433
|
+
i = 0
|
434
|
+
while i < @footnotes.length
|
435
|
+
name, data, _, repeat = *@footnotes[i]
|
434
436
|
li = Element.new(:li, nil, {'id' => "fn:#{name}"})
|
435
437
|
li.children = Marshal.load(Marshal.dump(data.children))
|
436
|
-
ol.children << li
|
437
438
|
|
438
439
|
if li.children.last.type == :p
|
439
440
|
para = li.children.last
|
@@ -447,6 +448,9 @@ module Kramdown
|
|
447
448
|
(1..repeat).each do |index|
|
448
449
|
para.children << Element.new(:raw, FOOTNOTE_BACKLINK_FMT % [" ", "#{name}:#{index}", "↩<sup>#{index+1}</sup>"])
|
449
450
|
end
|
451
|
+
|
452
|
+
ol.children << Element.new(:raw, convert(li, 4))
|
453
|
+
i += 1
|
450
454
|
end
|
451
455
|
(ol.children.empty? ? '' : format_as_indented_block_html('div', {:class => "footnotes"}, convert(ol, 2), 0))
|
452
456
|
end
|
@@ -105,6 +105,7 @@ module Kramdown
|
|
105
105
|
def convert_header(el, opts)
|
106
106
|
res = ''
|
107
107
|
res << "#{'#' * output_header_level(el.options[:level])} #{inner(el, opts)}"
|
108
|
+
res[-1, 1] = "\\#" if res[-1] == ?#
|
108
109
|
res << " {##{el.attr['id']}}" if el.attr['id'] && !el.attr['id'].strip.empty?
|
109
110
|
res << "\n"
|
110
111
|
end
|
@@ -32,8 +32,6 @@ module Kramdown
|
|
32
32
|
# Initialize the LaTeX converter with the +root+ element and the conversion +options+.
|
33
33
|
def initialize(root, options)
|
34
34
|
super
|
35
|
-
#TODO: set the footnote counter at the beginning of the document
|
36
|
-
@options[:footnote_nr]
|
37
35
|
@data[:packages] = Set.new
|
38
36
|
end
|
39
37
|
|
data/lib/kramdown/parser/base.rb
CHANGED
@@ -97,10 +97,11 @@ module Kramdown
|
|
97
97
|
# This helper method adds the given +text+ either to the last element in the +tree+ if it is a
|
98
98
|
# +type+ element or creates a new text element with the given +type+.
|
99
99
|
def add_text(text, tree = @tree, type = @text_type)
|
100
|
-
|
101
|
-
|
100
|
+
last = tree.children.last
|
101
|
+
if last && last.type == type
|
102
|
+
last.value << text
|
102
103
|
elsif !text.empty?
|
103
|
-
tree.children << Element.new(type, text)
|
104
|
+
tree.children << Element.new(type, text, nil, :location => (last && last.options[:location] || tree.options[:location]))
|
104
105
|
end
|
105
106
|
end
|
106
107
|
|
data/lib/kramdown/parser/gfm.rb
CHANGED
@@ -8,7 +8,7 @@ module Kramdown
|
|
8
8
|
|
9
9
|
def initialize(source, options)
|
10
10
|
super
|
11
|
-
@span_parsers.delete(:line_break)
|
11
|
+
@span_parsers.delete(:line_break) if @options[:hard_wrap]
|
12
12
|
{:codeblock_fenced => :codeblock_fenced_gfm,
|
13
13
|
:atx_header => :atx_header_gfm}.each do |current, replacement|
|
14
14
|
i = @block_parsers.index(current)
|
data/lib/kramdown/parser/html.rb
CHANGED
@@ -34,11 +34,11 @@ module Kramdown
|
|
34
34
|
HTML_ENTITY_RE = /&([\w:][\-\w\.:]*);|&#(\d+);|&\#x([0-9a-fA-F]+);/
|
35
35
|
|
36
36
|
HTML_CONTENT_MODEL_BLOCK = %w{address applet article aside button blockquote body
|
37
|
-
dd div dl fieldset figure figcaption footer form header hgroup iframe li map menu nav
|
38
|
-
noscript object section td}
|
37
|
+
dd details div dl fieldset figure figcaption footer form header hgroup iframe li map menu nav
|
38
|
+
noscript object section summary td}
|
39
39
|
HTML_CONTENT_MODEL_SPAN = %w{a abbr acronym b bdo big button cite caption del dfn dt em
|
40
40
|
h1 h2 h3 h4 h5 h6 i ins label legend optgroup p q rb rbc
|
41
|
-
rp rt rtc ruby select small span strong sub sup
|
41
|
+
rp rt rtc ruby select small span strong sub sup th tt}
|
42
42
|
HTML_CONTENT_MODEL_RAW = %w{script style math option textarea pre code kbd samp var}
|
43
43
|
# The following elements are also parsed as raw since they need child elements that cannot
|
44
44
|
# be expressed using kramdown syntax: colgroup table tbody thead tfoot tr ul ol
|
@@ -89,7 +89,7 @@ module Kramdown
|
|
89
89
|
parse_blocks(@root, adapt_source(source))
|
90
90
|
update_tree(@root)
|
91
91
|
replace_abbreviations(@root)
|
92
|
-
@footnotes.each {|name,data| update_tree(data[:
|
92
|
+
@footnotes.each {|name,data| update_tree(data[:content])}
|
93
93
|
end
|
94
94
|
|
95
95
|
#######
|
@@ -38,16 +38,20 @@ module Kramdown
|
|
38
38
|
if child.type == :text
|
39
39
|
if child.value =~ regexps.first
|
40
40
|
result = []
|
41
|
-
strscan = Kramdown::Utils::StringScanner.new(child.value)
|
41
|
+
strscan = Kramdown::Utils::StringScanner.new(child.value, child.options[:location])
|
42
|
+
text_lineno = strscan.current_line_number
|
42
43
|
while temp = strscan.scan_until(regexps.last)
|
44
|
+
abbr_lineno = strscan.current_line_number
|
43
45
|
abbr = strscan.scan(regexps.first) # begin of line case of abbr with \W char as first one
|
44
46
|
if abbr.nil?
|
45
47
|
temp << strscan.scan(/\W|^/)
|
46
48
|
abbr = strscan.scan(regexps.first)
|
47
49
|
end
|
48
|
-
result << Element.new(:text, temp
|
50
|
+
result << Element.new(:text, temp, nil, :location => text_lineno)
|
51
|
+
result << Element.new(:abbreviation, abbr, nil, :location => abbr_lineno)
|
52
|
+
text_lineno = strscan.current_line_number
|
49
53
|
end
|
50
|
-
result << Element.new(:text, strscan.rest)
|
54
|
+
result << Element.new(:text, strscan.rest, nil, :location => text_lineno)
|
51
55
|
else
|
52
56
|
child
|
53
57
|
end
|
@@ -18,7 +18,7 @@ module Kramdown
|
|
18
18
|
start_line_number = @src.current_line_number
|
19
19
|
result = @src.scan(CODESPAN_DELIMITER)
|
20
20
|
simple = (result.length == 1)
|
21
|
-
|
21
|
+
saved_pos = @src.save_pos
|
22
22
|
|
23
23
|
if simple && @src.pre_match =~ /\s\Z/ && @src.match?(/\s/)
|
24
24
|
add_text(result)
|
@@ -33,7 +33,7 @@ module Kramdown
|
|
33
33
|
end
|
34
34
|
@tree.children << Element.new(:codespan, text, nil, :location => start_line_number)
|
35
35
|
else
|
36
|
-
@src.
|
36
|
+
@src.revert_pos(saved_pos)
|
37
37
|
add_text(result)
|
38
38
|
end
|
39
39
|
end
|
@@ -16,10 +16,11 @@ module Kramdown
|
|
16
16
|
# Parse the emphasis at the current location.
|
17
17
|
def parse_emphasis
|
18
18
|
start_line_number = @src.current_line_number
|
19
|
+
saved_pos = @src.save_pos
|
20
|
+
|
19
21
|
result = @src.scan(EMPHASIS_START)
|
20
22
|
element = (result.length == 2 ? :strong : :em)
|
21
23
|
type = result[0..0]
|
22
|
-
reset_pos = @src.pos
|
23
24
|
|
24
25
|
if (type == '_' && @src.pre_match =~ /[[:alnum:]]\z/ && @src.check(/[[:alnum:]]/)) || @src.check(/\s/) ||
|
25
26
|
@tree.type == element || @stack.any? {|el, _| el.type == element}
|
@@ -40,14 +41,16 @@ module Kramdown
|
|
40
41
|
|
41
42
|
found, el, stop_re = sub_parse.call(result, element)
|
42
43
|
if !found && element == :strong && @tree.type != :em
|
43
|
-
@src.
|
44
|
+
@src.revert_pos(saved_pos)
|
45
|
+
@src.pos += 1
|
44
46
|
found, el, stop_re = sub_parse.call(type, :em)
|
45
47
|
end
|
46
48
|
if found
|
47
49
|
@src.scan(stop_re)
|
48
50
|
@tree.children << el
|
49
51
|
else
|
50
|
-
@src.
|
52
|
+
@src.revert_pos(saved_pos)
|
53
|
+
@src.pos += result.length
|
51
54
|
add_text(result)
|
52
55
|
end
|
53
56
|
end
|
@@ -54,13 +54,13 @@ module Kramdown
|
|
54
54
|
# Parse the generic extension at the current point. The parameter +type+ can either be :block
|
55
55
|
# or :span depending whether we parse a block or span extension tag.
|
56
56
|
def parse_extension_start_tag(type)
|
57
|
-
|
57
|
+
saved_pos = @src.save_pos
|
58
58
|
start_line_number = @src.current_line_number
|
59
59
|
@src.pos += @src.matched_size
|
60
60
|
|
61
61
|
error_block = lambda do |msg|
|
62
62
|
warning(msg)
|
63
|
-
@src.
|
63
|
+
@src.revert_pos(saved_pos)
|
64
64
|
add_text(@src.getch) if type == :span
|
65
65
|
false
|
66
66
|
end
|
@@ -85,20 +85,20 @@ module Kramdown
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
if !handle_extension(ext, opts, body, type)
|
88
|
+
if !handle_extension(ext, opts, body, type, start_line_number)
|
89
89
|
error_block.call("Invalid extension with name '#{ext}' specified on line #{start_line_number} - ignoring it")
|
90
90
|
else
|
91
91
|
true
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
def handle_extension(name, opts, body, type)
|
95
|
+
def handle_extension(name, opts, body, type, line_no = nil)
|
96
96
|
case name
|
97
97
|
when 'comment'
|
98
|
-
@tree.children << Element.new(:comment, body, nil, :category => type) if body.kind_of?(String)
|
98
|
+
@tree.children << Element.new(:comment, body, nil, :category => type, :location => line_no) if body.kind_of?(String)
|
99
99
|
true
|
100
100
|
when 'nomarkdown'
|
101
|
-
@tree.children << Element.new(:raw, body, nil, :category => type, :type => opts['type'].to_s.split(/\s+/)) if body.kind_of?(String)
|
101
|
+
@tree.children << Element.new(:raw, body, nil, :category => type, :location => line_no, :type => opts['type'].to_s.split(/\s+/)) if body.kind_of?(String)
|
102
102
|
true
|
103
103
|
when 'options'
|
104
104
|
opts.select do |k,v|
|
@@ -26,7 +26,7 @@ module Kramdown
|
|
26
26
|
parse_blocks(el, @src[2].gsub(INDENT, ''))
|
27
27
|
warning("Duplicate footnote name '#{@src[1]}' on line #{start_line_number} - overwriting") if @footnotes[@src[1]]
|
28
28
|
(@footnotes[@src[1]] = {})[:content] = el
|
29
|
-
@tree.children << Element.new(:eob, :footnote_def
|
29
|
+
@tree.children << Element.new(:eob, :footnote_def)
|
30
30
|
true
|
31
31
|
end
|
32
32
|
define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START)
|
@@ -34,7 +34,7 @@ module Kramdown
|
|
34
34
|
|
35
35
|
|
36
36
|
ATX_HEADER_START = /^\#{1,6}/
|
37
|
-
ATX_HEADER_MATCH = /^(\#{1,6})(.+?)\s*?#*#{HEADER_ID}\s*?\n/
|
37
|
+
ATX_HEADER_MATCH = /^(\#{1,6})(.+?(?:\\#)?)\s*?#*#{HEADER_ID}\s*?\n/
|
38
38
|
|
39
39
|
# Parse the Atx header at the current location.
|
40
40
|
def parse_atx_header
|
@@ -15,8 +15,8 @@ module Kramdown
|
|
15
15
|
|
16
16
|
# Parse the line break at the current location.
|
17
17
|
def parse_line_break
|
18
|
+
@tree.children << Element.new(:br, nil, nil, :location => @src.current_line_number)
|
18
19
|
@src.pos += @src.matched_size
|
19
|
-
@tree.children << Element.new(:br)
|
20
20
|
end
|
21
21
|
define_parser(:line_break, LINE_BREAK, '( |\\\\)(?=\n)')
|
22
22
|
|
@@ -57,7 +57,8 @@ module Kramdown
|
|
57
57
|
def parse_link
|
58
58
|
start_line_number = @src.current_line_number
|
59
59
|
result = @src.scan(LINK_START)
|
60
|
-
|
60
|
+
cur_pos = @src.pos
|
61
|
+
saved_pos = @src.save_pos
|
61
62
|
|
62
63
|
link_type = (result =~ /^!/ ? :img : :a)
|
63
64
|
|
@@ -74,11 +75,11 @@ module Kramdown
|
|
74
75
|
count - el.children.select {|c| c.type == :img}.size == 0
|
75
76
|
end
|
76
77
|
if !found || (link_type == :a && el.children.empty?)
|
77
|
-
@src.
|
78
|
+
@src.revert_pos(saved_pos)
|
78
79
|
add_text(result)
|
79
80
|
return
|
80
81
|
end
|
81
|
-
alt_text = extract_string(
|
82
|
+
alt_text = extract_string(cur_pos...@src.pos, @src).gsub(ESCAPED_CHARS, '\1')
|
82
83
|
@src.scan(LINK_BRACKET_STOP_RE)
|
83
84
|
|
84
85
|
# reference style link or no link url
|
@@ -88,7 +89,7 @@ module Kramdown
|
|
88
89
|
add_link(el, @link_defs[link_id].first, @link_defs[link_id].last, alt_text)
|
89
90
|
else
|
90
91
|
warning("No link definition for link ID '#{link_id}' found on line #{start_line_number}")
|
91
|
-
@src.
|
92
|
+
@src.revert_pos(saved_pos)
|
92
93
|
add_text(result)
|
93
94
|
end
|
94
95
|
return
|
@@ -127,7 +128,7 @@ module Kramdown
|
|
127
128
|
if @src.scan(LINK_INLINE_TITLE_RE)
|
128
129
|
add_link(el, link_url, @src[2], alt_text)
|
129
130
|
else
|
130
|
-
@src.
|
131
|
+
@src.revert_pos(saved_pos)
|
131
132
|
add_text(result)
|
132
133
|
end
|
133
134
|
end
|
@@ -25,14 +25,14 @@ module Kramdown
|
|
25
25
|
return false
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
saved_pos = @src.save_pos
|
29
29
|
@src.pos += @src.matched_size
|
30
30
|
data = @src[2]
|
31
31
|
if before_block_boundary?
|
32
32
|
@tree.children << new_block_el(:math, data, nil, :category => :block, :location => start_line_number)
|
33
33
|
true
|
34
34
|
else
|
35
|
-
@src.
|
35
|
+
@src.revert_pos(saved_pos)
|
36
36
|
false
|
37
37
|
end
|
38
38
|
end
|
@@ -156,13 +156,14 @@ module Kramdown
|
|
156
156
|
|
157
157
|
# Parse the smart quotes at current location.
|
158
158
|
def parse_smart_quotes
|
159
|
+
start_line_number = @src.current_line_number
|
159
160
|
substs = SQ_RULES.find {|reg, subst| @src.scan(reg)}[1]
|
160
161
|
substs.each do |subst|
|
161
162
|
if subst.kind_of?(Integer)
|
162
163
|
add_text(@src[subst])
|
163
164
|
else
|
164
165
|
val = SQ_SUBSTS[[subst, @src[subst.to_s[-1,1].to_i]]] || subst
|
165
|
-
@tree.children << Element.new(:smart_quote, val)
|
166
|
+
@tree.children << Element.new(:smart_quote, val, nil, :location => start_line_number)
|
166
167
|
end
|
167
168
|
end
|
168
169
|
end
|
@@ -25,6 +25,7 @@ module Kramdown
|
|
25
25
|
def parse_table
|
26
26
|
return false if !after_block_boundary?
|
27
27
|
|
28
|
+
saved_pos = @src.save_pos
|
28
29
|
orig_pos = @src.pos
|
29
30
|
table = new_block_el(:table, nil, nil, :alignment => [], :location => @src.current_line_number)
|
30
31
|
leading_pipe = (@src.check(TABLE_LINE) =~ /^\s*\|/)
|
@@ -104,7 +105,7 @@ module Kramdown
|
|
104
105
|
end
|
105
106
|
|
106
107
|
if !before_block_boundary?
|
107
|
-
@src.
|
108
|
+
@src.revert_pos(saved_pos)
|
108
109
|
return false
|
109
110
|
end
|
110
111
|
|
@@ -135,13 +136,13 @@ module Kramdown
|
|
135
136
|
pipe_on_line = (lines.size > 1 ? false : pipe_on_line) || (lines.last =~ /^#{TABLE_PIPE_CHECK}/)
|
136
137
|
end
|
137
138
|
end
|
138
|
-
@src.
|
139
|
+
@src.revert_pos(saved_pos) and return false if !pipe_on_line
|
139
140
|
|
140
141
|
add_container.call(has_footer ? :tfoot : :tbody, false) if !rows.empty?
|
141
142
|
|
142
143
|
if !table.children.any? {|el| el.type == :tbody}
|
143
144
|
warning("Found table without body on line #{table.options[:location]} - ignoring it")
|
144
|
-
@src.
|
145
|
+
@src.revert_pos(saved_pos)
|
145
146
|
return false
|
146
147
|
end
|
147
148
|
|
@@ -23,29 +23,32 @@ module Kramdown
|
|
23
23
|
@previous_line_number = @start_line_number
|
24
24
|
end
|
25
25
|
|
26
|
-
# To make this unicode (multibyte) aware, we have to use #charpos which was added in Ruby
|
27
|
-
# version 2.0.0.
|
28
|
-
#
|
29
|
-
# This method will work with older versions of Ruby, however it will report incorrect line
|
30
|
-
# numbers if the scanned string contains multibyte characters.
|
31
|
-
if instance_methods.include?(:charpos)
|
32
|
-
def best_pos
|
33
|
-
charpos
|
34
|
-
end
|
35
|
-
else
|
36
|
-
def best_pos
|
37
|
-
pos
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
26
|
# Sets the byte position of the scan pointer.
|
42
27
|
#
|
43
28
|
# Note: This also resets some internal variables, so always use pos= when setting the position
|
44
29
|
# and don't use any other method for that!
|
45
30
|
def pos=(pos)
|
31
|
+
if self.pos > pos
|
32
|
+
@previous_line_number = @start_line_number
|
33
|
+
@previous_pos = 0
|
34
|
+
end
|
46
35
|
super
|
47
|
-
|
48
|
-
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return information needed to revert the byte position of the string scanner in a performant
|
39
|
+
# way.
|
40
|
+
#
|
41
|
+
# The returned data can be fed to #revert_pos to revert the position to the saved one.
|
42
|
+
#
|
43
|
+
# Note: Just saving #pos won't be enough.
|
44
|
+
def save_pos
|
45
|
+
[pos, @previous_pos, @previous_line_number]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Revert the position to one saved by #save_pos.
|
49
|
+
def revert_pos(data)
|
50
|
+
self.pos = data[0]
|
51
|
+
@previous_pos, @previous_line_number = data[1], data[2]
|
49
52
|
end
|
50
53
|
|
51
54
|
# Returns the line number for current charpos.
|
@@ -61,7 +64,7 @@ module Kramdown
|
|
61
64
|
old_pos = pos + 1
|
62
65
|
@previous_line_number += 1 while strscan.skip_until(/\n/) && strscan.pos <= old_pos
|
63
66
|
|
64
|
-
@previous_pos = (eos? ?
|
67
|
+
@previous_pos = (eos? ? pos : pos + 1)
|
65
68
|
@previous_line_number
|
66
69
|
end
|
67
70
|
|
data/lib/kramdown/version.rb
CHANGED
data/test/test_location.rb
CHANGED
@@ -151,6 +151,16 @@ describe 'location' do
|
|
151
151
|
* {:.line-5} * {:.line-5} one
|
152
152
|
* {:.line-6} two
|
153
153
|
),
|
154
|
+
'gh issue 158' => %(
|
155
|
+
😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁
|
156
|
+
{:.line-1}
|
157
|
+
|
158
|
+
- {:.line-4} T
|
159
|
+
{:.line-4}
|
160
|
+
|
161
|
+
# T
|
162
|
+
{:.line-7}
|
163
|
+
),
|
154
164
|
}
|
155
165
|
test_cases.each do |name, test_string|
|
156
166
|
it "Handles #{ name }" do
|
@@ -169,4 +179,28 @@ describe 'location' do
|
|
169
179
|
doc.warnings.must_equal ["Duplicate abbreviation ID 'duplicate' on line 4 - overwriting"]
|
170
180
|
end
|
171
181
|
|
182
|
+
it 'handles abbreviations' do
|
183
|
+
str = "This *is* ABC and\n**and** ABC second\nanother ABC\nas ABC as\nABC at the end.\n\n*[ABC]: ABC"
|
184
|
+
doc = Kramdown::Document.new(str)
|
185
|
+
doc.root.children.first.children.select {|e| e.type == :abbreviation}.each_with_index do |e, i|
|
186
|
+
assert_equal(i + 1, e.options[:location])
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'handles line breaks' do
|
191
|
+
str = "First \nsecond\\\\\nthird \n"
|
192
|
+
doc = Kramdown::Document.new(str)
|
193
|
+
doc.root.children.first.children.select {|e| e.type == :br}.each_with_index do |e, i|
|
194
|
+
assert_equal(i + 1, e.options[:location])
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'handles smart quotes' do
|
199
|
+
str = "This is 'first'\nand 'second' and\n'third'"
|
200
|
+
doc = Kramdown::Document.new(str)
|
201
|
+
doc.root.children.first.children.select {|e| e.type == :smart_quote}.each_with_index do |e, i|
|
202
|
+
assert_equal(((i + 1) /2.0).ceil, e.options[:location])
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
172
206
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<p>Lorem ipsum<sup id="fnref:first"><a href="#fn:first" class="footnote">1</a></sup> dolor sit amet.</p>
|
2
|
+
|
3
|
+
<p>Lorem ipsum<sup id="fnref:second"><a href="#fn:second" class="footnote">2</a></sup> dolor sit amet.</p>
|
4
|
+
|
5
|
+
<div class="footnotes">
|
6
|
+
<ol>
|
7
|
+
<li id="fn:first">
|
8
|
+
<p>Consecutur adisping.<sup id="fnref:third"><a href="#fn:third" class="footnote">3</a></sup> <a href="#fnref:first" class="reversefootnote">↩</a></p>
|
9
|
+
</li>
|
10
|
+
<li id="fn:second">
|
11
|
+
<p>Sed ut perspiciatis unde omnis. <a href="#fnref:second" class="reversefootnote">↩</a></p>
|
12
|
+
</li>
|
13
|
+
<li id="fn:third">
|
14
|
+
<p>Sed ut. <a href="#fnref:third" class="reversefootnote">↩</a></p>
|
15
|
+
</li>
|
16
|
+
</ol>
|
17
|
+
</div>
|
@@ -1,2 +1,2 @@
|
|
1
|
-
<p>This is just a normal paragraph
|
2
|
-
Containing a line break.</p>
|
1
|
+
<p>This is just a normal paragraph.<br />
|
2
|
+
Containing a manual line break above.</p>
|
@@ -1,2 +1,2 @@
|
|
1
|
-
This is just a normal paragraph.
|
2
|
-
Containing a line break.
|
1
|
+
This is just a normal paragraph.
|
2
|
+
Containing a manual line break above.
|
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kramdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Leitner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '5.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: coderay
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: stringex
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 1.5.1
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.5.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: prawn
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0.13'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.13'
|
69
69
|
description: |
|
@@ -75,14 +75,12 @@ executables:
|
|
75
75
|
extensions: []
|
76
76
|
extra_rdoc_files: []
|
77
77
|
files:
|
78
|
-
-
|
79
|
-
-
|
78
|
+
- AUTHORS
|
79
|
+
- CONTRIBUTERS
|
80
80
|
- COPYING
|
81
81
|
- README.md
|
82
|
-
-
|
82
|
+
- Rakefile
|
83
83
|
- VERSION
|
84
|
-
- CONTRIBUTERS
|
85
|
-
- bin/kramdown
|
86
84
|
- benchmark/benchmark.rb
|
87
85
|
- benchmark/benchmark.sh
|
88
86
|
- benchmark/generate_data.rb
|
@@ -90,6 +88,27 @@ files:
|
|
90
88
|
- benchmark/mdsyntax.text
|
91
89
|
- benchmark/testing.sh
|
92
90
|
- benchmark/timing.sh
|
91
|
+
- bin/kramdown
|
92
|
+
- data/kramdown/document.html
|
93
|
+
- data/kramdown/document.latex
|
94
|
+
- doc/_design.scss
|
95
|
+
- doc/bg.png
|
96
|
+
- doc/default.scss
|
97
|
+
- doc/default.template
|
98
|
+
- doc/documentation.page
|
99
|
+
- doc/documentation.template
|
100
|
+
- doc/index.page
|
101
|
+
- doc/installation.page
|
102
|
+
- doc/links.markdown
|
103
|
+
- doc/metainfo
|
104
|
+
- doc/news.feed
|
105
|
+
- doc/news.page
|
106
|
+
- doc/options.page
|
107
|
+
- doc/quickref.page
|
108
|
+
- doc/sidebar.template
|
109
|
+
- doc/syntax.page
|
110
|
+
- doc/tests.page
|
111
|
+
- doc/virtual
|
93
112
|
- lib/kramdown.rb
|
94
113
|
- lib/kramdown/compatibility.rb
|
95
114
|
- lib/kramdown/converter.rb
|
@@ -142,26 +161,7 @@ files:
|
|
142
161
|
- lib/kramdown/utils/unidecoder.rb
|
143
162
|
- lib/kramdown/version.rb
|
144
163
|
- man/man1/kramdown.1
|
145
|
-
-
|
146
|
-
- data/kramdown/document.latex
|
147
|
-
- doc/_design.scss
|
148
|
-
- doc/bg.png
|
149
|
-
- doc/default.scss
|
150
|
-
- doc/default.template
|
151
|
-
- doc/documentation.page
|
152
|
-
- doc/documentation.template
|
153
|
-
- doc/index.page
|
154
|
-
- doc/installation.page
|
155
|
-
- doc/links.markdown
|
156
|
-
- doc/metainfo
|
157
|
-
- doc/news.feed
|
158
|
-
- doc/news.page
|
159
|
-
- doc/options.page
|
160
|
-
- doc/quickref.page
|
161
|
-
- doc/sidebar.template
|
162
|
-
- doc/syntax.page
|
163
|
-
- doc/tests.page
|
164
|
-
- doc/virtual
|
164
|
+
- setup.rb
|
165
165
|
- test/run_tests.rb
|
166
166
|
- test/test_files.rb
|
167
167
|
- test/test_location.rb
|
@@ -470,6 +470,8 @@ files:
|
|
470
470
|
- test/testcases/span/04_footnote/footnote_nr.latex
|
471
471
|
- test/testcases/span/04_footnote/footnote_nr.options
|
472
472
|
- test/testcases/span/04_footnote/footnote_nr.text
|
473
|
+
- test/testcases/span/04_footnote/inside_footnote.html
|
474
|
+
- test/testcases/span/04_footnote/inside_footnote.text
|
473
475
|
- test/testcases/span/04_footnote/markers.html
|
474
476
|
- test/testcases/span/04_footnote/markers.latex
|
475
477
|
- test/testcases/span/04_footnote/markers.text
|
@@ -551,23 +553,23 @@ licenses:
|
|
551
553
|
metadata: {}
|
552
554
|
post_install_message:
|
553
555
|
rdoc_options:
|
554
|
-
- --main
|
556
|
+
- "--main"
|
555
557
|
- lib/kramdown/document.rb
|
556
558
|
require_paths:
|
557
559
|
- lib
|
558
560
|
required_ruby_version: !ruby/object:Gem::Requirement
|
559
561
|
requirements:
|
560
|
-
- -
|
562
|
+
- - ">="
|
561
563
|
- !ruby/object:Gem::Version
|
562
564
|
version: '0'
|
563
565
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
564
566
|
requirements:
|
565
|
-
- -
|
567
|
+
- - ">="
|
566
568
|
- !ruby/object:Gem::Version
|
567
569
|
version: '0'
|
568
570
|
requirements: []
|
569
571
|
rubyforge_project:
|
570
|
-
rubygems_version: 2.
|
572
|
+
rubygems_version: 2.2.2
|
571
573
|
signing_key:
|
572
574
|
specification_version: 4
|
573
575
|
summary: kramdown is a fast, pure-Ruby Markdown-superset converter.
|