motion-markdown-it-plugins 1.0.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 +18 -0
- data/lib/motion-markdown-it-plugins.rb +24 -0
- data/lib/motion-markdown-it-plugins/abbr/abbr.rb +130 -0
- data/lib/motion-markdown-it-plugins/checkbox_replace/checkbox_replace.rb +103 -0
- data/lib/motion-markdown-it-plugins/container/container.rb +154 -0
- data/lib/motion-markdown-it-plugins/deflist/deflist.rb +185 -0
- data/lib/motion-markdown-it-plugins/ins/ins.rb +136 -0
- data/lib/motion-markdown-it-plugins/mark/mark.rb +136 -0
- data/lib/motion-markdown-it-plugins/sub/sub.rb +70 -0
- data/lib/motion-markdown-it-plugins/sup/sup.rb +71 -0
- data/lib/motion-markdown-it-plugins/version.rb +5 -0
- data/spec/abbr/abbr_spec.rb +8 -0
- data/spec/checkbox_replace/checkbox_replace_spec.rb +64 -0
- data/spec/container/api_spec.rb +76 -0
- data/spec/container/default_spec.rb +8 -0
- data/spec/container/misc_spec.rb +17 -0
- data/spec/deflist/deflist_spec.rb +9 -0
- data/spec/ins/ins_spec.rb +9 -0
- data/spec/mark/mark_spec.rb +9 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/sub/sub_spec.rb +9 -0
- data/spec/sup/sup_spec.rb +9 -0
- data/spec/testgen_helper.rb +80 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 932bce733bfd0e1070663a7b560a5e255817c85c
|
4
|
+
data.tar.gz: 54572d459acb95df6d00fd0736ee71f5ecc3691d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1bf53209e1279e1467415f9c9b8b91f59e57ec526edac36cad5b287993a8ea6b7409202490e84017b9487d98915e359a4012f59f232aaf568335546c5f9632b3
|
7
|
+
data.tar.gz: 9b67f602c172395eb74d7d9c2a114a6315df287eb3ae404c821eeb253c11fe0cd828e705bf2f2c17b59827ea47279d277a6882aa8cda0a6753b8d2d9769cbc91
|
data/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# motion-markdown-it-plugins
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/motion-markdown-it-plugins)
|
4
|
+
|
5
|
+
Various useful plugins for use with `motion-markdown-it`. Works with Ruby and RubyMotion.
|
6
|
+
|
7
|
+
## Plugins
|
8
|
+
|
9
|
+
Each one has a README with details
|
10
|
+
|
11
|
+
* [Abbreviations](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/abbr)
|
12
|
+
* [Checkbox/Tasklists](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/checkbox_replace)
|
13
|
+
* [Containers](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/container)
|
14
|
+
* [Definition Lists](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/deflist)
|
15
|
+
* [Insert](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/ins)
|
16
|
+
* [Mark](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/mark)
|
17
|
+
* [Subscript](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/sub)
|
18
|
+
* [Superscript](https://github.com/digitalmoksha/motion-markdown-it-plugins/tree/master/lib/motion-markdown-it-plugins/sup)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
if defined?(Motion::Project::Config)
|
4
|
+
|
5
|
+
lib_dir_path = File.dirname(File.expand_path(__FILE__))
|
6
|
+
Motion::Project::App.setup do |app|
|
7
|
+
app.files.unshift(Dir.glob(File.join(lib_dir_path, "motion-markdown-it-plugins/**/*.rb")))
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'motion-markdown-it'
|
11
|
+
|
12
|
+
else
|
13
|
+
|
14
|
+
require 'motion-markdown-it'
|
15
|
+
require 'motion-markdown-it-plugins/checkbox_replace/checkbox_replace'
|
16
|
+
require 'motion-markdown-it-plugins/deflist/deflist'
|
17
|
+
require 'motion-markdown-it-plugins/abbr/abbr'
|
18
|
+
require 'motion-markdown-it-plugins/ins/ins'
|
19
|
+
require 'motion-markdown-it-plugins/mark/mark'
|
20
|
+
require 'motion-markdown-it-plugins/sub/sub'
|
21
|
+
require 'motion-markdown-it-plugins/sup/sup'
|
22
|
+
require 'motion-markdown-it-plugins/container/container'
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# Enclose abbreviations in <abbr> tags
|
2
|
+
#
|
3
|
+
# Based on Javascript version: https://github.com/markdown-it/markdown-it-abbr
|
4
|
+
#------------------------------------------------------------------------------
|
5
|
+
include MarkdownIt::Common::Utils
|
6
|
+
|
7
|
+
module MotionMarkdownItPlugins
|
8
|
+
class Abbr
|
9
|
+
PUNCT_CHARS = ' \n()[]\'".,!?-'
|
10
|
+
PUNCT_CAHRS_ESCAPED = PUNCT_CHARS.chars.map {|c| escapeRE(c)}.join
|
11
|
+
|
12
|
+
#------------------------------------------------------------------------------
|
13
|
+
def self.init_plugin(md)
|
14
|
+
md.block.ruler.before('reference', 'abbr_def',
|
15
|
+
lambda { |state, startLine, endLine, silent| Abbr.abbr_def(state, startLine, endLine, silent) },
|
16
|
+
{alt: ['', 'paragraph', 'reference']})
|
17
|
+
md.core.ruler.after('inline', 'abbr_replace', lambda { |state| Abbr.abbr_replace(state) })
|
18
|
+
end
|
19
|
+
|
20
|
+
#------------------------------------------------------------------------------
|
21
|
+
def self.abbr_def(state, startLine, endLine, silent)
|
22
|
+
pos = state.bMarks[startLine] + state.tShift[startLine]
|
23
|
+
max = state.eMarks[startLine]
|
24
|
+
|
25
|
+
return false if (pos + 2 >= max)
|
26
|
+
return false if (state.src.charCodeAt(pos) != 0x2A) # '*'
|
27
|
+
pos += 1
|
28
|
+
return false if (state.src.charCodeAt(pos) != 0x5B) # '['
|
29
|
+
pos += 1
|
30
|
+
|
31
|
+
labelStart = pos
|
32
|
+
|
33
|
+
while pos < max
|
34
|
+
ch = state.src.charCodeAt(pos)
|
35
|
+
if (ch == 0x5B) # '['
|
36
|
+
return false
|
37
|
+
elsif (ch == 0x5D) # ']'
|
38
|
+
labelEnd = pos
|
39
|
+
break
|
40
|
+
elsif (ch == 0x5C) # '\'
|
41
|
+
pos += 1
|
42
|
+
end
|
43
|
+
pos += 1
|
44
|
+
end
|
45
|
+
|
46
|
+
return false if (labelEnd < 0 || state.src.charCodeAt(labelEnd + 1) != 0x3A) # ':'
|
47
|
+
return true if (silent)
|
48
|
+
|
49
|
+
label = state.src.slice(labelStart...labelEnd).gsub(/\\(.)/, '\1')
|
50
|
+
title = state.src.slice((labelEnd + 2)...max).strip
|
51
|
+
return false if (title.length == 0)
|
52
|
+
|
53
|
+
state.env[:abbreviations] = {} if (!state.env[:abbreviations])
|
54
|
+
state.env[:abbreviations][label] = title if state.env[:abbreviations][label].nil?
|
55
|
+
|
56
|
+
state.line = startLine + 1
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
|
60
|
+
#------------------------------------------------------------------------------
|
61
|
+
def self.abbr_replace(state)
|
62
|
+
blockTokens = state.tokens
|
63
|
+
|
64
|
+
return if (!state.env[:abbreviations])
|
65
|
+
if (!state.env[:abbrRegExp])
|
66
|
+
regText = "(^|[#{PUNCT_CAHRS_ESCAPED}])("
|
67
|
+
regText << state.env[:abbreviations].keys.sort {|a, b| b.length <=> a.length}.map {|x| escapeRE(x)}.join('|')
|
68
|
+
regText << ")($|[#{PUNCT_CAHRS_ESCAPED}])"
|
69
|
+
|
70
|
+
state.env[:abbrRegExp] = Regexp.new(regText)
|
71
|
+
end
|
72
|
+
reg = state.env[:abbrRegExp]
|
73
|
+
|
74
|
+
j = 0
|
75
|
+
l = blockTokens.length
|
76
|
+
while j < l
|
77
|
+
j += 1 and next if (blockTokens[j].type != 'inline')
|
78
|
+
tokens = blockTokens[j].children
|
79
|
+
|
80
|
+
# We scan from the end, to keep position when new tags added.
|
81
|
+
i = tokens.length - 1
|
82
|
+
while i >= 0
|
83
|
+
currentToken = tokens[i]
|
84
|
+
i -= 1 and next if (currentToken.type != 'text')
|
85
|
+
|
86
|
+
pos = 0
|
87
|
+
text = currentToken.content
|
88
|
+
lastIndex = 0
|
89
|
+
nodes = []
|
90
|
+
|
91
|
+
while ((m = reg.match(text, lastIndex)))
|
92
|
+
lastIndex = m.end(0)
|
93
|
+
if (lastIndex > pos)
|
94
|
+
token = MarkdownIt::Token.new('text', '', 0)
|
95
|
+
token.content = text.slice(pos...(m.begin(0) + m[1].length))
|
96
|
+
nodes.push(token)
|
97
|
+
end
|
98
|
+
|
99
|
+
token = MarkdownIt::Token.new('abbr_open', 'abbr', 1)
|
100
|
+
token.attrs = [ [ 'title', state.env[:abbreviations][m[2]] ] ]
|
101
|
+
nodes.push(token)
|
102
|
+
|
103
|
+
token = MarkdownIt::Token.new('text', '', 0)
|
104
|
+
token.content = m[2]
|
105
|
+
nodes.push(token)
|
106
|
+
|
107
|
+
token = MarkdownIt::Token.new('abbr_close', 'abbr', -1)
|
108
|
+
nodes.push(token)
|
109
|
+
|
110
|
+
pos = lastIndex - m[3].length
|
111
|
+
end
|
112
|
+
|
113
|
+
i -= 1 and next if nodes.empty?
|
114
|
+
|
115
|
+
if (pos < text.length)
|
116
|
+
token = MarkdownIt::Token.new('text', '', 0)
|
117
|
+
token.content = text.slice(pos..-1)
|
118
|
+
nodes.push(token)
|
119
|
+
end
|
120
|
+
|
121
|
+
# replace current node
|
122
|
+
blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes)
|
123
|
+
i -= 1
|
124
|
+
end
|
125
|
+
j += 1
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# Based on Javascript version: https://github.com/mcecot/markdown-it-checkbox
|
2
|
+
#------------------------------------------------------------------------------
|
3
|
+
include MarkdownIt::Common::Utils
|
4
|
+
|
5
|
+
module MotionMarkdownItPlugins
|
6
|
+
class CheckboxReplace
|
7
|
+
PATTERN = /\[(X|\s|\_|\-)\]\s(.*)/i
|
8
|
+
|
9
|
+
#------------------------------------------------------------------------------
|
10
|
+
def self.init_plugin(md, options)
|
11
|
+
check = CheckboxReplace.new(md, options)
|
12
|
+
md.core.ruler.push('checkbox', lambda { |state| check.checkbox(state) } )
|
13
|
+
end
|
14
|
+
|
15
|
+
#------------------------------------------------------------------------------
|
16
|
+
def initialize(md, options)
|
17
|
+
@lastId = 0
|
18
|
+
defaults = {divWrap: false, divClass: 'checkbox', idPrefix: 'checkbox'}
|
19
|
+
@options = defaults.merge(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
#------------------------------------------------------------------------------
|
23
|
+
def createTokens(checked, label)
|
24
|
+
nodes = []
|
25
|
+
|
26
|
+
# <div class="checkbox">
|
27
|
+
if @options[:divWrap]
|
28
|
+
token = MarkdownIt::Token.new("checkbox_open", "div", 1)
|
29
|
+
token.attrs = [["class", @options[:divClass]]]
|
30
|
+
nodes.push token
|
31
|
+
end
|
32
|
+
|
33
|
+
# <input type="checkbox" id="checkbox{n}" checked="true">
|
34
|
+
id = "#{@options[:idPrefix]}#{@lastId}"
|
35
|
+
@lastId += 1
|
36
|
+
token = MarkdownIt::Token.new("checkbox_input", "input", 0)
|
37
|
+
token.attrs = [["type","checkbox"],["id",id]]
|
38
|
+
if (checked == true)
|
39
|
+
token.attrs.push ["checked","true"]
|
40
|
+
end
|
41
|
+
nodes.push token
|
42
|
+
|
43
|
+
# <label for="checkbox{n}">
|
44
|
+
token = MarkdownIt::Token.new("label_open", "label", 1)
|
45
|
+
token.attrs = [["for",id]]
|
46
|
+
nodes.push token
|
47
|
+
|
48
|
+
# content of label tag
|
49
|
+
token = MarkdownIt::Token.new("text", "", 0)
|
50
|
+
token.content = label
|
51
|
+
nodes.push token
|
52
|
+
|
53
|
+
# closing tags
|
54
|
+
nodes.push MarkdownIt::Token.new("label_close", "label", -1)
|
55
|
+
if @options[:divWrap]
|
56
|
+
nodes.push MarkdownIt::Token.new("checkbox_close", "div", -1)
|
57
|
+
end
|
58
|
+
|
59
|
+
return nodes
|
60
|
+
end
|
61
|
+
|
62
|
+
#------------------------------------------------------------------------------
|
63
|
+
def splitTextToken(original)
|
64
|
+
|
65
|
+
text = original.content
|
66
|
+
matches = text.match(PATTERN)
|
67
|
+
|
68
|
+
return original if matches == nil
|
69
|
+
|
70
|
+
value = matches[1]
|
71
|
+
label = matches[2]
|
72
|
+
checked = false
|
73
|
+
checked = true if (value == "X" || value == "x")
|
74
|
+
|
75
|
+
return createTokens(checked, label)
|
76
|
+
end
|
77
|
+
|
78
|
+
#------------------------------------------------------------------------------
|
79
|
+
def checkbox(state)
|
80
|
+
blockTokens = state.tokens
|
81
|
+
j = 0
|
82
|
+
l = blockTokens.length
|
83
|
+
while j < l
|
84
|
+
if blockTokens[j].type != "inline"
|
85
|
+
j += 1
|
86
|
+
next
|
87
|
+
end
|
88
|
+
tokens = blockTokens[j].children
|
89
|
+
|
90
|
+
# We scan from the end, to keep position when new tags added.
|
91
|
+
# Use reversed logic in links start/end match
|
92
|
+
i = tokens.length - 1
|
93
|
+
while i >= 0
|
94
|
+
token = tokens[i]
|
95
|
+
blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, splitTextToken(token))
|
96
|
+
i -= 1
|
97
|
+
end
|
98
|
+
j += 1
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# Process block-level custom containers
|
2
|
+
#
|
3
|
+
# Based on Javascript version: https://github.com/markdown-it/markdown-it-container
|
4
|
+
#------------------------------------------------------------------------------
|
5
|
+
|
6
|
+
module MotionMarkdownItPlugins
|
7
|
+
class Container
|
8
|
+
extend MarkdownIt::Common::Utils
|
9
|
+
|
10
|
+
attr_accessor :render
|
11
|
+
|
12
|
+
#------------------------------------------------------------------------------
|
13
|
+
def self.init_plugin(md, name, options = {})
|
14
|
+
container_obj = Container.new(md, name, options)
|
15
|
+
md.block.ruler.before('fence', "container_#{name}",
|
16
|
+
lambda { |state, startLine, endLine, silent| container_obj.container(state, startLine, endLine, silent) },
|
17
|
+
{alt: [ '', 'paragraph', 'reference', 'blockquote', 'list' ]})
|
18
|
+
|
19
|
+
md.renderer.rules["container_#{name}_open"] = container_obj.render
|
20
|
+
md.renderer.rules["container_#{name}_close"] = container_obj.render
|
21
|
+
end
|
22
|
+
|
23
|
+
#------------------------------------------------------------------------------
|
24
|
+
def initialize(md, name, options)
|
25
|
+
@options = options || {}
|
26
|
+
@name = name
|
27
|
+
@min_markers = 3
|
28
|
+
@marker_str = @options[:marker] || ':'
|
29
|
+
@marker_char = @marker_str.charCodeAt(0)
|
30
|
+
@marker_len = @marker_str.length
|
31
|
+
@validate = @options[:validate] || lambda {|params| validateDefault(params) }
|
32
|
+
@render = @options[:render] || lambda {|tokens, idx, _options, env, renderer| renderDefault(tokens, idx, _options, env, renderer) }
|
33
|
+
end
|
34
|
+
|
35
|
+
#------------------------------------------------------------------------------
|
36
|
+
def validateDefault(params)
|
37
|
+
return params.strip.split(' ', 2)[0] == @name
|
38
|
+
end
|
39
|
+
|
40
|
+
#------------------------------------------------------------------------------
|
41
|
+
def renderDefault(tokens, idx, _options, env, renderer)
|
42
|
+
|
43
|
+
# add a class to the opening tag
|
44
|
+
if (tokens[idx].nesting == 1)
|
45
|
+
tokens[idx].attrPush([ 'class', @name ])
|
46
|
+
end
|
47
|
+
|
48
|
+
return renderer.renderToken(tokens, idx, _options, env, renderer)
|
49
|
+
end
|
50
|
+
|
51
|
+
#------------------------------------------------------------------------------
|
52
|
+
def container(state, startLine, endLine, silent)
|
53
|
+
auto_closed = false
|
54
|
+
start = state.bMarks[startLine] + state.tShift[startLine]
|
55
|
+
max = state.eMarks[startLine]
|
56
|
+
|
57
|
+
# Check out the first character quickly,
|
58
|
+
# this should filter out most of non-containers
|
59
|
+
return false if (@marker_char != state.src.charCodeAt(start))
|
60
|
+
|
61
|
+
# Check out the rest of the marker string
|
62
|
+
pos = start + 1
|
63
|
+
while pos <= max
|
64
|
+
break if (@marker_str[(pos - start) % @marker_len] != state.src[pos])
|
65
|
+
pos += 1
|
66
|
+
end
|
67
|
+
|
68
|
+
marker_count = ((pos - start) / @marker_len).floor
|
69
|
+
return false if (marker_count < @min_markers)
|
70
|
+
pos -= (pos - start) % @marker_len
|
71
|
+
|
72
|
+
markup = state.src.slice(start...pos)
|
73
|
+
params = state.src.slice(pos...max)
|
74
|
+
return false if (!@validate.call(params))
|
75
|
+
|
76
|
+
# Since start is found, we can report success here in validation mode
|
77
|
+
return true if (silent)
|
78
|
+
|
79
|
+
# Search for the end of the block
|
80
|
+
nextLine = startLine
|
81
|
+
|
82
|
+
while true
|
83
|
+
nextLine += 1
|
84
|
+
if (nextLine >= endLine)
|
85
|
+
# unclosed block should be autoclosed by end of document.
|
86
|
+
# also block seems to be autoclosed by end of parent
|
87
|
+
break
|
88
|
+
end
|
89
|
+
|
90
|
+
start = state.bMarks[nextLine] + state.tShift[nextLine]
|
91
|
+
max = state.eMarks[nextLine]
|
92
|
+
|
93
|
+
if (start < max && state.tShift[nextLine] < state.blkIndent)
|
94
|
+
# non-empty line with negative indent should stop the list:
|
95
|
+
# - ```
|
96
|
+
# test
|
97
|
+
break
|
98
|
+
end
|
99
|
+
|
100
|
+
next if (@marker_char != state.src.charCodeAt(start))
|
101
|
+
|
102
|
+
if (state.tShift[nextLine] - state.blkIndent >= 4)
|
103
|
+
# closing fence should be indented less than 4 spaces
|
104
|
+
next
|
105
|
+
end
|
106
|
+
|
107
|
+
pos = start + 1
|
108
|
+
while pos <= max
|
109
|
+
break if (@marker_str[(pos - start) % @marker_len] != state.src[pos])
|
110
|
+
pos += 1
|
111
|
+
end
|
112
|
+
|
113
|
+
# closing code fence must be at least as long as the opening one
|
114
|
+
next if (((pos - start).floor / @marker_len) < marker_count)
|
115
|
+
|
116
|
+
# make sure tail has spaces only
|
117
|
+
pos -= (pos - start) % @marker_len
|
118
|
+
pos = state.skipSpaces(pos)
|
119
|
+
|
120
|
+
next if (pos < max)
|
121
|
+
|
122
|
+
# found!
|
123
|
+
auto_closed = true
|
124
|
+
break
|
125
|
+
end
|
126
|
+
|
127
|
+
old_parent = state.parentType
|
128
|
+
old_line_max = state.lineMax
|
129
|
+
state.parentType = 'container'
|
130
|
+
|
131
|
+
# this will prevent lazy continuations from ever going past our end marker
|
132
|
+
state.lineMax = nextLine
|
133
|
+
|
134
|
+
token = state.push("container_#{@name}_open", 'div', 1)
|
135
|
+
token.markup = markup
|
136
|
+
token.block = true
|
137
|
+
token.info = params
|
138
|
+
token.map = [ startLine, nextLine ]
|
139
|
+
|
140
|
+
state.md.block.tokenize(state, startLine + 1, nextLine)
|
141
|
+
|
142
|
+
token = state.push("container_#{@name}_close", 'div', -1)
|
143
|
+
token.markup = state.src.slice(start...pos)
|
144
|
+
token.block = true
|
145
|
+
|
146
|
+
state.parentType = old_parent
|
147
|
+
state.lineMax = old_line_max
|
148
|
+
state.line = nextLine + (auto_closed ? 1 : 0)
|
149
|
+
|
150
|
+
return true
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# Process definition lists
|
2
|
+
#
|
3
|
+
# Based on Javascript version: https://github.com/markdown-it/markdown-it-deflist
|
4
|
+
#------------------------------------------------------------------------------
|
5
|
+
include MarkdownIt::Common::Utils
|
6
|
+
|
7
|
+
module MotionMarkdownItPlugins
|
8
|
+
class Deflist
|
9
|
+
|
10
|
+
#------------------------------------------------------------------------------
|
11
|
+
def self.init_plugin(md)
|
12
|
+
md.block.ruler.before('paragraph', 'deflist',
|
13
|
+
lambda { |state, startLine, endLine, silent| Deflist.deflist(state, startLine, endLine, silent) },
|
14
|
+
{alt: ['', 'paragraph', 'reference']})
|
15
|
+
end
|
16
|
+
|
17
|
+
# Search `[:~][\n ]`, returns next pos after marker on success
|
18
|
+
# or -1 on fail.
|
19
|
+
#------------------------------------------------------------------------------
|
20
|
+
def self.skipMarker(state, line)
|
21
|
+
start = state.bMarks[line] + state.tShift[line]
|
22
|
+
max = state.eMarks[line]
|
23
|
+
|
24
|
+
return -1 if (start >= max)
|
25
|
+
|
26
|
+
# Check bullet
|
27
|
+
marker = state.src.charCodeAt(start)
|
28
|
+
start += 1
|
29
|
+
return -1 if (marker != 0x7E && marker != 0x3A) # '~' ':'
|
30
|
+
|
31
|
+
pos = state.skipSpaces(start)
|
32
|
+
|
33
|
+
# require space after ":"
|
34
|
+
return -1 if (start == pos)
|
35
|
+
|
36
|
+
# no empty definitions, e.g. " : "
|
37
|
+
return -1 if (pos >= max)
|
38
|
+
|
39
|
+
return pos
|
40
|
+
end
|
41
|
+
|
42
|
+
#------------------------------------------------------------------------------
|
43
|
+
def self.markTightParagraphs(state, idx)
|
44
|
+
level = state.level + 2
|
45
|
+
i = idx + 2
|
46
|
+
l = state.tokens.length - 2
|
47
|
+
while i < l
|
48
|
+
if (state.tokens[i].level == level && state.tokens[i].type == 'paragraph_open')
|
49
|
+
state.tokens[i + 2].hidden = true
|
50
|
+
state.tokens[i].hidden = true
|
51
|
+
i += 2
|
52
|
+
end
|
53
|
+
i += 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#------------------------------------------------------------------------------
|
58
|
+
def self.deflist(state, startLine, endLine, silent)
|
59
|
+
if silent
|
60
|
+
# quirk: validation mode validates a dd block only, not a whole deflist
|
61
|
+
return false if (state.ddIndent < 0)
|
62
|
+
return skipMarker(state, startLine) >= 0
|
63
|
+
end
|
64
|
+
|
65
|
+
nextLine = startLine + 1
|
66
|
+
if (state.isEmpty(nextLine))
|
67
|
+
nextLine += 1
|
68
|
+
return false if (nextLine > endLine)
|
69
|
+
end
|
70
|
+
|
71
|
+
return false if (state.tShift[nextLine] < state.blkIndent)
|
72
|
+
contentStart = skipMarker(state, nextLine)
|
73
|
+
return false if (contentStart < 0)
|
74
|
+
|
75
|
+
# Start list
|
76
|
+
listTokIdx = state.tokens.length
|
77
|
+
token = state.push('dl_open', 'dl', 1)
|
78
|
+
token.map = listLines = [ startLine, 0 ]
|
79
|
+
|
80
|
+
#--- Iterate list items
|
81
|
+
|
82
|
+
dtLine = startLine
|
83
|
+
ddLine = nextLine
|
84
|
+
|
85
|
+
# One definition list can contain multiple DTs,
|
86
|
+
# and one DT can be followed by multiple DDs.
|
87
|
+
#
|
88
|
+
# Thus, there is two loops here, and label is
|
89
|
+
# needed to break out of the second one
|
90
|
+
# OUTER:
|
91
|
+
while true
|
92
|
+
break_outer = false
|
93
|
+
tight = true
|
94
|
+
prevEmptyEnd = false
|
95
|
+
|
96
|
+
token = state.push('dt_open', 'dt', 1)
|
97
|
+
token.map = [ dtLine, dtLine ]
|
98
|
+
|
99
|
+
token = state.push('inline', '', 0)
|
100
|
+
token.map = [ dtLine, dtLine ]
|
101
|
+
token.content = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).strip
|
102
|
+
token.children = []
|
103
|
+
|
104
|
+
token = state.push('dt_close', 'dt', -1)
|
105
|
+
|
106
|
+
while true
|
107
|
+
token = state.push('dd_open', 'dd', 1)
|
108
|
+
token.map = itemLines = [ nextLine, 0 ]
|
109
|
+
|
110
|
+
oldTight = state.tight
|
111
|
+
oldDDIndent = state.ddIndent
|
112
|
+
oldIndent = state.blkIndent
|
113
|
+
oldTShift = state.tShift[ddLine]
|
114
|
+
oldParentType = state.parentType
|
115
|
+
state.blkIndent = state.ddIndent = state.tShift[ddLine] + 2
|
116
|
+
state.tShift[ddLine] = contentStart - state.bMarks[ddLine]
|
117
|
+
state.tight = true
|
118
|
+
state.parentType = 'deflist'
|
119
|
+
|
120
|
+
state.md.block.tokenize(state, ddLine, endLine, true)
|
121
|
+
|
122
|
+
# If any of list item is tight, mark list as tight
|
123
|
+
if (!state.tight || prevEmptyEnd)
|
124
|
+
tight = false
|
125
|
+
end
|
126
|
+
# Item become loose if finish with empty line,
|
127
|
+
# but we should filter last element, because it means list finish
|
128
|
+
prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1)
|
129
|
+
|
130
|
+
state.tShift[ddLine] = oldTShift
|
131
|
+
state.tight = oldTight
|
132
|
+
state.parentType = oldParentType
|
133
|
+
state.blkIndent = oldIndent
|
134
|
+
state.ddIndent = oldDDIndent
|
135
|
+
|
136
|
+
token = state.push('dd_close', 'dd', -1)
|
137
|
+
|
138
|
+
itemLines[1] = nextLine = state.line
|
139
|
+
|
140
|
+
break_outer = true and break if (nextLine >= endLine)
|
141
|
+
break_outer = true and break if (state.tShift[nextLine] < state.blkIndent)
|
142
|
+
contentStart = skipMarker(state, nextLine)
|
143
|
+
break if (contentStart < 0)
|
144
|
+
|
145
|
+
ddLine = nextLine
|
146
|
+
|
147
|
+
# go to the next loop iteration:
|
148
|
+
# insert DD tag and repeat checking
|
149
|
+
end
|
150
|
+
break if break_outer
|
151
|
+
|
152
|
+
break if (nextLine >= endLine)
|
153
|
+
dtLine = nextLine
|
154
|
+
|
155
|
+
break if (state.isEmpty(dtLine))
|
156
|
+
break if (state.tShift[dtLine] < state.blkIndent)
|
157
|
+
|
158
|
+
ddLine = dtLine + 1
|
159
|
+
break if (ddLine >= endLine)
|
160
|
+
ddLine += 1 if (state.isEmpty(ddLine))
|
161
|
+
break if (ddLine >= endLine)
|
162
|
+
|
163
|
+
break if (state.tShift[ddLine] < state.blkIndent)
|
164
|
+
contentStart = skipMarker(state, ddLine)
|
165
|
+
break if (contentStart < 0)
|
166
|
+
|
167
|
+
# go to the next loop iteration:
|
168
|
+
# insert DT and DD tags and repeat checking
|
169
|
+
end
|
170
|
+
|
171
|
+
# Finilize list
|
172
|
+
token = state.push('dl_close', 'dl', -1)
|
173
|
+
listLines[1] = nextLine
|
174
|
+
state.line = nextLine
|
175
|
+
|
176
|
+
# mark paragraphs tight if needed
|
177
|
+
if (tight)
|
178
|
+
markTightParagraphs(state, listTokIdx)
|
179
|
+
end
|
180
|
+
|
181
|
+
return true
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
end
|