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 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.