bean-kramdown 0.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +1 -0
- data/CONTRIBUTERS +11 -0
- data/COPYING +24 -0
- data/ChangeLog +6683 -0
- data/GPL +674 -0
- data/README +43 -0
- data/VERSION +1 -0
- data/bin/kramdown +78 -0
- data/lib/kramdown.rb +23 -0
- data/lib/kramdown/compatibility.rb +49 -0
- data/lib/kramdown/converter.rb +41 -0
- data/lib/kramdown/converter/base.rb +169 -0
- data/lib/kramdown/converter/bean_html.rb +71 -0
- data/lib/kramdown/converter/html.rb +411 -0
- data/lib/kramdown/converter/kramdown.rb +428 -0
- data/lib/kramdown/converter/latex.rb +607 -0
- data/lib/kramdown/converter/toc.rb +82 -0
- data/lib/kramdown/document.rb +119 -0
- data/lib/kramdown/element.rb +524 -0
- data/lib/kramdown/error.rb +30 -0
- data/lib/kramdown/options.rb +373 -0
- data/lib/kramdown/parser.rb +39 -0
- data/lib/kramdown/parser/base.rb +136 -0
- data/lib/kramdown/parser/bean_kramdown.rb +25 -0
- data/lib/kramdown/parser/bean_kramdown/info_box.rb +52 -0
- data/lib/kramdown/parser/bean_kramdown/oembed.rb +230 -0
- data/lib/kramdown/parser/html.rb +570 -0
- data/lib/kramdown/parser/kramdown.rb +339 -0
- data/lib/kramdown/parser/kramdown/abbreviation.rb +71 -0
- data/lib/kramdown/parser/kramdown/autolink.rb +53 -0
- data/lib/kramdown/parser/kramdown/blank_line.rb +43 -0
- data/lib/kramdown/parser/kramdown/block_boundary.rb +46 -0
- data/lib/kramdown/parser/kramdown/blockquote.rb +51 -0
- data/lib/kramdown/parser/kramdown/codeblock.rb +63 -0
- data/lib/kramdown/parser/kramdown/codespan.rb +56 -0
- data/lib/kramdown/parser/kramdown/emphasis.rb +70 -0
- data/lib/kramdown/parser/kramdown/eob.rb +39 -0
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +38 -0
- data/lib/kramdown/parser/kramdown/extensions.rb +204 -0
- data/lib/kramdown/parser/kramdown/footnote.rb +74 -0
- data/lib/kramdown/parser/kramdown/header.rb +68 -0
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +39 -0
- data/lib/kramdown/parser/kramdown/html.rb +169 -0
- data/lib/kramdown/parser/kramdown/html_entity.rb +44 -0
- data/lib/kramdown/parser/kramdown/image.rb +157 -0
- data/lib/kramdown/parser/kramdown/line_break.rb +38 -0
- data/lib/kramdown/parser/kramdown/link.rb +154 -0
- data/lib/kramdown/parser/kramdown/list.rb +240 -0
- data/lib/kramdown/parser/kramdown/math.rb +65 -0
- data/lib/kramdown/parser/kramdown/paragraph.rb +63 -0
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +214 -0
- data/lib/kramdown/parser/kramdown/table.rb +178 -0
- data/lib/kramdown/parser/kramdown/typographic_symbol.rb +52 -0
- data/lib/kramdown/parser/markdown.rb +69 -0
- data/lib/kramdown/utils.rb +42 -0
- data/lib/kramdown/utils/entities.rb +348 -0
- data/lib/kramdown/utils/html.rb +85 -0
- data/lib/kramdown/utils/ordered_hash.rb +100 -0
- data/lib/kramdown/version.rb +28 -0
- metadata +140 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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
|
+
module Kramdown
|
24
|
+
module Parser
|
25
|
+
class Kramdown
|
26
|
+
|
27
|
+
BLANK_LINE = /(?:^\s*\n)+/
|
28
|
+
|
29
|
+
# Parse the blank line at the current postition.
|
30
|
+
def parse_blank_line
|
31
|
+
@src.pos += @src.matched_size
|
32
|
+
if @tree.children.last && @tree.children.last.type == :blank
|
33
|
+
@tree.children.last.value << @src.matched
|
34
|
+
else
|
35
|
+
@tree.children << new_block_el(:blank, @src.matched)
|
36
|
+
end
|
37
|
+
true
|
38
|
+
end
|
39
|
+
define_parser(:blank_line, BLANK_LINE)
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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/extensions'
|
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(self.class::BLOCK_BOUNDARY)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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/blank_line'
|
24
|
+
require 'kramdown/parser/kramdown/extensions'
|
25
|
+
require 'kramdown/parser/kramdown/eob'
|
26
|
+
|
27
|
+
module Kramdown
|
28
|
+
module Parser
|
29
|
+
class Kramdown
|
30
|
+
|
31
|
+
BLOCKQUOTE_START = /^#{OPT_SPACE}> ?/
|
32
|
+
|
33
|
+
# Parse the blockquote at the current location.
|
34
|
+
def parse_blockquote
|
35
|
+
result = @src.scan(PARAGRAPH_MATCH)
|
36
|
+
while !@src.match?(self.class::LAZY_END)
|
37
|
+
result << @src.scan(PARAGRAPH_MATCH)
|
38
|
+
end
|
39
|
+
result.gsub!(BLOCKQUOTE_START, '')
|
40
|
+
|
41
|
+
el = new_block_el(:blockquote)
|
42
|
+
@tree.children << el
|
43
|
+
parse_blocks(el, result)
|
44
|
+
true
|
45
|
+
end
|
46
|
+
define_parser(:blockquote, BLOCKQUOTE_START)
|
47
|
+
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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/blank_line'
|
24
|
+
require 'kramdown/parser/kramdown/extensions'
|
25
|
+
require 'kramdown/parser/kramdown/eob'
|
26
|
+
require 'kramdown/parser/kramdown/paragraph'
|
27
|
+
|
28
|
+
module Kramdown
|
29
|
+
module Parser
|
30
|
+
class Kramdown
|
31
|
+
|
32
|
+
CODEBLOCK_START = INDENT
|
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)*)*/
|
34
|
+
|
35
|
+
# Parse the indented codeblock at the current location.
|
36
|
+
def parse_codeblock
|
37
|
+
data = @src.scan(self.class::CODEBLOCK_MATCH)
|
38
|
+
data.gsub!(/\n( {0,3}\S)/, ' \\1')
|
39
|
+
data.gsub!(INDENT, '')
|
40
|
+
@tree.children << new_block_el(:codeblock, data)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
define_parser(:codeblock, CODEBLOCK_START)
|
44
|
+
|
45
|
+
|
46
|
+
FENCED_CODEBLOCK_START = /^~{3,}/
|
47
|
+
FENCED_CODEBLOCK_MATCH = /^(~{3,})\s*?\n(.*?)^\1~*\s*?\n/m
|
48
|
+
|
49
|
+
# Parse the fenced codeblock at the current location.
|
50
|
+
def parse_codeblock_fenced
|
51
|
+
if @src.check(FENCED_CODEBLOCK_MATCH)
|
52
|
+
@src.pos += @src.matched_size
|
53
|
+
@tree.children << new_block_el(:codeblock, @src[2])
|
54
|
+
true
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
define_parser(:codeblock_fenced, FENCED_CODEBLOCK_START)
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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
|
+
module Kramdown
|
24
|
+
module Parser
|
25
|
+
class Kramdown
|
26
|
+
|
27
|
+
CODESPAN_DELIMITER = /`+/
|
28
|
+
|
29
|
+
# Parse the codespan at the current scanner location.
|
30
|
+
def parse_codespan
|
31
|
+
result = @src.scan(CODESPAN_DELIMITER)
|
32
|
+
simple = (result.length == 1)
|
33
|
+
reset_pos = @src.pos
|
34
|
+
|
35
|
+
if simple && @src.pre_match =~ /\s\Z/ && @src.match?(/\s/)
|
36
|
+
add_text(result)
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
if text = @src.scan_until(/#{result}/)
|
41
|
+
text.sub!(/#{result}\Z/, '')
|
42
|
+
if !simple
|
43
|
+
text = text[1..-1] if text[0..0] == ' '
|
44
|
+
text = text[0..-2] if text[-1..-1] == ' '
|
45
|
+
end
|
46
|
+
@tree.children << Element.new(:codespan, text)
|
47
|
+
else
|
48
|
+
@src.pos = reset_pos
|
49
|
+
add_text(result)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
define_parser(:codespan, CODESPAN_DELIMITER, '`')
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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
|
+
module Kramdown
|
24
|
+
module Parser
|
25
|
+
class Kramdown
|
26
|
+
|
27
|
+
EMPHASIS_START = /(?:\*\*?|__?)/
|
28
|
+
|
29
|
+
# Parse the emphasis at the current location.
|
30
|
+
def parse_emphasis
|
31
|
+
result = @src.scan(EMPHASIS_START)
|
32
|
+
element = (result.length == 2 ? :strong : :em)
|
33
|
+
type = result[0..0]
|
34
|
+
reset_pos = @src.pos
|
35
|
+
|
36
|
+
if (type == '_' && @src.pre_match =~ /[[:alpha:]]\z/ && @src.check(/[[:alpha:]]/)) || @src.check(/\s/) ||
|
37
|
+
@tree.type == element || @stack.any? {|el, _| el.type == element}
|
38
|
+
add_text(result)
|
39
|
+
return
|
40
|
+
end
|
41
|
+
|
42
|
+
sub_parse = lambda do |delim, elem|
|
43
|
+
el = Element.new(elem)
|
44
|
+
stop_re = /#{Regexp.escape(delim)}/
|
45
|
+
found = parse_spans(el, stop_re) do
|
46
|
+
(@src.pre_match[-1, 1] !~ /\s/) &&
|
47
|
+
(elem != :em || !@src.match?(/#{Regexp.escape(delim*2)}(?!#{Regexp.escape(delim)})/)) &&
|
48
|
+
(type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alpha:]]/)) && el.children.size > 0
|
49
|
+
end
|
50
|
+
[found, el, stop_re]
|
51
|
+
end
|
52
|
+
|
53
|
+
found, el, stop_re = sub_parse.call(result, element)
|
54
|
+
if !found && element == :strong && @tree.type != :em
|
55
|
+
@src.pos = reset_pos - 1
|
56
|
+
found, el, stop_re = sub_parse.call(type, :em)
|
57
|
+
end
|
58
|
+
if found
|
59
|
+
@src.scan(stop_re)
|
60
|
+
@tree.children << el
|
61
|
+
else
|
62
|
+
@src.pos = reset_pos
|
63
|
+
add_text(result)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
define_parser(:emphasis, EMPHASIS_START, '\*|_')
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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
|
+
module Kramdown
|
24
|
+
module Parser
|
25
|
+
class Kramdown
|
26
|
+
|
27
|
+
EOB_MARKER = /^\^\s*?\n/
|
28
|
+
|
29
|
+
# Parse the EOB marker at the current location.
|
30
|
+
def parse_eob_marker
|
31
|
+
@src.pos += @src.matched_size
|
32
|
+
@tree.children << new_block_el(:eob)
|
33
|
+
true
|
34
|
+
end
|
35
|
+
define_parser(:eob_marker, EOB_MARKER)
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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
|
+
module Kramdown
|
24
|
+
module Parser
|
25
|
+
class Kramdown
|
26
|
+
|
27
|
+
ESCAPED_CHARS = /\\([\\.*_+`<>()\[\]{}#!:|"'\$=-])/
|
28
|
+
|
29
|
+
# Parse the backslash-escaped character at the current location.
|
30
|
+
def parse_escaped_chars
|
31
|
+
@src.pos += @src.matched_size
|
32
|
+
add_text(@src[1])
|
33
|
+
end
|
34
|
+
define_parser(:escaped_chars, ESCAPED_CHARS, '\\\\')
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 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
|
+
module Kramdown
|
24
|
+
module Parser
|
25
|
+
class Kramdown
|
26
|
+
|
27
|
+
IAL_CLASS_ATTR = 'class'
|
28
|
+
|
29
|
+
# Parse the string +str+ and extract all attributes and add all found attributes to the hash
|
30
|
+
# +opts+.
|
31
|
+
def parse_attribute_list(str, opts)
|
32
|
+
str.scan(ALD_TYPE_ANY).each do |key, sep, val, id_attr, class_attr, ref|
|
33
|
+
if ref
|
34
|
+
(opts[:refs] ||= []) << ref
|
35
|
+
elsif class_attr
|
36
|
+
opts[IAL_CLASS_ATTR] = (opts[IAL_CLASS_ATTR] || '') << " #{class_attr}"
|
37
|
+
opts[IAL_CLASS_ATTR].lstrip!
|
38
|
+
elsif id_attr
|
39
|
+
opts['id'] = id_attr
|
40
|
+
else
|
41
|
+
val.gsub!(/\\(\}|#{sep})/, "\\1")
|
42
|
+
opts[key] = val
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Update the +ial+ with the information from the inline attribute list +opts+.
|
48
|
+
def update_ial_with_ial(ial, opts)
|
49
|
+
(ial[:refs] ||= []) << opts[:refs]
|
50
|
+
opts.each do |k,v|
|
51
|
+
if k == IAL_CLASS_ATTR
|
52
|
+
ial[k] = (ial[k] || '') << " #{v}"
|
53
|
+
ial[k].lstrip!
|
54
|
+
elsif k.kind_of?(String)
|
55
|
+
ial[k] = v
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Parse the generic extension at the current point. The parameter +type+ can either be :block
|
61
|
+
# or :span depending whether we parse a block or span extension tag.
|
62
|
+
def parse_extension_start_tag(type)
|
63
|
+
orig_pos = @src.pos
|
64
|
+
@src.pos += @src.matched_size
|
65
|
+
|
66
|
+
error_block = lambda do |msg|
|
67
|
+
warning(msg)
|
68
|
+
@src.pos = orig_pos
|
69
|
+
add_text(@src.getch) if type == :span
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
if @src[4] || @src.matched == '{:/}'
|
74
|
+
name = (@src[4] ? "for '#{@src[4]}' " : '')
|
75
|
+
return error_block.call("Invalid extension stop tag #{name}found - ignoring it")
|
76
|
+
end
|
77
|
+
|
78
|
+
ext = @src[1]
|
79
|
+
opts = {}
|
80
|
+
body = nil
|
81
|
+
parse_attribute_list(@src[2] || '', opts)
|
82
|
+
|
83
|
+
if !@src[3]
|
84
|
+
stop_re = (type == :block ? /#{EXT_BLOCK_STOP_STR % ext}/ : /#{EXT_STOP_STR % ext}/)
|
85
|
+
if result = @src.scan_until(stop_re)
|
86
|
+
body = result.sub!(stop_re, '')
|
87
|
+
body.chomp! if type == :block
|
88
|
+
else
|
89
|
+
return error_block.call("No stop tag for extension '#{ext}' found - ignoring it")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if !handle_extension(ext, opts, body, type)
|
94
|
+
error_block.call("Invalid extension with name '#{ext}' specified - ignoring it")
|
95
|
+
else
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def handle_extension(name, opts, body, type)
|
101
|
+
case name
|
102
|
+
when 'comment'
|
103
|
+
@tree.children << Element.new(:comment, body, nil, :category => type) if body.kind_of?(String)
|
104
|
+
true
|
105
|
+
when 'nomarkdown'
|
106
|
+
@tree.children << Element.new(:raw, body, nil, :category => type, :type => opts['type'].to_s.split(/\s+/)) if body.kind_of?(String)
|
107
|
+
true
|
108
|
+
when 'options'
|
109
|
+
opts.select do |k,v|
|
110
|
+
k = k.to_sym
|
111
|
+
if Kramdown::Options.defined?(k)
|
112
|
+
begin
|
113
|
+
val = Kramdown::Options.parse(k, v)
|
114
|
+
@options[k] = val
|
115
|
+
(@root.options[:options] ||= {})[k] = val
|
116
|
+
rescue
|
117
|
+
end
|
118
|
+
false
|
119
|
+
else
|
120
|
+
true
|
121
|
+
end
|
122
|
+
end.each do |k,v|
|
123
|
+
warning("Unknown kramdown option '#{k}'")
|
124
|
+
end
|
125
|
+
@tree.children << Element.new(:eob, :extension) if type == :block
|
126
|
+
true
|
127
|
+
else
|
128
|
+
false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
ALD_ID_CHARS = /[\w-]/
|
134
|
+
ALD_ANY_CHARS = /\\\}|[^\}]/
|
135
|
+
ALD_ID_NAME = /\w#{ALD_ID_CHARS}*/
|
136
|
+
ALD_TYPE_KEY_VALUE_PAIR = /(#{ALD_ID_NAME})=("|')((?:\\\}|\\\2|[^\}\2])*?)\2/
|
137
|
+
ALD_TYPE_CLASS_NAME = /\.(#{ALD_ID_NAME})/
|
138
|
+
ALD_TYPE_ID_NAME = /#(\w[\w:-]*)/
|
139
|
+
ALD_TYPE_REF = /(#{ALD_ID_NAME})/
|
140
|
+
ALD_TYPE_ANY = /(?:\A|\s)(?:#{ALD_TYPE_KEY_VALUE_PAIR}|#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME}|#{ALD_TYPE_REF})(?=\s|\Z)/
|
141
|
+
ALD_START = /^#{OPT_SPACE}\{:(#{ALD_ID_NAME}):(#{ALD_ANY_CHARS}+)\}\s*?\n/
|
142
|
+
|
143
|
+
EXT_STOP_STR = "\\{:/(%s)?\\}"
|
144
|
+
EXT_START_STR = "\\{::(\\w+)(?:\\s(#{ALD_ANY_CHARS}*?)|)(\\/)?\\}"
|
145
|
+
EXT_BLOCK_START = /^#{OPT_SPACE}(?:#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME})\s*?\n/
|
146
|
+
EXT_BLOCK_STOP_STR = "^#{OPT_SPACE}#{EXT_STOP_STR}\s*?\n"
|
147
|
+
|
148
|
+
IAL_BLOCK = /\{:(?!:|\/)(#{ALD_ANY_CHARS}+)\}\s*?\n/
|
149
|
+
IAL_BLOCK_START = /^#{OPT_SPACE}#{IAL_BLOCK}/
|
150
|
+
|
151
|
+
BLOCK_EXTENSIONS_START = /^#{OPT_SPACE}\{:/
|
152
|
+
|
153
|
+
# Parse one of the block extensions (ALD, block IAL or generic extension) at the current
|
154
|
+
# location.
|
155
|
+
def parse_block_extensions
|
156
|
+
if @src.scan(ALD_START)
|
157
|
+
parse_attribute_list(@src[2], @alds[@src[1]] ||= Utils::OrderedHash.new)
|
158
|
+
@tree.children << Element.new(:eob, :ald)
|
159
|
+
true
|
160
|
+
elsif @src.check(EXT_BLOCK_START)
|
161
|
+
parse_extension_start_tag(:block)
|
162
|
+
elsif @src.scan(IAL_BLOCK_START)
|
163
|
+
if @tree.children.last && @tree.children.last.type != :blank && @tree.children.last.type != :eob
|
164
|
+
parse_attribute_list(@src[1], @tree.children.last.options[:ial] ||= Utils::OrderedHash.new)
|
165
|
+
@tree.children << Element.new(:eob, :ial) unless @src.check(IAL_BLOCK_START)
|
166
|
+
else
|
167
|
+
parse_attribute_list(@src[1], @block_ial = Utils::OrderedHash.new)
|
168
|
+
end
|
169
|
+
true
|
170
|
+
else
|
171
|
+
false
|
172
|
+
end
|
173
|
+
end
|
174
|
+
define_parser(:block_extensions, BLOCK_EXTENSIONS_START)
|
175
|
+
|
176
|
+
|
177
|
+
EXT_SPAN_START = /#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME}/
|
178
|
+
IAL_SPAN_START = /\{:(#{ALD_ANY_CHARS}+)\}/
|
179
|
+
SPAN_EXTENSIONS_START = /\{:/
|
180
|
+
|
181
|
+
# Parse the extension span at the current location.
|
182
|
+
def parse_span_extensions
|
183
|
+
if @src.check(EXT_SPAN_START)
|
184
|
+
parse_extension_start_tag(:span)
|
185
|
+
elsif @src.check(IAL_SPAN_START)
|
186
|
+
if @tree.children.last && @tree.children.last.type != :text
|
187
|
+
@src.pos += @src.matched_size
|
188
|
+
attr = Utils::OrderedHash.new
|
189
|
+
parse_attribute_list(@src[1], attr)
|
190
|
+
update_ial_with_ial(@tree.children.last.options[:ial] ||= Utils::OrderedHash.new, attr)
|
191
|
+
update_attr_with_ial(@tree.children.last.attr, attr)
|
192
|
+
else
|
193
|
+
warning("Found span IAL after text - ignoring it")
|
194
|
+
add_text(@src.getch)
|
195
|
+
end
|
196
|
+
else
|
197
|
+
add_text(@src.getch)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
define_parser(:span_extensions, SPAN_EXTENSIONS_START, '\{:')
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|