greenmat 3.5.1.1 → 3.5.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Rakefile +1 -0
- 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/markdown.c +139 -0
- data/ext/greenmat/markdown.h +3 -1
- data/lib/greenmat/version.rb +1 -1
- data/spec/greenmat/markdown_spec.rb +43 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: daa8ed611ae782a62d258d93782f3d1f16c22dc2652b585cccab4de9dfe42e89
|
4
|
+
data.tar.gz: afa9532f8877f4d9ba397e7cdee11977917121256726cf28770386964a11078d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0be5ca05b7c5fda9ef29e57737667724ca6d3cf700e849fd194e77d4813aeba3e86de1cc20a3aabe1b8bde2c4fb3e67cbcd2eafa0557b5ec3011b342bf59c4a
|
7
|
+
data.tar.gz: 97e0df05af1a790e5ce7af95812e824ce71bd1b3ff8981cb988a18ec570bedd54d493e0884818d1e2e76be7e3d7df8df3981c0d6b9e4ecba3cb2ea417d752171
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## v3.5.1.2
|
6
|
+
|
7
|
+
* Support custom block notation.
|
8
|
+
* It starts with `:::` and ends with `:::`.
|
9
|
+
* Output a `<div data-type="customblock" data-metadata="">` element.
|
10
|
+
* Passes the string following `:::` to the `data-metadata` attribute.
|
11
|
+
|
5
12
|
## v3.5.1.1
|
6
13
|
|
7
14
|
* Unsupport details and summary tags.
|
data/Rakefile
CHANGED
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/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/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
|
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.2
|
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: 2021-
|
12
|
+
date: 2021-07-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -261,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
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.
|