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,136 @@
1
+ # Based on Javascript version: https://github.com/markdown-it/markdown-it-ins
2
+ #------------------------------------------------------------------------------
3
+
4
+ module MotionMarkdownItPlugins
5
+ class Ins
6
+ extend MarkdownIt::Common::Utils
7
+
8
+ #------------------------------------------------------------------------------
9
+ def self.init_plugin(md)
10
+ md.inline.ruler.before('emphasis', 'ins', lambda { |state, silent| Ins.insert(state, silent) })
11
+ end
12
+
13
+ # parse sequence of markers,
14
+ # "start" should point at a valid marker
15
+ #------------------------------------------------------------------------------
16
+ def self.scanDelims(state, start)
17
+ pos = start
18
+ can_open = true
19
+ can_close = true
20
+ max = state.posMax
21
+ marker = state.src.charCodeAt(start)
22
+
23
+ # treat beginning of the line as a whitespace
24
+ lastChar = start > 0 ? state.src.charCodeAt(start - 1) : 0x20
25
+
26
+ while (pos < max && state.src.charCodeAt(pos) == marker)
27
+ pos += 1
28
+ end
29
+
30
+ if (pos >= max)
31
+ can_open = false
32
+ end
33
+
34
+ count = pos - start
35
+
36
+ # treat end of the line as a whitespace
37
+ nextChar = pos < max ? state.src.charCodeAt(pos) : 0x20
38
+
39
+ isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(lastChar.chr(Encoding::UTF_8))
40
+ isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(nextChar.chr(Encoding::UTF_8))
41
+
42
+ isLastWhiteSpace = isWhiteSpace(lastChar)
43
+ isNextWhiteSpace = isWhiteSpace(nextChar)
44
+
45
+ if (isNextWhiteSpace)
46
+ can_open = false
47
+ elsif (isNextPunctChar)
48
+ if (!(isLastWhiteSpace || isLastPunctChar))
49
+ can_open = false
50
+ end
51
+ end
52
+
53
+ if (isLastWhiteSpace)
54
+ can_close = false
55
+ elsif (isLastPunctChar)
56
+ if (!(isNextWhiteSpace || isNextPunctChar))
57
+ can_close = false
58
+ end
59
+ end
60
+
61
+ return {can_open: can_open, can_close: can_close, delims: count}
62
+ end
63
+
64
+ #------------------------------------------------------------------------------
65
+ def self.insert(state, silent)
66
+ max = state.posMax
67
+ start = state.pos
68
+ marker = state.src.charCodeAt(start)
69
+
70
+ return false if (marker != 0x2B) # '+'
71
+ return false if (silent) # don't run any pairs in validation mode
72
+
73
+ res = scanDelims(state, start)
74
+ startCount = res[:delims]
75
+
76
+ if (!res[:can_open])
77
+ state.pos += startCount
78
+ # Earlier we checked !silent, but this implementation does not need it
79
+ state.pending += state.src.slice(start...state.pos)
80
+ return true
81
+ end
82
+
83
+ stack = (startCount / 2).floor
84
+ return false if (stack <= 0)
85
+ state.pos = start + startCount
86
+
87
+ while (state.pos < max)
88
+ if (state.src.charCodeAt(state.pos) == marker)
89
+ res = scanDelims(state, state.pos)
90
+ count = res[:delims]
91
+ tagCount = (count / 2).floor
92
+ if (res[:can_close])
93
+ if (tagCount >= stack)
94
+ state.pos += count - 2
95
+ found = true
96
+ break
97
+ end
98
+ stack -= tagCount
99
+ state.pos += count
100
+ next
101
+ end
102
+
103
+ stack += tagCount if (res[:can_open])
104
+ state.pos += count
105
+ next
106
+ end
107
+
108
+ state.md.inline.skipToken(state)
109
+ end
110
+
111
+ if (!found)
112
+ # parser failed to find ending tag, so it's not valid emphasis
113
+ state.pos = start
114
+ return false
115
+ end
116
+
117
+ # found!
118
+ state.posMax = state.pos
119
+ state.pos = start + 2
120
+
121
+ # Earlier we checked !silent, but this implementation does not need it
122
+ token = state.push('ins_open', 'ins', 1)
123
+ token.markup = marker.chr * 2
124
+
125
+ state.md.inline.tokenize(state);
126
+
127
+ token = state.push('ins_close', 'ins', -1);
128
+ token.markup = marker.chr * 2
129
+
130
+ state.pos = state.posMax + 2
131
+ state.posMax = max
132
+ return true
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,136 @@
1
+ # Based on Javascript version: https://github.com/markdown-it/markdown-it-mark
2
+ #------------------------------------------------------------------------------
3
+
4
+ module MotionMarkdownItPlugins
5
+ class Mark
6
+ extend MarkdownIt::Common::Utils
7
+
8
+ #------------------------------------------------------------------------------
9
+ def self.init_plugin(md)
10
+ md.inline.ruler.before('emphasis', 'mark', lambda { |state, silent| Mark.mark(state, silent) })
11
+ end
12
+
13
+ # parse sequence of markers,
14
+ # "start" should point at a valid marker
15
+ #------------------------------------------------------------------------------
16
+ def self.scanDelims(state, start)
17
+ pos = start
18
+ can_open = true
19
+ can_close = true
20
+ max = state.posMax
21
+ marker = state.src.charCodeAt(start)
22
+
23
+ # treat beginning of the line as a whitespace
24
+ lastChar = start > 0 ? state.src.charCodeAt(start - 1) : 0x20
25
+
26
+ while (pos < max && state.src.charCodeAt(pos) == marker)
27
+ pos += 1
28
+ end
29
+
30
+ if (pos >= max)
31
+ can_open = false
32
+ end
33
+
34
+ count = pos - start
35
+
36
+ # treat end of the line as a whitespace
37
+ nextChar = pos < max ? state.src.charCodeAt(pos) : 0x20
38
+
39
+ isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(lastChar.chr(Encoding::UTF_8))
40
+ isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(nextChar.chr(Encoding::UTF_8))
41
+
42
+ isLastWhiteSpace = isWhiteSpace(lastChar)
43
+ isNextWhiteSpace = isWhiteSpace(nextChar)
44
+
45
+ if (isNextWhiteSpace)
46
+ can_open = false
47
+ elsif (isNextPunctChar)
48
+ if (!(isLastWhiteSpace || isLastPunctChar))
49
+ can_open = false
50
+ end
51
+ end
52
+
53
+ if (isLastWhiteSpace)
54
+ can_close = false
55
+ elsif (isLastPunctChar)
56
+ if (!(isNextWhiteSpace || isNextPunctChar))
57
+ can_close = false
58
+ end
59
+ end
60
+
61
+ return {can_open: can_open, can_close: can_close, delims: count}
62
+ end
63
+
64
+ #------------------------------------------------------------------------------
65
+ def self.mark(state, silent)
66
+ max = state.posMax
67
+ start = state.pos
68
+ marker = state.src.charCodeAt(start)
69
+
70
+ return false if (marker != 0x3D) # '='
71
+ return false if (silent) # don't run any pairs in validation mode
72
+
73
+ res = scanDelims(state, start)
74
+ startCount = res[:delims]
75
+
76
+ if (!res[:can_open])
77
+ state.pos += startCount
78
+ # Earlier we checked !silent, but this implementation does not need it
79
+ state.pending += state.src.slice(start...state.pos)
80
+ return true
81
+ end
82
+
83
+ stack = (startCount / 2).floor
84
+ return false if (stack <= 0)
85
+ state.pos = start + startCount
86
+
87
+ while (state.pos < max)
88
+ if (state.src.charCodeAt(state.pos) == marker)
89
+ res = scanDelims(state, state.pos)
90
+ count = res[:delims]
91
+ tagCount = (count / 2).floor
92
+ if (res[:can_close])
93
+ if (tagCount >= stack)
94
+ state.pos += count - 2
95
+ found = true
96
+ break
97
+ end
98
+ stack -= tagCount
99
+ state.pos += count
100
+ next
101
+ end
102
+
103
+ stack += tagCount if (res[:can_open])
104
+ state.pos += count
105
+ next
106
+ end
107
+
108
+ state.md.inline.skipToken(state)
109
+ end
110
+
111
+ if (!found)
112
+ # parser failed to find ending tag, so it's not valid emphasis
113
+ state.pos = start
114
+ return false
115
+ end
116
+
117
+ # found!
118
+ state.posMax = state.pos
119
+ state.pos = start + 2
120
+
121
+ # Earlier we checked !silent, but this implementation does not need it
122
+ token = state.push('mark_open', 'mark', 1)
123
+ token.markup = marker.chr * 2
124
+
125
+ state.md.inline.tokenize(state)
126
+
127
+ token = state.push('mark_close', 'mark', -1)
128
+ token.markup = marker.chr * 2
129
+
130
+ state.pos = state.posMax + 2
131
+ state.posMax = max
132
+ return true
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,70 @@
1
+ # Process ~subscript~
2
+ #
3
+ # Based on Javascript version: https://github.com/markdown-it/markdown-it-sub
4
+ #------------------------------------------------------------------------------
5
+
6
+ module MotionMarkdownItPlugins
7
+ class Sub
8
+ extend MarkdownIt::Common::Utils
9
+
10
+ # same as UNESCAPE_MD_RE plus a space
11
+ UNESCAPE_RE = /\\([ \!\"\#\$\%\&\'\(\)\*\+\,\-.\/:;<=>?@\[\\\]^_`{|}~])/
12
+
13
+ #------------------------------------------------------------------------------
14
+ def self.init_plugin(md)
15
+ md.inline.ruler.after('emphasis', 'sub', lambda { |state, silent| Sub.subscript(state, silent) })
16
+ end
17
+
18
+ #------------------------------------------------------------------------------
19
+ def self.subscript(state, silent)
20
+ max = state.posMax
21
+ start = state.pos
22
+
23
+ return false if (state.src.charCodeAt(start) != 0x7E) # '~'
24
+ return false if (silent) # don't run any pairs in validation mode
25
+ return false if (start + 2 >= max)
26
+
27
+ state.pos = start + 1
28
+
29
+ while (state.pos < max)
30
+ if (state.src.charCodeAt(state.pos) == 0x7E) # '~'
31
+ found = true
32
+ break
33
+ end
34
+
35
+ state.md.inline.skipToken(state)
36
+ end
37
+
38
+ if (!found || start + 1 == state.pos)
39
+ state.pos = start
40
+ return false
41
+ end
42
+
43
+ content = state.src.slice((start + 1)...state.pos)
44
+
45
+ # don't allow unescaped spaces/newlines inside
46
+ if (content.match(/(^|[^\\])(\\\\)*\s/))
47
+ state.pos = start
48
+ return false
49
+ end
50
+
51
+ # found!
52
+ state.posMax = state.pos
53
+ state.pos = start + 1
54
+
55
+ # Earlier we checked !silent, but this implementation does not need it
56
+ token = state.push('sub_open', 'sub', 1)
57
+ token.markup = '~'
58
+
59
+ token = state.push('text', '', 0)
60
+ token.content = content.gsub(UNESCAPE_RE, '\1')
61
+
62
+ token = state.push('sub_close', 'sub', -1)
63
+ token.markup = '~'
64
+
65
+ state.pos = state.posMax + 1
66
+ state.posMax = max
67
+ return true
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,71 @@
1
+ # Process ^superscript^
2
+ #
3
+ # Based on Javascript version: https://github.com/markdown-it/markdown-it-sup
4
+ #------------------------------------------------------------------------------
5
+
6
+ module MotionMarkdownItPlugins
7
+ class Sup
8
+ extend MarkdownIt::Common::Utils
9
+
10
+ # same as UNESCAPE_MD_RE plus a space
11
+ UNESCAPE_RE = /\\([ \!\"\#\$\%\&\'\(\)\*\+\,\-.\/:;<=>?@\[\\\]^_`{|}~])/
12
+
13
+ #------------------------------------------------------------------------------
14
+ def self.init_plugin(md)
15
+ md.inline.ruler.after('emphasis', 'sup', lambda { |state, silent| Sup.superscript(state, silent) })
16
+ end
17
+
18
+ #------------------------------------------------------------------------------
19
+ def self.superscript(state, silent)
20
+ max = state.posMax
21
+ start = state.pos
22
+
23
+ return false if (state.src.charCodeAt(start) != 0x5E) # '^'
24
+ return false if (silent) # don't run any pairs in validation mode
25
+ return false if (start + 2 >= max)
26
+
27
+ state.pos = start + 1
28
+
29
+ while (state.pos < max)
30
+ if (state.src.charCodeAt(state.pos) == 0x5E) # '^'
31
+ found = true
32
+ break
33
+ end
34
+
35
+ state.md.inline.skipToken(state)
36
+ end
37
+
38
+ if (!found || start + 1 == state.pos)
39
+ state.pos = start
40
+ return false
41
+ end
42
+
43
+ content = state.src.slice((start + 1)...state.pos)
44
+
45
+ # don't allow unescaped spaces/newlines inside
46
+ if (content.match(/(^|[^\\])(\\\\)*\s/))
47
+ state.pos = start
48
+ return false
49
+ end
50
+
51
+ # found!
52
+ state.posMax = state.pos
53
+ state.pos = start + 1
54
+
55
+ # Earlier we checked !silent, but this implementation does not need it
56
+ token = state.push('sup_open', 'sup', 1)
57
+ token.markup = '^'
58
+
59
+ token = state.push('text', '', 0)
60
+ token.content = content.gsub(UNESCAPE_RE, '\1')
61
+
62
+ token = state.push('sup_close', 'sup', -1)
63
+ token.markup = '^'
64
+
65
+ state.pos = state.posMax + 1
66
+ state.posMax = max
67
+ return true
68
+ end
69
+ end
70
+ end
71
+
@@ -0,0 +1,5 @@
1
+ module MotionMarkdownItPlugins
2
+
3
+ VERSION = '1.0.0'
4
+
5
+ end
@@ -0,0 +1,8 @@
1
+ fixture_dir = fixture_path('abbr/fixtures')
2
+
3
+ #------------------------------------------------------------------------------
4
+ describe 'markdown-it-abbr' do
5
+ md = MarkdownIt::Parser.new
6
+ md.use(MotionMarkdownItPlugins::Abbr)
7
+ generate(File.join(fixture_dir, 'abbr.txt'), md)
8
+ end
@@ -0,0 +1,64 @@
1
+ fixture_dir = fixture_path('checkbox_replace/fixtures')
2
+
3
+ describe 'markdown-it-checkbox' do
4
+
5
+ #------------------------------------------------------------------------------
6
+ describe 'markdown-it-checkbox()' do
7
+ md = MarkdownIt::Parser.new
8
+ md.use(MotionMarkdownItPlugins::CheckboxReplace, {divWrap: false})
9
+ specfile = File.join(fixture_dir, 'checkbox.txt')
10
+ tests = get_tests(specfile)
11
+ tests.each do |t|
12
+ define_test(t, md)
13
+ end
14
+
15
+ #------------------------------------------------------------------------------
16
+ it 'should pass irrelevant markdown' do
17
+ md = MarkdownIt::Parser.new
18
+ res = md.render('# test')
19
+ expect(res).to eq "<h1>test</h1>\n"
20
+ end
21
+ end
22
+
23
+ #------------------------------------------------------------------------------
24
+ describe 'markdown-it-checkbox(options)' do
25
+
26
+ #------------------------------------------------------------------------------
27
+ it 'should should optionally wrap arround a div layer' do
28
+ md = MarkdownIt::Parser.new
29
+ md.use(MotionMarkdownItPlugins::CheckboxReplace, {divWrap: true})
30
+ res = md.render('[X] test written')
31
+ expect(res).to eq '<p>' +
32
+ '<div class="checkbox">' +
33
+ '<input type="checkbox" id="checkbox0" checked="true">' +
34
+ '<label for="checkbox0">test written</label>' +
35
+ '</div>' +
36
+ "</p>\n"
37
+ end
38
+
39
+ #------------------------------------------------------------------------------
40
+ it 'should should optionally change class of div layer' do
41
+ md = MarkdownIt::Parser.new
42
+ md.use(MotionMarkdownItPlugins::CheckboxReplace, {divWrap: true, divClass: 'cb'})
43
+ res = md.render('[X] test written')
44
+ expect(res).to eq '<p>' +
45
+ '<div class="cb">' +
46
+ '<input type="checkbox" id="checkbox0" checked="true">' +
47
+ '<label for="checkbox0">test written</label>' +
48
+ '</div>' +
49
+ "</p>\n"
50
+ end
51
+
52
+ #------------------------------------------------------------------------------
53
+ it 'should should optionally change the id' do
54
+ md = MarkdownIt::Parser.new
55
+ md.use(MotionMarkdownItPlugins::CheckboxReplace, {idPrefix: 'cb'})
56
+ res = md.render('[X] test written')
57
+ expect(res).to eq '<p>' +
58
+ '<input type="checkbox" id="cb0" checked="true">' +
59
+ '<label for="cb0">test written</label>' +
60
+ "</p>\n"
61
+ end
62
+ end
63
+
64
+ end