github-markdown 0.5.2 → 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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