kramdown 0.10.0 → 0.11.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.
- data/CONTRIBUTERS +1 -1
- data/ChangeLog +594 -0
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/data/kramdown/document.html +11 -2
- data/doc/default.template +2 -2
- data/doc/index.page +1 -2
- data/doc/quickref.page +2 -2
- data/doc/syntax.page +270 -179
- data/lib/kramdown/converter/html.rb +43 -29
- data/lib/kramdown/converter/kramdown.rb +97 -73
- data/lib/kramdown/converter/latex.rb +18 -13
- data/lib/kramdown/document.rb +8 -6
- data/lib/kramdown/options.rb +7 -10
- data/lib/kramdown/parser/html.rb +29 -21
- data/lib/kramdown/parser/kramdown.rb +19 -3
- data/lib/kramdown/parser/kramdown/abbreviation.rb +1 -0
- data/lib/kramdown/parser/kramdown/attribute_list.rb +18 -12
- data/lib/kramdown/parser/kramdown/autolink.rb +1 -1
- data/lib/kramdown/parser/kramdown/block_boundary.rb +46 -0
- data/lib/kramdown/parser/kramdown/blockquote.rb +7 -3
- data/lib/kramdown/parser/kramdown/codeblock.rb +5 -3
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +1 -1
- data/lib/kramdown/parser/kramdown/extension.rb +22 -8
- data/lib/kramdown/parser/kramdown/footnote.rb +3 -2
- data/lib/kramdown/parser/kramdown/header.rb +10 -10
- data/lib/kramdown/parser/kramdown/html.rb +16 -14
- data/lib/kramdown/parser/kramdown/html_entity.rb +1 -1
- data/lib/kramdown/parser/kramdown/link.rb +8 -8
- data/lib/kramdown/parser/kramdown/list.rb +36 -29
- data/lib/kramdown/parser/kramdown/math.rb +15 -4
- data/lib/kramdown/parser/kramdown/paragraph.rb +14 -3
- data/lib/kramdown/parser/kramdown/table.rb +17 -9
- data/lib/kramdown/utils.rb +1 -0
- data/lib/kramdown/utils/html.rb +9 -9
- data/lib/kramdown/utils/ordered_hash.rb +79 -0
- data/lib/kramdown/version.rb +1 -1
- data/man/man1/kramdown.1 +9 -12
- data/test/test_files.rb +6 -1
- data/test/testcases/block/02_eob/middle.html +0 -1
- data/test/testcases/block/04_header/atx_header.html +5 -2
- data/test/testcases/block/04_header/atx_header.text +3 -1
- data/test/testcases/block/04_header/setext_header.html +4 -5
- data/test/testcases/block/04_header/setext_header.html.19 +30 -0
- data/test/testcases/block/05_blockquote/lazy.html +34 -0
- data/test/testcases/block/05_blockquote/lazy.text +20 -0
- data/test/testcases/block/05_blockquote/nested.html +1 -0
- data/test/testcases/block/05_blockquote/nested.text +1 -0
- data/test/testcases/block/05_blockquote/with_code_blocks.html +2 -2
- data/test/testcases/block/06_codeblock/lazy.html +4 -0
- data/test/testcases/block/06_codeblock/lazy.text +5 -0
- data/test/testcases/block/06_codeblock/no_newline_at_end_1.html +2 -0
- data/test/testcases/block/06_codeblock/no_newline_at_end_1.text +2 -0
- data/test/testcases/block/06_codeblock/with_ial.html +6 -0
- data/test/testcases/block/06_codeblock/with_ial.text +5 -0
- data/test/testcases/block/07_horizontal_rule/normal.html +0 -2
- data/test/testcases/block/07_horizontal_rule/normal.text +0 -2
- data/test/testcases/block/08_list/item_ial.html +1 -3
- data/test/testcases/block/08_list/lazy.html +39 -0
- data/test/testcases/block/08_list/lazy.text +29 -0
- data/test/testcases/block/08_list/list_and_others.html +5 -3
- data/test/testcases/block/08_list/list_and_others.text +1 -0
- data/test/testcases/block/08_list/other_first_element.html +2 -2
- data/test/testcases/block/08_list/other_first_element.text +1 -1
- data/test/testcases/block/08_list/simple_ul.html +0 -13
- data/test/testcases/block/08_list/simple_ul.text +0 -7
- data/test/testcases/block/08_list/special_cases.html +8 -31
- data/test/testcases/block/08_list/special_cases.text +2 -15
- data/test/testcases/block/09_html/comment.html +2 -2
- data/test/testcases/block/09_html/html_to_native/emphasis.html +2 -0
- data/test/testcases/block/09_html/html_to_native/emphasis.text +2 -0
- data/test/testcases/block/09_html/html_to_native/table_normal.html +2 -1
- data/test/testcases/block/09_html/html_to_native/table_simple.html +4 -2
- data/test/testcases/block/09_html/invalid_html_1.html +2 -0
- data/test/testcases/block/09_html/parse_as_raw.html +2 -2
- data/test/testcases/block/09_html/parse_as_span.html +1 -1
- data/test/testcases/block/09_html/simple.html +2 -0
- data/test/testcases/block/09_html/simple.html.19 +2 -0
- data/test/testcases/block/09_html/simple.text +2 -0
- data/test/testcases/block/11_ial/auto_id_and_ial.html +1 -1
- data/test/testcases/block/11_ial/simple.html +2 -3
- data/test/testcases/block/12_extension/comment.html +3 -1
- data/test/testcases/block/12_extension/comment.text +2 -1
- data/test/testcases/block/12_extension/ignored.html +5 -1
- data/test/testcases/block/12_extension/ignored.text +1 -1
- data/test/testcases/block/12_extension/nomarkdown.html +5 -1
- data/test/testcases/block/12_extension/nomarkdown.kramdown +20 -0
- data/test/testcases/block/12_extension/nomarkdown.latex +13 -0
- data/test/testcases/block/12_extension/nomarkdown.text +11 -1
- data/test/testcases/block/13_definition_list/item_ial.html +1 -3
- data/test/testcases/block/13_definition_list/item_ial.text +1 -1
- data/test/testcases/block/13_definition_list/simple.html +2 -2
- data/test/testcases/block/14_table/errors.html +5 -0
- data/test/testcases/block/14_table/errors.text +6 -0
- data/test/testcases/block/14_table/header.text +1 -1
- data/test/testcases/block/14_table/no_table.text +1 -1
- data/test/testcases/block/14_table/simple.html +78 -0
- data/test/testcases/block/14_table/simple.text +22 -0
- data/test/testcases/block/15_math/normal.html +11 -4
- data/test/testcases/block/15_math/normal.text +10 -0
- data/test/testcases/encoding.html +1 -1
- data/test/testcases/span/01_link/image_in_a.html +3 -3
- data/test/testcases/span/01_link/imagelinks.html +7 -7
- data/test/testcases/span/01_link/inline.html +11 -5
- data/test/testcases/span/01_link/inline.html.19 +11 -5
- data/test/testcases/span/01_link/inline.text +11 -5
- data/test/testcases/span/01_link/link_defs.html +2 -1
- data/test/testcases/span/01_link/link_defs.text +4 -0
- data/test/testcases/span/01_link/reference.html +3 -0
- data/test/testcases/span/01_link/reference.html.19 +3 -0
- data/test/testcases/span/01_link/reference.text +5 -0
- data/test/testcases/span/03_codespan/highlighting.html +1 -0
- data/test/testcases/span/03_codespan/highlighting.text +1 -0
- data/test/testcases/span/04_footnote/definitions.html +3 -0
- data/test/testcases/span/04_footnote/definitions.latex +3 -4
- data/test/testcases/span/04_footnote/definitions.text +6 -0
- data/test/testcases/span/04_footnote/footnote_nr.latex +1 -5
- data/test/testcases/span/04_footnote/markers.latex +5 -14
- data/test/testcases/span/05_html/markdown_attr.html +1 -1
- data/test/testcases/span/05_html/markdown_attr.text +1 -1
- data/test/testcases/span/05_html/normal.html +5 -3
- data/test/testcases/span/05_html/normal.text +2 -0
- data/test/testcases/span/escaped_chars/normal.html +2 -0
- data/test/testcases/span/escaped_chars/normal.text +2 -0
- data/test/testcases/span/extension/comment.html +2 -2
- data/test/testcases/span/extension/ignored.html +1 -1
- data/test/testcases/span/text_substitutions/typography.html +1 -1
- data/test/testcases/span/text_substitutions/typography.html.19 +1 -1
- data/test/testcases/span/text_substitutions/typography.text +1 -1
- metadata +20 -5
- data/test/testcases/block/05_blockquote/only_first_quoted.html +0 -8
- data/test/testcases/block/05_blockquote/only_first_quoted.text +0 -4
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown.
|
7
|
+
#
|
8
|
+
# kramdown is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'kramdown/parser/kramdown/attribute_list'
|
24
|
+
require 'kramdown/parser/kramdown/blank_line'
|
25
|
+
require 'kramdown/parser/kramdown/eob'
|
26
|
+
|
27
|
+
module Kramdown
|
28
|
+
module Parser
|
29
|
+
class Kramdown
|
30
|
+
|
31
|
+
BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|#{IAL_BLOCK_START}|\Z/
|
32
|
+
|
33
|
+
# Return +true+ if we are after a block boundary.
|
34
|
+
def after_block_boundary?
|
35
|
+
!@tree.children.last || @tree.children.last.type == :blank ||
|
36
|
+
(@tree.children.last.type == :eob && @tree.children.last.value.nil?) || @block_ial
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return +true+ if we are before a block boundary.
|
40
|
+
def before_block_boundary?
|
41
|
+
@src.check(BLOCK_BOUNDARY)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -20,23 +20,27 @@
|
|
20
20
|
#++
|
21
21
|
#
|
22
22
|
|
23
|
+
require 'kramdown/parser/kramdown/blank_line'
|
24
|
+
require 'kramdown/parser/kramdown/attribute_list'
|
25
|
+
require 'kramdown/parser/kramdown/eob'
|
26
|
+
|
23
27
|
module Kramdown
|
24
28
|
module Parser
|
25
29
|
class Kramdown
|
26
30
|
|
27
31
|
BLOCKQUOTE_START = /^#{OPT_SPACE}> ?/
|
28
|
-
BLOCKQUOTE_MATCH = /(
|
32
|
+
BLOCKQUOTE_MATCH = /(^.*\n)+?(?=#{BLANK_LINE}|#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z)/
|
29
33
|
|
30
34
|
# Parse the blockquote at the current location.
|
31
35
|
def parse_blockquote
|
32
|
-
result = @src.scan(BLOCKQUOTE_MATCH).gsub(BLOCKQUOTE_START, '')
|
33
36
|
el = new_block_el(:blockquote)
|
34
37
|
@tree.children << el
|
35
|
-
parse_blocks(el,
|
38
|
+
parse_blocks(el, @src.scan(BLOCKQUOTE_MATCH).gsub!(BLOCKQUOTE_START, ''))
|
36
39
|
true
|
37
40
|
end
|
38
41
|
define_parser(:blockquote, BLOCKQUOTE_START)
|
39
42
|
|
43
|
+
|
40
44
|
end
|
41
45
|
end
|
42
46
|
end
|
@@ -21,18 +21,20 @@
|
|
21
21
|
#
|
22
22
|
|
23
23
|
require 'kramdown/parser/kramdown/blank_line'
|
24
|
+
require 'kramdown/parser/kramdown/attribute_list'
|
25
|
+
require 'kramdown/parser/kramdown/eob'
|
26
|
+
require 'kramdown/parser/kramdown/paragraph'
|
24
27
|
|
25
28
|
module Kramdown
|
26
29
|
module Parser
|
27
30
|
class Kramdown
|
28
31
|
|
29
32
|
CODEBLOCK_START = INDENT
|
30
|
-
|
31
|
-
CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?#{CODEBLOCK_LINE})*/
|
33
|
+
CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+(?:(?!#{BLANK_LINE} {0,3}\S|#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START})^[ \t]*\S.*\n)*)*/
|
32
34
|
|
33
35
|
# Parse the indented codeblock at the current location.
|
34
36
|
def parse_codeblock
|
35
|
-
@tree.children << new_block_el(:codeblock, @src.scan(CODEBLOCK_MATCH).gsub!(INDENT, ''))
|
37
|
+
@tree.children << new_block_el(:codeblock, @src.scan(CODEBLOCK_MATCH).gsub(/\n( {0,3}\S)/, ' \\1').gsub!(INDENT, ''))
|
36
38
|
true
|
37
39
|
end
|
38
40
|
define_parser(:codeblock, CODEBLOCK_START)
|
@@ -27,12 +27,19 @@ module Kramdown
|
|
27
27
|
class Kramdown
|
28
28
|
|
29
29
|
def parse_extension_start_tag(type)
|
30
|
+
orig_pos = @src.pos
|
30
31
|
@src.pos += @src.matched_size
|
31
32
|
|
33
|
+
error_block = lambda do |msg|
|
34
|
+
warning(msg)
|
35
|
+
@src.pos = orig_pos
|
36
|
+
add_text(@src.scan(/./)) if type == :span
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
32
40
|
if @src[4] || @src.matched == '{:/}'
|
33
41
|
name = (@src[4] ? "for '#{@src[4]}' " : '')
|
34
|
-
|
35
|
-
return
|
42
|
+
return error_block.call("Invalid extension stop tag #{name}found - ignoring it")
|
36
43
|
end
|
37
44
|
|
38
45
|
ext = @src[1]
|
@@ -46,19 +53,25 @@ module Kramdown
|
|
46
53
|
body = result.sub!(stop_re, '')
|
47
54
|
body.chomp! if type == :block
|
48
55
|
else
|
49
|
-
|
56
|
+
return error_block.call("No stop tag for extension '#{ext}' found - ignoring it")
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
53
|
-
handle_extension(ext, opts, body, type)
|
60
|
+
if !handle_extension(ext, opts, body, type)
|
61
|
+
error_block.call("Invalid extension with name '#{ext}' specified - ignoring it")
|
62
|
+
else
|
63
|
+
true
|
64
|
+
end
|
54
65
|
end
|
55
66
|
|
56
67
|
def handle_extension(name, opts, body, type)
|
57
68
|
case name
|
58
69
|
when 'comment'
|
59
|
-
@tree.children << Element.new(:comment, body, :category => type) if body.kind_of?(String)
|
70
|
+
@tree.children << Element.new(:comment, body, nil, :category => type) if body.kind_of?(String)
|
71
|
+
true
|
60
72
|
when 'nomarkdown'
|
61
|
-
@tree.children << Element.new(:raw, body, :category => type) if body.kind_of?(String)
|
73
|
+
@tree.children << Element.new(:raw, body, nil, :category => type, :type => opts['type'].to_s.split(/\s+/)) if body.kind_of?(String)
|
74
|
+
true
|
62
75
|
when 'options'
|
63
76
|
opts.select do |k,v|
|
64
77
|
k = k.to_sym
|
@@ -71,8 +84,10 @@ module Kramdown
|
|
71
84
|
end.each do |k,v|
|
72
85
|
warning("Unknown kramdown option '#{k}'")
|
73
86
|
end
|
87
|
+
@tree.children << Element.new(:eob, :extension) if type == :block
|
88
|
+
true
|
74
89
|
else
|
75
|
-
|
90
|
+
false
|
76
91
|
end
|
77
92
|
end
|
78
93
|
|
@@ -86,7 +101,6 @@ module Kramdown
|
|
86
101
|
# Parse the extension block at the current location.
|
87
102
|
def parse_block_extension
|
88
103
|
parse_extension_start_tag(:block)
|
89
|
-
true
|
90
104
|
end
|
91
105
|
define_parser(:block_extension, EXT_BLOCK_START)
|
92
106
|
|
@@ -28,7 +28,7 @@ module Kramdown
|
|
28
28
|
module Parser
|
29
29
|
class Kramdown
|
30
30
|
|
31
|
-
FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n
|
31
|
+
FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/
|
32
32
|
|
33
33
|
# Parse the foot note definition at the current location.
|
34
34
|
def parse_footnote_definition
|
@@ -38,6 +38,7 @@ module Kramdown
|
|
38
38
|
parse_blocks(el, @src[2].gsub(INDENT, ''))
|
39
39
|
warning("Duplicate footnote name '#{@src[1]}' - overwriting") if @doc.parse_infos[:footnotes][@src[1]]
|
40
40
|
(@doc.parse_infos[:footnotes][@src[1]] = {})[:content] = el
|
41
|
+
@tree.children << Element.new(:eob, :footnote_def)
|
41
42
|
true
|
42
43
|
end
|
43
44
|
define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START)
|
@@ -54,7 +55,7 @@ module Kramdown
|
|
54
55
|
par.children.include?(child)
|
55
56
|
end
|
56
57
|
if !fn_def[:marker] || !valid
|
57
|
-
fn_def[:marker] = Element.new(:footnote, nil, :name => @src[1])
|
58
|
+
fn_def[:marker] = Element.new(:footnote, nil, nil, :name => @src[1])
|
58
59
|
fn_def[:marker].options[:stack] = [@stack.map {|s| s.first}, @tree, fn_def[:marker]].flatten.compact
|
59
60
|
@tree.children << fn_def[:marker]
|
60
61
|
else
|
@@ -20,6 +20,8 @@
|
|
20
20
|
#++
|
21
21
|
#
|
22
22
|
|
23
|
+
require 'kramdown/parser/kramdown/block_boundary'
|
24
|
+
|
23
25
|
module Kramdown
|
24
26
|
module Parser
|
25
27
|
class Kramdown
|
@@ -29,14 +31,13 @@ module Kramdown
|
|
29
31
|
|
30
32
|
# Parse the Setext header at the current location.
|
31
33
|
def parse_setext_header
|
32
|
-
|
33
|
-
|
34
|
-
end
|
34
|
+
return false if !after_block_boundary?
|
35
|
+
|
35
36
|
@src.pos += @src.matched_size
|
36
37
|
text, id, level = @src[1].strip, @src[2], @src[3]
|
37
|
-
el = new_block_el(:header, nil, :level => (level == '-' ? 2 : 1), :raw_text => text)
|
38
|
+
el = new_block_el(:header, nil, nil, :level => (level == '-' ? 2 : 1), :raw_text => text)
|
38
39
|
add_text(text, el)
|
39
|
-
el.
|
40
|
+
el.attr['id'] = id if id
|
40
41
|
@tree.children << el
|
41
42
|
true
|
42
43
|
end
|
@@ -48,14 +49,13 @@ module Kramdown
|
|
48
49
|
|
49
50
|
# Parse the Atx header at the current location.
|
50
51
|
def parse_atx_header
|
51
|
-
|
52
|
-
|
53
|
-
end
|
52
|
+
return false if !after_block_boundary?
|
53
|
+
|
54
54
|
result = @src.scan(ATX_HEADER_MATCH)
|
55
55
|
level, text, id = @src[1], @src[2].strip, @src[3]
|
56
|
-
el = new_block_el(:header, nil, :level => level.length, :raw_text => text)
|
56
|
+
el = new_block_el(:header, nil, nil, :level => level.length, :raw_text => text)
|
57
57
|
add_text(text, el)
|
58
|
-
el.
|
58
|
+
el.attr['id'] = id if id
|
59
59
|
@tree.children << el
|
60
60
|
true
|
61
61
|
end
|
@@ -34,13 +34,11 @@ module Kramdown
|
|
34
34
|
else
|
35
35
|
:raw
|
36
36
|
end
|
37
|
-
if val = html_parse_type(el.
|
37
|
+
if val = html_parse_type(el.attr.delete('markdown'))
|
38
38
|
parse_type = (val == :default ? HTML_PARSE_AS[el.value] : val)
|
39
39
|
end
|
40
40
|
|
41
41
|
@src.scan(/[ \t]*\n/) if parse_type == :block
|
42
|
-
el.options[:outer_element] = true if @tree.type != :html_element
|
43
|
-
el.options[:parent_is_raw] = true if @tree.type == :html_element && @tree.options[:parse_type] == :raw
|
44
42
|
el.options[:parse_type] = parse_type
|
45
43
|
|
46
44
|
if !closed
|
@@ -87,11 +85,11 @@ module Kramdown
|
|
87
85
|
# Parse the HTML at the current position as block level HTML.
|
88
86
|
def parse_block_html
|
89
87
|
if result = @src.scan(HTML_COMMENT_RE)
|
90
|
-
@tree.children << Element.new(:xml_comment, result, :category => :block)
|
88
|
+
@tree.children << Element.new(:xml_comment, result, nil, :category => :block)
|
91
89
|
@src.scan(/[ \t]*\n/)
|
92
90
|
true
|
93
91
|
elsif result = @src.scan(HTML_INSTRUCTION_RE)
|
94
|
-
@tree.children << Element.new(:xml_pi, result, :category => :block)
|
92
|
+
@tree.children << Element.new(:xml_pi, result, nil, :category => :block)
|
95
93
|
@src.scan(/[ \t]*\n/)
|
96
94
|
true
|
97
95
|
else
|
@@ -101,14 +99,13 @@ module Kramdown
|
|
101
99
|
Kramdown::Parser::Html::ElementConverter.new(@doc).process(@tree.children.last) if @doc.options[:html_to_native]
|
102
100
|
true
|
103
101
|
elsif result = @src.check(/^#{OPT_SPACE}#{HTML_TAG_CLOSE_RE}/) && !HTML_SPAN_ELEMENTS.include?(@src[1])
|
104
|
-
@src.pos += @src.matched_size
|
105
102
|
name = @src[1]
|
106
103
|
|
107
104
|
if @tree.type == :html_element && @tree.value == name
|
105
|
+
@src.pos += @src.matched_size
|
108
106
|
throw :stop_block_parsing, :found
|
109
107
|
else
|
110
|
-
|
111
|
-
true
|
108
|
+
false
|
112
109
|
end
|
113
110
|
else
|
114
111
|
false
|
@@ -123,16 +120,21 @@ module Kramdown
|
|
123
120
|
# Parse the HTML at the current position as span level HTML.
|
124
121
|
def parse_span_html
|
125
122
|
if result = @src.scan(HTML_COMMENT_RE)
|
126
|
-
@tree.children << Element.new(:xml_comment, result, :category => :span)
|
123
|
+
@tree.children << Element.new(:xml_comment, result, nil, :category => :span)
|
127
124
|
elsif result = @src.scan(HTML_INSTRUCTION_RE)
|
128
|
-
@tree.children << Element.new(:xml_pi, result, :category => :span)
|
125
|
+
@tree.children << Element.new(:xml_pi, result, nil, :category => :span)
|
129
126
|
elsif result = @src.scan(HTML_TAG_CLOSE_RE)
|
130
|
-
warning("Found invalidly used HTML closing tag for '#{@src[1]}'
|
127
|
+
warning("Found invalidly used HTML closing tag for '#{@src[1]}'")
|
128
|
+
add_text(result)
|
131
129
|
elsif result = @src.scan(HTML_TAG_RE)
|
132
|
-
|
130
|
+
if HTML_BLOCK_ELEMENTS.include?(@src[1])
|
131
|
+
warning("Found block HTML tag '#{@src[1]}' in span level text")
|
132
|
+
add_text(result)
|
133
|
+
return
|
134
|
+
end
|
133
135
|
|
134
136
|
reset_pos = @src.pos
|
135
|
-
attrs =
|
137
|
+
attrs = Utils::OrderedHash.new
|
136
138
|
@src[2].scan(HTML_ATTRIBUTE_RE).each {|name,sep,val| attrs[name] = val.gsub(/\n+/, ' ')}
|
137
139
|
|
138
140
|
do_parsing = (HTML_PARSE_AS_RAW.include?(@src[1]) || @tree.options[:parse_type] == :raw ? false : @doc.options[:parse_span_html])
|
@@ -148,7 +150,7 @@ module Kramdown
|
|
148
150
|
end
|
149
151
|
end
|
150
152
|
|
151
|
-
el = Element.new(:html_element, @src[1],
|
153
|
+
el = Element.new(:html_element, @src[1], attrs, :category => :span, :parse_type => (do_parsing ? :span : :raw))
|
152
154
|
@tree.children << el
|
153
155
|
stop_re = /<\/#{Regexp.escape(@src[1])}\s*>/
|
154
156
|
if !@src[4] && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value)
|
@@ -30,7 +30,7 @@ module Kramdown
|
|
30
30
|
def parse_html_entity
|
31
31
|
@src.pos += @src.matched_size
|
32
32
|
@tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity(@src[1] || (@src[2] && @src[2].to_i) || @src[3].hex),
|
33
|
-
:original => @src.matched)
|
33
|
+
nil, :original => @src.matched)
|
34
34
|
end
|
35
35
|
define_parser(:html_entity, Kramdown::Parser::Html::Constants::HTML_ENTITY_RE, '&')
|
36
36
|
|
@@ -27,7 +27,7 @@ module Kramdown
|
|
27
27
|
PUNCTUATION_CHARS = "_.:,;!?-"
|
28
28
|
LINK_ID_CHARS = /[a-zA-Z0-9 #{PUNCTUATION_CHARS}]/
|
29
29
|
LINK_ID_NON_CHARS = /[^a-zA-Z0-9 #{PUNCTUATION_CHARS}]/
|
30
|
-
LINK_DEFINITION_START = /^#{OPT_SPACE}\[(#{LINK_ID_CHARS}+)\]:[ \t]*(?:<(.*?)>|([
|
30
|
+
LINK_DEFINITION_START = /^#{OPT_SPACE}\[(#{LINK_ID_CHARS}+)\]:[ \t]*(?:<(.*?)>|([^'"\n]*?\S[^'"\n]*?))[ \t]*?(?:\n?[ \t]*?(["'])(.+?)\4[ \t]*?)?\n/
|
31
31
|
|
32
32
|
# Parse the link definition at the current location.
|
33
33
|
def parse_link_definition
|
@@ -35,6 +35,7 @@ module Kramdown
|
|
35
35
|
link_id, link_url, link_title = @src[1].downcase, @src[2] || @src[3], @src[5]
|
36
36
|
warning("Duplicate link ID '#{link_id}' - overwriting") if @doc.parse_infos[:link_defs][link_id]
|
37
37
|
@doc.parse_infos[:link_defs][link_id] = [link_url, link_title]
|
38
|
+
@tree.children << Element.new(:eob, :link_def)
|
38
39
|
true
|
39
40
|
end
|
40
41
|
define_parser(:link_definition, LINK_DEFINITION_START)
|
@@ -43,15 +44,14 @@ module Kramdown
|
|
43
44
|
# This helper methods adds the approriate attributes to the element +el+ of type +a+ or +img+
|
44
45
|
# and the element itself to the <tt>@tree</tt>.
|
45
46
|
def add_link(el, href, title, alt_text = nil)
|
46
|
-
el.options[:attr] ||= {}
|
47
|
-
el.options[:attr]['title'] = title if title
|
48
47
|
if el.type == :a
|
49
|
-
el.
|
48
|
+
el.attr['href'] = href
|
50
49
|
else
|
51
|
-
el.
|
52
|
-
el.
|
50
|
+
el.attr['src'] = href
|
51
|
+
el.attr['alt'] = alt_text
|
53
52
|
el.children.clear
|
54
53
|
end
|
54
|
+
el.attr['title'] = title if title
|
55
55
|
@tree.children << el
|
56
56
|
end
|
57
57
|
|
@@ -120,7 +120,7 @@ module Kramdown
|
|
120
120
|
end
|
121
121
|
else
|
122
122
|
link_url = ''
|
123
|
-
re = /\(|\)|\s/
|
123
|
+
re = /\(|\)|\s(?=['"])/
|
124
124
|
nr_of_brackets = 0
|
125
125
|
while temp = @src.scan_until(re)
|
126
126
|
link_url += temp
|
@@ -134,7 +134,7 @@ module Kramdown
|
|
134
134
|
break if nr_of_brackets == 0
|
135
135
|
end
|
136
136
|
end
|
137
|
-
link_url = link_url[1..-2]
|
137
|
+
link_url = link_url[1..-2].strip
|
138
138
|
|
139
139
|
if nr_of_brackets == 0
|
140
140
|
add_link(el, link_url, nil, alt_text)
|
@@ -29,10 +29,12 @@ module Kramdown
|
|
29
29
|
module Parser
|
30
30
|
class Kramdown
|
31
31
|
|
32
|
+
LIST_ITEM_IAL = /^\s*(#{IAL_SPAN_START})?\s*\n/
|
33
|
+
|
32
34
|
# Used for parsing the first line of a list item or a definition, i.e. the line with list item
|
33
35
|
# marker or the definition marker.
|
34
36
|
def parse_first_list_line(indentation, content)
|
35
|
-
if content =~
|
37
|
+
if content =~ LIST_ITEM_IAL
|
36
38
|
indentation = 4
|
37
39
|
else
|
38
40
|
while content =~ /^ *\t/
|
@@ -44,8 +46,9 @@ module Kramdown
|
|
44
46
|
content.sub!(/^\s*/, '')
|
45
47
|
|
46
48
|
indent_re = /^ {#{indentation}}/
|
47
|
-
content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}})
|
48
|
-
[
|
49
|
+
content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}}).*\S.*\n/
|
50
|
+
lazy_re = /(?!^ {0,#{[indentation, 3].min}}(?:#{IAL_BLOCK}|#{LAZY_END_HTML_STOP}|#{LAZY_END_HTML_START})).*\S.*\n/
|
51
|
+
[content, indentation, content_re, lazy_re, indent_re]
|
49
52
|
end
|
50
53
|
|
51
54
|
|
@@ -55,24 +58,23 @@ module Kramdown
|
|
55
58
|
|
56
59
|
# Parse the ordered or unordered list at the current location.
|
57
60
|
def parse_list
|
58
|
-
if @tree.children.last && @tree.children.last.type == :p # last element must not be a paragraph
|
59
|
-
return false
|
60
|
-
end
|
61
|
-
|
62
61
|
type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL])
|
63
62
|
list = new_block_el(type)
|
64
63
|
|
65
64
|
item = nil
|
66
|
-
indent_re = nil
|
67
|
-
content_re = nil
|
65
|
+
content_re, lazy_re, indent_re = nil
|
68
66
|
eob_found = false
|
69
67
|
nested_list_found = false
|
68
|
+
last_is_blank = false
|
70
69
|
while !@src.eos?
|
71
|
-
if @src.check(HR_START)
|
70
|
+
if last_is_blank && @src.check(HR_START)
|
71
|
+
break
|
72
|
+
elsif @src.scan(EOB_MARKER)
|
73
|
+
eob_found = true
|
72
74
|
break
|
73
75
|
elsif @src.scan(list_start_re)
|
74
76
|
item = Element.new(:li)
|
75
|
-
item.value, indentation, content_re, indent_re = parse_first_list_line(@src[1].length, @src[2])
|
77
|
+
item.value, indentation, content_re, lazy_re, indent_re = parse_first_list_line(@src[1].length, @src[2])
|
76
78
|
list.children << item
|
77
79
|
|
78
80
|
item.value.sub!(/^#{IAL_SPAN_START}\s*/) do |match|
|
@@ -82,26 +84,21 @@ module Kramdown
|
|
82
84
|
|
83
85
|
list_start_re = (type == :ul ? /^( {0,#{[3, indentation - 1].min}}[+*-])([\t| ].*?\n)/ :
|
84
86
|
/^( {0,#{[3, indentation - 1].min}}\d+\.)([\t| ].*?\n)/)
|
85
|
-
nested_list_found =
|
86
|
-
|
87
|
+
nested_list_found = (item.value =~ LIST_START)
|
88
|
+
last_is_blank = false
|
89
|
+
elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re)))
|
87
90
|
result.sub!(/^(\t+)/) { " "*4*($1 ? $1.length : 0) }
|
88
91
|
result.sub!(indent_re, '')
|
89
92
|
if !nested_list_found && result =~ LIST_START
|
90
|
-
|
91
|
-
if item.children.length == 1 && item.children.first.type == :p
|
92
|
-
item.value = ''
|
93
|
-
else
|
94
|
-
item.children.clear
|
95
|
-
end
|
93
|
+
item.value << "^\n"
|
96
94
|
nested_list_found = true
|
97
95
|
end
|
98
96
|
item.value << result
|
97
|
+
last_is_blank = false
|
99
98
|
elsif result = @src.scan(BLANK_LINE)
|
100
99
|
nested_list_found = true
|
100
|
+
last_is_blank = true
|
101
101
|
item.value << result
|
102
|
-
elsif @src.scan(EOB_MARKER)
|
103
|
-
eob_found = true
|
104
|
-
break
|
105
102
|
else
|
106
103
|
break
|
107
104
|
end
|
@@ -113,12 +110,17 @@ module Kramdown
|
|
113
110
|
list.children.each do |it|
|
114
111
|
temp = Element.new(:temp)
|
115
112
|
parse_blocks(temp, it.value)
|
116
|
-
it.children
|
113
|
+
it.children = temp.children
|
117
114
|
it.value = nil
|
118
115
|
next if it.children.size == 0
|
119
116
|
|
120
|
-
|
121
|
-
|
117
|
+
# Handle the case where an EOB marker is inserted by a block IAL for the first paragraph
|
118
|
+
it.children.delete_at(1) if it.children.first.type == :p &&
|
119
|
+
it.children.length >= 2 && it.children[1].type == :eob && it.children.first.options[:ial]
|
120
|
+
|
121
|
+
if it.children.first.type == :p &&
|
122
|
+
(it.children.length < 2 || it.children[1].type != :blank ||
|
123
|
+
(it == list.children.last && it.children.length == 2 && !eob_found)) &&
|
122
124
|
(list.children.last != it || list.children.size == 1 ||
|
123
125
|
list.children[0..-2].any? {|cit| cit.children.first.type != :p || cit.children.first.options[:transparent]})
|
124
126
|
it.children.first.children.first.value += "\n" if it.children.size > 1 && it.children[1].type != :blank
|
@@ -163,14 +165,14 @@ module Kramdown
|
|
163
165
|
end
|
164
166
|
|
165
167
|
item = nil
|
166
|
-
indent_re = nil
|
167
|
-
content_re = nil
|
168
|
+
content_re, lazy_re, indent_re = nil
|
168
169
|
def_start_re = DEFINITION_LIST_START
|
170
|
+
last_is_blank = false
|
169
171
|
while !@src.eos?
|
170
172
|
if @src.scan(def_start_re)
|
171
173
|
item = Element.new(:dd)
|
172
174
|
item.options[:first_as_para] = first_as_para
|
173
|
-
item.value, indentation, content_re, indent_re = parse_first_list_line(@src[1].length, @src[2])
|
175
|
+
item.value, indentation, content_re, lazy_re, indent_re = parse_first_list_line(@src[1].length, @src[2])
|
174
176
|
deflist.children << item
|
175
177
|
|
176
178
|
item.value.sub!(/^#{IAL_SPAN_START}\s*/) do |match|
|
@@ -180,14 +182,19 @@ module Kramdown
|
|
180
182
|
|
181
183
|
def_start_re = /^( {0,#{[3, indentation - 1].min}}:)([\t| ].*?\n)/
|
182
184
|
first_as_para = false
|
183
|
-
|
185
|
+
last_is_blank = false
|
186
|
+
elsif @src.check(EOB_MARKER)
|
187
|
+
break
|
188
|
+
elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re)))
|
184
189
|
result.sub!(/^(\t+)/) { " "*4*($1 ? $1.length : 0) }
|
185
190
|
result.sub!(indent_re, '')
|
186
191
|
item.value << result
|
187
192
|
first_as_para = false
|
193
|
+
last_is_blank = false
|
188
194
|
elsif result = @src.scan(BLANK_LINE)
|
189
195
|
first_as_para = true
|
190
196
|
item.value << result
|
197
|
+
last_is_blank = true
|
191
198
|
else
|
192
199
|
break
|
193
200
|
end
|