kramdown 2.0.0.beta2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of kramdown might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CONTRIBUTERS +14 -3
- data/VERSION +1 -1
- data/bin/kramdown +48 -19
- data/lib/kramdown/converter/base.rb +2 -1
- data/lib/kramdown/converter/html.rb +47 -25
- data/lib/kramdown/converter/kramdown.rb +11 -6
- data/lib/kramdown/converter/latex.rb +1 -1
- data/lib/kramdown/converter/math_engine/mathjax.rb +7 -33
- data/lib/kramdown/converter/syntax_highlighter.rb +1 -1
- data/lib/kramdown/converter/syntax_highlighter/rouge.rb +20 -9
- data/lib/kramdown/element.rb +30 -3
- data/lib/kramdown/options.rb +57 -8
- data/lib/kramdown/parser/base.rb +3 -1
- data/lib/kramdown/parser/html.rb +8 -8
- data/lib/kramdown/parser/kramdown.rb +11 -2
- data/lib/kramdown/parser/kramdown/autolink.rb +2 -2
- data/lib/kramdown/parser/kramdown/blank_line.rb +2 -2
- data/lib/kramdown/parser/kramdown/block_boundary.rb +3 -2
- data/lib/kramdown/parser/kramdown/codespan.rb +12 -2
- data/lib/kramdown/parser/kramdown/emphasis.rb +1 -1
- data/lib/kramdown/parser/kramdown/extensions.rb +14 -8
- data/lib/kramdown/parser/kramdown/header.rb +3 -2
- data/lib/kramdown/parser/kramdown/html.rb +4 -10
- data/lib/kramdown/parser/kramdown/link.rb +3 -2
- data/lib/kramdown/parser/kramdown/list.rb +64 -33
- data/lib/kramdown/parser/kramdown/math.rb +1 -1
- data/lib/kramdown/parser/kramdown/paragraph.rb +3 -3
- data/lib/kramdown/parser/kramdown/table.rb +3 -3
- data/lib/kramdown/utils/html.rb +9 -0
- data/lib/kramdown/version.rb +1 -1
- data/man/man1/kramdown.1 +31 -1
- data/test/test_files.rb +18 -11
- data/test/test_location.rb +2 -2
- data/test/test_string_scanner_kramdown.rb +1 -1
- data/test/testcases/block/03_paragraph/standalone_image.html +8 -0
- data/test/testcases/block/03_paragraph/standalone_image.text +6 -0
- data/test/testcases/block/04_header/atx_header.html +6 -0
- data/test/testcases/block/04_header/atx_header.text +6 -0
- data/test/testcases/block/06_codeblock/guess_lang_css_class.html +15 -0
- data/test/testcases/block/06_codeblock/guess_lang_css_class.options +2 -0
- data/test/testcases/block/06_codeblock/guess_lang_css_class.text +13 -0
- data/test/testcases/block/09_html/processing_instruction.html +5 -6
- data/test/testcases/block/09_html/standalone_image_in_div.htmlinput +7 -0
- data/test/testcases/block/09_html/standalone_image_in_div.text +8 -0
- data/test/testcases/block/12_extension/options.html +4 -4
- data/test/testcases/block/12_extension/options.text +2 -0
- data/test/testcases/block/12_extension/options2.html +4 -4
- data/test/testcases/block/14_table/table_with_footnote.html +4 -4
- data/test/testcases/block/15_math/gh_128.html +1 -2
- data/test/testcases/block/15_math/normal.html +16 -15
- data/test/testcases/block/16_toc/toc_with_footnotes.html +4 -4
- data/test/testcases/cjk-line-break.html +4 -0
- data/test/testcases/cjk-line-break.options +1 -0
- data/test/testcases/cjk-line-break.text +12 -0
- data/test/testcases/span/02_emphasis/normal.html +4 -0
- data/test/testcases/span/02_emphasis/normal.text +4 -0
- data/test/testcases/span/03_codespan/normal-css-class.html +1 -0
- data/test/testcases/span/03_codespan/normal-css-class.options +2 -0
- data/test/testcases/span/03_codespan/normal-css-class.text +1 -0
- data/test/testcases/span/04_footnote/backlink_inline.html +21 -21
- data/test/testcases/span/04_footnote/backlink_text.html +4 -4
- data/test/testcases/span/04_footnote/footnote_nr.html +6 -6
- data/test/testcases/span/04_footnote/footnote_prefix.html +12 -0
- data/test/testcases/span/04_footnote/footnote_prefix.options +1 -0
- data/test/testcases/span/04_footnote/footnote_prefix.text +4 -0
- data/test/testcases/span/04_footnote/inside_footnote.html +9 -9
- data/test/testcases/span/04_footnote/markers.html +16 -16
- data/test/testcases/span/04_footnote/placement.html +4 -4
- data/test/testcases/span/04_footnote/regexp_problem.html +4 -4
- data/test/testcases/span/04_footnote/without_backlink.html +3 -3
- data/test/testcases/span/05_html/normal.html +1 -1
- data/test/testcases/span/abbreviations/in_footnote.html +4 -4
- data/test/testcases/span/math/normal.html +4 -4
- metadata +35 -15
- data/test/testcases/block/15_math/mathjax_preview.html +0 -4
- data/test/testcases/block/15_math/mathjax_preview.options +0 -2
- data/test/testcases/block/15_math/mathjax_preview.text +0 -5
- data/test/testcases/block/15_math/mathjax_preview_as_code.html +0 -4
- data/test/testcases/block/15_math/mathjax_preview_as_code.options +0 -3
- data/test/testcases/block/15_math/mathjax_preview_as_code.text +0 -5
- data/test/testcases/block/15_math/mathjax_preview_simple.html +0 -4
- data/test/testcases/block/15_math/mathjax_preview_simple.options +0 -2
- data/test/testcases/block/15_math/mathjax_preview_simple.text +0 -5
@@ -42,7 +42,7 @@ module Kramdown
|
|
42
42
|
#
|
43
43
|
# == Special Implementation Details
|
44
44
|
#
|
45
|
-
# HTML converter:: If the syntax highlighter is used with
|
45
|
+
# HTML converter:: If the syntax highlighter is used with an HTML converter, it should return
|
46
46
|
# :block type text correctly wrapped (i.e. normally inside a pre-tag, but may
|
47
47
|
# also be a table-tag or just a div-tag) but :span type text *without* a
|
48
48
|
# code-tag!
|
@@ -24,8 +24,11 @@ module Kramdown::Converter::SyntaxHighlighter
|
|
24
24
|
def self.call(converter, text, lang, type, call_opts)
|
25
25
|
opts = options(converter, type)
|
26
26
|
call_opts[:default_lang] = opts[:default_lang]
|
27
|
+
return nil unless lang || opts[:default_lang] || opts[:guess_lang]
|
28
|
+
|
27
29
|
lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text)
|
28
|
-
return nil if opts[:disable] || !lexer || lexer.tag == "plaintext"
|
30
|
+
return nil if opts[:disable] || !lexer || (lexer.tag == "plaintext" && !opts[:guess_lang])
|
31
|
+
|
29
32
|
opts[:css_class] ||= 'highlight' # For backward compatibility when using Rouge 2.0
|
30
33
|
formatter = formatter_class(opts).new(opts)
|
31
34
|
formatter.format(lexer.lex(text))
|
@@ -42,18 +45,26 @@ module Kramdown::Converter::SyntaxHighlighter
|
|
42
45
|
cache = converter.data[:syntax_highlighter_rouge] = {}
|
43
46
|
|
44
47
|
opts = converter.options[:syntax_highlighter_opts].dup
|
45
|
-
span_opts = (opts.delete(:span) || {}).dup
|
46
|
-
block_opts = (opts.delete(:block) || {}).dup
|
47
|
-
[span_opts, block_opts].each do |hash|
|
48
|
-
hash.keys.each do |k|
|
49
|
-
hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k)
|
50
|
-
end
|
51
|
-
end
|
52
48
|
|
53
|
-
|
49
|
+
span_opts = opts.delete(:span)&.dup || {}
|
50
|
+
block_opts = opts.delete(:block)&.dup || {}
|
51
|
+
normalize_keys(span_opts)
|
52
|
+
normalize_keys(block_opts)
|
53
|
+
|
54
|
+
cache[:span] = opts.merge(span_opts)
|
55
|
+
cache[:span][:wrap] = false
|
56
|
+
|
54
57
|
cache[:block] = opts.merge(block_opts)
|
55
58
|
end
|
56
59
|
|
60
|
+
def self.normalize_keys(hash)
|
61
|
+
return if hash.empty?
|
62
|
+
|
63
|
+
hash.keys.each do |k|
|
64
|
+
hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
57
68
|
def self.formatter_class(opts = {})
|
58
69
|
case formatter = opts[:formatter]
|
59
70
|
when Class
|
data/lib/kramdown/element.rb
CHANGED
@@ -14,6 +14,14 @@ module Kramdown
|
|
14
14
|
# kramdown only uses this one class for representing all available elements in an element tree
|
15
15
|
# (paragraphs, headers, emphasis, ...). The type of element can be set via the #type accessor.
|
16
16
|
#
|
17
|
+
# The root of a kramdown element tree has to be an element of type :root. It needs to have certain
|
18
|
+
# option keys set so that conversions work correctly. If only a part of a tree should be
|
19
|
+
# converted, duplicate the root node and assign the #children appropriately, e.g:
|
20
|
+
#
|
21
|
+
# root = doc.root
|
22
|
+
# new_root = root.dup
|
23
|
+
# new_root.children = [root.children[0]] # assign new array with elements to convert
|
24
|
+
#
|
17
25
|
# Following is a description of all supported element types.
|
18
26
|
#
|
19
27
|
# Note that the option :location may contain the start line number of an element in the source
|
@@ -42,6 +50,7 @@ module Kramdown
|
|
42
50
|
#
|
43
51
|
# :options:: This key may be used to store options that were set during parsing of the document.
|
44
52
|
#
|
53
|
+
# :footnote_count:: This key stores the number of actually referenced footnotes of the document.
|
45
54
|
#
|
46
55
|
# === :blank
|
47
56
|
#
|
@@ -500,9 +509,11 @@ module Kramdown
|
|
500
509
|
end
|
501
510
|
|
502
511
|
def inspect #:nodoc:
|
503
|
-
"<kd:#{@type}
|
504
|
-
"#{
|
505
|
-
"#{
|
512
|
+
"<kd:#{@type}" \
|
513
|
+
"#{value.nil? ? '' : ' value=' + value.inspect}" \
|
514
|
+
"#{attr.empty? ? '' : ' attr=' + attr.inspect}" \
|
515
|
+
"#{options.empty? ? '' : ' options=' + options.inspect}" \
|
516
|
+
"#{children.empty? ? '' : ' children=' + children.inspect}>"
|
506
517
|
end
|
507
518
|
|
508
519
|
CATEGORY = {} # :nodoc:
|
@@ -519,6 +530,22 @@ module Kramdown
|
|
519
530
|
CATEGORY[el.type] || el.options[:category]
|
520
531
|
end
|
521
532
|
|
533
|
+
# syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :block+ with
|
534
|
+
# +el.block?+.
|
535
|
+
#
|
536
|
+
# Returns boolean true or false.
|
537
|
+
def block?
|
538
|
+
(CATEGORY[type] || options[:category]) == :block
|
539
|
+
end
|
540
|
+
|
541
|
+
# syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :span+ with
|
542
|
+
# +el.span?+.
|
543
|
+
#
|
544
|
+
# Returns boolean true or false.
|
545
|
+
def span?
|
546
|
+
(CATEGORY[type] || options[:category]) == :span
|
547
|
+
end
|
548
|
+
|
522
549
|
end
|
523
550
|
|
524
551
|
end
|
data/lib/kramdown/options.rb
CHANGED
@@ -328,7 +328,11 @@ module Kramdown
|
|
328
328
|
Used by: HTML converter, kramdown converter
|
329
329
|
EOF
|
330
330
|
|
331
|
-
|
331
|
+
TOC_LEVELS_RANGE = (1..6).freeze
|
332
|
+
TOC_LEVELS_ARRAY = TOC_LEVELS_RANGE.to_a.freeze
|
333
|
+
private_constant :TOC_LEVELS_RANGE, :TOC_LEVELS_ARRAY
|
334
|
+
|
335
|
+
define(:toc_levels, Object, TOC_LEVELS_ARRAY, <<~EOF) do |val|
|
332
336
|
Defines the levels that are used for the table of contents
|
333
337
|
|
334
338
|
The individual levels can be specified by separating them with commas
|
@@ -347,12 +351,20 @@ module Kramdown
|
|
347
351
|
else
|
348
352
|
raise Kramdown::Error, "Invalid syntax for option toc_levels"
|
349
353
|
end
|
350
|
-
when Array
|
351
|
-
|
354
|
+
when Array
|
355
|
+
unless val.eql?(TOC_LEVELS_ARRAY)
|
356
|
+
val = val.map(&:to_i).uniq
|
357
|
+
end
|
358
|
+
when Range
|
359
|
+
if val.eql?(TOC_LEVELS_RANGE)
|
360
|
+
val = TOC_LEVELS_ARRAY
|
361
|
+
else
|
362
|
+
val = val.map(&:to_i).uniq
|
363
|
+
end
|
352
364
|
else
|
353
365
|
raise Kramdown::Error, "Invalid type #{val.class} for option toc_levels"
|
354
366
|
end
|
355
|
-
if val.any? {|i| !
|
367
|
+
if val.any? {|i| !TOC_LEVELS_RANGE.cover?(i) }
|
356
368
|
raise Kramdown::Error, "Level numbers for option toc_levels have to be integers from 1 to 6"
|
357
369
|
end
|
358
370
|
val
|
@@ -377,7 +389,11 @@ module Kramdown
|
|
377
389
|
simple_array_validator(val, :latex_headers, 6)
|
378
390
|
end
|
379
391
|
|
380
|
-
|
392
|
+
SMART_QUOTES_ENTITIES = %w[lsquo rsquo ldquo rdquo].freeze
|
393
|
+
SMART_QUOTES_STR = SMART_QUOTES_ENTITIES.join(',').freeze
|
394
|
+
private_constant :SMART_QUOTES_ENTITIES, :SMART_QUOTES_STR
|
395
|
+
|
396
|
+
define(:smart_quotes, Object, SMART_QUOTES_ENTITIES, <<~EOF) do |val|
|
381
397
|
Defines the HTML entity names or code points for smart quote output
|
382
398
|
|
383
399
|
The entities identified by entity name or code point that should be
|
@@ -388,9 +404,13 @@ module Kramdown
|
|
388
404
|
Default: lsquo,rsquo,ldquo,rdquo
|
389
405
|
Used by: HTML/Latex converter
|
390
406
|
EOF
|
391
|
-
val
|
392
|
-
|
393
|
-
|
407
|
+
if val == SMART_QUOTES_STR || val == SMART_QUOTES_ENTITIES
|
408
|
+
SMART_QUOTES_ENTITIES
|
409
|
+
else
|
410
|
+
val = simple_array_validator(val, :smart_quotes, 4)
|
411
|
+
val.map! {|v| Integer(v) rescue v }
|
412
|
+
val
|
413
|
+
end
|
394
414
|
end
|
395
415
|
|
396
416
|
define(:typographic_symbols, Object, {}, <<~EOF) do |val|
|
@@ -550,6 +570,35 @@ module Kramdown
|
|
550
570
|
Used by: HTML converter
|
551
571
|
EOF
|
552
572
|
|
573
|
+
define(:footnote_prefix, String, '', <<~EOF)
|
574
|
+
Prefix used for footnote IDs
|
575
|
+
|
576
|
+
This option can be used to set a prefix for footnote IDs. This is useful
|
577
|
+
when rendering multiple documents into the same output file to avoid
|
578
|
+
duplicate IDs. The prefix should only contain characters that are valid
|
579
|
+
in an ID!
|
580
|
+
|
581
|
+
Default: ''
|
582
|
+
Used by: HTML
|
583
|
+
EOF
|
584
|
+
|
585
|
+
define(:remove_line_breaks_for_cjk, Boolean, false, <<~EOF)
|
586
|
+
Specifies whether line breaks should be removed between CJK characters
|
587
|
+
|
588
|
+
Default: false
|
589
|
+
Used by: HTML converter
|
590
|
+
EOF
|
591
|
+
|
592
|
+
define(:forbidden_inline_options, Object, %w[template], <<~EOF) do |val|
|
593
|
+
Defines the options that may not be set using the {::options} extension
|
594
|
+
|
595
|
+
Default: template
|
596
|
+
Used by: HTML converter
|
597
|
+
EOF
|
598
|
+
val.map! {|item| item.kind_of?(String) ? str_to_sym(item) : item }
|
599
|
+
simple_array_validator(val, :forbidden_inline_options)
|
600
|
+
end
|
601
|
+
|
553
602
|
end
|
554
603
|
|
555
604
|
end
|
data/lib/kramdown/parser/base.rb
CHANGED
@@ -93,7 +93,9 @@ module Kramdown
|
|
93
93
|
raise "The source text contains invalid characters for the used encoding #{source.encoding}"
|
94
94
|
end
|
95
95
|
source = source.encode('UTF-8')
|
96
|
-
source.gsub(/\r\n?/, "\n")
|
96
|
+
source.gsub!(/\r\n?/, "\n")
|
97
|
+
source.chomp!
|
98
|
+
source << "\n"
|
97
99
|
end
|
98
100
|
|
99
101
|
# This helper method adds the given +text+ either to the last element in the +tree+ if it is a
|
data/lib/kramdown/parser/html.rb
CHANGED
@@ -16,7 +16,7 @@ module Kramdown
|
|
16
16
|
|
17
17
|
module Parser
|
18
18
|
|
19
|
-
# Used for parsing
|
19
|
+
# Used for parsing an HTML document.
|
20
20
|
#
|
21
21
|
# The parsing code is in the Parser module that can also be used by other parsers.
|
22
22
|
class Html < Base
|
@@ -286,7 +286,7 @@ module Kramdown
|
|
286
286
|
src = Kramdown::Utils::StringScanner.new(raw)
|
287
287
|
result = []
|
288
288
|
until src.eos?
|
289
|
-
if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/))
|
289
|
+
if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/o))
|
290
290
|
result << Element.new(:text, tmp)
|
291
291
|
src.scan(HTML_ENTITY_RE)
|
292
292
|
val = src[1] || (src[2]&.to_i) || src[3].hex
|
@@ -324,7 +324,7 @@ module Kramdown
|
|
324
324
|
tmp = []
|
325
325
|
last_is_p = false
|
326
326
|
el.children.each do |c|
|
327
|
-
if
|
327
|
+
if !c.block? || c.type == :text
|
328
328
|
unless last_is_p
|
329
329
|
tmp << Element.new(:p, nil, nil, transparent: true)
|
330
330
|
last_is_p = true
|
@@ -354,8 +354,8 @@ module Kramdown
|
|
354
354
|
el.children = el.children.reject do |c|
|
355
355
|
i += 1
|
356
356
|
c.type == :text && c.value.strip.empty? &&
|
357
|
-
(i == 0 || i == el.children.length - 1 || (
|
358
|
-
|
357
|
+
(i == 0 || i == el.children.length - 1 || ((el.children[i - 1]).block? &&
|
358
|
+
(el.children[i + 1]).block?))
|
359
359
|
end
|
360
360
|
end
|
361
361
|
|
@@ -581,11 +581,11 @@ module Kramdown
|
|
581
581
|
@src = Kramdown::Utils::StringScanner.new(adapt_source(source))
|
582
582
|
|
583
583
|
while true
|
584
|
-
if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/))
|
584
|
+
if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/o))
|
585
585
|
@tree.children << Element.new(:xml_pi, result.strip, nil, category: :block)
|
586
|
-
elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/))
|
586
|
+
elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/o))
|
587
587
|
# ignore the doctype
|
588
|
-
elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/))
|
588
|
+
elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/o))
|
589
589
|
@tree.children << Element.new(:xml_comment, result.strip, nil, category: :block)
|
590
590
|
else
|
591
591
|
break
|
@@ -79,6 +79,8 @@ module Kramdown
|
|
79
79
|
@span_parsers = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link,
|
80
80
|
:smart_quotes, :inline_math, :span_extensions, :html_entity,
|
81
81
|
:typographic_syms, :line_break, :escaped_chars]
|
82
|
+
|
83
|
+
@span_pattern_cache ||= Hash.new { |h, k| h[k] = {} }
|
82
84
|
end
|
83
85
|
private_class_method(:new, :allocate)
|
84
86
|
|
@@ -93,11 +95,13 @@ module Kramdown
|
|
93
95
|
update_tree(data[:content])
|
94
96
|
replace_abbreviations(data[:content])
|
95
97
|
end
|
98
|
+
footnote_count = 0
|
96
99
|
@footnotes.each do |name, data|
|
97
|
-
next if data.key?(:marker)
|
100
|
+
(footnote_count += 1; next) if data.key?(:marker)
|
98
101
|
line = data[:content].options[:location]
|
99
102
|
warning("Footnote definition for '#{name}' on line #{line} is unreferenced - ignoring")
|
100
103
|
end
|
104
|
+
@root.options[:footnote_count] = footnote_count
|
101
105
|
end
|
102
106
|
|
103
107
|
protected
|
@@ -193,6 +197,11 @@ module Kramdown
|
|
193
197
|
end.flatten!
|
194
198
|
end
|
195
199
|
|
200
|
+
def span_pattern_cache(stop_re, span_start)
|
201
|
+
@span_pattern_cache[stop_re][span_start] ||= /(?=#{Regexp.union(stop_re, span_start)})/
|
202
|
+
end
|
203
|
+
private :span_pattern_cache
|
204
|
+
|
196
205
|
# Parse all span-level elements in the source string of @src into +el+.
|
197
206
|
#
|
198
207
|
# If the parameter +stop_re+ (a regexp) is used, parsing is immediately stopped if the regexp
|
@@ -211,7 +220,7 @@ module Kramdown
|
|
211
220
|
span_start, span_start_re = span_parser_regexps(parsers) if parsers
|
212
221
|
parsers ||= @span_parsers
|
213
222
|
|
214
|
-
used_re = (stop_re.nil? ? span_start_re :
|
223
|
+
used_re = (stop_re.nil? ? span_start_re : span_pattern_cache(stop_re, span_start))
|
215
224
|
stop_re_found = false
|
216
225
|
while !@src.eos? && !stop_re_found
|
217
226
|
if (result = @src.scan_until(used_re))
|
@@ -11,8 +11,8 @@ module Kramdown
|
|
11
11
|
module Parser
|
12
12
|
class Kramdown
|
13
13
|
|
14
|
-
ACHARS = '[[:alnum:]]_'
|
15
|
-
AUTOLINK_START_STR = "<((mailto|https?|ftps?):.+?|[
|
14
|
+
ACHARS = '[[:alnum:]]-_.'
|
15
|
+
AUTOLINK_START_STR = "<((mailto|https?|ftps?):.+?|[#{ACHARS}]+?@[#{ACHARS}]+?)>"
|
16
16
|
AUTOLINK_START = /#{AUTOLINK_START_STR}/u
|
17
17
|
|
18
18
|
# Parse the autolink at the current location.
|
@@ -16,8 +16,8 @@ module Kramdown
|
|
16
16
|
# Parse the blank line at the current postition.
|
17
17
|
def parse_blank_line
|
18
18
|
@src.pos += @src.matched_size
|
19
|
-
if @tree.children.last &&
|
20
|
-
|
19
|
+
if (last_child = @tree.children.last) && last_child.type == :blank
|
20
|
+
last_child.value << @src.matched
|
21
21
|
else
|
22
22
|
@tree.children << new_block_el(:blank, @src.matched)
|
23
23
|
end
|
@@ -19,8 +19,9 @@ module Kramdown
|
|
19
19
|
|
20
20
|
# Return +true+ if we are after a block boundary.
|
21
21
|
def after_block_boundary?
|
22
|
-
|
23
|
-
|
22
|
+
last_child = @tree.children.last
|
23
|
+
!last_child || last_child.type == :blank ||
|
24
|
+
(last_child.type == :eob && last_child.value.nil?) || @block_ial
|
24
25
|
end
|
25
26
|
|
26
27
|
# Return +true+ if we are before a block boundary.
|
@@ -25,8 +25,18 @@ module Kramdown
|
|
25
25
|
return
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
# assign static regex to avoid allocating the same on every instance
|
29
|
+
# where +result+ equals a single-backtick. Interpolate otherwise.
|
30
|
+
if result == '`'
|
31
|
+
scan_pattern = /`/
|
32
|
+
str_sub_pattern = /`\Z/
|
33
|
+
else
|
34
|
+
scan_pattern = /#{result}/
|
35
|
+
str_sub_pattern = /#{result}\Z/
|
36
|
+
end
|
37
|
+
|
38
|
+
if (text = @src.scan_until(scan_pattern))
|
39
|
+
text.sub!(str_sub_pattern, '')
|
30
40
|
unless simple
|
31
41
|
text = text[1..-1] if text[0..0] == ' '
|
32
42
|
text = text[0..-2] if text[-1..-1] == ' '
|
@@ -22,7 +22,7 @@ module Kramdown
|
|
22
22
|
element = (result.length == 2 ? :strong : :em)
|
23
23
|
type = result[0..0]
|
24
24
|
|
25
|
-
if (type == '_' && @src.pre_match =~ /[[:alpha:]
|
25
|
+
if (type == '_' && @src.pre_match =~ /[[:alpha:]]-?[[:alpha:]]*\z/) || @src.check(/\s/) ||
|
26
26
|
@tree.type == element || @stack.any? {|el, _| el.type == element }
|
27
27
|
add_text(result)
|
28
28
|
return
|
@@ -39,7 +39,7 @@ module Kramdown
|
|
39
39
|
|
40
40
|
# Update the +ial+ with the information from the inline attribute list +opts+.
|
41
41
|
def update_ial_with_ial(ial, opts)
|
42
|
-
(ial[:refs] ||= [])
|
42
|
+
(ial[:refs] ||= []).concat(opts[:refs]) if opts.key?(:refs)
|
43
43
|
opts.each do |k, v|
|
44
44
|
if k == IAL_CLASS_ATTR
|
45
45
|
ial[k] = "#{ial[k]} #{v}".lstrip
|
@@ -110,6 +110,12 @@ module Kramdown
|
|
110
110
|
opts.select do |k, v|
|
111
111
|
k = k.to_sym
|
112
112
|
if Kramdown::Options.defined?(k)
|
113
|
+
if @options[:forbidden_inline_options].include?(k) ||
|
114
|
+
k == :forbidden_inline_options
|
115
|
+
warning("Option #{k} may not be set inline")
|
116
|
+
next false
|
117
|
+
end
|
118
|
+
|
113
119
|
begin
|
114
120
|
val = Kramdown::Options.parse(k, v)
|
115
121
|
@options[k] = val
|
@@ -163,10 +169,10 @@ module Kramdown
|
|
163
169
|
elsif @src.check(EXT_BLOCK_START)
|
164
170
|
parse_extension_start_tag(:block)
|
165
171
|
elsif @src.scan(IAL_BLOCK_START)
|
166
|
-
if @tree.children.last &&
|
167
|
-
(
|
168
|
-
[:link_def, :abbrev_def, :footnote_def].include?(
|
169
|
-
parse_attribute_list(@src[1],
|
172
|
+
if (last_child = @tree.children.last) && last_child.type != :blank &&
|
173
|
+
(last_child.type != :eob ||
|
174
|
+
[:link_def, :abbrev_def, :footnote_def].include?(last_child.value))
|
175
|
+
parse_attribute_list(@src[1], last_child.options[:ial] ||= {})
|
170
176
|
@tree.children << new_block_el(:eob, :ial) unless @src.check(IAL_BLOCK_START)
|
171
177
|
else
|
172
178
|
parse_attribute_list(@src[1], @block_ial ||= {})
|
@@ -187,12 +193,12 @@ module Kramdown
|
|
187
193
|
if @src.check(EXT_SPAN_START)
|
188
194
|
parse_extension_start_tag(:span)
|
189
195
|
elsif @src.check(IAL_SPAN_START)
|
190
|
-
if @tree.children.last &&
|
196
|
+
if (last_child = @tree.children.last) && last_child.type != :text
|
191
197
|
@src.pos += @src.matched_size
|
192
198
|
attr = {}
|
193
199
|
parse_attribute_list(@src[1], attr)
|
194
|
-
update_ial_with_ial(
|
195
|
-
update_attr_with_ial(
|
200
|
+
update_ial_with_ial(last_child.options[:ial] ||= {}, attr)
|
201
|
+
update_attr_with_ial(last_child.attr, attr)
|
196
202
|
else
|
197
203
|
warning("Found span IAL after text - ignoring it")
|
198
204
|
add_text(@src.getch)
|
@@ -8,6 +8,7 @@
|
|
8
8
|
#
|
9
9
|
|
10
10
|
require 'kramdown/parser/kramdown/block_boundary'
|
11
|
+
require 'rexml/xmltokens'
|
11
12
|
|
12
13
|
module Kramdown
|
13
14
|
module Parser
|
@@ -31,7 +32,7 @@ module Kramdown
|
|
31
32
|
def parse_atx_header
|
32
33
|
return false unless after_block_boundary?
|
33
34
|
text, id = parse_header_contents
|
34
|
-
text.sub!(/
|
35
|
+
text.sub!(/(?<!\\)#+\z/, '') && text.rstrip!
|
35
36
|
return false if text.empty?
|
36
37
|
add_header(@src["level"].length, text, id)
|
37
38
|
true
|
@@ -40,7 +41,7 @@ module Kramdown
|
|
40
41
|
|
41
42
|
protected
|
42
43
|
|
43
|
-
HEADER_ID = /[\t ]{#(?<id
|
44
|
+
HEADER_ID = /[\t ]{#(?<id>#{REXML::XMLTokens::NAME_START_CHAR}#{REXML::XMLTokens::NAME_CHAR}*)}\z/
|
44
45
|
|
45
46
|
# Returns header text and optional ID.
|
46
47
|
def parse_header_contents
|