kramdown 2.0.0 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTERS +13 -3
- data/README.md +8 -2
- data/VERSION +1 -1
- data/bin/kramdown +48 -19
- data/lib/kramdown/converter/base.rb +2 -1
- data/lib/kramdown/converter/html.rb +36 -29
- data/lib/kramdown/converter/kramdown.rb +12 -7
- data/lib/kramdown/converter/latex.rb +2 -2
- 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 -10
- data/lib/kramdown/element.rb +24 -0
- data/lib/kramdown/options.rb +53 -12
- data/lib/kramdown/parser/base.rb +3 -1
- data/lib/kramdown/parser/html.rb +8 -8
- data/lib/kramdown/parser/kramdown.rb +8 -1
- data/lib/kramdown/parser/kramdown/abbreviation.rb +1 -1
- 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 +13 -3
- data/lib/kramdown/parser/kramdown/emphasis.rb +1 -1
- data/lib/kramdown/parser/kramdown/extensions.rb +13 -7
- 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 +22 -1
- data/test/test_files.rb +27 -18
- 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 +5 -0
- data/test/testcases/block/03_paragraph/standalone_image.text +3 -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/06_codeblock/rouge/multiple.html +1 -1
- data/test/testcases/block/06_codeblock/rouge/simple.html +1 -1
- 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/09_html/table.kramdown +8 -0
- data/test/testcases/block/09_html/table.text +7 -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/03_codespan/normal.html +4 -0
- data/test/testcases/span/03_codespan/normal.text +4 -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 +6 -6
- 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/abbrev_in_html.html +9 -0
- data/test/testcases/span/abbreviations/abbrev_in_html.text +10 -0
- data/test/testcases/span/abbreviations/in_footnote.html +4 -4
- data/test/testcases/span/math/normal.html +4 -4
- data/test/testcases/span/text_substitutions/entities.html +1 -1
- data/test/testcases/span/text_substitutions/entities.text +1 -1
- metadata +40 -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!
|
@@ -25,8 +25,10 @@ module Kramdown::Converter::SyntaxHighlighter
|
|
25
25
|
opts = options(converter, type)
|
26
26
|
call_opts[:default_lang] = opts[:default_lang]
|
27
27
|
return nil unless lang || opts[:default_lang] || opts[:guess_lang]
|
28
|
+
|
28
29
|
lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text)
|
29
|
-
return nil if opts[:disable] || !lexer || lexer.tag == "plaintext"
|
30
|
+
return nil if opts[:disable] || !lexer || (lexer.tag == "plaintext" && !opts[:guess_lang])
|
31
|
+
|
30
32
|
opts[:css_class] ||= 'highlight' # For backward compatibility when using Rouge 2.0
|
31
33
|
formatter = formatter_class(opts).new(opts)
|
32
34
|
formatter.format(lexer.lex(text))
|
@@ -43,24 +45,32 @@ module Kramdown::Converter::SyntaxHighlighter
|
|
43
45
|
cache = converter.data[:syntax_highlighter_rouge] = {}
|
44
46
|
|
45
47
|
opts = converter.options[:syntax_highlighter_opts].dup
|
46
|
-
span_opts = (opts.delete(:span) || {}).dup
|
47
|
-
block_opts = (opts.delete(:block) || {}).dup
|
48
|
-
[span_opts, block_opts].each do |hash|
|
49
|
-
hash.keys.each do |k|
|
50
|
-
hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k)
|
51
|
-
end
|
52
|
-
end
|
53
48
|
|
54
|
-
|
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
|
+
|
55
57
|
cache[:block] = opts.merge(block_opts)
|
56
58
|
end
|
57
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
|
+
|
58
68
|
def self.formatter_class(opts = {})
|
59
69
|
case formatter = opts[:formatter]
|
60
70
|
when Class
|
61
71
|
formatter
|
62
72
|
when /\A[[:upper:]][[:alnum:]_]*\z/
|
63
|
-
::Rouge::Formatters.const_get(formatter)
|
73
|
+
::Rouge::Formatters.const_get(formatter, false)
|
64
74
|
else
|
65
75
|
# Available in Rouge 2.0 or later
|
66
76
|
::Rouge::Formatters::HTMLLegacy
|
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
|
@@ -522,6 +530,22 @@ module Kramdown
|
|
522
530
|
CATEGORY[el.type] || el.options[:category]
|
523
531
|
end
|
524
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
|
+
|
525
549
|
end
|
526
550
|
|
527
551
|
end
|
data/lib/kramdown/options.rb
CHANGED
@@ -39,6 +39,7 @@ module Kramdown
|
|
39
39
|
ALLOWED_TYPES = [String, Integer, Float, Symbol, Boolean, Object]
|
40
40
|
|
41
41
|
@options = {}
|
42
|
+
@cached_defaults = nil
|
42
43
|
|
43
44
|
# Define a new option called +name+ (a Symbol) with the given +type+ (String, Integer, Float,
|
44
45
|
# Symbol, Boolean, Object), default value +default+ and the description +desc+. If a block is
|
@@ -54,6 +55,7 @@ module Kramdown
|
|
54
55
|
raise ArgumentError, "Invalid type for default value" if !(type === default) && !default.nil?
|
55
56
|
raise ArgumentError, "Missing validator block" if type == Object && block.nil?
|
56
57
|
@options[name] = Definition.new(name, type, default, desc, block)
|
58
|
+
@cached_defaults = nil
|
57
59
|
end
|
58
60
|
|
59
61
|
# Return all option definitions.
|
@@ -68,15 +70,17 @@ module Kramdown
|
|
68
70
|
|
69
71
|
# Return a Hash with the default values for all options.
|
70
72
|
def self.defaults
|
71
|
-
|
72
|
-
|
73
|
-
|
73
|
+
@cached_defaults ||= begin
|
74
|
+
temp = {}
|
75
|
+
@options.each {|_n, o| temp[o.name] = o.default }
|
76
|
+
temp.freeze
|
77
|
+
end
|
74
78
|
end
|
75
79
|
|
76
80
|
# Merge the #defaults Hash with the *parsed* options from the given Hash, i.e. only valid option
|
77
81
|
# names are considered and their value is run through the #parse method.
|
78
82
|
def self.merge(hash)
|
79
|
-
temp = defaults
|
83
|
+
temp = defaults.dup
|
80
84
|
hash.each do |k, v|
|
81
85
|
k = k.to_sym
|
82
86
|
temp[k] = @options.key?(k) ? parse(k, v) : v
|
@@ -328,7 +332,11 @@ module Kramdown
|
|
328
332
|
Used by: HTML converter, kramdown converter
|
329
333
|
EOF
|
330
334
|
|
331
|
-
|
335
|
+
TOC_LEVELS_RANGE = (1..6).freeze
|
336
|
+
TOC_LEVELS_ARRAY = TOC_LEVELS_RANGE.to_a.freeze
|
337
|
+
private_constant :TOC_LEVELS_RANGE, :TOC_LEVELS_ARRAY
|
338
|
+
|
339
|
+
define(:toc_levels, Object, TOC_LEVELS_ARRAY, <<~EOF) do |val|
|
332
340
|
Defines the levels that are used for the table of contents
|
333
341
|
|
334
342
|
The individual levels can be specified by separating them with commas
|
@@ -347,12 +355,20 @@ module Kramdown
|
|
347
355
|
else
|
348
356
|
raise Kramdown::Error, "Invalid syntax for option toc_levels"
|
349
357
|
end
|
350
|
-
when Array
|
351
|
-
|
358
|
+
when Array
|
359
|
+
unless val.eql?(TOC_LEVELS_ARRAY)
|
360
|
+
val = val.map(&:to_i).uniq
|
361
|
+
end
|
362
|
+
when Range
|
363
|
+
if val.eql?(TOC_LEVELS_RANGE)
|
364
|
+
val = TOC_LEVELS_ARRAY
|
365
|
+
else
|
366
|
+
val = val.map(&:to_i).uniq
|
367
|
+
end
|
352
368
|
else
|
353
369
|
raise Kramdown::Error, "Invalid type #{val.class} for option toc_levels"
|
354
370
|
end
|
355
|
-
if val.any? {|i| !
|
371
|
+
if val.any? {|i| !TOC_LEVELS_RANGE.cover?(i) }
|
356
372
|
raise Kramdown::Error, "Level numbers for option toc_levels have to be integers from 1 to 6"
|
357
373
|
end
|
358
374
|
val
|
@@ -377,7 +393,11 @@ module Kramdown
|
|
377
393
|
simple_array_validator(val, :latex_headers, 6)
|
378
394
|
end
|
379
395
|
|
380
|
-
|
396
|
+
SMART_QUOTES_ENTITIES = %w[lsquo rsquo ldquo rdquo].freeze
|
397
|
+
SMART_QUOTES_STR = SMART_QUOTES_ENTITIES.join(',').freeze
|
398
|
+
private_constant :SMART_QUOTES_ENTITIES, :SMART_QUOTES_STR
|
399
|
+
|
400
|
+
define(:smart_quotes, Object, SMART_QUOTES_ENTITIES, <<~EOF) do |val|
|
381
401
|
Defines the HTML entity names or code points for smart quote output
|
382
402
|
|
383
403
|
The entities identified by entity name or code point that should be
|
@@ -388,9 +408,13 @@ module Kramdown
|
|
388
408
|
Default: lsquo,rsquo,ldquo,rdquo
|
389
409
|
Used by: HTML/Latex converter
|
390
410
|
EOF
|
391
|
-
val
|
392
|
-
|
393
|
-
|
411
|
+
if val == SMART_QUOTES_STR || val == SMART_QUOTES_ENTITIES
|
412
|
+
SMART_QUOTES_ENTITIES
|
413
|
+
else
|
414
|
+
val = simple_array_validator(val, :smart_quotes, 4)
|
415
|
+
val.map! {|v| Integer(v) rescue v }
|
416
|
+
val
|
417
|
+
end
|
394
418
|
end
|
395
419
|
|
396
420
|
define(:typographic_symbols, Object, {}, <<~EOF) do |val|
|
@@ -562,6 +586,23 @@ module Kramdown
|
|
562
586
|
Used by: HTML
|
563
587
|
EOF
|
564
588
|
|
589
|
+
define(:remove_line_breaks_for_cjk, Boolean, false, <<~EOF)
|
590
|
+
Specifies whether line breaks should be removed between CJK characters
|
591
|
+
|
592
|
+
Default: false
|
593
|
+
Used by: HTML converter
|
594
|
+
EOF
|
595
|
+
|
596
|
+
define(:forbidden_inline_options, Object, %w[template], <<~EOF) do |val|
|
597
|
+
Defines the options that may not be set using the {::options} extension
|
598
|
+
|
599
|
+
Default: template
|
600
|
+
Used by: HTML converter
|
601
|
+
EOF
|
602
|
+
val.map! {|item| item.kind_of?(String) ? str_to_sym(item) : item }
|
603
|
+
simple_array_validator(val, :forbidden_inline_options)
|
604
|
+
end
|
605
|
+
|
565
606
|
end
|
566
607
|
|
567
608
|
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
|
|
@@ -195,6 +197,11 @@ module Kramdown
|
|
195
197
|
end.flatten!
|
196
198
|
end
|
197
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
|
+
|
198
205
|
# Parse all span-level elements in the source string of @src into +el+.
|
199
206
|
#
|
200
207
|
# If the parameter +stop_re+ (a regexp) is used, parsing is immediately stopped if the regexp
|
@@ -213,7 +220,7 @@ module Kramdown
|
|
213
220
|
span_start, span_start_re = span_parser_regexps(parsers) if parsers
|
214
221
|
parsers ||= @span_parsers
|
215
222
|
|
216
|
-
used_re = (stop_re.nil? ? span_start_re :
|
223
|
+
used_re = (stop_re.nil? ? span_start_re : span_pattern_cache(stop_re, span_start))
|
217
224
|
stop_re_found = false
|
218
225
|
while !@src.eos? && !stop_re_found
|
219
226
|
if (result = @src.scan_until(used_re))
|
@@ -46,7 +46,7 @@ module Kramdown
|
|
46
46
|
regexps << /(?=(?:\W|^)#{regexps.first}(?!\w))/ # regexp should only match on word boundaries
|
47
47
|
end
|
48
48
|
el.children.map! do |child|
|
49
|
-
if child.type == :text
|
49
|
+
if child.type == :text && el.options[:content_model] != :raw
|
50
50
|
if child.value =~ regexps.first
|
51
51
|
result = []
|
52
52
|
strscan = Kramdown::Utils::StringScanner.new(child.value, child.options[:location])
|
@@ -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.
|
@@ -20,13 +20,23 @@ module Kramdown
|
|
20
20
|
simple = (result.length == 1)
|
21
21
|
saved_pos = @src.save_pos
|
22
22
|
|
23
|
-
if simple && @src.pre_match =~ /\s\Z/ && @src.match?(/\s/)
|
23
|
+
if simple && @src.pre_match =~ /\s\Z|\A\Z/ && @src.match?(/\s/)
|
24
24
|
add_text(result)
|
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
|
@@ -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)
|