motion-markdown-it-plugins 1.0.0

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