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.
@@ -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
@@ -0,0 +1,18 @@
1
+ # motion-markdown-it-plugins
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/motion-markdown-it-plugins.svg)](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