bean-kramdown 0.13.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|