kramdown 1.11.1 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kramdown might be problematic. Click here for more details.

Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTERS +4 -1
  3. data/Rakefile +1 -1
  4. data/VERSION +1 -1
  5. data/doc/index.page +2 -2
  6. data/doc/syntax.page +52 -1
  7. data/lib/kramdown/compatibility.rb +12 -0
  8. data/lib/kramdown/converter/base.rb +11 -4
  9. data/lib/kramdown/converter/html.rb +16 -12
  10. data/lib/kramdown/converter/kramdown.rb +10 -2
  11. data/lib/kramdown/converter/syntax_highlighter/rouge.rb +1 -1
  12. data/lib/kramdown/document.rb +1 -1
  13. data/lib/kramdown/options.rb +32 -3
  14. data/lib/kramdown/parser/gfm.rb +33 -2
  15. data/lib/kramdown/parser/html.rb +3 -3
  16. data/lib/kramdown/parser/kramdown.rb +9 -8
  17. data/lib/kramdown/parser/kramdown/list.rb +5 -0
  18. data/lib/kramdown/parser/kramdown/paragraph.rb +5 -1
  19. data/lib/kramdown/version.rb +1 -1
  20. data/man/man1/kramdown.1 +27 -0
  21. data/test/test_files.rb +29 -1
  22. data/test/testcases/block/06_codeblock/rouge/multiple.html +11 -0
  23. data/test/testcases/block/06_codeblock/rouge/multiple.options +4 -0
  24. data/test/testcases/block/06_codeblock/rouge/multiple.text +11 -0
  25. data/test/testcases/block/13_definition_list/auto_ids.html +15 -0
  26. data/test/testcases/block/13_definition_list/auto_ids.text +18 -0
  27. data/test/testcases/block/13_definition_list/item_ial.html +5 -0
  28. data/test/testcases/block/13_definition_list/item_ial.text +8 -0
  29. data/test/testcases/block/15_math/no_engine.html +3 -0
  30. data/test/testcases/block/15_math/no_engine.options +1 -0
  31. data/test/testcases/block/15_math/no_engine.text +2 -0
  32. data/test/testcases/span/autolinks/url_links.html +5 -5
  33. data/test/testcases/span/math/no_engine.html +1 -0
  34. data/test/testcases/span/math/no_engine.options +1 -0
  35. data/test/testcases/span/math/no_engine.text +1 -0
  36. data/test/testcases_gfm/paragraph_end-disabled.html +31 -0
  37. data/test/testcases_gfm/paragraph_end-disabled.options +1 -0
  38. data/test/testcases_gfm/paragraph_end-disabled.text +27 -0
  39. data/test/testcases_gfm/paragraph_end.html +38 -0
  40. data/test/testcases_gfm/paragraph_end.text +27 -0
  41. metadata +18 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8bc1e487da8d63a73fe2118ad1e7615cf3c1d3d3
4
- data.tar.gz: 52412dce1a755ebdc0a5534311533150417046de
3
+ metadata.gz: d6f21a2a725bc5ab410d5402155cb27018d6edec
4
+ data.tar.gz: eaae19e9a6f514b79947e72fa76b2f6ab8f3a51b
5
5
  SHA512:
6
- metadata.gz: a3e7c3a5e8dc8826ad39c1cd2c051aab9bf0632310adfae7a921287b1b16c049675f2a96a1994b29671dc1b7a2278d230cd9939c30a60c2ae40c813104e4b753
7
- data.tar.gz: 7d5c35699257687c3968f49e042d3683886691a493c18211d4dc06ddb82232edb56fe2fdb3603f0d20a22ab7c25210377155d2ca495b5cc52be0f314fa0154b0
6
+ metadata.gz: 519e94399dbcfa7acb14b77078e39f7db120b6c10da0510e0d7ad6754fb158cf96923f592ad4ec12ff11861eb2dd73585257e9dd6eed27eacb47bebb32c0aaae
7
+ data.tar.gz: 715a23901826864e7fc25aa93dd3566222931d3d22b5ecdb92db20e0cc4fd454cdae729d01004c18088f8398f9a88d5e2cbea3c05ef2d13bcc79afc34f50185a
@@ -1,6 +1,6 @@
1
1
  Count Name
2
2
  ======= ====
3
- 802 Thomas Leitner <t_leitner@gmx.at>
3
+ 816 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>
@@ -10,6 +10,7 @@
10
10
  3 Ben Armston <ben.armston@googlemail.com>
11
11
  3 Alex Marandon <contact@alexmarandon.com>
12
12
  2 Tom Thorogood <me+github@tomthorogood.co.uk>
13
+ 2 Shuanglei Tao <tsl0922@gmail.com>
13
14
  2 Parker Moore <parkrmoore@gmail.com>
14
15
  2 Nathanael Jones <nathanael.jones@gmail.com>
15
16
  2 Max Meyer <dev@fedux.org>
@@ -43,4 +44,6 @@
43
44
  1 Diego Galeota <diegobg123@gmail.com>
44
45
  1 Damien Pollet <damien.pollet@gmail.com>
45
46
  1 Christopher Jefferson <caj21@st-andrews.ac.uk>
47
+ 1 Cédric Boutillier <cedric.boutillier@gmail.com>
46
48
  1 Alex Tomlins <alex.tomlins@digital.cabinet-office.gov.uk>
49
+ 1 Alexey Vasiliev <le0pard@users.noreply.github.com>
data/Rakefile CHANGED
@@ -75,7 +75,7 @@ end
75
75
  if defined?(Webgen)
76
76
  desc "Generate the HTML documentation"
77
77
  task :htmldoc do
78
- ruby "-S webgen"
78
+ ruby "-Ilib -S webgen"
79
79
  end
80
80
  CLOBBER << "htmldoc/"
81
81
  CLOBBER << "webgen-tmp"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.11.1
1
+ 1.12.0
@@ -97,8 +97,8 @@ extensions that have been made popular by the [PHP Markdown Extra] package and [
97
97
  It is probably the fastest pure-Ruby Markdown converter available (September 2014), being about 3x
98
98
  faster than [Maruku] and about 4.5x faster than [BlueFeather].
99
99
 
100
- Version **1.11.1**{:itemprop="softwareVersion"} released on
101
- **2016-05-01**{:itemprop="datePublished"}, [more news](news.html)
100
+ Version **1.12.0**{:itemprop="softwareVersion"} released on
101
+ **2016-08-15**{:itemprop="datePublished"}, [more news](news.html)
102
102
  {: style="text-align: center; font-size: 80%"}
103
103
 
104
104
  </div>
@@ -500,6 +500,46 @@ It is much better to write such a list in the following way:
500
500
  > Also, Markdown uses a fixed number of spaces/tabs to indent the lines that belong to a list item!
501
501
  {: .markdown-difference}
502
502
 
503
+ Unordered and ordered lists work the same way in regard to the indentation:
504
+
505
+ * list 1 item 1
506
+ * list 1 item 2 (indent 1 space)
507
+ * list 1 item 3 (indent 2 spaces)
508
+ * list 1 item 4 (indent 3 spaces)
509
+ * lazy text belonging to above item 4
510
+
511
+ ^
512
+
513
+ 1. list 1 item 1
514
+ 2. list 1 item 2 (indent 1 space)
515
+ 3. list 1 item 3 (indent 2 spaces)
516
+ 4. list 1 item 4 (indent 3 spaces)
517
+ 5. lazy text belonging to above item 4
518
+
519
+ ^
520
+
521
+ * list 1 item 1
522
+ * nested list item 1
523
+ * nested list item 2
524
+ * list 1 item 2
525
+ * nested list item 1
526
+
527
+ ^
528
+
529
+ 1. list 1 item 1
530
+ 1. nested list item 1
531
+ 2. nested list item 2
532
+ 10. list 1 item 2
533
+ 1. nested list item 1
534
+
535
+ ^
536
+
537
+ 1. text for this list item
538
+ further text (indent 3 spaces)
539
+
540
+ 10. text for this list item
541
+ further text (indent 4 spaces)
542
+
503
543
  When using tabs for indenting the content of a list item, remember that tab stops occur at multiples
504
544
  of four for kramdown. Tabs are correctly converted to spaces for calculating the indentation. For
505
545
  example:
@@ -642,7 +682,8 @@ then the first part of the definition. The line with the definition marker may o
642
682
  separated from the preceding paragraph by a blank line. The leading tabs or spaces are stripped away
643
683
  from this first line of the definition to allow for a nice alignment with the following definition
644
684
  content. Each line of the preceding paragraph is taken to be a term and the lines separately parsed
645
- as span-level elements.
685
+ as span-level elements. Each such term may optionally start with an [IAL](#inline-attribute-lists)
686
+ that should be applied to the term.
646
687
 
647
688
  The following is a simple definition list:
648
689
 
@@ -697,6 +738,16 @@ paragraph otherwise:
697
738
  The rules about having any block-level element as first element in a list item also apply to a
698
739
  definition.
699
740
 
741
+ As mentioned at the beginning, an optional IAL for applying attributes to a term or a definition can
742
+ be used:
743
+
744
+ {:#term} Term with id="term"
745
+ : {:.cls} Definition with class "cls"
746
+
747
+ {:#term1} First term
748
+ {:#term2} Second term
749
+ : {:.cls} Definition
750
+
700
751
 
701
752
  ## Tables
702
753
 
@@ -10,6 +10,8 @@
10
10
  #
11
11
  # :stopdoc:
12
12
 
13
+ require 'rbconfig'
14
+
13
15
  if RUBY_VERSION <= '1.8.6'
14
16
  require 'rexml/parsers/baseparser'
15
17
  module REXML
@@ -34,3 +36,13 @@ if RUBY_VERSION <= '1.8.6'
34
36
  end
35
37
 
36
38
  end
39
+
40
+ if !Symbol.instance_methods.include?("<=>")
41
+
42
+ class Symbol
43
+ def <=>(other)
44
+ self.to_s <=> other.to_s
45
+ end
46
+ end
47
+
48
+ end
@@ -231,10 +231,7 @@ module Kramdown
231
231
  # ID.
232
232
  def generate_id(str)
233
233
  str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids]
234
- gen_id = str.gsub(/^[^a-zA-Z]+/, '')
235
- gen_id.tr!('^a-zA-Z0-9 -', '')
236
- gen_id.tr!(' ', '-')
237
- gen_id.downcase!
234
+ gen_id = basic_generate_id(str)
238
235
  gen_id = 'section' if gen_id.length == 0
239
236
  @used_ids ||= {}
240
237
  if @used_ids.has_key?(gen_id)
@@ -245,6 +242,16 @@ module Kramdown
245
242
  @options[:auto_id_prefix] + gen_id
246
243
  end
247
244
 
245
+ # The basic version of the ID generator, without any special provisions for empty or unique
246
+ # IDs.
247
+ def basic_generate_id(str)
248
+ gen_id = str.gsub(/^[^a-zA-Z]+/, '')
249
+ gen_id.tr!('^a-zA-Z0-9 -', '')
250
+ gen_id.tr!(' ', '-')
251
+ gen_id.downcase!
252
+ gen_id
253
+ end
254
+
248
255
  SMART_QUOTE_INDICES = {:lsquo => 0, :rsquo => 1, :ldquo => 2, :rdquo => 3} # :nodoc:
249
256
 
250
257
  # Return the entity that represents the given smart_quote element.
@@ -165,7 +165,14 @@ module Kramdown
165
165
  alias :convert_dd :convert_li
166
166
 
167
167
  def convert_dt(el, indent)
168
- format_as_block_html(el.type, el.attr, inner(el, indent), indent)
168
+ attr = el.attr.dup
169
+ @stack.last.options[:ial][:refs].each do |ref|
170
+ if ref =~ /\Aauto_ids(?:-([\w-]+))?/
171
+ attr['id'] = ($1 ? $1 : '') << basic_generate_id(el.options[:raw_text])
172
+ break
173
+ end
174
+ end if !attr['id'] && @stack.last.options[:ial] && @stack.last.options[:ial][:refs]
175
+ format_as_block_html(el.type, attr, inner(el, indent), indent)
169
176
  end
170
177
 
171
178
  def convert_html_element(el, indent)
@@ -236,14 +243,7 @@ module Kramdown
236
243
  end
237
244
 
238
245
  def convert_a(el, indent)
239
- res = inner(el, indent)
240
- attr = el.attr.dup
241
- if attr['href'].start_with?('mailto:')
242
- mail_addr = attr['href'][7..-1]
243
- attr['href'] = obfuscate('mailto') << ":" << obfuscate(mail_addr)
244
- res = obfuscate(res) if res == mail_addr
245
- end
246
- format_as_span_html(el.type, attr, res)
246
+ format_as_span_html(el.type, el.attr, inner(el, indent))
247
247
  end
248
248
 
249
249
  def convert_img(el, indent)
@@ -315,10 +315,14 @@ module Kramdown
315
315
  def convert_math(el, indent)
316
316
  if (result = format_math(el, :indent => indent))
317
317
  result
318
- elsif el.options[:category] == :block
319
- format_as_block_html('pre', el.attr, "$$\n#{el.value}\n$$", indent)
320
318
  else
321
- format_as_span_html('span', el.attr, "$#{el.value}$")
319
+ attr = el.attr.dup
320
+ (attr['class'] = (attr['class'] || '') << " kdmath").lstrip!
321
+ if el.options[:category] == :block
322
+ format_as_block_html('div', attr, "$$\n#{el.value}\n$$", indent)
323
+ else
324
+ format_as_span_html('span', attr, "$#{el.value}$")
325
+ end
322
326
  end
323
327
  end
324
328
 
@@ -31,7 +31,7 @@ module Kramdown
31
31
 
32
32
  def convert(el, opts = {:indent => 0})
33
33
  res = send("convert_#{el.type}", el, opts)
34
- if ![:html_element, :li, :dd, :td].include?(el.type) && (ial = ial_for_element(el))
34
+ if ![:html_element, :li, :dt, :dd, :td].include?(el.type) && (ial = ial_for_element(el))
35
35
  res << ial
36
36
  res << "\n\n" if Element.category(el) == :block
37
37
  elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] &&
@@ -174,7 +174,11 @@ module Kramdown
174
174
  end
175
175
 
176
176
  def convert_dt(el, opts)
177
- inner(el, opts) << "\n"
177
+ result = ''
178
+ if ial = ial_for_element(el)
179
+ result << ial << " "
180
+ end
181
+ result << inner(el, opts) << "\n"
178
182
  end
179
183
 
180
184
  HTML_TAGS_WITH_BODY=['div', 'script', 'iframe', 'textarea']
@@ -414,6 +418,10 @@ module Kramdown
414
418
  (el.options[:ial][:refs].include?('toc') rescue nil)
415
419
  res = "footnotes" << (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
416
420
  (el.options[:ial][:refs].include?('footnotes') rescue nil)
421
+ if el.type == :dl && el.options[:ial] && el.options[:ial][:refs]
422
+ auto_ids = el.options[:ial][:refs].select {|ref| ref =~ /\Aauto_ids/}.join(" ")
423
+ res = auto_ids << (res.strip.empty? ? '' : " #{res}") unless auto_ids.empty?
424
+ end
417
425
  res.strip.empty? ? nil : "{:#{res}}"
418
426
  end
419
427
 
@@ -27,7 +27,7 @@ module Kramdown::Converter::SyntaxHighlighter
27
27
  lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text)
28
28
  return nil if opts[:disable] || !lexer
29
29
 
30
- formatter = (opts.delete(:formatter) || ::Rouge::Formatters::HTML).new(opts)
30
+ formatter = (opts.fetch(:formatter, ::Rouge::Formatters::HTML)).new(opts)
31
31
  formatter.format(lexer.lex(text))
32
32
  end
33
33
 
@@ -53,7 +53,7 @@ module Kramdown
53
53
  unless defined?(@@data_dir)
54
54
  require 'rbconfig'
55
55
  @@data_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'kramdown'))
56
- @@data_dir = File.expand_path(File.join(Config::CONFIG["datadir"], "kramdown")) if !File.exists?(@@data_dir)
56
+ @@data_dir = File.expand_path(File.join(RbConfig::CONFIG["datadir"], "kramdown")) if !File.exists?(@@data_dir)
57
57
  raise "kramdown data directory not found! This is a bug, please report it!" unless File.directory?(@@data_dir)
58
58
  end
59
59
  @@data_dir
@@ -133,14 +133,14 @@ module Kramdown
133
133
  # - a comma separated string which is split into an array of values
134
134
  # - or an array.
135
135
  #
136
- # Additionally, the array is checked for the correct size.
137
- def self.simple_array_validator(val, name, size)
136
+ # Optionally, the array is checked for the correct size.
137
+ def self.simple_array_validator(val, name, size = nil)
138
138
  if String === val
139
139
  val = val.split(/,/)
140
140
  elsif !(Array === val)
141
141
  raise Kramdown::Error, "Invalid type #{val.class} for option #{name}"
142
142
  end
143
- if val.size != size
143
+ if size && val.size != size
144
144
  raise Kramdown::Error, "Option #{name} needs exactly #{size} values"
145
145
  end
146
146
  val
@@ -593,6 +593,35 @@ Default: '&8617;'
593
593
  Used by: HTML converter
594
594
  EOF
595
595
 
596
+ define(:gfm_quirks, Object, [:paragraph_end], <<EOF) do |val|
597
+ Enables a set of GFM specific quirks
598
+
599
+ The way how GFM is transformed on Github often differs from the way
600
+ kramdown does things. Many of these differences are negligible but
601
+ others are not.
602
+
603
+ This option allows one to enable/disable certain GFM quirks, i.e. ways
604
+ in which GFM parsing differs from kramdown parsing.
605
+
606
+ The value has to be a list of quirk names that should be enabled,
607
+ separated by commas. Possible names are:
608
+
609
+ * paragraph_end
610
+
611
+ Disables the kramdown restriction that at least one blank line has to
612
+ be used after a paragraph before a new block element can be started.
613
+
614
+ Note that if this quirk is used, lazy line wrapping does not fully
615
+ work anymore!
616
+
617
+ Default: paragraph_end
618
+ Used by: GFM parser
619
+ EOF
620
+ val = simple_array_validator(val, :gfm_quirks)
621
+ val.map! {|v| str_to_sym(v.to_s)}
622
+ val
623
+ end
624
+
596
625
  end
597
626
 
598
627
  end
@@ -17,8 +17,16 @@ module Kramdown
17
17
  def initialize(source, options)
18
18
  super
19
19
  @span_parsers.delete(:line_break) if @options[:hard_wrap]
20
+ if @options[:gfm_quirks].include?(:paragraph_end)
21
+ atx_header_parser = :atx_header_gfm_quirk
22
+ @paragraph_end = self.class::PARAGRAPH_END_GFM
23
+ else
24
+ atx_header_parser = :atx_header_gfm
25
+ @paragraph_end = self.class::PARAGRAPH_END
26
+ end
27
+
20
28
  {:codeblock_fenced => :codeblock_fenced_gfm,
21
- :atx_header => :atx_header_gfm}.each do |current, replacement|
29
+ :atx_header => atx_header_parser}.each do |current, replacement|
22
30
  i = @block_parsers.index(current)
23
31
  @block_parsers.delete(current)
24
32
  @block_parsers.insert(i, replacement)
@@ -60,9 +68,26 @@ module Kramdown
60
68
 
61
69
  ATX_HEADER_START = /^\#{1,6}\s/
62
70
  define_parser(:atx_header_gfm, ATX_HEADER_START, nil, 'parse_atx_header')
71
+ define_parser(:atx_header_gfm_quirk, ATX_HEADER_START)
72
+
73
+ # Copied from kramdown/parser/kramdown/header.rb, removed the first line
74
+ def parse_atx_header_gfm_quirk
75
+ start_line_number = @src.current_line_number
76
+ @src.check(ATX_HEADER_MATCH)
77
+ level, text, id = @src[1], @src[2].to_s.strip, @src[3]
78
+ return false if text.empty?
79
+
80
+ @src.pos += @src.matched_size
81
+ el = new_block_el(:header, nil, nil, :level => level.length, :raw_text => text, :location => start_line_number)
82
+ add_text(text, el)
83
+ el.attr['id'] = id if id
84
+ @tree.children << el
85
+ true
86
+ end
63
87
 
88
+ FENCED_CODEBLOCK_START = /^[~`]{3,}/
64
89
  FENCED_CODEBLOCK_MATCH = /^(([~`]){3,})\s*?((\S+?)(?:\?\S*)?)?\s*?\n(.*?)^\1\2*\s*?\n/m
65
- define_parser(:codeblock_fenced_gfm, /^[~`]{3,}/, nil, 'parse_codeblock_fenced')
90
+ define_parser(:codeblock_fenced_gfm, FENCED_CODEBLOCK_START, nil, 'parse_codeblock_fenced')
66
91
 
67
92
  STRIKETHROUGH_DELIM = /~~/
68
93
  STRIKETHROUGH_MATCH = /#{STRIKETHROUGH_DELIM}[^\s~](.*?)[^\s~]#{STRIKETHROUGH_DELIM}/m
@@ -87,6 +112,12 @@ module Kramdown
87
112
  ESCAPED_CHARS_GFM = /\\([\\.*_+`<>()\[\]{}#!:\|"'\$=\-~])/
88
113
  define_parser(:escaped_chars_gfm, ESCAPED_CHARS_GFM, '\\\\', :parse_escaped_chars)
89
114
 
115
+ PARAGRAPH_END_GFM = /#{LAZY_END}|#{LIST_START}|#{ATX_HEADER_START}|#{DEFINITION_LIST_START}|#{BLOCKQUOTE_START}|#{FENCED_CODEBLOCK_START}/
116
+
117
+ def paragraph_end
118
+ @paragraph_end
119
+ end
120
+
90
121
  end
91
122
  end
92
123
  end
@@ -35,8 +35,8 @@ module Kramdown
35
35
  HTML_ENTITY_RE = /&([\w:][\-\w\.:]*);|&#(\d+);|&\#x([0-9a-fA-F]+);/
36
36
 
37
37
  HTML_CONTENT_MODEL_BLOCK = %w{address applet article aside blockquote body
38
- dd details div dl fieldset figure figcaption footer form header hgroup iframe li map menu nav
39
- noscript object section summary td}
38
+ dd details div dl fieldset figure figcaption footer form header hgroup iframe li main
39
+ map menu nav noscript object section summary td}
40
40
  HTML_CONTENT_MODEL_SPAN = %w{a abbr acronym b bdo big button cite caption del dfn dt em
41
41
  h1 h2 h3 h4 h5 h6 i ins label legend optgroup p q rb rbc
42
42
  rp rt rtc ruby select small span strong sub sup th tt}
@@ -57,7 +57,7 @@ module Kramdown
57
57
  strong sub sup tt u var}
58
58
  HTML_BLOCK_ELEMENTS = %w{address article aside applet body blockquote caption col colgroup dd div dl dt fieldset
59
59
  figcaption footer form h1 h2 h3 h4 h5 h6 header hgroup hr html head iframe legend menu
60
- li map nav ol optgroup p pre section summary table tbody td th thead tfoot tr ul}
60
+ li main map nav ol optgroup p pre section summary table tbody td th thead tfoot tr ul}
61
61
  HTML_ELEMENTS_WITHOUT_BODY = %w{area base br col command embed hr img input keygen link meta param source track wbr}
62
62
 
63
63
  HTML_ELEMENT = Hash.new(false)
@@ -178,7 +178,11 @@ module Kramdown
178
178
  last_blank = nil
179
179
  update_tree(child)
180
180
  update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial]
181
- update_raw_header_text(child) if child.type == :header
181
+ # DEPRECATED: option auto_id_stripping will be removed in 2.0 because then this will be
182
+ # the default behaviour
183
+ if child.type == :dt || (child.type == :header && @options[:auto_id_stripping])
184
+ update_raw_text(child)
185
+ end
182
186
  child
183
187
  end
184
188
  end.flatten!
@@ -267,11 +271,8 @@ module Kramdown
267
271
  end
268
272
  end
269
273
 
270
- # Update the raw header text for automatic ID generation.
271
- def update_raw_header_text(header)
272
- # DEPRECATED: option auto_id_stripping will be removed in 2.0 because then this will be the
273
- # default behaviour
274
- return unless @options[:auto_id_stripping]
274
+ # Update the raw text for automatic ID generation.
275
+ def update_raw_text(item)
275
276
  raw_text = ''
276
277
 
277
278
  append_text = lambda do |child|
@@ -282,8 +283,8 @@ module Kramdown
282
283
  end
283
284
  end
284
285
 
285
- append_text.call(header)
286
- header.options[:raw_text] = raw_text
286
+ append_text.call(item)
287
+ item.options[:raw_text] = raw_text
287
288
  end
288
289
 
289
290
  # Create a new block-level element, taking care of applying a preceding block IAL if it
@@ -166,6 +166,11 @@ module Kramdown
166
166
  deflist.options[:location] = para.options[:location] # take location from preceding para which is the first definition term
167
167
  para.children.first.value.split(/\n/).each do |term|
168
168
  el = Element.new(:dt, nil, nil, :location => @src.current_line_number)
169
+ term.sub!(self.class::LIST_ITEM_IAL) do
170
+ parse_attribute_list($1, el.options[:ial] ||= {})
171
+ ''
172
+ end
173
+ el.options[:raw_text] = term
169
174
  el.children << Element.new(:raw_text, term)
170
175
  deflist.children << el
171
176
  end
@@ -31,7 +31,7 @@ module Kramdown
31
31
  def parse_paragraph
32
32
  start_line_number = @src.current_line_number
33
33
  result = @src.scan(PARAGRAPH_MATCH)
34
- while !@src.match?(self.class::PARAGRAPH_END)
34
+ while !@src.match?(paragraph_end)
35
35
  result << @src.scan(PARAGRAPH_MATCH)
36
36
  end
37
37
  result.rstrip!
@@ -46,6 +46,10 @@ module Kramdown
46
46
  end
47
47
  define_parser(:paragraph, PARAGRAPH_START)
48
48
 
49
+ def paragraph_end
50
+ self.class::PARAGRAPH_END
51
+ end
52
+
49
53
  end
50
54
  end
51
55
  end
@@ -10,6 +10,6 @@
10
10
  module Kramdown
11
11
 
12
12
  # The kramdown version.
13
- VERSION = '1.11.1'
13
+ VERSION = '1.12.0'
14
14
 
15
15
  end
@@ -208,6 +208,33 @@ Default: 1
208
208
  Used by: HTML converter
209
209
 
210
210
 
211
+ .TP
212
+ .B \-\-gfm-quirks ARG
213
+
214
+ Enables a set of GFM specific quirks
215
+
216
+ The way how GFM is transformed on Github often differs from the way
217
+ kramdown does things. Many of these differences are negligible but
218
+ others are not.
219
+
220
+ This option allows one to enable/disable certain GFM quirks, i.e. ways
221
+ in which GFM parsing differs from kramdown parsing.
222
+
223
+ The value has to be a list of quirk names that should be enabled,
224
+ separated by commas. Possible names are:
225
+
226
+ * paragraph_end
227
+
228
+ Disables the kramdown restriction that at least one blank line has to
229
+ be used after a paragraph before a new block element can be started.
230
+
231
+ Note that if this quirk is used, lazy line wrapping does not fully
232
+ work anymore!
233
+
234
+ Default: paragraph_end
235
+ Used by: GFM parser
236
+
237
+
211
238
  .TP
212
239
  .B \-\-[no\-]hard-wrap
213
240
 
@@ -12,6 +12,22 @@ require 'kramdown'
12
12
  require 'yaml'
13
13
  require 'tmpdir'
14
14
 
15
+ begin
16
+ require 'kramdown/converter/syntax_highlighter/rouge'
17
+
18
+ # custom formatter for tests
19
+ class RougeHTMLFormatters < ::Rouge::Formatters::HTML
20
+ tag 'rouge_html_formatters'
21
+
22
+ def stream(tokens, &b)
23
+ yield %(<div class="custom-class">)
24
+ super
25
+ yield %(</div>)
26
+ end
27
+ end
28
+ rescue LoadError, SyntaxError, NameError
29
+ end
30
+
15
31
  Encoding.default_external = 'utf-8' if RUBY_VERSION >= '1.9'
16
32
 
17
33
  class TestFiles < Minitest::Test
@@ -19,7 +35,8 @@ class TestFiles < Minitest::Test
19
35
  EXCLUDE_KD_FILES = [('test/testcases/block/04_header/with_auto_ids.text' if RUBY_VERSION <= '1.8.6'), # bc of dep stringex not working
20
36
  ('test/testcases/span/03_codespan/rouge/' if RUBY_VERSION < '2.0'), #bc of rouge
21
37
  ('test/testcases/block/06_codeblock/rouge/' if RUBY_VERSION < '2.0'), #bc of rouge
22
-
38
+ ('test/testcases/block/15_math/itex2mml.text' if RUBY_PLATFORM == 'java'), # bc of itextomml
39
+ ('test/testcases/span/math/itex2mml.text' if RUBY_PLATFORM == 'java'), # bc of itextomml
23
40
  ].compact
24
41
 
25
42
  # Generate test methods for kramdown-to-xxx conversion
@@ -52,6 +69,7 @@ class TestFiles < Minitest::Test
52
69
  'test/testcases/block/04_header/with_auto_ids.html', # bc of auto_ids=true option
53
70
  'test/testcases/block/04_header/header_type_offset.html', # bc of header_offset option
54
71
  'test/testcases/block/06_codeblock/rouge/simple.html', # bc of double surrounding <div>
72
+ 'test/testcases/block/06_codeblock/rouge/multiple.html', # bc of double surrounding <div>
55
73
  ('test/testcases/span/03_codespan/rouge/simple.html' if RUBY_VERSION < '2.0'),
56
74
  ('test/testcases/span/03_codespan/rouge/disabled.html' if RUBY_VERSION < '2.0'),
57
75
  'test/testcases/block/15_math/ritex.html', # bc of tidy
@@ -161,6 +179,7 @@ class TestFiles < Minitest::Test
161
179
  ('test/testcases/span/03_codespan/rouge/simple.text' if RUBY_VERSION < '2.0'), #bc of rouge
162
180
  ('test/testcases/span/03_codespan/rouge/disabled.text' if RUBY_VERSION < '2.0'), #bc of rouge
163
181
  'test/testcases/block/06_codeblock/rouge/simple.text',
182
+ 'test/testcases/block/06_codeblock/rouge/multiple.text', # check, what document contain more, than one code block
164
183
  'test/testcases/block/15_math/ritex.text', # bc of tidy
165
184
  'test/testcases/span/math/ritex.text', # bc of tidy
166
185
  'test/testcases/block/15_math/itex2mml.text', # bc of tidy
@@ -203,6 +222,7 @@ class TestFiles < Minitest::Test
203
222
  'test/testcases/block/09_html/html_to_native/table_simple.html', # bc of invalidly converted simple table
204
223
  'test/testcases/block/06_codeblock/whitespace.html', # bc of entity to char conversion
205
224
  'test/testcases/block/06_codeblock/rouge/simple.html', # bc of double surrounding <div>
225
+ 'test/testcases/block/06_codeblock/rouge/multiple.html', # bc of double surrounding <div>
206
226
  'test/testcases/block/11_ial/simple.html', # bc of change of ordering of attributes in header
207
227
  'test/testcases/span/03_codespan/highlighting.html', # bc of span elements inside code element
208
228
  'test/testcases/block/04_header/with_auto_ids.html', # bc of auto_ids=true option
@@ -294,6 +314,7 @@ class TestFiles < Minitest::Test
294
314
  'test/testcases/span/extension/comment.text',
295
315
  'test/testcases/span/ial/simple.text',
296
316
  'test/testcases/span/line_breaks/normal.text',
317
+ 'test/testcases/span/math/normal.text',
297
318
  'test/testcases/span/text_substitutions/entities_as_char.text',
298
319
  'test/testcases/span/text_substitutions/entities.text',
299
320
  'test/testcases/span/text_substitutions/typography.text',
@@ -301,6 +322,9 @@ class TestFiles < Minitest::Test
301
322
  ('test/testcases/span/03_codespan/rouge/disabled.text' if RUBY_VERSION < '2.0'),
302
323
  ('test/testcases/block/06_codeblock/rouge/simple.text' if RUBY_VERSION < '2.0'), #bc of rouge
303
324
  ('test/testcases/block/06_codeblock/rouge/disabled.text' if RUBY_VERSION < '2.0'), #bc of rouge
325
+ ('test/testcases/block/06_codeblock/rouge/multiple.text' if RUBY_VERSION < '2.0'), #bc of rouge
326
+ ('test/testcases/block/15_math/itex2mml.text' if RUBY_PLATFORM == 'java'), # bc of itextomml
327
+ ('test/testcases/span/math/itex2mml.text' if RUBY_PLATFORM == 'java'), # bc of itextomml
304
328
  ].compact
305
329
 
306
330
  # Generate test methods for gfm-to-html conversion
@@ -331,11 +355,15 @@ class TestFiles < Minitest::Test
331
355
  'test/testcases/block/04_header/with_auto_ids.text',
332
356
  ].compact
333
357
 
358
+ EXCLUDE_MODIFY = ['test/testcases/block/06_codeblock/rouge/multiple.text', # bc of HTMLFormater in options
359
+ ]
360
+
334
361
  # Generate test methods for asserting that converters don't modify the document tree.
335
362
  Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file|
336
363
  opts_file = text_file.sub(/\.text$/, '.options')
337
364
  options = File.exist?(opts_file) ? YAML::load(File.read(opts_file)) : {:auto_ids => false, :footnote_nr => 1}
338
365
  (Kramdown::Converter.constants.map {|c| c.to_sym} - [:Base, :RemoveHtmlTags, :MathEngine, :SyntaxHighlighter]).each do |conv_class|
366
+ next if EXCLUDE_MODIFY.any? {|f| text_file =~ /#{f}$/}
339
367
  next if conv_class == :Pdf && (RUBY_VERSION < '2.0' || EXCLUDE_PDF_MODIFY.any? {|f| text_file =~ /#{f}$/})
340
368
  define_method("test_whether_#{conv_class}_modifies_tree_with_file_#{text_file.tr('.', '_')}") do
341
369
  doc = Kramdown::Document.new(File.read(text_file), options)
@@ -0,0 +1,11 @@
1
+ <div class="language-ruby highlighter-rouge"><div class="custom-class"><pre class="highlight"><code><span class="nb">puts</span> <span class="s2">"Hello"</span>
2
+ </code></pre>
3
+ </div></div>
4
+
5
+ <div class="language-ruby highlighter-rouge"><div class="custom-class"><pre class="highlight"><code><span class="nb">puts</span> <span class="s2">"World"</span>
6
+ </code></pre>
7
+ </div></div>
8
+
9
+ <div class="language-php highlighter-rouge"><div class="custom-class"><pre class="highlight"><code><span class="nv">$foo</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Bar</span><span class="p">;</span>
10
+ </code></pre>
11
+ </div></div>
@@ -0,0 +1,4 @@
1
+ :syntax_highlighter: rouge
2
+ :syntax_highlighter_opts:
3
+ default_lang: ruby
4
+ formatter: !ruby/class 'RougeHTMLFormatters'
@@ -0,0 +1,11 @@
1
+ ~~~ ruby
2
+ puts "Hello"
3
+ ~~~
4
+
5
+ ~~~ ruby
6
+ puts "World"
7
+ ~~~
8
+
9
+ ~~~ php?start_inline=1
10
+ $foo = new Bar;
11
+ ~~~
@@ -0,0 +1,15 @@
1
+ <dl>
2
+ <dt id="item">item</dt>
3
+ <dd>def</dd>
4
+ <dt id="item2">item2</dt>
5
+ <dd>def</dd>
6
+ </dl>
7
+
8
+ <dl>
9
+ <dt id="prefix-item">item</dt>
10
+ <dd>def</dd>
11
+ <dt id="prefix-item2">item2</dt>
12
+ <dd>def</dd>
13
+ <dt id="id">item3</dt>
14
+ <dd>def</dd>
15
+ </dl>
@@ -0,0 +1,18 @@
1
+ {:auto_ids}
2
+ item
3
+ : def
4
+
5
+ item2
6
+ : def
7
+
8
+ ^
9
+
10
+ {:auto_ids-prefix-}
11
+ item
12
+ : def
13
+
14
+ item2
15
+ : def
16
+
17
+ {:#id} item3
18
+ : def
@@ -9,4 +9,9 @@ continued</dd>
9
9
  </dd>
10
10
  <dd class="cls">IAL at last
11
11
  no code bc of text</dd>
12
+ <dt class="class">term</dt>
13
+ <dd>definition</dd>
14
+ <dt class="class1">term1</dt>
15
+ <dt class="class2">term2</dt>
16
+ <dd>definition</dd>
12
17
  </dl>
@@ -6,3 +6,11 @@ item
6
6
  code
7
7
  : {:.cls} IAL at last
8
8
  no code bc of text
9
+
10
+
11
+ {:.class} term
12
+ : definition
13
+
14
+ {:.class1} term1
15
+ {:.class2} term2
16
+ : definition
@@ -0,0 +1,3 @@
1
+ <div id="math-id" class="kdmath">$$
2
+ 5+5
3
+ $$</div>
@@ -0,0 +1 @@
1
+ :math_engine: ~
@@ -0,0 +1,2 @@
1
+ {: #math-id}
2
+ $$5+5$$
@@ -1,12 +1,12 @@
1
1
  <p>This should be a <a href="http://www.example.com/">http://www.example.com/</a> link.
2
- This should be a <a href="&#109;&#097;&#105;&#108;&#116;&#111;:&#106;&#111;&#104;&#110;&#046;&#100;&#111;&#101;&#064;&#101;&#120;&#097;&#109;&#112;&#108;&#101;&#046;&#099;&#111;&#109;">&#106;&#111;&#104;&#110;&#046;&#100;&#111;&#101;&#064;&#101;&#120;&#097;&#109;&#112;&#108;&#101;&#046;&#099;&#111;&#109;</a> link.
3
- As should <a href="&#109;&#097;&#105;&#108;&#116;&#111;:&#106;&#111;&#104;&#110;&#046;&#100;&#111;&#101;&#064;&#101;&#120;&#097;&#109;&#112;&#108;&#101;&#046;&#099;&#111;&#109;">&#106;&#111;&#104;&#110;&#046;&#100;&#111;&#101;&#064;&#101;&#120;&#097;&#109;&#112;&#108;&#101;&#046;&#099;&#111;&#109;</a> this.
4
- As should <a href="&#109;&#097;&#105;&#108;&#116;&#111;:&#106;&#111;&#104;&#110;&#095;&#100;&#111;&#101;&#064;&#101;&#120;&#097;&#109;&#112;&#108;&#101;&#046;&#099;&#111;&#109;">&#106;&#111;&#104;&#110;&#095;&#100;&#111;&#101;&#064;&#101;&#120;&#097;&#109;&#112;&#108;&#101;&#046;&#099;&#111;&#109;</a> this.
5
- As should <a href="&#109;&#097;&#105;&#108;&#116;&#111;:&#067;&#083;&#083;&#064;&#101;&#120;&#097;&#109;&#112;&#108;&#101;&#046;&#099;&#111;&#109;"><abbr title="Cascading">CSS</abbr>@example.com</a> this.
2
+ This should be a <a href="mailto:john.doe@example.com">john.doe@example.com</a> link.
3
+ As should <a href="mailto:john.doe@example.com">john.doe@example.com</a> this.
4
+ As should <a href="mailto:john_doe@example.com">john_doe@example.com</a> this.
5
+ As should <a href="mailto:CSS@example.com"><abbr title="Cascading">CSS</abbr>@example.com</a> this.
6
6
  Another ampersand <a href="http://www.example.com/?doit&amp;x=y">http://www.example.com/?doit&amp;x=y</a> link.
7
7
  More entities <a href="http://www.example.com/?doit&amp;x=&quot;y&amp;z=y">http://www.example.com/?doit&amp;x=&quot;y&amp;z=y</a>.</p>
8
8
 
9
- <p>Email international <a href="&#109;&#097;&#105;&#108;&#116;&#111;:ü&#098;&#117;&#110;&#103;&#064;&#109;&#097;&#099;&#104;&#116;&#046;&#100;&#101;&#110;&#046;&#109;&#101;&#105;&#115;&#116;&#101;&#114;&#046;&#100;&#101;">ü&#098;&#117;&#110;&#103;&#064;&#109;&#097;&#099;&#104;&#116;&#046;&#100;&#101;&#110;&#046;&#109;&#101;&#105;&#115;&#116;&#101;&#114;&#046;&#100;&#101;</a>, <a href="&#109;&#097;&#105;&#108;&#116;&#111;:ü&#046;äß&#064;&#104;ü&#108;&#115;&#101;&#046;&#100;&#101;">ü&#046;äß&#064;&#104;ü&#108;&#115;&#101;&#046;&#100;&#101;</a>
9
+ <p>Email international <a href="mailto:übung@macht.den.meister.de">übung@macht.den.meister.de</a>, <a href="mailto:ü.äß@hülse.de">ü.äß@hülse.de</a>
10
10
  Email invalid: &lt;<a href="mailtos:me@example.com">me@example.com</a>&gt;</p>
11
11
 
12
12
  <p>Autolink with underscore: <a href="http://www.example.com/with_under_score">http://www.example.com/with_under_score</a></p>
@@ -0,0 +1 @@
1
+ <p><span class="kdmath">$5+5$</span> inline math</p>
@@ -0,0 +1 @@
1
+ :math_engine: ~
@@ -0,0 +1 @@
1
+ $$5+5$$ inline math
@@ -0,0 +1,31 @@
1
+ <p>A<br />
2
+ - b</p>
3
+
4
+ <p>This is a list<br />
5
+ - or is it</p>
6
+
7
+ <p>blockquote<br />
8
+ &gt; text</p>
9
+
10
+ <p>header<br />
11
+ # text</p>
12
+
13
+ <p>codeblock fenced<br />
14
+ <code>
15
+ puts hello world
16
+ </code></p>
17
+
18
+ <ul>
19
+ <li>
20
+ <p>level 1<br />
21
+ some text</p>
22
+
23
+ <p>begin level 2<br />
24
+ * level 2<br />
25
+ * level 2</p>
26
+ </li>
27
+ </ul>
28
+
29
+ <h1 id="h1">h1</h1>
30
+ <p>## h2<br />
31
+ ### h3</p>
@@ -0,0 +1 @@
1
+ :gfm_quirks: []
@@ -0,0 +1,27 @@
1
+ A
2
+ - b
3
+
4
+ This is a list
5
+ - or is it
6
+
7
+ blockquote
8
+ > text
9
+
10
+ header
11
+ # text
12
+
13
+ codeblock fenced
14
+ ```
15
+ puts hello world
16
+ ```
17
+
18
+ * level 1
19
+ some text
20
+
21
+ begin level 2
22
+ * level 2
23
+ * level 2
24
+
25
+ # h1
26
+ ## h2
27
+ ### h3
@@ -0,0 +1,38 @@
1
+ <p>A</p>
2
+ <ul>
3
+ <li>b</li>
4
+ </ul>
5
+
6
+ <p>This is a list</p>
7
+ <ul>
8
+ <li>or is it</li>
9
+ </ul>
10
+
11
+ <p>blockquote</p>
12
+ <blockquote>
13
+ <p>text</p>
14
+ </blockquote>
15
+
16
+ <p>header</p>
17
+ <h1>text</h1>
18
+
19
+ <p>codeblock fenced</p>
20
+ <pre><code>puts hello world
21
+ </code></pre>
22
+
23
+ <ul>
24
+ <li>
25
+ <p>level 1<br />
26
+ some text</p>
27
+
28
+ <p>begin level 2</p>
29
+ <ul>
30
+ <li>level 2</li>
31
+ <li>level 2</li>
32
+ </ul>
33
+ </li>
34
+ </ul>
35
+
36
+ <h1>h1</h1>
37
+ <h2>h2</h2>
38
+ <h3>h3</h3>
@@ -0,0 +1,27 @@
1
+ A
2
+ - b
3
+
4
+ This is a list
5
+ - or is it
6
+
7
+ blockquote
8
+ > text
9
+
10
+ header
11
+ # text
12
+
13
+ codeblock fenced
14
+ ```
15
+ puts hello world
16
+ ```
17
+
18
+ * level 1
19
+ some text
20
+
21
+ begin level 2
22
+ * level 2
23
+ * level 2
24
+
25
+ # h1
26
+ ## h2
27
+ ### h3
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kramdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.1
4
+ version: 1.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-01 00:00:00.000000000 Z
11
+ date: 2016-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -316,6 +316,9 @@ files:
316
316
  - test/testcases/block/06_codeblock/rouge/disabled.html
317
317
  - test/testcases/block/06_codeblock/rouge/disabled.options
318
318
  - test/testcases/block/06_codeblock/rouge/disabled.text
319
+ - test/testcases/block/06_codeblock/rouge/multiple.html
320
+ - test/testcases/block/06_codeblock/rouge/multiple.options
321
+ - test/testcases/block/06_codeblock/rouge/multiple.text
319
322
  - test/testcases/block/06_codeblock/rouge/simple.html
320
323
  - test/testcases/block/06_codeblock/rouge/simple.options
321
324
  - test/testcases/block/06_codeblock/rouge/simple.text
@@ -467,6 +470,8 @@ files:
467
470
  - test/testcases/block/12_extension/options2.text
468
471
  - test/testcases/block/12_extension/options3.html
469
472
  - test/testcases/block/12_extension/options3.text
473
+ - test/testcases/block/13_definition_list/auto_ids.html
474
+ - test/testcases/block/13_definition_list/auto_ids.text
470
475
  - test/testcases/block/13_definition_list/definition_at_beginning.html
471
476
  - test/testcases/block/13_definition_list/definition_at_beginning.text
472
477
  - test/testcases/block/13_definition_list/deflist_ial.html
@@ -525,6 +530,9 @@ files:
525
530
  - test/testcases/block/15_math/mathjaxnode_semantics.html.19
526
531
  - test/testcases/block/15_math/mathjaxnode_semantics.options
527
532
  - test/testcases/block/15_math/mathjaxnode_semantics.text
533
+ - test/testcases/block/15_math/no_engine.html
534
+ - test/testcases/block/15_math/no_engine.options
535
+ - test/testcases/block/15_math/no_engine.text
528
536
  - test/testcases/block/15_math/normal.html
529
537
  - test/testcases/block/15_math/normal.text
530
538
  - test/testcases/block/15_math/ritex.html
@@ -657,6 +665,9 @@ files:
657
665
  - test/testcases/span/math/mathjaxnode.html.19
658
666
  - test/testcases/span/math/mathjaxnode.options
659
667
  - test/testcases/span/math/mathjaxnode.text
668
+ - test/testcases/span/math/no_engine.html
669
+ - test/testcases/span/math/no_engine.options
670
+ - test/testcases/span/math/no_engine.text
660
671
  - test/testcases/span/math/normal.html
661
672
  - test/testcases/span/math/normal.text
662
673
  - test/testcases/span/math/ritex.html
@@ -697,6 +708,11 @@ files:
697
708
  - test/testcases_gfm/hard_line_breaks_off.html
698
709
  - test/testcases_gfm/hard_line_breaks_off.options
699
710
  - test/testcases_gfm/hard_line_breaks_off.text
711
+ - test/testcases_gfm/paragraph_end-disabled.html
712
+ - test/testcases_gfm/paragraph_end-disabled.options
713
+ - test/testcases_gfm/paragraph_end-disabled.text
714
+ - test/testcases_gfm/paragraph_end.html
715
+ - test/testcases_gfm/paragraph_end.text
700
716
  - test/testcases_gfm/strikethrough.html
701
717
  - test/testcases_gfm/strikethrough.html.19
702
718
  - test/testcases_gfm/strikethrough.text