github-markdown 0.5.2 → 0.6.9

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a2f2a20e79b2838e629c702b785c60edc0fd286f
4
+ data.tar.gz: 633a0cb21dfb034293b8449b7f65bcc77d51e96b
5
+ SHA512:
6
+ metadata.gz: 2d0fa591d20cfcaa459fde53061ad9c59da05f2f6a6163dc79305d29b971663c16ccedf3882a01039e1ffbfd29e86cad2e6d15f4459b40a2568b51fe7693d2e6
7
+ data.tar.gz: 5c705bf59ec494a7032c2e94821a7d12713073381e8c2658c2c5d8be26e6151473389aa8973e1716041b4b5c583677733cb77e157a037451e88c7384ab5b9fc4
data/Rakefile CHANGED
@@ -14,6 +14,22 @@ Rake::ExtensionTask.new('markdown') do |ext|
14
14
  ext.lib_dir = 'lib/github'
15
15
  end
16
16
 
17
+ # ==========================================================
18
+ # Helpers
19
+ # ==========================================================
20
+
21
+ def name
22
+ @name ||= "github-markdown"
23
+ end
24
+
25
+ def version
26
+ @version ||= File.read("#{name}.gemspec").match(/^\s*s.version\s*=\s*['"](.*)['"]/)[1]
27
+ end
28
+
29
+ def gem_file
30
+ "#{name}-#{version}.gem"
31
+ end
32
+
17
33
  # ==========================================================
18
34
  # Testing
19
35
  # ==========================================================
@@ -44,6 +60,20 @@ file package('.gem') => %w[pkg/ github-markdown.gemspec] + $spec.files do |f|
44
60
  mv File.basename(f.name), f.name
45
61
  end
46
62
 
63
+
64
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
65
+ task :release => :package do
66
+ unless `git branch` =~ /^\* master$/
67
+ puts "You must be on the master branch to release!"
68
+ exit!
69
+ end
70
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
71
+ sh "git tag v#{version}"
72
+ sh "git push origin master"
73
+ sh "git push origin v#{version}"
74
+ sh "gem push pkg/#{name}-#{version}.gem"
75
+ end
76
+
47
77
  # GEMSPEC HELPERS ==========================================================
48
78
 
49
79
  task :update_gem do
@@ -84,5 +114,3 @@ end
84
114
  file 'sundown/src/markdown.h' do |t|
85
115
  abort "The Sundown submodule is required."
86
116
  end
87
-
88
-
@@ -51,7 +51,7 @@ sd_autolink_issafe(const uint8_t *link, size_t link_len)
51
51
  static size_t
52
52
  autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
53
53
  {
54
- uint8_t cclose, copen = 0;
54
+ uint8_t cclose, copen;
55
55
  size_t i;
56
56
 
57
57
  for (i = 0; i < link_end; ++i)
@@ -61,7 +61,7 @@ autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
61
61
  }
62
62
 
63
63
  while (link_end > 0) {
64
- if (strchr("?!.,", data[link_end - 1]) != NULL)
64
+ if (strchr("?!.,:", data[link_end - 1]) != NULL)
65
65
  link_end--;
66
66
 
67
67
  else if (data[link_end - 1] == ';') {
@@ -78,20 +78,21 @@ autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
78
78
  else break;
79
79
  }
80
80
 
81
- if (link_end == 0)
82
- return 0;
83
-
84
- cclose = data[link_end - 1];
85
-
86
- switch (cclose) {
87
- case '"': copen = '"'; break;
88
- case '\'': copen = '\''; break;
89
- case ')': copen = '('; break;
90
- case ']': copen = '['; break;
91
- case '}': copen = '{'; break;
92
- }
81
+ while (link_end > 0) {
82
+ cclose = data[link_end - 1];
83
+
84
+ switch (cclose) {
85
+ case '"': copen = '"'; break;
86
+ case '\'': copen = '\''; break;
87
+ case ')': copen = '('; break;
88
+ case ']': copen = '['; break;
89
+ case '}': copen = '{'; break;
90
+ default: copen = 0;
91
+ }
93
92
 
94
- if (copen != 0) {
93
+ if (copen == 0)
94
+ break;
95
+
95
96
  size_t closing = 0;
96
97
  size_t opening = 0;
97
98
  size_t i = 0;
@@ -110,7 +111,7 @@ autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
110
111
  * => http://www.pokemon.com/Pikachu_(Electric)
111
112
  *
112
113
  * foo http://www.pokemon.com/Pikachu_(Electric)) bar
113
- * => http://www.pokemon.com/Pikachu_(Electric))
114
+ * => http://www.pokemon.com/Pikachu_(Electric)
114
115
  *
115
116
  * (foo http://www.pokemon.com/Pikachu_(Electric)) bar
116
117
  * => foo http://www.pokemon.com/Pikachu_(Electric)
@@ -125,8 +126,10 @@ autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
125
126
  i++;
126
127
  }
127
128
 
128
- if (closing != opening)
129
- link_end--;
129
+ if (closing == opening)
130
+ break;
131
+
132
+ link_end--;
130
133
  }
131
134
 
132
135
  return link_end;
@@ -135,16 +138,20 @@ autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
135
138
  static size_t
136
139
  check_domain(uint8_t *data, size_t size, int allow_short)
137
140
  {
138
- size_t i, np = 0;
141
+ size_t i, np = 0, uscore1 = 0, uscore2 = 0;
139
142
 
140
- if (!isalnum(data[0]))
141
- return 0;
142
-
143
- for (i = 1; i < size - 1; ++i) {
144
- if (data[i] == '.') np++;
143
+ for (i = 1; i < size - 1; i++) {
144
+ if (data[i] == '_') uscore2++;
145
+ else if (data[i] == '.') {
146
+ uscore1 = uscore2;
147
+ uscore2 = 0;
148
+ np++;
149
+ }
145
150
  else if (!isalnum(data[i]) && data[i] != '-') break;
146
151
  }
147
152
 
153
+ if (uscore1 > 0 || uscore2 > 0) return 0;
154
+
148
155
  if (allow_short) {
149
156
  /* We don't need a valid domain in the strict sense (with
150
157
  * least one dot; so just make sure it's composed of valid
@@ -169,7 +176,7 @@ sd_autolink__www(
169
176
  {
170
177
  size_t link_end;
171
178
 
172
- if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
179
+ if (max_rewind > 0 && data[-1] != '(' && data[-1] != '[' && !isspace(data[-1]))
173
180
  return 0;
174
181
 
175
182
  if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
@@ -204,7 +211,7 @@ sd_autolink__email(
204
211
  unsigned int flags)
205
212
  {
206
213
  size_t link_end, rewind;
207
- int nb = 0, np = 0;
214
+ int nb = 0, np = 0, ns = 0;
208
215
 
209
216
  for (rewind = 0; rewind < max_rewind; ++rewind) {
210
217
  uint8_t c = data[-rewind - 1];
@@ -215,10 +222,13 @@ sd_autolink__email(
215
222
  if (strchr(".+-_", c) != NULL)
216
223
  continue;
217
224
 
225
+ if (c == '/')
226
+ ns++;
227
+
218
228
  break;
219
229
  }
220
230
 
221
- if (rewind == 0)
231
+ if (rewind == 0 || ns > 0)
222
232
  return 0;
223
233
 
224
234
  for (link_end = 0; link_end < size; ++link_end) {
@@ -235,7 +245,8 @@ sd_autolink__email(
235
245
  break;
236
246
  }
237
247
 
238
- if (link_end < 2 || nb != 1 || np == 0)
248
+ if (link_end < 2 || nb != 1 || np == 0 ||
249
+ (!isalpha(data[link_end - 1]) && data[link_end - 1] != '.'))
239
250
  return 0;
240
251
 
241
252
  link_end = autolink_delim(data, link_end, max_rewind, size);
@@ -293,4 +304,3 @@ sd_autolink__url(
293
304
 
294
305
  return link_end;
295
306
  }
296
-
@@ -233,6 +233,15 @@ free_link_refs(struct link_ref **references)
233
233
  }
234
234
  }
235
235
 
236
+ /*
237
+ Wrap isalnum so that characters outside of the ASCII range don't count.
238
+ */
239
+ static inline int
240
+ _isalnum(int c)
241
+ {
242
+ return isalnum(c) && c < 0x7f;
243
+ }
244
+
236
245
  /*
237
246
  * Check whether a char is a Markdown space.
238
247
 
@@ -297,25 +306,24 @@ tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink)
297
306
 
298
307
  /* begins with a '<' optionally followed by '/', followed by letter or number */
299
308
  if (data[0] != '<') return 0;
309
+
310
+ if ((i = is_mail_autolink(data + 1, size - 1)) != 0) {
311
+ *autolink = MKDA_EMAIL;
312
+ return i + 1;
313
+ }
314
+
300
315
  i = (data[1] == '/') ? 2 : 1;
301
316
 
302
- if (!isalnum(data[i]))
317
+ if (!_isalnum(data[i]))
303
318
  return 0;
304
319
 
305
320
  /* scheme test */
306
321
  *autolink = MKDA_NOT_AUTOLINK;
307
322
 
308
323
  /* try to find the beginning of an URI */
309
- while (i < size && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-'))
324
+ while (i < size && (_isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-'))
310
325
  i++;
311
326
 
312
- if (i > 1 && data[i] == '@') {
313
- if ((j = is_mail_autolink(data + i, size - i)) != 0) {
314
- *autolink = MKDA_EMAIL;
315
- return i + j;
316
- }
317
- }
318
-
319
327
  if (i > 2 && data[i] == ':') {
320
328
  *autolink = MKDA_NORMAL;
321
329
  i++;
@@ -352,7 +360,7 @@ tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink)
352
360
  static void
353
361
  parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
354
362
  {
355
- size_t i = 0, end = 0;
363
+ size_t i = 0, end = 0, consumed = 0;
356
364
  uint8_t action = 0;
357
365
  struct buf work = { 0, 0, 0, 0 };
358
366
 
@@ -377,12 +385,13 @@ parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t siz
377
385
  if (end >= size) break;
378
386
  i = end;
379
387
 
380
- end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i);
388
+ end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i - consumed, size - i);
381
389
  if (!end) /* no action from the callback */
382
390
  end = i + 1;
383
391
  else {
384
392
  i += end;
385
393
  end = i;
394
+ consumed = i;
386
395
  }
387
396
  }
388
397
  }
@@ -394,7 +403,7 @@ find_emph_char(uint8_t *data, size_t size, uint8_t c)
394
403
  size_t i = 1;
395
404
 
396
405
  while (i < size) {
397
- while (i < size && data[i] != c && data[i] != '`' && data[i] != '[')
406
+ while (i < size && data[i] != c && data[i] != '[')
398
407
  i++;
399
408
 
400
409
  if (i == size)
@@ -500,8 +509,8 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
500
509
 
501
510
  if (data[i] == c && !_isspace(data[i - 1])) {
502
511
 
503
- if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
504
- if (i + 1 < size && isalnum(data[i + 1]))
512
+ if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS && c == '_') {
513
+ if (i + 1 < size && (_isalnum(data[i + 1]) || data[i + 1] == c))
505
514
  continue;
506
515
  }
507
516
 
@@ -536,6 +545,12 @@ parse_emph2(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
536
545
  i += len;
537
546
 
538
547
  if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) {
548
+
549
+ if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS && c == '_') {
550
+ if (i + 2 < size && (_isalnum(data[i + 2]) || data[i + 2] == c))
551
+ continue;
552
+ }
553
+
539
554
  work = rndr_newbuf(rndr, BUFFER_SPAN);
540
555
  parse_inline(work, rndr, data, i);
541
556
  r = render_method(ob, work, rndr->opaque);
@@ -565,6 +580,12 @@ parse_emph3(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
565
580
  continue;
566
581
 
567
582
  if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && rndr->cb.triple_emphasis) {
583
+
584
+ if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS && c == '_') {
585
+ if (i + 3 < size && (_isalnum(data[i + 3]) || data[i + 3] == c))
586
+ continue;
587
+ }
588
+
568
589
  /* triple symbol found */
569
590
  struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN);
570
591
 
@@ -596,9 +617,10 @@ char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t of
596
617
  uint8_t c = data[0];
597
618
  size_t ret;
598
619
 
599
- if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
600
- if (offset > 0 && !_isspace(data[-1]) && data[-1] != '>')
620
+ if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS && c == '_') {
621
+ if (offset > 0 && !_isspace(data[-1]) && (_isalnum(data[-1]) || data[-1] == data[0])) {
601
622
  return 0;
623
+ }
602
624
  }
603
625
 
604
626
  if (size > 2 && data[1] != c) {
@@ -721,7 +743,7 @@ char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offs
721
743
  if (end < size && data[end] == '#')
722
744
  end++;
723
745
 
724
- while (end < size && isalnum(data[end]))
746
+ while (end < size && _isalnum(data[end]))
725
747
  end++;
726
748
 
727
749
  if (end < size && data[end] == ';')
@@ -895,10 +917,18 @@ char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset
895
917
  link_b = i;
896
918
 
897
919
  /* looking for link end: ' " ) */
920
+ /* Count the number of open parenthesis */
921
+ size_t nb_p = 0;
922
+
898
923
  while (i < size) {
899
924
  if (data[i] == '\\') i += 2;
900
- else if (data[i] == ')') break;
901
- else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break;
925
+ else if (data[i] == '(' && i != 0) {
926
+ nb_p++; i++;
927
+ }
928
+ else if (data[i] == ')') {
929
+ if (nb_p == 0) break;
930
+ nb_p--; i++;
931
+ } else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break;
902
932
  else i++;
903
933
  }
904
934
 
@@ -1364,7 +1394,7 @@ prefix_uli(uint8_t *data, size_t size)
1364
1394
 
1365
1395
  if (i < size && data[i] == ' ') i++;
1366
1396
  if (i < size && data[i] == ' ') i++;
1367
- if (i < size && data[i] == ' ') i++;
1397
+ if (i < size && data[i] == ' ') i++;
1368
1398
 
1369
1399
  if (i + 1 >= size ||
1370
1400
  (data[i] != '*' && data[i] != '+' && data[i] != '-') ||
@@ -1461,7 +1491,7 @@ parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
1461
1491
  * let's check to see if there's some kind of block starting
1462
1492
  * here
1463
1493
  */
1464
- if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !isalnum(data[i])) {
1494
+ if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !_isalnum(data[i])) {
1465
1495
  if (prefix_oli(data + i, size - i) ||
1466
1496
  prefix_uli(data + i, size - i)) {
1467
1497
  end = i;
@@ -1629,8 +1659,8 @@ static size_t
1629
1659
  parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int *flags)
1630
1660
  {
1631
1661
  struct buf *work = 0, *inter = 0;
1632
- size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
1633
- int in_empty = 0, has_inside_empty = 0, in_fence = 0;
1662
+ size_t beg = 0, end, pre, sublist = 0, orgpre = 0, previous_indent = 0, i;
1663
+ int empty_lines = 0, has_inside_empty = 0, has_trailing_empty = 0, in_fence = 0, previous_indent_diff = 0;
1634
1664
 
1635
1665
  /* keeping track of the first indentation prefix */
1636
1666
  while (orgpre < 3 && orgpre < size && data[orgpre] == ' ')
@@ -1667,7 +1697,7 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
1667
1697
 
1668
1698
  /* process an empty line */
1669
1699
  if (is_empty(data + beg, end - beg)) {
1670
- in_empty = 1;
1700
+ empty_lines++;
1671
1701
  beg = end;
1672
1702
  continue;
1673
1703
  }
@@ -1677,11 +1707,26 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
1677
1707
  while (i < 4 && beg + i < end && data[beg + i] == ' ')
1678
1708
  i++;
1679
1709
 
1710
+ /* don't bother calculating, this is probably the first item if == 0 */
1711
+ if (previous_indent > 0) {
1712
+ previous_indent_diff = i - previous_indent;
1713
+ /* allow indentations between 2 and 4 spaces to count as a new list */
1714
+ if (previous_indent_diff > 1 && previous_indent_diff < 4)
1715
+ i = 2;
1716
+ }
1717
+
1680
1718
  pre = i;
1719
+ previous_indent = pre;
1681
1720
 
1682
1721
  if (rndr->ext_flags & MKDEXT_FENCED_CODE) {
1683
- if (is_codefence(data + beg + i, end - beg - i, NULL) != 0)
1722
+ if (is_codefence(data + beg + i, end - beg - i, NULL) != 0) {
1723
+ /* If the fenced code isn't indented, then end the list */
1724
+ if (pre == 0 && !in_fence) {
1725
+ *flags |= MKD_LI_END;
1726
+ break;
1727
+ }
1684
1728
  in_fence = !in_fence;
1729
+ }
1685
1730
  }
1686
1731
 
1687
1732
  /* Only check for new list items if we are **not** inside
@@ -1691,46 +1736,48 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
1691
1736
  has_next_oli = prefix_oli(data + beg + i, end - beg - i);
1692
1737
  }
1693
1738
 
1694
- /* checking for ul/ol switch */
1695
- if (in_empty && (
1696
- ((*flags & MKD_LIST_ORDERED) && has_next_uli) ||
1697
- (!(*flags & MKD_LIST_ORDERED) && has_next_oli))){
1698
- *flags |= MKD_LI_END;
1699
- break; /* the following item must have same list type */
1700
- }
1701
-
1702
1739
  /* checking for a new item */
1703
1740
  if ((has_next_uli && !is_hrule(data + beg + i, end - beg - i)) || has_next_oli) {
1704
- if (in_empty)
1705
- has_inside_empty = 1;
1706
-
1707
- if (pre == orgpre) /* the following item must have */
1708
- break; /* the same indentation */
1741
+ /* the following item must have the same indentation */
1742
+ if (pre == orgpre) {
1743
+ if (empty_lines > 0) {
1744
+ has_trailing_empty = 1;
1745
+
1746
+ /* checking for ul/ol switch */
1747
+ if (((*flags & MKD_LIST_ORDERED) && has_next_uli) ||
1748
+ (!(*flags & MKD_LIST_ORDERED) && has_next_oli)) {
1749
+ *flags |= MKD_LI_END;
1750
+ }
1751
+ }
1752
+ break;
1753
+ }
1709
1754
 
1710
1755
  if (!sublist)
1711
1756
  sublist = work->size;
1712
1757
  }
1758
+
1713
1759
  /* joining only indented stuff after empty lines;
1714
1760
  * note that now we only require 1 space of indentation
1715
1761
  * to continue a list */
1716
- else if (in_empty && pre == 0) {
1762
+ if (empty_lines > 0 && pre == 0 && !in_fence) {
1717
1763
  *flags |= MKD_LI_END;
1718
1764
  break;
1719
1765
  }
1720
- else if (in_empty) {
1721
- bufputc(work, '\n');
1766
+ else if (empty_lines > 0) {
1767
+ /* preserve all the empty lines because they
1768
+ * may be meaningful inside a code block */
1769
+ for (; empty_lines > 0; empty_lines--)
1770
+ bufputc(work, '\n');
1722
1771
  has_inside_empty = 1;
1723
1772
  }
1724
1773
 
1725
- in_empty = 0;
1726
-
1727
1774
  /* adding the line without prefix into the working buffer */
1728
1775
  bufput(work, data + beg + i, end - beg - i);
1729
1776
  beg = end;
1730
1777
  }
1731
1778
 
1732
1779
  /* render of li contents */
1733
- if (has_inside_empty)
1780
+ if (has_inside_empty || has_trailing_empty)
1734
1781
  *flags |= MKD_LI_BLOCK;
1735
1782
 
1736
1783
  if (*flags & MKD_LI_BLOCK) {
@@ -1751,6 +1798,9 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
1751
1798
  parse_inline(inter, rndr, work->data, work->size);
1752
1799
  }
1753
1800
 
1801
+ if (!has_trailing_empty)
1802
+ *flags &= ~MKD_LI_BLOCK;
1803
+
1754
1804
  /* render of li itself */
1755
1805
  if (rndr->cb.listitem)
1756
1806
  rndr->cb.listitem(ob, inter, *flags, rndr->opaque);
@@ -1989,8 +2039,9 @@ parse_table_row(
1989
2039
  int *col_data,
1990
2040
  int header_flag)
1991
2041
  {
1992
- size_t i = 0, col;
2042
+ size_t i = 0, j, code_end, col;
1993
2043
  struct buf *row_work = 0;
2044
+ int nb = 0, is_escaped = 0;
1994
2045
 
1995
2046
  if (!rndr->cb.table_cell || !rndr->cb.table_row)
1996
2047
  return;
@@ -2011,8 +2062,35 @@ parse_table_row(
2011
2062
 
2012
2063
  cell_start = i;
2013
2064
 
2014
- while (i < size && data[i] != '|')
2015
- i++;
2065
+ /* find the | marking the end of this cell */
2066
+ while (i < size) {
2067
+ if (!is_escaped && data[i] == '|')
2068
+ break;
2069
+
2070
+ /* find code spans because they can contain |s */
2071
+ if (!is_escaped && data[i] == '`') {
2072
+ for (nb=0; i < size && data[i] == '`'; i++)
2073
+ nb++;
2074
+
2075
+ for (j=0, code_end=i; code_end < size && j < nb; code_end++) {
2076
+ if (data[code_end] == '`') j++;
2077
+ else j = 0;
2078
+ }
2079
+
2080
+ /* bail if there's no matching delimiter */
2081
+ if (j < nb) {
2082
+ i++;
2083
+ continue;
2084
+ }
2085
+
2086
+ i = code_end;
2087
+ is_escaped = 0;
2088
+ }
2089
+ else {
2090
+ is_escaped = !is_escaped && data[i] == '\\';
2091
+ i++;
2092
+ }
2093
+ }
2016
2094
 
2017
2095
  cell_end = i - 1;
2018
2096
 
@@ -2282,11 +2360,11 @@ is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_re
2282
2360
  i++;
2283
2361
  if (i >= end || data[i] != ':') return 0;
2284
2362
  i++;
2285
- while (i < end && data[i] == ' ') i++;
2363
+ while (i < end && (data[i] == ' ' || data[i] == '\t')) i++;
2286
2364
  if (i < end && (data[i] == '\n' || data[i] == '\r')) {
2287
2365
  i++;
2288
2366
  if (i < end && data[i] == '\r' && data[i - 1] == '\n') i++; }
2289
- while (i < end && data[i] == ' ') i++;
2367
+ while (i < end && (data[i] == ' ' || data[i] == '\t')) i++;
2290
2368
  if (i >= end) return 0;
2291
2369
 
2292
2370
  /* link: whitespace-free sequence, optionally between angle brackets */
@@ -2295,14 +2373,14 @@ is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_re
2295
2373
 
2296
2374
  link_offset = i;
2297
2375
 
2298
- while (i < end && data[i] != ' ' && data[i] != '\n' && data[i] != '\r')
2376
+ while (i < end && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r')
2299
2377
  i++;
2300
2378
 
2301
2379
  if (data[i - 1] == '>') link_end = i - 1;
2302
2380
  else link_end = i;
2303
2381
 
2304
2382
  /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */
2305
- while (i < end && data[i] == ' ') i++;
2383
+ while (i < end && (data[i] == ' ' || data[i] == '\t')) i++;
2306
2384
  if (i < end && data[i] != '\n' && data[i] != '\r'
2307
2385
  && data[i] != '\'' && data[i] != '"' && data[i] != '(')
2308
2386
  return 0;
@@ -2315,7 +2393,7 @@ is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_re
2315
2393
  /* optional (space|tab)* spacer after a newline */
2316
2394
  if (line_end) {
2317
2395
  i = line_end + 1;
2318
- while (i < end && data[i] == ' ') i++; }
2396
+ while (i < end && (data[i] == ' ' || data[i] == '\t')) i++; }
2319
2397
 
2320
2398
  /* optional title: any non-newline sequence enclosed in '"()
2321
2399
  alone on its line */
@@ -2331,7 +2409,7 @@ is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_re
2331
2409
  else title_end = i;
2332
2410
  /* stepping back */
2333
2411
  i -= 1;
2334
- while (i > title_offset && data[i] == ' ')
2412
+ while (i > title_offset && (data[i] == ' ' || data[i] == '\t'))
2335
2413
  i -= 1;
2336
2414
  if (i > title_offset
2337
2415
  && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) {
@@ -2460,7 +2538,8 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
2460
2538
  static const char UTF8_BOM[] = {0xEF, 0xBB, 0xBF};
2461
2539
 
2462
2540
  struct buf *text;
2463
- size_t beg, end;
2541
+ size_t beg, end, expanded_beg;
2542
+ int in_code_block = 0;
2464
2543
 
2465
2544
  text = bufnew(64);
2466
2545
  if (!text)
@@ -2481,7 +2560,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
2481
2560
  beg += 3;
2482
2561
 
2483
2562
  while (beg < doc_size) /* iterating over lines */
2484
- if (is_ref(document, beg, doc_size, &end, md->refs))
2563
+ if (!in_code_block && is_ref(document, beg, doc_size, &end, md->refs))
2485
2564
  beg = end;
2486
2565
  else { /* skipping to the next line */
2487
2566
  end = beg;
@@ -2489,9 +2568,17 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
2489
2568
  end++;
2490
2569
 
2491
2570
  /* adding the line body if present */
2492
- if (end > beg)
2571
+ if (end > beg) {
2572
+ expanded_beg = text->size;
2573
+
2493
2574
  expand_tabs(text, document + beg, end - beg);
2494
2575
 
2576
+ /* check for a fenced code block */
2577
+ if ((md->ext_flags & MKDEXT_FENCED_CODE) != 0 &&
2578
+ is_codefence(text->data + expanded_beg, text->size - expanded_beg, NULL) != 0)
2579
+ in_code_block = !in_code_block;
2580
+ }
2581
+
2495
2582
  while (end < doc_size && (document[end] == '\n' || document[end] == '\r')) {
2496
2583
  /* add one \n per newline */
2497
2584
  if (document[end] == '\n' || (end + 1 < doc_size && document[end + 1] != '\n'))
@@ -109,12 +109,6 @@ rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque)
109
109
  plaintext_block(ob, text);
110
110
  }
111
111
 
112
- static void
113
- rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque)
114
- {
115
- /* NO OP */
116
- }
117
-
118
112
  static void
119
113
  rndr_hrule(struct buf *ob, void *opaque)
120
114
  {
@@ -159,7 +153,7 @@ sdtext_renderer(struct sd_callbacks *callbacks)
159
153
  static const struct sd_callbacks cb_default = {
160
154
  rndr_blockcode,
161
155
  rndr_blockquote,
162
- rndr_raw_block,
156
+ NULL,
163
157
  rndr_header,
164
158
  rndr_hrule,
165
159
  rndr_list,
@@ -1,12 +1,10 @@
1
1
  # encoding: utf-8
2
2
  Gem::Specification.new do |s|
3
3
  s.name = 'github-markdown'
4
- s.version = '0.5.2'
5
- s.summary = 'The Markdown parser for GitHub.com'
6
- s.description = 'Self-contained Markdown parser for GitHub, with all our custom extensions'
7
- s.date = '2012-07-08'
8
- s.email = 'vicent@github.com'
9
- s.homepage = 'http://github.github.com/github-flavored-markdown/'
4
+ s.version = '0.6.9'
5
+ s.summary = 'THIS GEM IS NOT MAINTAINED AND NOT SUPPORTED. The Markdown parser for GitHub.com'
6
+ s.description = 'THIS GEM IS NOT MAINTAINED AND NOT SUPPORTED. Self-contained Markdown parser for GitHub, with all our custom extensions'
7
+ s.license = 'MIT'
10
8
  s.authors = ['GitHub, Inc']
11
9
  # = MANIFEST =
12
10
  s.files = %w[
@@ -38,5 +36,4 @@ Gem::Specification.new do |s|
38
36
  s.test_files = ["test/gfm_test.rb"]
39
37
  s.extensions = ["ext/markdown/extconf.rb"]
40
38
  s.require_paths = ["lib"]
41
- s.add_development_dependency "rake-compiler"
42
39
  end
@@ -16,6 +16,33 @@ def html_equal(html_a, html_b)
16
16
  end
17
17
 
18
18
  class GFMBasicTest < Test::Unit::TestCase
19
+ Dir['test/fixtures/*.text', 'test/fixtures/Markdown_Redcarpet/**/*.text'].each do |md_file|
20
+ dirname = File.dirname(md_file)
21
+ markup = md_file.split('/').last.gsub(/\.text/, '').gsub(/(\s+)/, "_")
22
+ define_method "test_#{dirname}_#{markup}" do
23
+ source = File.read(md_file)
24
+
25
+ expected_file = "#{dirname}/#{markup}.html"
26
+ expected = File.read(expected_file).rstrip
27
+ actual = GitHub::Markdown.render(source).rstrip
28
+
29
+ if source != expected
30
+ assert(source != actual, "#{markup} did not render anything")
31
+ end
32
+
33
+ diff = IO.popen("diff -u - #{expected_file}", 'r+') do |f|
34
+ f.write actual
35
+ f.close_write
36
+ f.read
37
+ end
38
+
39
+ assert expected == actual, <<message
40
+ #{File.basename expected_file}'s contents don't match command output:
41
+ #{diff}
42
+ message
43
+ end
44
+ end
45
+
19
46
  def test_that_render_works
20
47
  GitHub::Markdown.to_html("Hello **world**!", :gfm)
21
48
  end
@@ -50,7 +77,7 @@ class GFMBasicTest < Test::Unit::TestCase
50
77
  parsed = Nokogiri::HTML::DocumentFragment.parse(html)
51
78
 
52
79
  items.inject(parsed) do |node, expected_item|
53
- child = node.at('.//ul/li')
80
+ child = node.xpath('.//ul/li')
54
81
  child_item = child.children.detect{|e| e.text?}.text.strip
55
82
  assert_equal expected_item, child_item
56
83
  node = child
metadata CHANGED
@@ -1,46 +1,23 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: github-markdown
3
- version: !ruby/object:Gem::Version
4
- hash: 15
5
- prerelease:
6
- segments:
7
- - 0
8
- - 5
9
- - 2
10
- version: 0.5.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.9
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - GitHub, Inc
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2012-07-08 00:00:00 +02:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: rake-compiler
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
33
- type: :development
34
- version_requirements: *id001
35
- description: Self-contained Markdown parser for GitHub, with all our custom extensions
36
- email: vicent@github.com
11
+ date: 2015-08-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: THIS GEM IS NOT MAINTAINED AND NOT SUPPORTED. Self-contained Markdown
14
+ parser for GitHub, with all our custom extensions
15
+ email:
37
16
  executables: []
38
-
39
- extensions:
17
+ extensions:
40
18
  - ext/markdown/extconf.rb
41
19
  extra_rdoc_files: []
42
-
43
- files:
20
+ files:
44
21
  - Rakefile
45
22
  - bin/gfm
46
23
  - ext/markdown/autolink.c
@@ -64,39 +41,29 @@ files:
64
41
  - github-markdown.gemspec
65
42
  - lib/github/markdown.rb
66
43
  - test/gfm_test.rb
67
- has_rdoc: true
68
- homepage: http://github.github.com/github-flavored-markdown/
69
- licenses: []
70
-
44
+ homepage:
45
+ licenses:
46
+ - MIT
47
+ metadata: {}
71
48
  post_install_message:
72
49
  rdoc_options: []
73
-
74
- require_paths:
50
+ require_paths:
75
51
  - lib
76
- required_ruby_version: !ruby/object:Gem::Requirement
77
- none: false
78
- requirements:
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
79
54
  - - ">="
80
- - !ruby/object:Gem::Version
81
- hash: 3
82
- segments:
83
- - 0
84
- version: "0"
85
- required_rubygems_version: !ruby/object:Gem::Requirement
86
- none: false
87
- requirements:
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
88
59
  - - ">="
89
- - !ruby/object:Gem::Version
90
- hash: 3
91
- segments:
92
- - 0
93
- version: "0"
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
94
62
  requirements: []
95
-
96
63
  rubyforge_project:
97
- rubygems_version: 1.6.2
64
+ rubygems_version: 2.2.3
98
65
  signing_key:
99
- specification_version: 3
100
- summary: The Markdown parser for GitHub.com
101
- test_files:
66
+ specification_version: 4
67
+ summary: THIS GEM IS NOT MAINTAINED AND NOT SUPPORTED. The Markdown parser for GitHub.com
68
+ test_files:
102
69
  - test/gfm_test.rb