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