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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ebea41bf33e060dc7d4a5c28fbac9e49759062ac85dcbea55b14b1485cd18f1
4
- data.tar.gz: 18cf03b8c7b166736b13326d3e601384b3776d6a65384f46dbf7d7d9545a5528
3
+ metadata.gz: daa8ed611ae782a62d258d93782f3d1f16c22dc2652b585cccab4de9dfe42e89
4
+ data.tar.gz: afa9532f8877f4d9ba397e7cdee11977917121256726cf28770386964a11078d
5
5
  SHA512:
6
- metadata.gz: 7e2eb93fbef73b7bb5853db8e107910bf3e7b8e89a649496040cdf665a9b97f54fd0031e0f042c1f6622764e51a85d87bada46d60b0ccbcb352e7743134daab3
7
- data.tar.gz: 6da0421b78cf1b71fd92c080b62aeec8dc74726b999d5d4afb9dc10e465e15b0db28fef67d1d0343940bea56717ec94e944d47a6dfabbe8269dfd0d100fbd746
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
@@ -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')
@@ -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
 
@@ -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,
@@ -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;
@@ -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);
@@ -1,3 +1,3 @@
1
1
  module Greenmat
2
- VERSION = '3.5.1.1'
2
+ VERSION = '3.5.1.2'
3
3
  end
@@ -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.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-03-03 00:00:00.000000000 Z
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.0.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.