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.

Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTERS +1 -1
  3. data/VERSION +1 -1
  4. data/data/kramdown/document.latex +2 -0
  5. data/doc/index.page +2 -2
  6. data/doc/sidebar.template +2 -2
  7. data/doc/tests.page +42 -43
  8. data/lib/kramdown/converter/html.rb +6 -2
  9. data/lib/kramdown/converter/kramdown.rb +1 -0
  10. data/lib/kramdown/converter/latex.rb +0 -2
  11. data/lib/kramdown/parser/base.rb +4 -3
  12. data/lib/kramdown/parser/gfm.rb +1 -1
  13. data/lib/kramdown/parser/html.rb +3 -3
  14. data/lib/kramdown/parser/kramdown.rb +1 -1
  15. data/lib/kramdown/parser/kramdown/abbreviation.rb +7 -3
  16. data/lib/kramdown/parser/kramdown/codespan.rb +2 -2
  17. data/lib/kramdown/parser/kramdown/emphasis.rb +6 -3
  18. data/lib/kramdown/parser/kramdown/extensions.rb +6 -6
  19. data/lib/kramdown/parser/kramdown/footnote.rb +1 -1
  20. data/lib/kramdown/parser/kramdown/header.rb +1 -1
  21. data/lib/kramdown/parser/kramdown/line_break.rb +1 -1
  22. data/lib/kramdown/parser/kramdown/link.rb +6 -5
  23. data/lib/kramdown/parser/kramdown/math.rb +2 -2
  24. data/lib/kramdown/parser/kramdown/paragraph.rb +1 -1
  25. data/lib/kramdown/parser/kramdown/smart_quotes.rb +2 -1
  26. data/lib/kramdown/parser/kramdown/table.rb +4 -3
  27. data/lib/kramdown/utils/string_scanner.rb +21 -18
  28. data/lib/kramdown/version.rb +1 -1
  29. data/test/test_location.rb +34 -0
  30. data/test/testcases/block/04_header/atx_header.html +2 -0
  31. data/test/testcases/block/04_header/atx_header.text +1 -0
  32. data/test/testcases/span/04_footnote/inside_footnote.html +17 -0
  33. data/test/testcases/span/04_footnote/inside_footnote.text +9 -0
  34. data/test/testcases_gfm/hard_line_breaks_off.html +2 -2
  35. data/test/testcases_gfm/hard_line_breaks_off.text +2 -2
  36. data/test/testcases_gfm/two_para_hard_line_breaks.html +1 -1
  37. data/test/testcases_gfm/two_para_hard_line_breaks.text +1 -1
  38. metadata +41 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 558b4355efb3892936bc7f01dd747401964a4f2c
4
- data.tar.gz: 4e3deeabf3bd99defba379802b3ff0007ed8cb9f
3
+ metadata.gz: d76ec0e7087a62788b9eb1d27027b1d4b4a2610e
4
+ data.tar.gz: 4b6fcefcd89fd851be053d975cdd825e07278c58
5
5
  SHA512:
6
- metadata.gz: f59c155c5d6d29b2e0f74ead74808b5f6f535abe879cc8dc4cba244d76b4d5fe372916c9d6f207b86cb7a5dcee29af9731ed12553db8c12ed897c3a53f2ccd10
7
- data.tar.gz: b18d1c60ea05561b59a37e97cd5208968cbce22cff4f4178d283a9772af7d60eaa85d3470f8f11728c2758284419af21c2f52f94fbb2882e7f291d7cb733b040
6
+ metadata.gz: 9c34e8bb6438d78c04d45c4237856530669933add8620ce12e3847729d6a49429b114be6dc00dcefe3ff2b450a4f947bfc36c2854dbb6c43799437f5429efbb8
7
+ data.tar.gz: 902838d7ee4add0e5dc66e67899b75fd9f44dddfff181eb6c99b20ffebd1af97c920f15bf6a87317c410ffef89f57ba28d9b6e48bbf1bc7de714389833ffee6a
@@ -1,6 +1,6 @@
1
1
  Count Name
2
2
  ======= ====
3
- 681 Thomas Leitner <t_leitner@gmx.at>
3
+ 700 Thomas Leitner <t_leitner@gmx.at>
4
4
  6 Gioele Barabucci <gioele@svario.it>
5
5
  4 Ted Pak <powerpak006@gmail.com>
6
6
  4 Arne Brasseur <arne@arnebrasseur.net>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.1
1
+ 1.4.2
@@ -41,6 +41,8 @@ encmap = {
41
41
  <% end %>
42
42
  <% end %>
43
43
 
44
+ \setcounter{footnote}{<%= @converter.options[:footnote_nr] - 1 %>}
45
+
44
46
  \hypersetup{colorlinks=true,urlcolor=blue}
45
47
 
46
48
  \begin{document}
@@ -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 (March 2013), being about 4x
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
@@ -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.1</span> and it was released
4
- on <span class="inline-important">2014-08-02</span></p>
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
 
@@ -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 (January 2014) ~2.5x faster than Maruku, ~4-6x faster
37
- than BlueFeather but ~30x slower than BlueCloth and RDiscount and ~150x slower than Redcarpet:
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-01-05 under ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux]
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.3.0 1.090000 0.020000 1.110000 ( 1.102094)
45
- Maruku 0.7.0 3.140000 0.010000 3.150000 ( 3.151116)
46
- BlueFeather 0.41 5.140000 0.000000 5.140000 ( 5.136591)
47
- BlueCloth 2.2.0 0.050000 0.000000 0.050000 ( 0.057502)
48
- RDiscount 2.0.7 0.020000 0.000000 0.020000 ( 0.015115)
49
- redcarpet 3.0.0 0.000000 0.000000 0.000000 ( 0.004641)
50
- ------------------------------------------- total: 9.470000sec
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.3.0 1.200000 0.000000 1.200000 ( 1.199684)
54
- Maruku 0.7.0 3.010000 0.040000 3.050000 ( 3.043411)
55
- BlueFeather 0.41 5.720000 0.000000 5.720000 ( 5.723845)
56
- BlueCloth 2.2.0 0.040000 0.000000 0.040000 ( 0.040749)
57
- RDiscount 2.0.7 0.020000 0.000000 0.020000 ( 0.017600)
58
- redcarpet 3.0.0 0.000000 0.000000 0.000000 ( 0.004822)
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.5368
62
- BlueFeather 4.7711
63
- BlueCloth 0.034
64
- RDiscount 0.0147
65
- redcarpet 0.004
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.3.0 0.220000 0.000000 0.220000 ( 0.217277)
70
- Maruku 0.7.0 0.850000 0.000000 0.850000 ( 0.847144)
71
- BlueFeather 0.41 1.290000 0.010000 1.300000 ( 1.291695)
72
- BlueCloth 2.2.0 0.010000 0.000000 0.010000 ( 0.012484)
73
- RDiscount 2.0.7 0.000000 0.000000 0.000000 ( 0.004158)
74
- redcarpet 3.0.0 0.000000 0.000000 0.000000 ( 0.001721)
75
- ------------------------------------------- total: 2.380000sec
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.3.0 0.210000 0.000000 0.210000 ( 0.215760)
79
- Maruku 0.7.0 0.590000 0.000000 0.590000 ( 0.591681)
80
- BlueFeather 0.41 1.360000 0.000000 1.360000 ( 1.362281)
81
- BlueCloth 2.2.0 0.010000 0.000000 0.010000 ( 0.013973)
82
- RDiscount 2.0.7 0.010000 0.000000 0.010000 ( 0.005797)
83
- redcarpet 3.0.0 0.000000 0.000000 0.000000 ( 0.001692)
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 2.7423
87
- BlueFeather 6.3139
88
- BlueCloth 0.0648
89
- RDiscount 0.0269
90
- redcarpet 0.0078
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.0p0]({relocatable: img/graph-ruby-2.1.0p0-0.png})
101
- ![jruby 1.7.3]({relocatable: img/graph-jruby-1.7.3-385.png})
102
- ![rubinius 2.0.0]({relocatable: img/graph-rubinius-2.0.0-0.png})
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
- @footnotes.each do |name, data, _, repeat|
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}", "&#8617;<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
 
@@ -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
- if tree.children.last && tree.children.last.type == type
101
- tree.children.last.value << text
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
 
@@ -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)
@@ -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 summary th tt}
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[:marker].last.value) if data[:marker]}
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) << Element.new(:abbreviation, abbr)
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
- reset_pos = @src.pos
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.pos = reset_pos
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.pos = reset_pos - 1
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.pos = reset_pos
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
- orig_pos = @src.pos
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.pos = orig_pos
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, nil, :location => start_line_number)
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
- reset_pos = @src.pos
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.pos = reset_pos
78
+ @src.revert_pos(saved_pos)
78
79
  add_text(result)
79
80
  return
80
81
  end
81
- alt_text = extract_string(reset_pos...@src.pos, @src).gsub(ESCAPED_CHARS, '\1')
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.pos = reset_pos
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.pos = reset_pos
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
- orig_pos = @src.pos
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.pos = orig_pos
35
+ @src.revert_pos(saved_pos)
36
36
  false
37
37
  end
38
38
  end
@@ -40,7 +40,7 @@ module Kramdown
40
40
  else
41
41
  @tree.children << new_block_el(:p, nil, nil, :location => start_line_number)
42
42
  result.lstrip!
43
- @tree.children.last.children << Element.new(@text_type, result)
43
+ add_text(result, @tree.children.last)
44
44
  end
45
45
  true
46
46
  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.pos = orig_pos
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.pos = orig_pos and return false if !pipe_on_line
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.pos = orig_pos
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
- @previous_line_number = @start_line_number
48
- @previous_pos = 0
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? ? best_pos : best_pos + 1)
67
+ @previous_pos = (eos? ? pos : pos + 1)
65
68
  @previous_line_number
66
69
  end
67
70
 
@@ -10,6 +10,6 @@
10
10
  module Kramdown
11
11
 
12
12
  # The kramdown version.
13
- VERSION = '1.4.1'
13
+ VERSION = '1.4.2'
14
14
 
15
15
  end
@@ -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
@@ -26,6 +26,8 @@
26
26
  ### not a header</p>
27
27
  </blockquote>
28
28
 
29
+ <h1>header #</h1>
30
+
29
31
  <h1>header</h1>
30
32
 
31
33
  <p># </p>
@@ -23,6 +23,7 @@ paragraph
23
23
  > blockquote
24
24
  ### not a header
25
25
 
26
+ # header \#
26
27
 
27
28
  # header
28
29
 
@@ -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">&#8617;</a></p>
9
+ </li>
10
+ <li id="fn:second">
11
+ <p>Sed ut perspiciatis unde omnis. <a href="#fnref:second" class="reversefootnote">&#8617;</a></p>
12
+ </li>
13
+ <li id="fn:third">
14
+ <p>Sed ut. <a href="#fnref:third" class="reversefootnote">&#8617;</a></p>
15
+ </li>
16
+ </ol>
17
+ </div>
@@ -0,0 +1,9 @@
1
+ Lorem ipsum[^first] dolor sit amet.
2
+
3
+ Lorem ipsum[^second] dolor sit amet.
4
+
5
+ [^first]: Consecutur adisping.[^third]
6
+
7
+ [^second]: Sed ut perspiciatis unde omnis.
8
+
9
+ [^third]: Sed ut.
@@ -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.
@@ -1,4 +1,4 @@
1
- <p>This is just a normal paragraph.<br />
1
+ <p>This is just a normal paragraph. <br />
2
2
  Containing a line break.</p>
3
3
 
4
4
  <p>Another paragraph.</p>
@@ -1,4 +1,4 @@
1
- This is just a normal paragraph.
1
+ This is just a normal paragraph.
2
2
  Containing a line break.
3
3
 
4
4
  Another paragraph.
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.1
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-08-02 00:00:00.000000000 Z
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
- - Rakefile
79
- - setup.rb
78
+ - AUTHORS
79
+ - CONTRIBUTERS
80
80
  - COPYING
81
81
  - README.md
82
- - AUTHORS
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
- - data/kramdown/document.html
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.0.3
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.