greenmat 3.5.1.1 → 3.5.1.2
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.
- 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.
|