motion-kramdown 0.5.0
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.
- checksums.yaml +7 -0
- data/README.md +84 -0
- data/lib/kramdown/compatibility.rb +36 -0
- data/lib/kramdown/converter/base.rb +259 -0
- data/lib/kramdown/converter/html.rb +461 -0
- data/lib/kramdown/converter/kramdown.rb +423 -0
- data/lib/kramdown/converter/latex.rb +600 -0
- data/lib/kramdown/converter/math_engine/itex2mml.rb +39 -0
- data/lib/kramdown/converter/math_engine/mathjax.rb +33 -0
- data/lib/kramdown/converter/math_engine/ritex.rb +38 -0
- data/lib/kramdown/converter/pdf.rb +624 -0
- data/lib/kramdown/converter/remove_html_tags.rb +53 -0
- data/lib/kramdown/converter/syntax_highlighter/coderay.rb +78 -0
- data/lib/kramdown/converter/syntax_highlighter/rouge.rb +37 -0
- data/lib/kramdown/converter/toc.rb +69 -0
- data/lib/kramdown/converter.rb +69 -0
- data/lib/kramdown/document.rb +144 -0
- data/lib/kramdown/element.rb +515 -0
- data/lib/kramdown/error.rb +17 -0
- data/lib/kramdown/options.rb +584 -0
- data/lib/kramdown/parser/base.rb +130 -0
- data/lib/kramdown/parser/gfm.rb +55 -0
- data/lib/kramdown/parser/html.rb +575 -0
- data/lib/kramdown/parser/kramdown/abbreviation.rb +67 -0
- data/lib/kramdown/parser/kramdown/autolink.rb +37 -0
- data/lib/kramdown/parser/kramdown/blank_line.rb +30 -0
- data/lib/kramdown/parser/kramdown/block_boundary.rb +33 -0
- data/lib/kramdown/parser/kramdown/blockquote.rb +39 -0
- data/lib/kramdown/parser/kramdown/codeblock.rb +56 -0
- data/lib/kramdown/parser/kramdown/codespan.rb +44 -0
- data/lib/kramdown/parser/kramdown/emphasis.rb +61 -0
- data/lib/kramdown/parser/kramdown/eob.rb +26 -0
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +25 -0
- data/lib/kramdown/parser/kramdown/extensions.rb +201 -0
- data/lib/kramdown/parser/kramdown/footnote.rb +56 -0
- data/lib/kramdown/parser/kramdown/header.rb +59 -0
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +27 -0
- data/lib/kramdown/parser/kramdown/html.rb +160 -0
- data/lib/kramdown/parser/kramdown/html_entity.rb +33 -0
- data/lib/kramdown/parser/kramdown/line_break.rb +25 -0
- data/lib/kramdown/parser/kramdown/link.rb +139 -0
- data/lib/kramdown/parser/kramdown/list.rb +256 -0
- data/lib/kramdown/parser/kramdown/math.rb +54 -0
- data/lib/kramdown/parser/kramdown/paragraph.rb +54 -0
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +174 -0
- data/lib/kramdown/parser/kramdown/table.rb +171 -0
- data/lib/kramdown/parser/kramdown/typographic_symbol.rb +44 -0
- data/lib/kramdown/parser/kramdown.rb +359 -0
- data/lib/kramdown/parser/markdown.rb +56 -0
- data/lib/kramdown/parser.rb +27 -0
- data/lib/kramdown/utils/configurable.rb +44 -0
- data/lib/kramdown/utils/entities.rb +347 -0
- data/lib/kramdown/utils/html.rb +75 -0
- data/lib/kramdown/utils/ordered_hash.rb +87 -0
- data/lib/kramdown/utils/string_scanner.rb +74 -0
- data/lib/kramdown/utils/unidecoder.rb +51 -0
- data/lib/kramdown/utils.rb +58 -0
- data/lib/kramdown/version.rb +15 -0
- data/lib/kramdown.rb +10 -0
- data/lib/motion-kramdown.rb +47 -0
- data/lib/rubymotion/encodings.rb +37 -0
- data/lib/rubymotion/rexml_shim.rb +25 -0
- data/lib/rubymotion/set.rb +1349 -0
- data/lib/rubymotion/version.rb +6 -0
- data/spec/document_tree.rb +48 -0
- data/spec/gfm_to_html.rb +95 -0
- data/spec/helpers/it_behaves_like.rb +27 -0
- data/spec/helpers/option_file.rb +46 -0
- data/spec/helpers/spec_options.rb +37 -0
- data/spec/helpers/tidy.rb +12 -0
- data/spec/html_to_html.rb +40 -0
- data/spec/html_to_kramdown_to_html.rb +46 -0
- data/spec/kramdown_to_xxx.rb +40 -0
- data/spec/test_location.rb +203 -0
- data/spec/test_string_scanner_kramdown.rb +19 -0
- data/spec/text_to_kramdown_to_html.rb +52 -0
- data/spec/text_to_latex.rb +33 -0
- metadata +164 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module Parser
|
12
|
+
class Kramdown
|
13
|
+
|
14
|
+
if RUBY_VERSION == '1.8.5'
|
15
|
+
ACHARS = '\w\x80-\xFF'
|
16
|
+
elsif RUBY_VERSION < '1.9.0'
|
17
|
+
ACHARS = '\w'
|
18
|
+
else
|
19
|
+
ACHARS = '[[:alnum:]]'
|
20
|
+
end
|
21
|
+
AUTOLINK_START_STR = "<((mailto|https?|ftps?):.+?|[-.#{ACHARS}]+@[-#{ACHARS}]+(?:\.[-#{ACHARS}]+)*\.[a-z]+)>"
|
22
|
+
AUTOLINK_START = /#{AUTOLINK_START_STR}/u
|
23
|
+
|
24
|
+
# Parse the autolink at the current location.
|
25
|
+
def parse_autolink
|
26
|
+
start_line_number = @src.current_line_number
|
27
|
+
@src.pos += @src.matched_size
|
28
|
+
href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1])
|
29
|
+
el = Element.new(:a, nil, {'href' => href}, :location => start_line_number)
|
30
|
+
add_text(@src[1].sub(/^mailto:/, ''), el)
|
31
|
+
@tree.children << el
|
32
|
+
end
|
33
|
+
define_parser(:autolink, AUTOLINK_START, '<')
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module Parser
|
12
|
+
class Kramdown
|
13
|
+
|
14
|
+
BLANK_LINE = /(?:^\s*\n)+/m # RM Oniguruma -> ICU
|
15
|
+
|
16
|
+
# Parse the blank line at the current postition.
|
17
|
+
def parse_blank_line
|
18
|
+
@src.pos += @src.matched_size
|
19
|
+
if @tree.children.last && @tree.children.last.type == :blank
|
20
|
+
@tree.children.last.value << @src.matched
|
21
|
+
else
|
22
|
+
@tree.children << new_block_el(:blank, @src.matched)
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
define_parser(:blank_line, BLANK_LINE)
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'kramdown/parser/kramdown/extensions'
|
11
|
+
# RM require 'kramdown/parser/kramdown/blank_line'
|
12
|
+
# RM require 'kramdown/parser/kramdown/eob'
|
13
|
+
|
14
|
+
module Kramdown
|
15
|
+
module Parser
|
16
|
+
class Kramdown
|
17
|
+
|
18
|
+
BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|#{IAL_BLOCK_START}|\Z/
|
19
|
+
|
20
|
+
# Return +true+ if we are after a block boundary.
|
21
|
+
def after_block_boundary?
|
22
|
+
!@tree.children.last || @tree.children.last.type == :blank ||
|
23
|
+
(@tree.children.last.type == :eob && @tree.children.last.value.nil?) || @block_ial
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return +true+ if we are before a block boundary.
|
27
|
+
def before_block_boundary?
|
28
|
+
@src.check(self.class::BLOCK_BOUNDARY)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'kramdown/parser/kramdown/blank_line'
|
11
|
+
# RM require 'kramdown/parser/kramdown/extensions'
|
12
|
+
# RM require 'kramdown/parser/kramdown/eob'
|
13
|
+
|
14
|
+
module Kramdown
|
15
|
+
module Parser
|
16
|
+
class Kramdown
|
17
|
+
|
18
|
+
BLOCKQUOTE_START = /^#{OPT_SPACE}> ?/
|
19
|
+
|
20
|
+
# Parse the blockquote at the current location.
|
21
|
+
def parse_blockquote
|
22
|
+
start_line_number = @src.current_line_number
|
23
|
+
result = @src.scan(PARAGRAPH_MATCH)
|
24
|
+
while !@src.match?(self.class::LAZY_END)
|
25
|
+
result << @src.scan(PARAGRAPH_MATCH)
|
26
|
+
end
|
27
|
+
result.gsub!(BLOCKQUOTE_START, '')
|
28
|
+
|
29
|
+
el = new_block_el(:blockquote, nil, nil, :location => start_line_number)
|
30
|
+
@tree.children << el
|
31
|
+
parse_blocks(el, result)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
define_parser(:blockquote, BLOCKQUOTE_START)
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'kramdown/parser/kramdown/blank_line'
|
11
|
+
# RM require 'kramdown/parser/kramdown/extensions'
|
12
|
+
# RM require 'kramdown/parser/kramdown/eob'
|
13
|
+
# RM require 'kramdown/parser/kramdown/paragraph'
|
14
|
+
|
15
|
+
module Kramdown
|
16
|
+
module Parser
|
17
|
+
class Kramdown
|
18
|
+
|
19
|
+
CODEBLOCK_START = INDENT
|
20
|
+
CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+(?:(?!#{IAL_BLOCK_START}|#{EOB_MARKER}|#{OPT_SPACE_LAZY_END_HTML_STOP}|#{OPT_SPACE_LAZY_END_HTML_START})^[ \t]*\S.*\n)*)*/
|
21
|
+
# RM modified CODEBLOCK_MATCH with new combined OPT_SPACE_LAZY_END_HTML_STOP/START to support RM changes
|
22
|
+
|
23
|
+
# Parse the indented codeblock at the current location.
|
24
|
+
def parse_codeblock
|
25
|
+
start_line_number = @src.current_line_number
|
26
|
+
data = @src.scan(self.class::CODEBLOCK_MATCH)
|
27
|
+
data.gsub!(/\n( {0,3}\S)/, ' \\1')
|
28
|
+
data.gsub!(INDENT, '')
|
29
|
+
@tree.children << new_block_el(:codeblock, data, nil, :location => start_line_number)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
define_parser(:codeblock, CODEBLOCK_START)
|
33
|
+
|
34
|
+
|
35
|
+
FENCED_CODEBLOCK_START = /^~{3,}/
|
36
|
+
FENCED_CODEBLOCK_MATCH = /^((~){3,})\s*?(\w+)?\s*?\n(.*?)^\1\2*\s*?\n/m
|
37
|
+
|
38
|
+
# Parse the fenced codeblock at the current location.
|
39
|
+
def parse_codeblock_fenced
|
40
|
+
if @src.check(self.class::FENCED_CODEBLOCK_MATCH)
|
41
|
+
start_line_number = @src.current_line_number
|
42
|
+
@src.pos += @src.matched_size
|
43
|
+
el = new_block_el(:codeblock, @src[4], nil, :location => start_line_number)
|
44
|
+
lang = @src[3].to_s.strip
|
45
|
+
el.attr['class'] = "language-#{lang}" unless lang.empty?
|
46
|
+
@tree.children << el
|
47
|
+
true
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
define_parser(:codeblock_fenced, FENCED_CODEBLOCK_START)
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module Parser
|
12
|
+
class Kramdown
|
13
|
+
|
14
|
+
CODESPAN_DELIMITER = /`+/
|
15
|
+
|
16
|
+
# Parse the codespan at the current scanner location.
|
17
|
+
def parse_codespan
|
18
|
+
start_line_number = @src.current_line_number
|
19
|
+
result = @src.scan(CODESPAN_DELIMITER)
|
20
|
+
simple = (result.length == 1)
|
21
|
+
saved_pos = @src.save_pos
|
22
|
+
|
23
|
+
if simple && @src.pre_match =~ /\s\Z/ && @src.match?(/\s/)
|
24
|
+
add_text(result)
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
if text = @src.scan_until(/#{result}/)
|
29
|
+
text.sub!(/#{result}\Z/, '')
|
30
|
+
if !simple
|
31
|
+
text = text[1..-1] if text[0..0] == ' '
|
32
|
+
text = text[0..-2] if text[-1..-1] == ' '
|
33
|
+
end
|
34
|
+
@tree.children << Element.new(:codespan, text, nil, :location => start_line_number)
|
35
|
+
else
|
36
|
+
@src.revert_pos(saved_pos)
|
37
|
+
add_text(result)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
define_parser(:codespan, CODESPAN_DELIMITER, '`')
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module Parser
|
12
|
+
class Kramdown
|
13
|
+
|
14
|
+
EMPHASIS_START = /(?:\*\*?|__?)/
|
15
|
+
|
16
|
+
# Parse the emphasis at the current location.
|
17
|
+
def parse_emphasis
|
18
|
+
start_line_number = @src.current_line_number
|
19
|
+
saved_pos = @src.save_pos
|
20
|
+
|
21
|
+
result = @src.scan(EMPHASIS_START)
|
22
|
+
element = (result.length == 2 ? :strong : :em)
|
23
|
+
type = result[0..0]
|
24
|
+
|
25
|
+
if (type == '_' && @src.pre_match =~ /[[:alnum:]]\z/ && @src.check(/[[:alnum:]]/)) || @src.check(/\s/) ||
|
26
|
+
@tree.type == element || @stack.any? {|el, _| el.type == element}
|
27
|
+
add_text(result)
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
sub_parse = lambda do |delim, elem|
|
32
|
+
el = Element.new(elem, nil, nil, :location => start_line_number)
|
33
|
+
stop_re = /#{Regexp.escape(delim)}/
|
34
|
+
found = parse_spans(el, stop_re) do
|
35
|
+
(@src.pre_match[-1, 1] !~ /\s/) &&
|
36
|
+
(elem != :em || !@src.match?(/#{Regexp.escape(delim*2)}(?!#{Regexp.escape(delim)})/)) &&
|
37
|
+
(type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alnum:]]/)) && el.children.size > 0
|
38
|
+
end
|
39
|
+
[found, el, stop_re]
|
40
|
+
end
|
41
|
+
|
42
|
+
found, el, stop_re = sub_parse.call(result, element)
|
43
|
+
if !found && element == :strong && @tree.type != :em
|
44
|
+
@src.revert_pos(saved_pos)
|
45
|
+
@src.pos += 1
|
46
|
+
found, el, stop_re = sub_parse.call(type, :em)
|
47
|
+
end
|
48
|
+
if found
|
49
|
+
@src.scan(stop_re)
|
50
|
+
@tree.children << el
|
51
|
+
else
|
52
|
+
@src.revert_pos(saved_pos)
|
53
|
+
@src.pos += result.length
|
54
|
+
add_text(result)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
define_parser(:emphasis, EMPHASIS_START, '\*|_')
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module Parser
|
12
|
+
class Kramdown
|
13
|
+
|
14
|
+
EOB_MARKER = /^\^\s*?\n/m # RM Oniguruma -> ICU
|
15
|
+
|
16
|
+
# Parse the EOB marker at the current location.
|
17
|
+
def parse_eob_marker
|
18
|
+
@src.pos += @src.matched_size
|
19
|
+
@tree.children << new_block_el(:eob)
|
20
|
+
true
|
21
|
+
end
|
22
|
+
define_parser(:eob_marker, EOB_MARKER)
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module Parser
|
12
|
+
class Kramdown
|
13
|
+
|
14
|
+
ESCAPED_CHARS = /\\([\\.*_+`<>()\[\]{}#!:|"'\$=-])/
|
15
|
+
|
16
|
+
# Parse the backslash-escaped character at the current location.
|
17
|
+
def parse_escaped_chars
|
18
|
+
@src.pos += @src.matched_size
|
19
|
+
add_text(@src[1])
|
20
|
+
end
|
21
|
+
define_parser(:escaped_chars, ESCAPED_CHARS, '\\\\')
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module Parser
|
12
|
+
class Kramdown
|
13
|
+
|
14
|
+
IAL_CLASS_ATTR = 'class'
|
15
|
+
|
16
|
+
# Parse the string +str+ and extract all attributes and add all found attributes to the hash
|
17
|
+
# +opts+.
|
18
|
+
def parse_attribute_list(str, opts)
|
19
|
+
return if str.strip.empty? || str.strip == ':'
|
20
|
+
attrs = str.scan(ALD_TYPE_ANY)
|
21
|
+
attrs.each do |key, sep, val, ref, id_and_or_class, _, _|
|
22
|
+
if ref
|
23
|
+
(opts[:refs] ||= []) << ref
|
24
|
+
elsif id_and_or_class
|
25
|
+
id_and_or_class.scan(ALD_TYPE_ID_OR_CLASS).each do |id_attr, class_attr|
|
26
|
+
if class_attr
|
27
|
+
opts[IAL_CLASS_ATTR] = (opts[IAL_CLASS_ATTR] || '') << " #{class_attr}"
|
28
|
+
opts[IAL_CLASS_ATTR].lstrip!
|
29
|
+
else
|
30
|
+
opts['id'] = id_attr
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
val.gsub!(/\\(\}|#{sep})/, "\\1")
|
35
|
+
opts[key] = val
|
36
|
+
end
|
37
|
+
end
|
38
|
+
warning("No or invalid attributes found in IAL/ALD content: #{str}") if attrs.length == 0
|
39
|
+
end
|
40
|
+
|
41
|
+
# Update the +ial+ with the information from the inline attribute list +opts+.
|
42
|
+
def update_ial_with_ial(ial, opts)
|
43
|
+
(ial[:refs] ||= []) << opts[:refs]
|
44
|
+
opts.each do |k,v|
|
45
|
+
if k == IAL_CLASS_ATTR
|
46
|
+
ial[k] = (ial[k] || '') << " #{v}"
|
47
|
+
ial[k].lstrip!
|
48
|
+
elsif k.kind_of?(String)
|
49
|
+
ial[k] = v
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Parse the generic extension at the current point. The parameter +type+ can either be :block
|
55
|
+
# or :span depending whether we parse a block or span extension tag.
|
56
|
+
def parse_extension_start_tag(type)
|
57
|
+
saved_pos = @src.save_pos
|
58
|
+
start_line_number = @src.current_line_number
|
59
|
+
@src.pos += @src.matched_size
|
60
|
+
|
61
|
+
error_block = lambda do |msg|
|
62
|
+
warning(msg)
|
63
|
+
@src.revert_pos(saved_pos)
|
64
|
+
add_text(@src.getch) if type == :span
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
if @src[4] || @src.matched == '{:/}'
|
69
|
+
name = (@src[4] ? "for '#{@src[4]}' " : '')
|
70
|
+
return error_block.call("Invalid extension stop tag #{name} found on line #{start_line_number} - ignoring it")
|
71
|
+
end
|
72
|
+
|
73
|
+
ext = @src[1]
|
74
|
+
opts = {}
|
75
|
+
body = nil
|
76
|
+
parse_attribute_list(@src[2] || '', opts)
|
77
|
+
|
78
|
+
if !@src[3]
|
79
|
+
stop_re = (type == :block ? /#{EXT_BLOCK_STOP_STR % ext}/ : /#{EXT_STOP_STR % ext}/)
|
80
|
+
if result = @src.scan_until(stop_re)
|
81
|
+
body = result.sub!(stop_re, '')
|
82
|
+
body.chomp! if type == :block
|
83
|
+
else
|
84
|
+
return error_block.call("No stop tag for extension '#{ext}' found on line #{start_line_number} - ignoring it")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if !handle_extension(ext, opts, body, type, start_line_number)
|
89
|
+
error_block.call("Invalid extension with name '#{ext}' specified on line #{start_line_number} - ignoring it")
|
90
|
+
else
|
91
|
+
true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def handle_extension(name, opts, body, type, line_no = nil)
|
96
|
+
case name
|
97
|
+
when 'comment'
|
98
|
+
@tree.children << Element.new(:comment, body, nil, :category => type, :location => line_no) if body.kind_of?(String)
|
99
|
+
true
|
100
|
+
when 'nomarkdown'
|
101
|
+
@tree.children << Element.new(:raw, body, nil, :category => type, :location => line_no, :type => opts['type'].to_s.split(/\s+/)) if body.kind_of?(String)
|
102
|
+
true
|
103
|
+
when 'options'
|
104
|
+
opts.select do |k,v|
|
105
|
+
k = k.to_sym
|
106
|
+
if Kramdown::Options.defined?(k)
|
107
|
+
begin
|
108
|
+
val = Kramdown::Options.parse(k, v)
|
109
|
+
@options[k] = val
|
110
|
+
(@root.options[:options] ||= {})[k] = val
|
111
|
+
rescue
|
112
|
+
end
|
113
|
+
false
|
114
|
+
else
|
115
|
+
true
|
116
|
+
end
|
117
|
+
end.each do |k,v|
|
118
|
+
warning("Unknown kramdown option '#{k}'")
|
119
|
+
end
|
120
|
+
@tree.children << Element.new(:eob, :extension) if type == :block
|
121
|
+
true
|
122
|
+
else
|
123
|
+
false
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
ALD_ID_CHARS = /[\w-]/
|
129
|
+
ALD_ANY_CHARS = /\\\}|[^\}]/
|
130
|
+
ALD_ID_NAME = /\w#{ALD_ID_CHARS}*/
|
131
|
+
ALD_TYPE_KEY_VALUE_PAIR = /(#{ALD_ID_NAME})=("|')((?:\\\}|\\\2|[^\}\2])*?)\2/
|
132
|
+
ALD_TYPE_CLASS_NAME = /\.(#{ALD_ID_NAME})/
|
133
|
+
ALD_TYPE_ID_NAME = /#([A-Za-z][\w:-]*)/
|
134
|
+
ALD_TYPE_ID_OR_CLASS = /#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME}/
|
135
|
+
ALD_TYPE_ID_OR_CLASS_MULTI = /((?:#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME})+)/
|
136
|
+
ALD_TYPE_REF = /(#{ALD_ID_NAME})/
|
137
|
+
ALD_TYPE_ANY = /(?:\A|\s)(?:#{ALD_TYPE_KEY_VALUE_PAIR}|#{ALD_TYPE_REF}|#{ALD_TYPE_ID_OR_CLASS_MULTI})(?=\s|\Z)/
|
138
|
+
ALD_START = /^#{OPT_SPACE}\{:(#{ALD_ID_NAME}):(#{ALD_ANY_CHARS}+)\}\s*?\n/
|
139
|
+
|
140
|
+
EXT_STOP_STR = "\\{:/(%s)?\\}"
|
141
|
+
EXT_START_STR = "\\{::(\\w+)(?:\\s(#{ALD_ANY_CHARS}*?)|)(\\/)?\\}"
|
142
|
+
EXT_BLOCK_START = /^#{OPT_SPACE}(?:#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME})\s*?\n/
|
143
|
+
EXT_BLOCK_STOP_STR = "^#{OPT_SPACE}#{EXT_STOP_STR}\s*?\n"
|
144
|
+
|
145
|
+
IAL_BLOCK = /\{:(?!:|\/)(#{ALD_ANY_CHARS}+)\}\s*?\n/
|
146
|
+
IAL_BLOCK_START = /^#{OPT_SPACE}#{IAL_BLOCK}/m # RM Oniguruma -> ICU
|
147
|
+
|
148
|
+
BLOCK_EXTENSIONS_START = /^#{OPT_SPACE}\{:/
|
149
|
+
|
150
|
+
# Parse one of the block extensions (ALD, block IAL or generic extension) at the current
|
151
|
+
# location.
|
152
|
+
def parse_block_extensions
|
153
|
+
if @src.scan(ALD_START)
|
154
|
+
parse_attribute_list(@src[2], @alds[@src[1]] ||= Utils::OrderedHash.new)
|
155
|
+
@tree.children << Element.new(:eob, :ald)
|
156
|
+
true
|
157
|
+
elsif @src.check(EXT_BLOCK_START)
|
158
|
+
parse_extension_start_tag(:block)
|
159
|
+
elsif @src.scan(IAL_BLOCK_START)
|
160
|
+
if @tree.children.last && @tree.children.last.type != :blank && @tree.children.last.type != :eob
|
161
|
+
parse_attribute_list(@src[1], @tree.children.last.options[:ial] ||= Utils::OrderedHash.new)
|
162
|
+
@tree.children << Element.new(:eob, :ial) unless @src.check(IAL_BLOCK_START)
|
163
|
+
else
|
164
|
+
parse_attribute_list(@src[1], @block_ial = Utils::OrderedHash.new)
|
165
|
+
end
|
166
|
+
true
|
167
|
+
else
|
168
|
+
false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
define_parser(:block_extensions, BLOCK_EXTENSIONS_START)
|
172
|
+
|
173
|
+
|
174
|
+
EXT_SPAN_START = /#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME}/
|
175
|
+
IAL_SPAN_START = /\{:(#{ALD_ANY_CHARS}+)\}/
|
176
|
+
SPAN_EXTENSIONS_START = /\{:/
|
177
|
+
|
178
|
+
# Parse the extension span at the current location.
|
179
|
+
def parse_span_extensions
|
180
|
+
if @src.check(EXT_SPAN_START)
|
181
|
+
parse_extension_start_tag(:span)
|
182
|
+
elsif @src.check(IAL_SPAN_START)
|
183
|
+
if @tree.children.last && @tree.children.last.type != :text
|
184
|
+
@src.pos += @src.matched_size
|
185
|
+
attr = Utils::OrderedHash.new
|
186
|
+
parse_attribute_list(@src[1], attr)
|
187
|
+
update_ial_with_ial(@tree.children.last.options[:ial] ||= Utils::OrderedHash.new, attr)
|
188
|
+
update_attr_with_ial(@tree.children.last.attr, attr)
|
189
|
+
else
|
190
|
+
warning("Found span IAL after text - ignoring it")
|
191
|
+
add_text(@src.getch)
|
192
|
+
end
|
193
|
+
else
|
194
|
+
add_text(@src.getch)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
define_parser(:span_extensions, SPAN_EXTENSIONS_START, '\{:')
|
198
|
+
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'kramdown/parser/kramdown/extensions'
|
11
|
+
# RM require 'kramdown/parser/kramdown/blank_line'
|
12
|
+
# RM require 'kramdown/parser/kramdown/codeblock'
|
13
|
+
|
14
|
+
module Kramdown
|
15
|
+
module Parser
|
16
|
+
class Kramdown
|
17
|
+
|
18
|
+
FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/
|
19
|
+
|
20
|
+
# Parse the foot note definition at the current location.
|
21
|
+
def parse_footnote_definition
|
22
|
+
start_line_number = @src.current_line_number
|
23
|
+
@src.pos += @src.matched_size
|
24
|
+
|
25
|
+
el = Element.new(:footnote_def, nil, nil, :location => start_line_number)
|
26
|
+
parse_blocks(el, @src[2].gsub(INDENT, ''))
|
27
|
+
warning("Duplicate footnote name '#{@src[1]}' on line #{start_line_number} - overwriting") if @footnotes[@src[1]]
|
28
|
+
(@footnotes[@src[1]] = {})[:content] = el
|
29
|
+
@tree.children << Element.new(:eob, :footnote_def)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START)
|
33
|
+
|
34
|
+
|
35
|
+
FOOTNOTE_MARKER_START = /\[\^(#{ALD_ID_NAME})\]/
|
36
|
+
|
37
|
+
# Parse the footnote marker at the current location.
|
38
|
+
def parse_footnote_marker
|
39
|
+
start_line_number = @src.current_line_number
|
40
|
+
@src.pos += @src.matched_size
|
41
|
+
fn_def = @footnotes[@src[1]]
|
42
|
+
if fn_def
|
43
|
+
fn_def[:marker] ||= []
|
44
|
+
fn_def[:marker].push(Element.new(:footnote, fn_def[:content], nil, :name => @src[1], :location => start_line_number))
|
45
|
+
fn_def[:stack] = [@stack.map {|s| s.first}, @tree, fn_def[:marker]].flatten.compact
|
46
|
+
@tree.children << fn_def[:marker].last
|
47
|
+
else
|
48
|
+
warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}")
|
49
|
+
add_text(@src.matched)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
define_parser(:footnote_marker, FOOTNOTE_MARKER_START, '\[')
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'kramdown/parser/kramdown/block_boundary'
|
11
|
+
|
12
|
+
module Kramdown
|
13
|
+
module Parser
|
14
|
+
class Kramdown
|
15
|
+
|
16
|
+
HEADER_ID=/(?:[ \t]+\{#([A-Za-z][\w:-]*)\})?/
|
17
|
+
SETEXT_HEADER_START = /^(#{OPT_SPACE}[^ \t].*?)#{HEADER_ID}[ \t]*?\n(-|=)+\s*?\n/
|
18
|
+
|
19
|
+
# Parse the Setext header at the current location.
|
20
|
+
def parse_setext_header
|
21
|
+
return false if !after_block_boundary?
|
22
|
+
|
23
|
+
start_line_number = @src.current_line_number
|
24
|
+
@src.pos += @src.matched_size
|
25
|
+
text, id, level = @src[1], @src[2], @src[3]
|
26
|
+
text.strip!
|
27
|
+
el = new_block_el(:header, nil, nil, :level => (level == '-' ? 2 : 1), :raw_text => text, :location => start_line_number)
|
28
|
+
add_text(text, el)
|
29
|
+
el.attr['id'] = id if id
|
30
|
+
@tree.children << el
|
31
|
+
true
|
32
|
+
end
|
33
|
+
define_parser(:setext_header, SETEXT_HEADER_START)
|
34
|
+
|
35
|
+
|
36
|
+
ATX_HEADER_START = /^\#{1,6}/
|
37
|
+
ATX_HEADER_MATCH = /^(\#{1,6})(.+?(?:\\#)?)\s*?#*#{HEADER_ID}\s*?\n/
|
38
|
+
|
39
|
+
# Parse the Atx header at the current location.
|
40
|
+
def parse_atx_header
|
41
|
+
return false if !after_block_boundary?
|
42
|
+
|
43
|
+
start_line_number = @src.current_line_number
|
44
|
+
@src.check(ATX_HEADER_MATCH)
|
45
|
+
level, text, id = @src[1], @src[2].to_s.strip, @src[3]
|
46
|
+
return false if text.empty?
|
47
|
+
|
48
|
+
@src.pos += @src.matched_size
|
49
|
+
el = new_block_el(:header, nil, nil, :level => level.length, :raw_text => text, :location => start_line_number)
|
50
|
+
add_text(text, el)
|
51
|
+
el.attr['id'] = id if id
|
52
|
+
@tree.children << el
|
53
|
+
true
|
54
|
+
end
|
55
|
+
define_parser(:atx_header, ATX_HEADER_START)
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|