greenmat 3.5.1.0 → 3.5.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +47 -0
- data/CHANGELOG.md +18 -0
- data/Rakefile +2 -1
- data/ext/greenmat/gm_markdown.c +3 -0
- data/ext/greenmat/gm_render.c +8 -0
- data/ext/greenmat/html.c +48 -0
- data/ext/greenmat/html_blocks.h +70 -68
- data/ext/greenmat/markdown.c +139 -0
- data/ext/greenmat/markdown.h +3 -1
- data/greenmat.gemspec +2 -2
- data/lib/greenmat/version.rb +1 -1
- data/spec/greenmat/markdown_spec.rb +43 -0
- data/test/html5_test.rb +15 -6
- metadata +7 -7
- data/.travis.yml +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb401dc6f336d00057b17f5e59b2c9b99a1d55e3c7949d662aa06e781a8b8284
|
4
|
+
data.tar.gz: 0e3acbf68f1ec78bc8b2832a2ed163d350b6576d6f1b7de40b5aafe0b4e00a32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a64e6ecef30e67ff86c96a1d9a17a7f86ab6282264729952a6b1cb72a3fe7b530a01a5a5b285cd8369998196c9eb3903825d9b5f2c332bcfd2a835750ec5e50
|
7
|
+
data.tar.gz: 5cf349212cf416ee2a0bc0dda663297b3166954c4552d5160ce1f9ebeace107cb238e90c3630cdd85f3bd144b7750c2dba1f57b83b8314eedce1d9796072f0f0
|
@@ -0,0 +1,47 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
push:
|
6
|
+
branches:
|
7
|
+
- master
|
8
|
+
workflow_dispatch:
|
9
|
+
|
10
|
+
permissions:
|
11
|
+
contents: read
|
12
|
+
|
13
|
+
jobs:
|
14
|
+
test:
|
15
|
+
strategy:
|
16
|
+
fail-fast: false
|
17
|
+
matrix:
|
18
|
+
os: ['ubuntu-18.04', 'macos-latest']
|
19
|
+
ruby: ['2.5', '2.6', '2.7', '3.0', '3.1']
|
20
|
+
experimental: [false]
|
21
|
+
include:
|
22
|
+
- os: 'ubuntu-18.04'
|
23
|
+
ruby: 'head'
|
24
|
+
experimental: true
|
25
|
+
runs-on: ${{ matrix.os }}
|
26
|
+
continue-on-error: ${{ matrix.experimental }}
|
27
|
+
env:
|
28
|
+
BUNDLE_WITHOUT: benchmark
|
29
|
+
steps:
|
30
|
+
- uses: actions/checkout@v2
|
31
|
+
- name: Install prerequirements
|
32
|
+
if: runner.os == 'Linux'
|
33
|
+
run: |
|
34
|
+
sudo apt-get update
|
35
|
+
sudo apt-get install tidy
|
36
|
+
- uses: ruby/setup-ruby@v1
|
37
|
+
with:
|
38
|
+
ruby-version: ${{ matrix.ruby }}
|
39
|
+
bundler-cache: true
|
40
|
+
- name: Build
|
41
|
+
run: bundle exec rake compile
|
42
|
+
- name: Check prerequirements
|
43
|
+
run: |
|
44
|
+
tidy --version
|
45
|
+
bin/greenmat --version
|
46
|
+
- name: Run test
|
47
|
+
run: bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,24 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## v3.5.1.3
|
6
|
+
|
7
|
+
* Remove support for ruby 2.5 and below
|
8
|
+
* Bump nokogiri from 1.6.0 to 1.11.7
|
9
|
+
* Support cpu archtecture for arm64/aarch64 systems (like Apple's M1)
|
10
|
+
* Change ci platform to Github Actions
|
11
|
+
|
12
|
+
## v3.5.1.2
|
13
|
+
|
14
|
+
* Support custom block notation.
|
15
|
+
* It starts with `:::` and ends with `:::`.
|
16
|
+
* Output a `<div data-type="customblock" data-metadata="">` element.
|
17
|
+
* Passes the string following `:::` to the `data-metadata` attribute.
|
18
|
+
|
19
|
+
## v3.5.1.1
|
20
|
+
|
21
|
+
* Unsupport details and summary tags.
|
22
|
+
|
5
23
|
## v3.5.1.0
|
6
24
|
|
7
25
|
* Update base Redcarpet version to 3.5.1.
|
data/Rakefile
CHANGED
@@ -4,6 +4,7 @@ require 'rake/extensiontask'
|
|
4
4
|
require 'digest/md5'
|
5
5
|
|
6
6
|
task :default => [:test, :spec]
|
7
|
+
task :spec => [:compile]
|
7
8
|
|
8
9
|
# Gem Spec
|
9
10
|
gem_spec = Gem::Specification.load('greenmat.gemspec')
|
@@ -34,7 +35,7 @@ task 'test:conformance' => :compile do |t|
|
|
34
35
|
lib_dir = "#{pwd}/lib"
|
35
36
|
|
36
37
|
chdir("test/MarkdownTest_#{version}") do
|
37
|
-
sh "RUBYLIB
|
38
|
+
sh "RUBYLIB=\"$RUBYLIB:#{lib_dir}\" ./MarkdownTest.pl --script='#{script}' --tidy"
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
data/ext/greenmat/gm_markdown.c
CHANGED
@@ -48,6 +48,9 @@ static void rb_greenmat_md_flags(VALUE hash, unsigned int *enabled_extensions_p)
|
|
48
48
|
if (rb_hash_lookup(hash, CSTR2SYM("fenced_code_blocks")) == Qtrue)
|
49
49
|
extensions |= MKDEXT_FENCED_CODE;
|
50
50
|
|
51
|
+
if (rb_hash_lookup(hash, CSTR2SYM("fenced_custom_blocks")) == Qtrue)
|
52
|
+
extensions |= MKDEXT_FENCED_CUSTOM;
|
53
|
+
|
51
54
|
if (rb_hash_lookup(hash, CSTR2SYM("disable_indented_code_blocks")) == Qtrue)
|
52
55
|
extensions |= MKDEXT_DISABLE_INDENTED_CODE;
|
53
56
|
|
data/ext/greenmat/gm_render.c
CHANGED
@@ -54,6 +54,12 @@ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, v
|
|
54
54
|
BLOCK_CALLBACK("block_code", 2, buf2str(text), buf2str(lang));
|
55
55
|
}
|
56
56
|
|
57
|
+
static void
|
58
|
+
rndr_blockcustom(struct buf *ob, const struct buf *text, const struct buf *type, void *opaque)
|
59
|
+
{
|
60
|
+
BLOCK_CALLBACK("block_custom", 2, buf2str(text), buf2str(type));
|
61
|
+
}
|
62
|
+
|
57
63
|
static void
|
58
64
|
rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque)
|
59
65
|
{
|
@@ -293,6 +299,7 @@ rndr_link_attributes(struct buf *ob, const struct buf *url, void *opaque)
|
|
293
299
|
|
294
300
|
static struct sd_callbacks rb_greenmat_callbacks = {
|
295
301
|
rndr_blockcode,
|
302
|
+
rndr_blockcustom,
|
296
303
|
rndr_blockquote,
|
297
304
|
rndr_raw_block,
|
298
305
|
rndr_header,
|
@@ -331,6 +338,7 @@ static struct sd_callbacks rb_greenmat_callbacks = {
|
|
331
338
|
|
332
339
|
static const char *rb_greenmat_method_names[] = {
|
333
340
|
"block_code",
|
341
|
+
"block_custom",
|
334
342
|
"block_quote",
|
335
343
|
"block_html",
|
336
344
|
"header",
|
data/ext/greenmat/html.c
CHANGED
@@ -120,6 +120,52 @@ rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, vo
|
|
120
120
|
return 1;
|
121
121
|
}
|
122
122
|
|
123
|
+
static void
|
124
|
+
rndr_blockcustom(struct buf *ob, const struct buf *text, const struct buf *type, void *opaque)
|
125
|
+
{
|
126
|
+
struct html_renderopt *options = opaque;
|
127
|
+
|
128
|
+
if (ob->size) bufputc(ob, '\n');
|
129
|
+
|
130
|
+
if (type && type->size) {
|
131
|
+
size_t i, cls;
|
132
|
+
if (options->flags & HTML_PRETTIFY) {
|
133
|
+
BUFPUTSL(ob, "<div data-type=\"customblock prettyprint\" data-metadata=\"");
|
134
|
+
cls++;
|
135
|
+
} else {
|
136
|
+
BUFPUTSL(ob, "<div data-type=\"customblock\" data-metadata=\"");
|
137
|
+
}
|
138
|
+
|
139
|
+
for (i = 0, cls = 0; i < type->size; ++i, ++cls) {
|
140
|
+
while (i < type->size && isspace(type->data[i]))
|
141
|
+
i++;
|
142
|
+
|
143
|
+
if (i < type->size) {
|
144
|
+
size_t org = i;
|
145
|
+
while (i < type->size && is_non_space(type->data[i]))
|
146
|
+
i++;
|
147
|
+
|
148
|
+
if (type->data[org] == '.')
|
149
|
+
org++;
|
150
|
+
|
151
|
+
if (cls) bufputc(ob, ' ');
|
152
|
+
escape_html(ob, type->data + org, i - org);
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
BUFPUTSL(ob, "\">");
|
157
|
+
} else if (options->flags & HTML_PRETTIFY) {
|
158
|
+
BUFPUTSL(ob, "<div data-type=\"customblock prettyprint\">");
|
159
|
+
} else {
|
160
|
+
BUFPUTSL(ob, "<div data-type=\"customblock\">");
|
161
|
+
}
|
162
|
+
|
163
|
+
if (text)
|
164
|
+
escape_html(ob, text->data, text->size);
|
165
|
+
|
166
|
+
BUFPUTSL(ob, "</div>\n");
|
167
|
+
}
|
168
|
+
|
123
169
|
static void
|
124
170
|
rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque)
|
125
171
|
{
|
@@ -749,6 +795,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
|
|
749
795
|
NULL,
|
750
796
|
NULL,
|
751
797
|
NULL,
|
798
|
+
NULL,
|
752
799
|
toc_header,
|
753
800
|
NULL,
|
754
801
|
NULL,
|
@@ -794,6 +841,7 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
|
|
794
841
|
{
|
795
842
|
static const struct sd_callbacks cb_default = {
|
796
843
|
rndr_blockcode,
|
844
|
+
rndr_blockcustom,
|
797
845
|
rndr_blockquote,
|
798
846
|
rndr_raw_block,
|
799
847
|
rndr_header,
|
data/ext/greenmat/html_blocks.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
/* C code produced by gperf version 3.0.
|
1
|
+
/* C code produced by gperf version 3.0.4 */
|
2
2
|
/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */
|
3
|
-
/* See
|
3
|
+
/* See http://git.io/RN0ncw for the list of recognized elements */
|
4
4
|
/* Computed positions: -k'1-2' */
|
5
5
|
|
6
6
|
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
@@ -30,7 +30,7 @@
|
|
30
30
|
error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
|
31
31
|
#endif
|
32
32
|
|
33
|
-
/* maximum key range =
|
33
|
+
/* maximum key range = 67, duplicates = 0 */
|
34
34
|
|
35
35
|
#ifndef GPERF_DOWNCASE
|
36
36
|
#define GPERF_DOWNCASE 1
|
@@ -94,34 +94,34 @@ hash_block_tag (str, len)
|
|
94
94
|
{
|
95
95
|
static const unsigned char asso_values[] =
|
96
96
|
{
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
0,
|
105
|
-
0,
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
97
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
98
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
99
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
100
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
101
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
102
|
+
55, 50, 45, 40, 35, 30, 68, 68, 68, 68,
|
103
|
+
68, 68, 68, 68, 68, 15, 10, 15, 15, 15,
|
104
|
+
0, 20, 10, 10, 5, 68, 68, 0, 20, 25,
|
105
|
+
0, 68, 68, 0, 25, 0, 15, 68, 68, 68,
|
106
|
+
68, 68, 68, 68, 68, 68, 68, 15, 10, 15,
|
107
|
+
15, 15, 0, 20, 10, 10, 5, 68, 68, 0,
|
108
|
+
20, 25, 0, 68, 68, 0, 25, 0, 15, 68,
|
109
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
110
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
111
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
112
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
113
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
114
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
115
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
116
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
117
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
118
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
119
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
120
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
121
|
+
68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
122
|
+
68, 68, 68, 68, 68, 68, 68
|
123
123
|
};
|
124
|
-
register
|
124
|
+
register int hval = len;
|
125
125
|
|
126
126
|
switch (hval)
|
127
127
|
{
|
@@ -135,6 +135,12 @@ hash_block_tag (str, len)
|
|
135
135
|
return hval;
|
136
136
|
}
|
137
137
|
|
138
|
+
#ifdef __GNUC__
|
139
|
+
__inline
|
140
|
+
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
|
141
|
+
__attribute__ ((__gnu_inline__))
|
142
|
+
#endif
|
143
|
+
#endif
|
138
144
|
const char *
|
139
145
|
find_block_tag (str, len)
|
140
146
|
register const char *str;
|
@@ -142,80 +148,76 @@ find_block_tag (str, len)
|
|
142
148
|
{
|
143
149
|
enum
|
144
150
|
{
|
145
|
-
TOTAL_KEYWORDS =
|
151
|
+
TOTAL_KEYWORDS = 41,
|
146
152
|
MIN_WORD_LENGTH = 1,
|
147
153
|
MAX_WORD_LENGTH = 10,
|
148
154
|
MIN_HASH_VALUE = 1,
|
149
|
-
MAX_HASH_VALUE =
|
155
|
+
MAX_HASH_VALUE = 67
|
150
156
|
};
|
151
157
|
|
152
158
|
static const char * const wordlist[] =
|
153
159
|
{
|
154
160
|
"",
|
155
161
|
"p",
|
156
|
-
"
|
157
|
-
"
|
162
|
+
"ul",
|
163
|
+
"pre",
|
158
164
|
"form",
|
159
|
-
"",
|
165
|
+
"style",
|
160
166
|
"footer",
|
161
|
-
"
|
162
|
-
"
|
163
|
-
"", "",
|
167
|
+
"section",
|
168
|
+
"", "", "",
|
164
169
|
"figure",
|
165
|
-
"
|
170
|
+
"hr",
|
166
171
|
"fieldset",
|
167
|
-
"",
|
172
|
+
"math",
|
168
173
|
"figcaption",
|
169
174
|
"header",
|
170
|
-
"
|
171
|
-
"
|
172
|
-
"math",
|
173
|
-
"video",
|
174
|
-
"script",
|
175
|
-
"section",
|
176
|
-
"noscript",
|
175
|
+
"dl",
|
176
|
+
"del",
|
177
177
|
"",
|
178
178
|
"blockquote",
|
179
|
-
"
|
180
|
-
"
|
181
|
-
"
|
182
|
-
"",
|
183
|
-
"style",
|
184
|
-
"output",
|
185
|
-
"summary",
|
186
|
-
"nav",
|
179
|
+
"script",
|
180
|
+
"article",
|
181
|
+
"div",
|
187
182
|
"",
|
188
|
-
"
|
183
|
+
"video",
|
184
|
+
"hgroup",
|
185
|
+
"ol",
|
186
|
+
"noscript",
|
187
|
+
"", "",
|
189
188
|
"canvas",
|
190
189
|
"dd",
|
191
|
-
"
|
190
|
+
"nav",
|
192
191
|
"abbr",
|
193
|
-
"
|
192
|
+
"audio",
|
194
193
|
"iframe",
|
195
|
-
"
|
196
|
-
"",
|
197
|
-
"
|
194
|
+
"address",
|
195
|
+
"ins",
|
196
|
+
"",
|
197
|
+
"table",
|
198
198
|
"",
|
199
199
|
"h6",
|
200
200
|
"", "",
|
201
|
+
"aside",
|
202
|
+
"output",
|
203
|
+
"h5",
|
204
|
+
"", "",
|
201
205
|
"tfoot",
|
202
206
|
"",
|
203
|
-
"h5",
|
204
|
-
"", "", "", "",
|
205
207
|
"h4",
|
206
208
|
"", "", "", "",
|
207
|
-
"address",
|
208
|
-
"", "", "", "",
|
209
209
|
"h3",
|
210
210
|
"", "", "", "",
|
211
|
-
"h2"
|
211
|
+
"h2",
|
212
|
+
"", "", "", "",
|
213
|
+
"h1"
|
212
214
|
};
|
213
215
|
|
214
216
|
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
215
217
|
{
|
216
|
-
|
218
|
+
register int key = hash_block_tag (str, len);
|
217
219
|
|
218
|
-
if (key <= MAX_HASH_VALUE)
|
220
|
+
if (key <= MAX_HASH_VALUE && key >= 0)
|
219
221
|
{
|
220
222
|
register const char *s = wordlist[key];
|
221
223
|
|
data/ext/greenmat/markdown.c
CHANGED
@@ -1442,6 +1442,37 @@ prefix_codefence(uint8_t *data, size_t size)
|
|
1442
1442
|
return i;
|
1443
1443
|
}
|
1444
1444
|
|
1445
|
+
/* check if a line begins with a custom fence; return the
|
1446
|
+
* width of the custom fence */
|
1447
|
+
static size_t
|
1448
|
+
prefix_customfence(uint8_t *data, size_t size)
|
1449
|
+
{
|
1450
|
+
size_t i = 0, n = 0;
|
1451
|
+
uint8_t c;
|
1452
|
+
|
1453
|
+
/* skipping initial spaces */
|
1454
|
+
if (size < 3) return 0;
|
1455
|
+
if (data[0] == ' ') { i++;
|
1456
|
+
if (data[1] == ' ') { i++;
|
1457
|
+
if (data[2] == ' ') { i++; } } }
|
1458
|
+
|
1459
|
+
/* looking at the hrule uint8_t */
|
1460
|
+
if (i + 2 >= size || !(data[i] == ':'))
|
1461
|
+
return 0;
|
1462
|
+
|
1463
|
+
c = data[i];
|
1464
|
+
|
1465
|
+
/* the whole line must be the uint8_t or whitespace */
|
1466
|
+
while (i < size && data[i] == c) {
|
1467
|
+
n++; i++;
|
1468
|
+
}
|
1469
|
+
|
1470
|
+
if (n < 3)
|
1471
|
+
return 0;
|
1472
|
+
|
1473
|
+
return i;
|
1474
|
+
}
|
1475
|
+
|
1445
1476
|
/* check if a line is a code fence; return its size if it is */
|
1446
1477
|
static size_t
|
1447
1478
|
is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
@@ -1499,6 +1530,63 @@ is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
|
1499
1530
|
return i + 1;
|
1500
1531
|
}
|
1501
1532
|
|
1533
|
+
/* check if a line is a custom fence; return its size if it is */
|
1534
|
+
static size_t
|
1535
|
+
is_customfence(uint8_t *data, size_t size, struct buf *syntax)
|
1536
|
+
{
|
1537
|
+
size_t i = 0, syn_len = 0;
|
1538
|
+
uint8_t *syn_start;
|
1539
|
+
|
1540
|
+
i = prefix_customfence(data, size);
|
1541
|
+
if (i == 0)
|
1542
|
+
return 0;
|
1543
|
+
|
1544
|
+
while (i < size && data[i] == ' ')
|
1545
|
+
i++;
|
1546
|
+
|
1547
|
+
syn_start = data + i;
|
1548
|
+
|
1549
|
+
if (i < size && data[i] == '{') {
|
1550
|
+
i++; syn_start++;
|
1551
|
+
|
1552
|
+
while (i < size && data[i] != '}' && data[i] != '\n') {
|
1553
|
+
syn_len++; i++;
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
if (i == size || data[i] != '}')
|
1557
|
+
return 0;
|
1558
|
+
|
1559
|
+
/* strip all whitespace at the beginning and the end
|
1560
|
+
* of the {} block */
|
1561
|
+
while (syn_len > 0 && _isspace(syn_start[0])) {
|
1562
|
+
syn_start++; syn_len--;
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
while (syn_len > 0 && _isspace(syn_start[syn_len - 1]))
|
1566
|
+
syn_len--;
|
1567
|
+
|
1568
|
+
i++;
|
1569
|
+
} else {
|
1570
|
+
while (i < size && data[i] != '\n') {
|
1571
|
+
syn_len++; i++;
|
1572
|
+
}
|
1573
|
+
}
|
1574
|
+
|
1575
|
+
if (syntax) {
|
1576
|
+
syntax->data = syn_start;
|
1577
|
+
syntax->size = syn_len;
|
1578
|
+
}
|
1579
|
+
|
1580
|
+
while (i < size && data[i] != '\n') {
|
1581
|
+
if (!_isspace(data[i]))
|
1582
|
+
return 0;
|
1583
|
+
|
1584
|
+
i++;
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
return i + 1;
|
1588
|
+
}
|
1589
|
+
|
1502
1590
|
/* is_atxheader • returns whether the line is a hash-prefixed header */
|
1503
1591
|
static int
|
1504
1592
|
is_atxheader(struct sd_markdown *rndr, uint8_t *data, size_t size)
|
@@ -1877,6 +1965,53 @@ parse_blockcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1877
1965
|
return beg;
|
1878
1966
|
}
|
1879
1967
|
|
1968
|
+
|
1969
|
+
|
1970
|
+
/* parse_fencedcustom • handles parsing of a block-level custom fragment */
|
1971
|
+
static size_t
|
1972
|
+
parse_fencedcustom(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
|
1973
|
+
{
|
1974
|
+
size_t beg, end;
|
1975
|
+
struct buf *work = 0;
|
1976
|
+
struct buf type = { 0, 0, 0, 0 };
|
1977
|
+
|
1978
|
+
beg = is_customfence(data, size, &type);
|
1979
|
+
if (beg == 0) return 0;
|
1980
|
+
|
1981
|
+
work = rndr_newbuf(rndr, BUFFER_BLOCK);
|
1982
|
+
|
1983
|
+
while (beg < size) {
|
1984
|
+
size_t fence_end;
|
1985
|
+
struct buf fence_trail = { 0, 0, 0, 0 };
|
1986
|
+
|
1987
|
+
fence_end = is_customfence(data + beg, size - beg, &fence_trail);
|
1988
|
+
if (fence_end != 0 && fence_trail.size == 0) {
|
1989
|
+
beg += fence_end;
|
1990
|
+
break;
|
1991
|
+
}
|
1992
|
+
|
1993
|
+
for (end = beg + 1; end < size && data[end - 1] != '\n'; end++);
|
1994
|
+
|
1995
|
+
if (beg < end) {
|
1996
|
+
/* verbatim copy to the working buffer,
|
1997
|
+
escaping entities */
|
1998
|
+
if (is_empty(data + beg, end - beg))
|
1999
|
+
bufputc(work, '\n');
|
2000
|
+
else bufput(work, data + beg, end - beg);
|
2001
|
+
}
|
2002
|
+
beg = end;
|
2003
|
+
}
|
2004
|
+
|
2005
|
+
if (work->size && work->data[work->size - 1] != '\n')
|
2006
|
+
bufputc(work, '\n');
|
2007
|
+
|
2008
|
+
if (rndr->cb.blockcustom)
|
2009
|
+
rndr->cb.blockcustom(ob, work, type.size ? &type : NULL, rndr->opaque);
|
2010
|
+
|
2011
|
+
rndr_popbuf(rndr, BUFFER_BLOCK);
|
2012
|
+
return beg;
|
2013
|
+
}
|
2014
|
+
|
1880
2015
|
/* parse_listitem • parsing of a single list item */
|
1881
2016
|
/* assuming initial prefix is already removed */
|
1882
2017
|
static size_t
|
@@ -2513,6 +2648,10 @@ parse_block(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
|
|
2513
2648
|
(i = parse_fencedcode(ob, rndr, txt_data, end)) != 0)
|
2514
2649
|
beg += i;
|
2515
2650
|
|
2651
|
+
else if ((rndr->ext_flags & MKDEXT_FENCED_CUSTOM) != 0 &&
|
2652
|
+
(i = parse_fencedcustom(ob, rndr, txt_data, end)) != 0)
|
2653
|
+
beg += i;
|
2654
|
+
|
2516
2655
|
else if ((rndr->ext_flags & MKDEXT_TABLES) != 0 &&
|
2517
2656
|
(i = parse_table(ob, rndr, txt_data, end)) != 0)
|
2518
2657
|
beg += i;
|
data/ext/greenmat/markdown.h
CHANGED
@@ -64,13 +64,15 @@ enum mkd_extensions {
|
|
64
64
|
MKDEXT_HIGHLIGHT = (1 << 10),
|
65
65
|
MKDEXT_FOOTNOTES = (1 << 11),
|
66
66
|
MKDEXT_QUOTE = (1 << 12),
|
67
|
-
MKDEXT_NO_MENTION_EMPHASIS = (1 << 13)
|
67
|
+
MKDEXT_NO_MENTION_EMPHASIS = (1 << 13),
|
68
|
+
MKDEXT_FENCED_CUSTOM = (1 << 14)
|
68
69
|
};
|
69
70
|
|
70
71
|
/* sd_callbacks - functions for rendering parsed data */
|
71
72
|
struct sd_callbacks {
|
72
73
|
/* block level callbacks - NULL skips the block */
|
73
74
|
void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque);
|
75
|
+
void (*blockcustom)(struct buf *ob, const struct buf *text, const struct buf *type, void *opaque);
|
74
76
|
void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque);
|
75
77
|
void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque);
|
76
78
|
void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque);
|
data/greenmat.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.homepage = 'https://github.com/increments/greenmat'
|
13
13
|
s.authors = ["Natacha Porté", "Vicent Martí"]
|
14
14
|
s.license = 'MIT'
|
15
|
-
s.required_ruby_version = '>= 2.
|
15
|
+
s.required_ruby_version = '>= 2.5.0'
|
16
16
|
|
17
17
|
s.files = `git ls-files -z`.split("\x0")
|
18
18
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.require_paths = ["lib"]
|
23
23
|
|
24
24
|
s.add_development_dependency "activesupport"
|
25
|
-
s.add_development_dependency "nokogiri", "~> 1.
|
25
|
+
s.add_development_dependency "nokogiri", "~> 1.11.7"
|
26
26
|
s.add_development_dependency "rake", "~> 12.2.1"
|
27
27
|
s.add_development_dependency "rake-compiler", "~> 1.0.3"
|
28
28
|
s.add_development_dependency "rspec", "~> 3.2"
|
data/lib/greenmat/version.rb
CHANGED
@@ -184,5 +184,48 @@ module Greenmat
|
|
184
184
|
EOS
|
185
185
|
end
|
186
186
|
end
|
187
|
+
|
188
|
+
context 'with fenced_custom_blocks option' do
|
189
|
+
let(:options) { { fenced_custom_blocks: true } }
|
190
|
+
|
191
|
+
context 'with custom block with any metadata' do
|
192
|
+
let(:text) do
|
193
|
+
<<-EOS.strip_heredoc
|
194
|
+
:::foo bar
|
195
|
+
message
|
196
|
+
:::
|
197
|
+
EOS
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'renders text with <div> tag that have customblock class & metadata in a data-metadata attribute' do
|
201
|
+
expect(rendered_html).to eq <<-EOS.strip_heredoc
|
202
|
+
<div data-type="customblock" data-metadata="foo bar">message
|
203
|
+
</div>
|
204
|
+
EOS
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'without fenced_custom_blocks option' do
|
210
|
+
let(:options) { {} }
|
211
|
+
|
212
|
+
context 'with custom block with any metadata' do
|
213
|
+
let(:text) do
|
214
|
+
<<-EOS.strip_heredoc
|
215
|
+
:::foo bar
|
216
|
+
message
|
217
|
+
:::
|
218
|
+
EOS
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'renders text with p tag' do
|
222
|
+
expect(rendered_html).to eq <<-EOS.strip_heredoc
|
223
|
+
<p>:::foo bar
|
224
|
+
message
|
225
|
+
:::</p>
|
226
|
+
EOS
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
187
230
|
end
|
188
231
|
end
|
data/test/html5_test.rb
CHANGED
@@ -68,15 +68,24 @@ class HTML5Test < Greenmat::TestCase
|
|
68
68
|
assert_renders html, html
|
69
69
|
end
|
70
70
|
|
71
|
-
def
|
71
|
+
def test_details_tags_ignoring
|
72
72
|
details = <<-HTML.chomp.strip_heredoc
|
73
|
-
<details>
|
74
|
-
log:
|
73
|
+
<details><summary>Folding sample</summary><div>
|
75
74
|
|
76
|
-
|
75
|
+
```rb
|
76
|
+
puts 'Hello, World'
|
77
|
+
```
|
78
|
+
</div></details>
|
77
79
|
HTML
|
80
|
+
html = <<-HTML.chomp.strip_heredoc
|
81
|
+
<p><details><summary>Folding sample</summary><div></p>
|
78
82
|
|
79
|
-
|
80
|
-
|
83
|
+
<p><code>rb
|
84
|
+
puts 'Hello, World'
|
85
|
+
</code>
|
86
|
+
</div></details></p>
|
87
|
+
HTML
|
81
88
|
|
89
|
+
assert_renders html, details
|
90
|
+
end
|
82
91
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: greenmat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.5.1.
|
4
|
+
version: 3.5.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Natacha Porté
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 1.
|
34
|
+
version: 1.11.7
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 1.
|
41
|
+
version: 1.11.7
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,9 +104,9 @@ extensions:
|
|
104
104
|
extra_rdoc_files:
|
105
105
|
- COPYING
|
106
106
|
files:
|
107
|
+
- ".github/workflows/test.yml"
|
107
108
|
- ".gitignore"
|
108
109
|
- ".rspec"
|
109
|
-
- ".travis.yml"
|
110
110
|
- CHANGELOG.md
|
111
111
|
- COPYING
|
112
112
|
- Gemfile
|
@@ -254,14 +254,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
254
254
|
requirements:
|
255
255
|
- - ">="
|
256
256
|
- !ruby/object:Gem::Version
|
257
|
-
version: 2.
|
257
|
+
version: 2.5.0
|
258
258
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
259
|
requirements:
|
260
260
|
- - ">="
|
261
261
|
- !ruby/object:Gem::Version
|
262
262
|
version: '0'
|
263
263
|
requirements: []
|
264
|
-
rubygems_version: 3.
|
264
|
+
rubygems_version: 3.1.4
|
265
265
|
signing_key:
|
266
266
|
specification_version: 4
|
267
267
|
summary: A Markdown parser for Qiita, based on Redcarpet.
|
data/.travis.yml
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
dist: trusty
|
3
|
-
|
4
|
-
addons:
|
5
|
-
apt:
|
6
|
-
packages:
|
7
|
-
- tidy
|
8
|
-
- tcl
|
9
|
-
- tk
|
10
|
-
|
11
|
-
install: bundle install --without=benchmark
|
12
|
-
|
13
|
-
rvm:
|
14
|
-
- 2.0.0
|
15
|
-
- 2.1
|
16
|
-
- 2.2
|
17
|
-
- 2.3
|
18
|
-
- 2.4
|
19
|
-
- 2.5
|
20
|
-
- ruby-head
|
21
|
-
|
22
|
-
matrix:
|
23
|
-
allow_failures:
|
24
|
-
- rvm: ruby-head
|
25
|
-
|
26
|
-
notifications:
|
27
|
-
email: false
|