redcarpet 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of redcarpet might be problematic. Click here for more details.
- data/Gemfile +2 -0
- data/Gemfile.lock +20 -0
- data/README.markdown +25 -20
- data/Rakefile +8 -20
- data/ext/redcarpet/autolink.c +52 -16
- data/ext/redcarpet/autolink.h +22 -7
- data/ext/redcarpet/buffer.c +2 -0
- data/ext/redcarpet/buffer.h +8 -0
- data/ext/redcarpet/html.c +8 -1
- data/ext/redcarpet/html.h +1 -0
- data/ext/redcarpet/html_smartypants.c +4 -0
- data/ext/redcarpet/markdown.c +173 -85
- data/ext/redcarpet/markdown.h +13 -5
- data/ext/redcarpet/rc_markdown.c +2 -2
- data/ext/redcarpet/rc_render.c +30 -3
- data/ext/redcarpet/redcarpet.h +2 -0
- data/ext/redcarpet/stack.h +8 -0
- data/lib/redcarpet.rb +2 -2
- data/redcarpet.gemspec +6 -3
- data/test/redcarpet_test.rb +24 -1
- metadata +26 -8
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
redcarpet (2.1.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
nokogiri (1.5.5)
|
10
|
+
rake (0.9.2.2)
|
11
|
+
rake-compiler (0.8.1)
|
12
|
+
rake
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
nokogiri
|
19
|
+
rake-compiler
|
20
|
+
redcarpet!
|
data/README.markdown
CHANGED
@@ -9,14 +9,14 @@ case since version 2 -- it now has its own API, but retains the old name. Yes,
|
|
9
9
|
that does mean that Redcarpet 2 is not backwards-compatible with the 1.X
|
10
10
|
versions.
|
11
11
|
|
12
|
-
Redcarpet is powered by the [Sundown](https://www.github.com/
|
12
|
+
Redcarpet is powered by the [Sundown](https://www.github.com/vmg/sundown)
|
13
13
|
library. You might want to find out more about Sundown to see what makes this
|
14
14
|
Ruby library so awesome.
|
15
15
|
|
16
16
|
This library is written by people
|
17
17
|
-------------------------------------------------------
|
18
18
|
|
19
|
-
Redcarpet 2 has been rewritten from scratch by Vicent Martí (@
|
19
|
+
Redcarpet 2 has been rewritten from scratch by Vicent Martí (@vmg). Why
|
20
20
|
are you not following me on Twitter?
|
21
21
|
|
22
22
|
Redcarpet would not be possible without the Sundown library and its authors
|
@@ -32,7 +32,7 @@ extensions, but the parser is standalone and requires no installed libraries.
|
|
32
32
|
|
33
33
|
The Redcarpet source (including Sundown as a submodule) is available at GitHub:
|
34
34
|
|
35
|
-
$ git clone git://github.com/
|
35
|
+
$ git clone git://github.com/vmg/redcarpet.git
|
36
36
|
|
37
37
|
And it's like *really* simple to use
|
38
38
|
------------------------------------
|
@@ -78,7 +78,7 @@ settings, and reused between parses.
|
|
78
78
|
Two `~` characters mark the start of a strikethrough,
|
79
79
|
e.g. `this is ~~good~~ bad`
|
80
80
|
|
81
|
-
:
|
81
|
+
:lax_spacing - HTML blocks do not require to be surrounded
|
82
82
|
by an empty line as in the Markdown standard.
|
83
83
|
|
84
84
|
:space_after_headers - A space is always required between the
|
@@ -126,32 +126,33 @@ instantiating the renderer:
|
|
126
126
|
|
127
127
|
Render::HTML.new(render_options={})
|
128
128
|
|
129
|
-
|
129
|
+
Initializes an HTML renderer. The following flags are available:
|
130
130
|
|
131
|
-
|
131
|
+
:filter_html - do not allow any user-inputted HTML in the output
|
132
132
|
|
133
|
-
|
133
|
+
:no_images - do not generate any `<img>` tags
|
134
134
|
|
135
|
-
|
135
|
+
:no_links - do not generate any `<a>` tags
|
136
136
|
|
137
|
-
|
137
|
+
:no_styles - do not generate any `<style>` tags
|
138
138
|
|
139
|
-
|
139
|
+
:safe_links_only - only generate links for protocols which are considered safe
|
140
140
|
|
141
|
-
|
142
|
-
|
141
|
+
:with_toc_data - add HTML anchors to each header in the output HTML,
|
142
|
+
to allow linking to each section.
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
|
144
|
+
:hard_wrap - insert HTML `<br>` tags inside on paragraphs where the origin
|
145
|
+
Markdown document had newlines (by default, Markdown ignores these
|
146
|
+
newlines).
|
147
147
|
|
148
|
-
|
149
|
-
|
148
|
+
:xhtml - output XHTML-conformant tags. This option is always enabled in the
|
149
|
+
`Render::XHTML` renderer.
|
150
150
|
|
151
|
+
:link_attributes - hash of extra attributes to add to links
|
151
152
|
|
152
|
-
|
153
|
+
Example:
|
153
154
|
|
154
|
-
|
155
|
+
rndr = Redcarpet::Render::HTML.new(:no_links => true, :hard_wrap => true)
|
155
156
|
|
156
157
|
|
157
158
|
The `HTML` renderer has an alternate version, `Redcarpet::Render::HTML_TOC`,
|
@@ -295,7 +296,7 @@ software accordingly, and force your users to install it. That's the
|
|
295
296
|
only way to have reliable and predictable Markdown output on your program.
|
296
297
|
|
297
298
|
Still, if major forces (let's say, tornadoes or other natural disasters) force you
|
298
|
-
to keep a Markdown-compatibility
|
299
|
+
to keep a Markdown-compatibility layer, Redcarpet also supports this:
|
299
300
|
|
300
301
|
require 'redcarpet/compat'
|
301
302
|
|
@@ -311,6 +312,10 @@ that's a maintance nightmare and won't work.
|
|
311
312
|
On a related topic: if your Markdown gem has a `lib/markdown.rb` file that
|
312
313
|
monkeypatches the Markdown class, you're a terrible human being. Just saying.
|
313
314
|
|
315
|
+
Testing
|
316
|
+
-------
|
317
|
+
Tests run a lot faster without `bundle exec` :)
|
318
|
+
|
314
319
|
Boring legal stuff
|
315
320
|
------------------
|
316
321
|
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rake/clean'
|
|
3
3
|
require 'rake/extensiontask'
|
4
4
|
require 'digest/md5'
|
5
5
|
|
6
|
-
task :default => :test
|
6
|
+
task :default => [:checkout, :test]
|
7
7
|
|
8
8
|
# ==========================================================
|
9
9
|
# Ruby Extension
|
@@ -11,6 +11,13 @@ task :default => :test
|
|
11
11
|
|
12
12
|
Rake::ExtensionTask.new('redcarpet')
|
13
13
|
|
14
|
+
task :checkout do |t|
|
15
|
+
unless File.exists?('sundown/src/markdown.h')
|
16
|
+
sh 'git submodule init'
|
17
|
+
sh 'git submodule update'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
14
21
|
# ==========================================================
|
15
22
|
# Testing
|
16
23
|
# ==========================================================
|
@@ -109,22 +116,3 @@ task :update_gem do
|
|
109
116
|
puts "updated #{GEMFILE}"
|
110
117
|
end
|
111
118
|
|
112
|
-
desc 'Gather required Sundown sources into extension directory'
|
113
|
-
task :gather => 'sundown/src/markdown.h' do |t|
|
114
|
-
files =
|
115
|
-
FileList[
|
116
|
-
'sundown/src/{markdown,buffer,stack,autolink,html_blocks}.h',
|
117
|
-
'sundown/src/{markdown,buffer,stack,autolink}.c',
|
118
|
-
'sundown/html/{html,html_smartypants,houdini_html_e,houdini_href_e}.c',
|
119
|
-
'sundown/html/{html,houdini}.h',
|
120
|
-
]
|
121
|
-
cp files, 'ext/redcarpet/',
|
122
|
-
:preserve => true,
|
123
|
-
:verbose => true
|
124
|
-
end
|
125
|
-
|
126
|
-
file 'sundown/src/markdown.h' do |t|
|
127
|
-
abort "The Sundown submodule is required."
|
128
|
-
end
|
129
|
-
|
130
|
-
|
data/ext/redcarpet/autolink.c
CHANGED
@@ -15,12 +15,17 @@
|
|
15
15
|
*/
|
16
16
|
|
17
17
|
#include "buffer.h"
|
18
|
+
#include "autolink.h"
|
18
19
|
|
19
20
|
#include <string.h>
|
20
21
|
#include <stdlib.h>
|
21
22
|
#include <stdio.h>
|
22
23
|
#include <ctype.h>
|
23
24
|
|
25
|
+
#if defined(_WIN32)
|
26
|
+
#define strncasecmp _strnicmp
|
27
|
+
#endif
|
28
|
+
|
24
29
|
int
|
25
30
|
sd_autolink_issafe(const uint8_t *link, size_t link_len)
|
26
31
|
{
|
@@ -44,7 +49,7 @@ sd_autolink_issafe(const uint8_t *link, size_t link_len)
|
|
44
49
|
}
|
45
50
|
|
46
51
|
static size_t
|
47
|
-
autolink_delim(uint8_t *data, size_t link_end, size_t
|
52
|
+
autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
|
48
53
|
{
|
49
54
|
uint8_t cclose, copen = 0;
|
50
55
|
size_t i;
|
@@ -128,7 +133,7 @@ autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size)
|
|
128
133
|
}
|
129
134
|
|
130
135
|
static size_t
|
131
|
-
check_domain(uint8_t *data, size_t size)
|
136
|
+
check_domain(uint8_t *data, size_t size, int allow_short)
|
132
137
|
{
|
133
138
|
size_t i, np = 0;
|
134
139
|
|
@@ -140,23 +145,37 @@ check_domain(uint8_t *data, size_t size)
|
|
140
145
|
else if (!isalnum(data[i]) && data[i] != '-') break;
|
141
146
|
}
|
142
147
|
|
143
|
-
|
144
|
-
|
145
|
-
|
148
|
+
if (allow_short) {
|
149
|
+
/* We don't need a valid domain in the strict sense (with
|
150
|
+
* least one dot; so just make sure it's composed of valid
|
151
|
+
* domain characters and return the length of the the valid
|
152
|
+
* sequence. */
|
153
|
+
return i;
|
154
|
+
} else {
|
155
|
+
/* a valid domain needs to have at least a dot.
|
156
|
+
* that's as far as we get */
|
157
|
+
return np ? i : 0;
|
158
|
+
}
|
146
159
|
}
|
147
160
|
|
148
161
|
size_t
|
149
|
-
sd_autolink__www(
|
162
|
+
sd_autolink__www(
|
163
|
+
size_t *rewind_p,
|
164
|
+
struct buf *link,
|
165
|
+
uint8_t *data,
|
166
|
+
size_t max_rewind,
|
167
|
+
size_t size,
|
168
|
+
unsigned int flags)
|
150
169
|
{
|
151
170
|
size_t link_end;
|
152
171
|
|
153
|
-
if (
|
172
|
+
if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
|
154
173
|
return 0;
|
155
174
|
|
156
175
|
if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
|
157
176
|
return 0;
|
158
177
|
|
159
|
-
link_end = check_domain(data, size);
|
178
|
+
link_end = check_domain(data, size, 0);
|
160
179
|
|
161
180
|
if (link_end == 0)
|
162
181
|
return 0;
|
@@ -164,7 +183,7 @@ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offse
|
|
164
183
|
while (link_end < size && !isspace(data[link_end]))
|
165
184
|
link_end++;
|
166
185
|
|
167
|
-
link_end = autolink_delim(data, link_end,
|
186
|
+
link_end = autolink_delim(data, link_end, max_rewind, size);
|
168
187
|
|
169
188
|
if (link_end == 0)
|
170
189
|
return 0;
|
@@ -176,12 +195,18 @@ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offse
|
|
176
195
|
}
|
177
196
|
|
178
197
|
size_t
|
179
|
-
sd_autolink__email(
|
198
|
+
sd_autolink__email(
|
199
|
+
size_t *rewind_p,
|
200
|
+
struct buf *link,
|
201
|
+
uint8_t *data,
|
202
|
+
size_t max_rewind,
|
203
|
+
size_t size,
|
204
|
+
unsigned int flags)
|
180
205
|
{
|
181
206
|
size_t link_end, rewind;
|
182
207
|
int nb = 0, np = 0;
|
183
208
|
|
184
|
-
for (rewind = 0; rewind <
|
209
|
+
for (rewind = 0; rewind < max_rewind; ++rewind) {
|
185
210
|
uint8_t c = data[-rewind - 1];
|
186
211
|
|
187
212
|
if (isalnum(c))
|
@@ -213,7 +238,7 @@ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t off
|
|
213
238
|
if (link_end < 2 || nb != 1 || np == 0)
|
214
239
|
return 0;
|
215
240
|
|
216
|
-
link_end = autolink_delim(data, link_end,
|
241
|
+
link_end = autolink_delim(data, link_end, max_rewind, size);
|
217
242
|
|
218
243
|
if (link_end == 0)
|
219
244
|
return 0;
|
@@ -225,21 +250,32 @@ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t off
|
|
225
250
|
}
|
226
251
|
|
227
252
|
size_t
|
228
|
-
sd_autolink__url(
|
253
|
+
sd_autolink__url(
|
254
|
+
size_t *rewind_p,
|
255
|
+
struct buf *link,
|
256
|
+
uint8_t *data,
|
257
|
+
size_t max_rewind,
|
258
|
+
size_t size,
|
259
|
+
unsigned int flags)
|
229
260
|
{
|
230
261
|
size_t link_end, rewind = 0, domain_len;
|
231
262
|
|
232
263
|
if (size < 4 || data[1] != '/' || data[2] != '/')
|
233
264
|
return 0;
|
234
265
|
|
235
|
-
while (rewind <
|
266
|
+
while (rewind < max_rewind && isalpha(data[-rewind - 1]))
|
236
267
|
rewind++;
|
237
268
|
|
238
269
|
if (!sd_autolink_issafe(data - rewind, size + rewind))
|
239
270
|
return 0;
|
271
|
+
|
240
272
|
link_end = strlen("://");
|
241
273
|
|
242
|
-
domain_len = check_domain(
|
274
|
+
domain_len = check_domain(
|
275
|
+
data + link_end,
|
276
|
+
size - link_end,
|
277
|
+
flags & SD_AUTOLINK_SHORT_DOMAINS);
|
278
|
+
|
243
279
|
if (domain_len == 0)
|
244
280
|
return 0;
|
245
281
|
|
@@ -247,7 +283,7 @@ sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offse
|
|
247
283
|
while (link_end < size && !isspace(data[link_end]))
|
248
284
|
link_end++;
|
249
285
|
|
250
|
-
link_end = autolink_delim(data, link_end,
|
286
|
+
link_end = autolink_delim(data, link_end, max_rewind, size);
|
251
287
|
|
252
288
|
if (link_end == 0)
|
253
289
|
return 0;
|
data/ext/redcarpet/autolink.h
CHANGED
@@ -19,17 +19,32 @@
|
|
19
19
|
|
20
20
|
#include "buffer.h"
|
21
21
|
|
22
|
-
|
22
|
+
#ifdef __cplusplus
|
23
|
+
extern "C" {
|
24
|
+
#endif
|
25
|
+
|
26
|
+
enum {
|
27
|
+
SD_AUTOLINK_SHORT_DOMAINS = (1 << 0),
|
28
|
+
};
|
29
|
+
|
30
|
+
int
|
23
31
|
sd_autolink_issafe(const uint8_t *link, size_t link_len);
|
24
32
|
|
25
|
-
|
26
|
-
sd_autolink__www(size_t *rewind_p, struct buf *link,
|
33
|
+
size_t
|
34
|
+
sd_autolink__www(size_t *rewind_p, struct buf *link,
|
35
|
+
uint8_t *data, size_t offset, size_t size, unsigned int flags);
|
27
36
|
|
28
|
-
|
29
|
-
sd_autolink__email(size_t *rewind_p, struct buf *link,
|
37
|
+
size_t
|
38
|
+
sd_autolink__email(size_t *rewind_p, struct buf *link,
|
39
|
+
uint8_t *data, size_t offset, size_t size, unsigned int flags);
|
30
40
|
|
31
|
-
|
32
|
-
sd_autolink__url(size_t *rewind_p, struct buf *link,
|
41
|
+
size_t
|
42
|
+
sd_autolink__url(size_t *rewind_p, struct buf *link,
|
43
|
+
uint8_t *data, size_t offset, size_t size, unsigned int flags);
|
44
|
+
|
45
|
+
#ifdef __cplusplus
|
46
|
+
}
|
47
|
+
#endif
|
33
48
|
|
34
49
|
#endif
|
35
50
|
|
data/ext/redcarpet/buffer.c
CHANGED
data/ext/redcarpet/buffer.h
CHANGED
@@ -22,6 +22,10 @@
|
|
22
22
|
#include <stdarg.h>
|
23
23
|
#include <stdint.h>
|
24
24
|
|
25
|
+
#ifdef __cplusplus
|
26
|
+
extern "C" {
|
27
|
+
#endif
|
28
|
+
|
25
29
|
#if defined(_MSC_VER)
|
26
30
|
#define __attribute__(x)
|
27
31
|
#define inline
|
@@ -85,4 +89,8 @@ void bufslurp(struct buf *, size_t);
|
|
85
89
|
/* bufprintf: formatted printing to a buffer */
|
86
90
|
void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
|
87
91
|
|
92
|
+
#ifdef __cplusplus
|
93
|
+
}
|
94
|
+
#endif
|
95
|
+
|
88
96
|
#endif
|
data/ext/redcarpet/html.c
CHANGED
@@ -491,6 +491,13 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
491
491
|
{
|
492
492
|
struct html_renderopt *options = opaque;
|
493
493
|
|
494
|
+
/* set the level offset if this is the first header
|
495
|
+
* we're parsing for the document */
|
496
|
+
if (options->toc_data.current_level == 0) {
|
497
|
+
options->toc_data.level_offset = level - 1;
|
498
|
+
}
|
499
|
+
level -= options->toc_data.level_offset;
|
500
|
+
|
494
501
|
if (level > options->toc_data.current_level) {
|
495
502
|
while (level > options->toc_data.current_level) {
|
496
503
|
BUFPUTSL(ob, "<ul>\n<li>\n");
|
@@ -516,7 +523,7 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
516
523
|
static int
|
517
524
|
toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque)
|
518
525
|
{
|
519
|
-
if (content && content->size)
|
526
|
+
if (content && content->size)
|
520
527
|
bufput(ob, content->data, content->size);
|
521
528
|
return 1;
|
522
529
|
}
|
data/ext/redcarpet/html.h
CHANGED
data/ext/redcarpet/markdown.c
CHANGED
@@ -25,6 +25,10 @@
|
|
25
25
|
#include <ctype.h>
|
26
26
|
#include <stdio.h>
|
27
27
|
|
28
|
+
#if defined(_WIN32)
|
29
|
+
#define strncasecmp _strnicmp
|
30
|
+
#endif
|
31
|
+
|
28
32
|
#define REF_TABLE_SIZE 8
|
29
33
|
|
30
34
|
#define BUFFER_BLOCK 0
|
@@ -497,7 +501,7 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
|
|
497
501
|
if (data[i] == c && !_isspace(data[i - 1])) {
|
498
502
|
|
499
503
|
if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
|
500
|
-
if (
|
504
|
+
if (i + i < size && isalnum(data[i + 1]))
|
501
505
|
continue;
|
502
506
|
}
|
503
507
|
|
@@ -592,6 +596,11 @@ char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t of
|
|
592
596
|
uint8_t c = data[0];
|
593
597
|
size_t ret;
|
594
598
|
|
599
|
+
if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
|
600
|
+
if (offset > 0 && !_isspace(data[-1]) && data[-1] != '>')
|
601
|
+
return 0;
|
602
|
+
}
|
603
|
+
|
595
604
|
if (size > 2 && data[1] != c) {
|
596
605
|
/* whitespace cannot follow an opening emphasis;
|
597
606
|
* strikethrough only takes two characters '~~' */
|
@@ -767,7 +776,7 @@ char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_
|
|
767
776
|
|
768
777
|
link = rndr_newbuf(rndr, BUFFER_SPAN);
|
769
778
|
|
770
|
-
if ((link_len = sd_autolink__www(&rewind, link, data, offset, size)) > 0) {
|
779
|
+
if ((link_len = sd_autolink__www(&rewind, link, data, offset, size, 0)) > 0) {
|
771
780
|
link_url = rndr_newbuf(rndr, BUFFER_SPAN);
|
772
781
|
BUFPUTSL(link_url, "http://");
|
773
782
|
bufput(link_url, link->data, link->size);
|
@@ -799,7 +808,7 @@ char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, siz
|
|
799
808
|
|
800
809
|
link = rndr_newbuf(rndr, BUFFER_SPAN);
|
801
810
|
|
802
|
-
if ((link_len = sd_autolink__email(&rewind, link, data, offset, size)) > 0) {
|
811
|
+
if ((link_len = sd_autolink__email(&rewind, link, data, offset, size, 0)) > 0) {
|
803
812
|
ob->size -= rewind;
|
804
813
|
rndr->cb.autolink(ob, link, MKDA_EMAIL, rndr->opaque);
|
805
814
|
}
|
@@ -819,7 +828,7 @@ char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_
|
|
819
828
|
|
820
829
|
link = rndr_newbuf(rndr, BUFFER_SPAN);
|
821
830
|
|
822
|
-
if ((link_len = sd_autolink__url(&rewind, link, data, offset, size)) > 0) {
|
831
|
+
if ((link_len = sd_autolink__url(&rewind, link, data, offset, size, 0)) > 0) {
|
823
832
|
ob->size -= rewind;
|
824
833
|
rndr->cb.autolink(ob, link, MKDA_NORMAL, rndr->opaque);
|
825
834
|
}
|
@@ -1150,9 +1159,10 @@ is_hrule(uint8_t *data, size_t size)
|
|
1150
1159
|
return n >= 3;
|
1151
1160
|
}
|
1152
1161
|
|
1153
|
-
/* check if a line
|
1162
|
+
/* check if a line begins with a code fence; return the
|
1163
|
+
* width of the code fence */
|
1154
1164
|
static size_t
|
1155
|
-
|
1165
|
+
prefix_codefence(uint8_t *data, size_t size)
|
1156
1166
|
{
|
1157
1167
|
size_t i = 0, n = 0;
|
1158
1168
|
uint8_t c;
|
@@ -1177,41 +1187,54 @@ is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
|
1177
1187
|
if (n < 3)
|
1178
1188
|
return 0;
|
1179
1189
|
|
1180
|
-
|
1181
|
-
|
1190
|
+
return i;
|
1191
|
+
}
|
1182
1192
|
|
1183
|
-
|
1184
|
-
|
1193
|
+
/* check if a line is a code fence; return its size if it is */
|
1194
|
+
static size_t
|
1195
|
+
is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
1196
|
+
{
|
1197
|
+
size_t i = 0, syn_len = 0;
|
1198
|
+
uint8_t *syn_start;
|
1185
1199
|
|
1186
|
-
|
1200
|
+
i = prefix_codefence(data, size);
|
1201
|
+
if (i == 0)
|
1202
|
+
return 0;
|
1187
1203
|
|
1188
|
-
|
1189
|
-
|
1204
|
+
while (i < size && data[i] == ' ')
|
1205
|
+
i++;
|
1190
1206
|
|
1191
|
-
|
1192
|
-
syn++; i++;
|
1193
|
-
}
|
1207
|
+
syn_start = data + i;
|
1194
1208
|
|
1195
|
-
|
1196
|
-
|
1209
|
+
if (i < size && data[i] == '{') {
|
1210
|
+
i++; syn_start++;
|
1197
1211
|
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
syntax->data++; syn--;
|
1202
|
-
}
|
1212
|
+
while (i < size && data[i] != '}' && data[i] != '\n') {
|
1213
|
+
syn_len++; i++;
|
1214
|
+
}
|
1203
1215
|
|
1204
|
-
|
1205
|
-
|
1216
|
+
if (i == size || data[i] != '}')
|
1217
|
+
return 0;
|
1206
1218
|
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
}
|
1219
|
+
/* strip all whitespace at the beginning and the end
|
1220
|
+
* of the {} block */
|
1221
|
+
while (syn_len > 0 && _isspace(syn_start[0])) {
|
1222
|
+
syn_start++; syn_len--;
|
1212
1223
|
}
|
1213
1224
|
|
1214
|
-
|
1225
|
+
while (syn_len > 0 && _isspace(syn_start[syn_len - 1]))
|
1226
|
+
syn_len--;
|
1227
|
+
|
1228
|
+
i++;
|
1229
|
+
} else {
|
1230
|
+
while (i < size && !_isspace(data[i])) {
|
1231
|
+
syn_len++; i++;
|
1232
|
+
}
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
if (syntax) {
|
1236
|
+
syntax->data = syn_start;
|
1237
|
+
syntax->size = syn_len;
|
1215
1238
|
}
|
1216
1239
|
|
1217
1240
|
while (i < size && data[i] != '\n') {
|
@@ -1416,19 +1439,48 @@ parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1416
1439
|
while (i < size) {
|
1417
1440
|
for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */;
|
1418
1441
|
|
1419
|
-
if (is_empty(data + i, size - i)
|
1442
|
+
if (is_empty(data + i, size - i))
|
1443
|
+
break;
|
1444
|
+
|
1445
|
+
if ((level = is_headerline(data + i, size - i)) != 0)
|
1446
|
+
break;
|
1447
|
+
|
1448
|
+
if (is_atxheader(rndr, data + i, size - i) ||
|
1449
|
+
is_hrule(data + i, size - i) ||
|
1450
|
+
prefix_quote(data + i, size - i)) {
|
1451
|
+
end = i;
|
1420
1452
|
break;
|
1453
|
+
}
|
1421
1454
|
|
1422
|
-
|
1423
|
-
|
1455
|
+
/*
|
1456
|
+
* Early termination of a paragraph with the same logic
|
1457
|
+
* as Markdown 1.0.0. If this logic is applied, the
|
1458
|
+
* Markdown 1.0.3 test suite won't pass cleanly
|
1459
|
+
*
|
1460
|
+
* :: If the first character in a new line is not a letter,
|
1461
|
+
* let's check to see if there's some kind of block starting
|
1462
|
+
* here
|
1463
|
+
*/
|
1464
|
+
if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !isalnum(data[i])) {
|
1465
|
+
if (prefix_oli(data + i, size - i) ||
|
1466
|
+
prefix_uli(data + i, size - i)) {
|
1424
1467
|
end = i;
|
1425
1468
|
break;
|
1426
1469
|
}
|
1427
|
-
}
|
1428
1470
|
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1471
|
+
/* see if an html block starts here */
|
1472
|
+
if (data[i] == '<' && rndr->cb.blockhtml &&
|
1473
|
+
parse_htmlblock(ob, rndr, data + i, size - i, 0)) {
|
1474
|
+
end = i;
|
1475
|
+
break;
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
/* see if a code fence starts here */
|
1479
|
+
if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 &&
|
1480
|
+
is_codefence(data + i, size - i, NULL) != 0) {
|
1481
|
+
end = i;
|
1482
|
+
break;
|
1483
|
+
}
|
1432
1484
|
}
|
1433
1485
|
|
1434
1486
|
i = end;
|
@@ -1500,9 +1552,10 @@ parse_fencedcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1500
1552
|
|
1501
1553
|
while (beg < size) {
|
1502
1554
|
size_t fence_end;
|
1555
|
+
struct buf fence_trail = { 0, 0, 0, 0 };
|
1503
1556
|
|
1504
|
-
fence_end = is_codefence(data + beg, size - beg,
|
1505
|
-
if (fence_end != 0) {
|
1557
|
+
fence_end = is_codefence(data + beg, size - beg, &fence_trail);
|
1558
|
+
if (fence_end != 0 && fence_trail.size == 0) {
|
1506
1559
|
beg += fence_end;
|
1507
1560
|
break;
|
1508
1561
|
}
|
@@ -1577,8 +1630,7 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
|
|
1577
1630
|
{
|
1578
1631
|
struct buf *work = 0, *inter = 0;
|
1579
1632
|
size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
|
1580
|
-
int in_empty = 0, has_inside_empty = 0;
|
1581
|
-
size_t has_next_uli, has_next_oli;
|
1633
|
+
int in_empty = 0, has_inside_empty = 0, in_fence = 0;
|
1582
1634
|
|
1583
1635
|
/* keeping track of the first indentation prefix */
|
1584
1636
|
while (orgpre < 3 && orgpre < size && data[orgpre] == ' ')
|
@@ -1606,6 +1658,8 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
|
|
1606
1658
|
|
1607
1659
|
/* process the following lines */
|
1608
1660
|
while (beg < size) {
|
1661
|
+
size_t has_next_uli = 0, has_next_oli = 0;
|
1662
|
+
|
1609
1663
|
end++;
|
1610
1664
|
|
1611
1665
|
while (end < size && data[end - 1] != '\n')
|
@@ -1625,8 +1679,17 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
|
|
1625
1679
|
|
1626
1680
|
pre = i;
|
1627
1681
|
|
1628
|
-
|
1629
|
-
|
1682
|
+
if (rndr->ext_flags & MKDEXT_FENCED_CODE) {
|
1683
|
+
if (is_codefence(data + beg + i, end - beg - i, NULL) != 0)
|
1684
|
+
in_fence = !in_fence;
|
1685
|
+
}
|
1686
|
+
|
1687
|
+
/* Only check for new list items if we are **not** inside
|
1688
|
+
* a fenced code block */
|
1689
|
+
if (!in_fence) {
|
1690
|
+
has_next_uli = prefix_uli(data + beg + i, end - beg - i);
|
1691
|
+
has_next_oli = prefix_oli(data + beg + i, end - beg - i);
|
1692
|
+
}
|
1630
1693
|
|
1631
1694
|
/* checking for ul/ol switch */
|
1632
1695
|
if (in_empty && (
|
@@ -1647,10 +1710,12 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
|
|
1647
1710
|
if (!sublist)
|
1648
1711
|
sublist = work->size;
|
1649
1712
|
}
|
1650
|
-
/* joining only indented stuff after empty lines
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1713
|
+
/* joining only indented stuff after empty lines;
|
1714
|
+
* note that now we only require 1 space of indentation
|
1715
|
+
* to continue a list */
|
1716
|
+
else if (in_empty && pre == 0) {
|
1717
|
+
*flags |= MKD_LI_END;
|
1718
|
+
break;
|
1654
1719
|
}
|
1655
1720
|
else if (in_empty) {
|
1656
1721
|
bufputc(work, '\n');
|
@@ -1758,7 +1823,12 @@ parse_atxheader(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1758
1823
|
/* htmlblock_end • checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */
|
1759
1824
|
/* returns the length on match, 0 otherwise */
|
1760
1825
|
static size_t
|
1761
|
-
|
1826
|
+
htmlblock_end_tag(
|
1827
|
+
const char *tag,
|
1828
|
+
size_t tag_len,
|
1829
|
+
struct sd_markdown *rndr,
|
1830
|
+
uint8_t *data,
|
1831
|
+
size_t size)
|
1762
1832
|
{
|
1763
1833
|
size_t i, w;
|
1764
1834
|
|
@@ -1776,25 +1846,60 @@ htmlblock_end(const char *tag, size_t tag_len, struct sd_markdown *rndr, uint8_t
|
|
1776
1846
|
i += w;
|
1777
1847
|
w = 0;
|
1778
1848
|
|
1779
|
-
if (
|
1780
|
-
|
1781
|
-
w = is_empty(data + i, size - i);
|
1782
|
-
} else {
|
1783
|
-
if (i < size && (w = is_empty(data + i, size - i)) == 0)
|
1784
|
-
return 0; /* non-blank line after tag line */
|
1785
|
-
}
|
1849
|
+
if (i < size)
|
1850
|
+
w = is_empty(data + i, size - i);
|
1786
1851
|
|
1787
1852
|
return i + w;
|
1788
1853
|
}
|
1789
1854
|
|
1855
|
+
static size_t
|
1856
|
+
htmlblock_end(const char *curtag,
|
1857
|
+
struct sd_markdown *rndr,
|
1858
|
+
uint8_t *data,
|
1859
|
+
size_t size,
|
1860
|
+
int start_of_line)
|
1861
|
+
{
|
1862
|
+
size_t tag_size = strlen(curtag);
|
1863
|
+
size_t i = 1, end_tag;
|
1864
|
+
int block_lines = 0;
|
1865
|
+
|
1866
|
+
while (i < size) {
|
1867
|
+
i++;
|
1868
|
+
while (i < size && !(data[i - 1] == '<' && data[i] == '/')) {
|
1869
|
+
if (data[i] == '\n')
|
1870
|
+
block_lines++;
|
1871
|
+
|
1872
|
+
i++;
|
1873
|
+
}
|
1874
|
+
|
1875
|
+
/* If we are only looking for unindented tags, skip the tag
|
1876
|
+
* if it doesn't follow a newline.
|
1877
|
+
*
|
1878
|
+
* The only exception to this is if the tag is still on the
|
1879
|
+
* initial line; in that case it still counts as a closing
|
1880
|
+
* tag
|
1881
|
+
*/
|
1882
|
+
if (start_of_line && block_lines > 0 && data[i - 2] != '\n')
|
1883
|
+
continue;
|
1884
|
+
|
1885
|
+
if (i + 2 + tag_size >= size)
|
1886
|
+
break;
|
1887
|
+
|
1888
|
+
end_tag = htmlblock_end_tag(curtag, tag_size, rndr, data + i - 1, size - i + 1);
|
1889
|
+
if (end_tag)
|
1890
|
+
return i + end_tag - 1;
|
1891
|
+
}
|
1892
|
+
|
1893
|
+
return 0;
|
1894
|
+
}
|
1895
|
+
|
1790
1896
|
|
1791
1897
|
/* parse_htmlblock • parsing of inline HTML block */
|
1792
1898
|
static size_t
|
1793
1899
|
parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render)
|
1794
1900
|
{
|
1795
|
-
size_t i, j = 0;
|
1901
|
+
size_t i, j = 0, tag_end;
|
1796
1902
|
const char *curtag = NULL;
|
1797
|
-
int found;
|
1798
1903
|
struct buf work = { data, 0, 0, 0 };
|
1799
1904
|
|
1800
1905
|
/* identification of the opening tag */
|
@@ -1855,40 +1960,23 @@ parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1855
1960
|
|
1856
1961
|
/* looking for an unindented matching closing tag */
|
1857
1962
|
/* followed by a blank line */
|
1858
|
-
|
1859
|
-
found = 0;
|
1963
|
+
tag_end = htmlblock_end(curtag, rndr, data, size, 1);
|
1860
1964
|
|
1861
1965
|
/* if not found, trying a second pass looking for indented match */
|
1862
1966
|
/* but not if tag is "ins" or "del" (following original Markdown.pl) */
|
1863
|
-
if (strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) {
|
1864
|
-
|
1865
|
-
i = 1;
|
1866
|
-
while (i < size) {
|
1867
|
-
i++;
|
1868
|
-
while (i < size && !(data[i - 1] == '<' && data[i] == '/'))
|
1869
|
-
i++;
|
1870
|
-
|
1871
|
-
if (i + 2 + tag_size >= size)
|
1872
|
-
break;
|
1873
|
-
|
1874
|
-
j = htmlblock_end(curtag, tag_size, rndr, data + i - 1, size - i + 1);
|
1875
|
-
|
1876
|
-
if (j) {
|
1877
|
-
i += j - 1;
|
1878
|
-
found = 1;
|
1879
|
-
break;
|
1880
|
-
}
|
1881
|
-
}
|
1967
|
+
if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) {
|
1968
|
+
tag_end = htmlblock_end(curtag, rndr, data, size, 0);
|
1882
1969
|
}
|
1883
1970
|
|
1884
|
-
if (!
|
1971
|
+
if (!tag_end)
|
1972
|
+
return 0;
|
1885
1973
|
|
1886
1974
|
/* the end of the block has been found */
|
1887
|
-
work.size =
|
1975
|
+
work.size = tag_end;
|
1888
1976
|
if (do_render && rndr->cb.blockhtml)
|
1889
1977
|
rndr->cb.blockhtml(ob, &work, rndr->opaque);
|
1890
1978
|
|
1891
|
-
return
|
1979
|
+
return tag_end;
|
1892
1980
|
}
|
1893
1981
|
|
1894
1982
|
static void
|
@@ -2460,9 +2548,9 @@ sd_markdown_free(struct sd_markdown *md)
|
|
2460
2548
|
void
|
2461
2549
|
sd_version(int *ver_major, int *ver_minor, int *ver_revision)
|
2462
2550
|
{
|
2463
|
-
*ver_major =
|
2464
|
-
*ver_minor =
|
2465
|
-
*ver_revision =
|
2551
|
+
*ver_major = SUNDOWN_VER_MAJOR;
|
2552
|
+
*ver_minor = SUNDOWN_VER_MINOR;
|
2553
|
+
*ver_revision = SUNDOWN_VER_REVISION;
|
2466
2554
|
}
|
2467
2555
|
|
2468
2556
|
/* vim: set filetype=c: */
|
data/ext/redcarpet/markdown.h
CHANGED
@@ -22,10 +22,14 @@
|
|
22
22
|
#include "buffer.h"
|
23
23
|
#include "autolink.h"
|
24
24
|
|
25
|
-
#
|
26
|
-
|
27
|
-
#
|
28
|
-
|
25
|
+
#ifdef __cplusplus
|
26
|
+
extern "C" {
|
27
|
+
#endif
|
28
|
+
|
29
|
+
#define SUNDOWN_VERSION "1.16.0"
|
30
|
+
#define SUNDOWN_VER_MAJOR 1
|
31
|
+
#define SUNDOWN_VER_MINOR 16
|
32
|
+
#define SUNDOWN_VER_REVISION 0
|
29
33
|
|
30
34
|
/********************
|
31
35
|
* TYPE DEFINITIONS *
|
@@ -52,9 +56,9 @@ enum mkd_extensions {
|
|
52
56
|
MKDEXT_FENCED_CODE = (1 << 2),
|
53
57
|
MKDEXT_AUTOLINK = (1 << 3),
|
54
58
|
MKDEXT_STRIKETHROUGH = (1 << 4),
|
55
|
-
MKDEXT_LAX_HTML_BLOCKS = (1 << 5),
|
56
59
|
MKDEXT_SPACE_HEADERS = (1 << 6),
|
57
60
|
MKDEXT_SUPERSCRIPT = (1 << 7),
|
61
|
+
MKDEXT_LAX_SPACING = (1 << 8),
|
58
62
|
};
|
59
63
|
|
60
64
|
/* sd_callbacks - functions for rendering parsed data */
|
@@ -125,6 +129,10 @@ sd_markdown_free(struct sd_markdown *md);
|
|
125
129
|
extern void
|
126
130
|
sd_version(int *major, int *minor, int *revision);
|
127
131
|
|
132
|
+
#ifdef __cplusplus
|
133
|
+
}
|
134
|
+
#endif
|
135
|
+
|
128
136
|
#endif
|
129
137
|
|
130
138
|
/* vim: set filetype=c: */
|
data/ext/redcarpet/rc_markdown.c
CHANGED
@@ -44,8 +44,8 @@ static void rb_redcarpet_md_flags(VALUE hash, unsigned int *enabled_extensions_p
|
|
44
44
|
if (rb_hash_lookup(hash, CSTR2SYM("strikethrough")) == Qtrue)
|
45
45
|
extensions |= MKDEXT_STRIKETHROUGH;
|
46
46
|
|
47
|
-
if (rb_hash_lookup(hash, CSTR2SYM("
|
48
|
-
extensions |=
|
47
|
+
if (rb_hash_lookup(hash, CSTR2SYM("lax_spacing")) == Qtrue)
|
48
|
+
extensions |= MKDEXT_LAX_SPACING;
|
49
49
|
|
50
50
|
if (rb_hash_lookup(hash, CSTR2SYM("space_after_headers")) == Qtrue)
|
51
51
|
extensions |= MKDEXT_SPACE_HEADERS;
|
data/ext/redcarpet/rc_render.c
CHANGED
@@ -234,6 +234,27 @@ rndr_doc_footer(struct buf *ob, void *opaque)
|
|
234
234
|
BLOCK_CALLBACK("doc_footer", 0);
|
235
235
|
}
|
236
236
|
|
237
|
+
static int
|
238
|
+
cb_link_attribute(VALUE key, VALUE val, VALUE payload)
|
239
|
+
{
|
240
|
+
struct buf *ob = (struct buf *)payload;
|
241
|
+
key = rb_obj_as_string(key);
|
242
|
+
val = rb_obj_as_string(val);
|
243
|
+
bufprintf(ob, " %s=\"%s\"", StringValueCStr(key), StringValueCStr(val));
|
244
|
+
return ST_CONTINUE;
|
245
|
+
}
|
246
|
+
|
247
|
+
static void
|
248
|
+
rndr_link_attributes(struct buf *ob, const struct buf *url, void *opaque)
|
249
|
+
{
|
250
|
+
struct redcarpet_renderopt *opt = opaque;
|
251
|
+
struct rb_redcarpet_rndr *rndr;
|
252
|
+
|
253
|
+
Data_Get_Struct(opt->self, struct rb_redcarpet_rndr, rndr);
|
254
|
+
Check_Type(opt->link_attributes, T_HASH);
|
255
|
+
rb_hash_foreach(opt->link_attributes, &cb_link_attribute, (VALUE)ob);
|
256
|
+
}
|
257
|
+
|
237
258
|
static struct sd_callbacks rb_redcarpet_callbacks = {
|
238
259
|
rndr_blockcode,
|
239
260
|
rndr_blockquote,
|
@@ -342,12 +363,11 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
|
|
342
363
|
{
|
343
364
|
struct rb_redcarpet_rndr *rndr;
|
344
365
|
unsigned int render_flags = 0;
|
345
|
-
VALUE hash;
|
366
|
+
VALUE hash, link_attr = Qnil;
|
346
367
|
|
347
368
|
Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
|
348
369
|
|
349
|
-
if (rb_scan_args(argc, argv, "01", &hash) == 1)
|
350
|
-
{
|
370
|
+
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
|
351
371
|
Check_Type(hash, T_HASH);
|
352
372
|
|
353
373
|
/* escape_html */
|
@@ -382,11 +402,18 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
|
|
382
402
|
|
383
403
|
if (rb_hash_aref(hash, CSTR2SYM("xhtml")) == Qtrue)
|
384
404
|
render_flags |= HTML_USE_XHTML;
|
405
|
+
|
406
|
+
link_attr = rb_hash_aref(hash, CSTR2SYM("link_attributes"));
|
385
407
|
}
|
386
408
|
|
387
409
|
sdhtml_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags);
|
388
410
|
rb_redcarpet__overload(self, rb_cRenderHTML);
|
389
411
|
|
412
|
+
if (!NIL_P(link_attr)) {
|
413
|
+
rndr->options.link_attributes = link_attr;
|
414
|
+
rndr->options.html.link_attributes = &rndr_link_attributes;
|
415
|
+
}
|
416
|
+
|
390
417
|
return Qnil;
|
391
418
|
}
|
392
419
|
|
data/ext/redcarpet/redcarpet.h
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
#define RSTRING_NOT_MODIFIED
|
5
5
|
#include "ruby.h"
|
6
|
+
#include "st.h"
|
6
7
|
#include <stdio.h>
|
7
8
|
|
8
9
|
#ifdef HAVE_RUBY_ENCODING_H
|
@@ -21,6 +22,7 @@ extern void Init_redcarpet_rndr();
|
|
21
22
|
|
22
23
|
struct redcarpet_renderopt {
|
23
24
|
struct html_renderopt html;
|
25
|
+
VALUE link_attributes;
|
24
26
|
VALUE self;
|
25
27
|
VALUE base_class;
|
26
28
|
#ifdef HAVE_RUBY_ENCODING_H
|
data/ext/redcarpet/stack.h
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
|
4
4
|
#include <stdlib.h>
|
5
5
|
|
6
|
+
#ifdef __cplusplus
|
7
|
+
extern "C" {
|
8
|
+
#endif
|
9
|
+
|
6
10
|
struct stack {
|
7
11
|
void **item;
|
8
12
|
size_t size;
|
@@ -18,4 +22,8 @@ int stack_push(struct stack *, void *);
|
|
18
22
|
void *stack_pop(struct stack *);
|
19
23
|
void *stack_top(struct stack *);
|
20
24
|
|
25
|
+
#ifdef __cplusplus
|
26
|
+
}
|
27
|
+
#endif
|
28
|
+
|
21
29
|
#endif
|
data/lib/redcarpet.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'redcarpet.so'
|
2
2
|
|
3
3
|
module Redcarpet
|
4
|
-
VERSION = '2.
|
4
|
+
VERSION = '2.2.0'
|
5
5
|
|
6
6
|
class Markdown
|
7
7
|
attr_reader :renderer
|
@@ -77,7 +77,7 @@ class RedcarpetCompat
|
|
77
77
|
:fenced_code => :fenced_code_blocks,
|
78
78
|
:filter_html => :filter_html,
|
79
79
|
:hard_wrap => :hard_wrap,
|
80
|
-
:lax_htmlblock => :
|
80
|
+
:lax_htmlblock => :lax_spacing,
|
81
81
|
:no_image => :no_images,
|
82
82
|
:no_intraemphasis => :no_intra_emphasis,
|
83
83
|
:no_links => :no_links,
|
data/redcarpet.gemspec
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = 'redcarpet'
|
4
|
-
s.version = '2.
|
4
|
+
s.version = '2.2.0'
|
5
5
|
s.summary = "Markdown that smells nice"
|
6
6
|
s.description = 'A fast, safe and extensible Markdown to (X)HTML parser'
|
7
|
-
s.date = '
|
7
|
+
s.date = '2012-10-11'
|
8
8
|
s.email = 'vicent@github.com'
|
9
|
-
s.homepage = 'http://github.com/
|
9
|
+
s.homepage = 'http://github.com/vmg/redcarpet'
|
10
10
|
s.authors = ["Natacha Porté", "Vicent Martí"]
|
11
11
|
# = MANIFEST =
|
12
12
|
s.files = %w[
|
13
13
|
COPYING
|
14
|
+
Gemfile
|
15
|
+
Gemfile.lock
|
14
16
|
README.markdown
|
15
17
|
Rakefile
|
16
18
|
bin/redcarpet
|
@@ -47,5 +49,6 @@ Gem::Specification.new do |s|
|
|
47
49
|
s.extensions = ["ext/redcarpet/extconf.rb"]
|
48
50
|
s.executables = ["redcarpet"]
|
49
51
|
s.require_paths = ["lib"]
|
52
|
+
s.add_development_dependency "nokogiri"
|
50
53
|
s.add_development_dependency "rake-compiler"
|
51
54
|
end
|
data/test/redcarpet_test.rb
CHANGED
@@ -127,6 +127,12 @@ EOE
|
|
127
127
|
|
128
128
|
assert rd =~ /<br>/
|
129
129
|
end
|
130
|
+
|
131
|
+
def test_that_link_attributes_work
|
132
|
+
rndr = Redcarpet::Render::HTML.new(:link_attributes => {:rel => 'blank'})
|
133
|
+
md = Redcarpet::Markdown.new(rndr)
|
134
|
+
assert md.render('This is a [simple](http://test.com) test.').include?('rel="blank"')
|
135
|
+
end
|
130
136
|
end
|
131
137
|
|
132
138
|
class MarkdownTest < Test::Unit::TestCase
|
@@ -187,7 +193,7 @@ class MarkdownTest < Test::Unit::TestCase
|
|
187
193
|
end
|
188
194
|
|
189
195
|
def test_para_before_block_html_should_not_wrap_in_p_tag
|
190
|
-
markdown = render_with({:
|
196
|
+
markdown = render_with({:lax_spacing => true},
|
191
197
|
"Things to watch out for\n" +
|
192
198
|
"<ul>\n<li>Blah</li>\n</ul>\n")
|
193
199
|
|
@@ -311,6 +317,15 @@ fenced
|
|
311
317
|
assert render_with({:fenced_code_blocks => true}, text) =~ /<code/
|
312
318
|
end
|
313
319
|
|
320
|
+
def test_that_fenced_flag_works_without_space
|
321
|
+
text = "foo\nbar\n```\nsome\ncode\n```\nbaz"
|
322
|
+
out = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :fenced_code_blocks => true, :lax_spacing => true).render(text)
|
323
|
+
assert out.include?("<pre><code>")
|
324
|
+
|
325
|
+
out = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :fenced_code_blocks => true).render(text)
|
326
|
+
assert !out.include?("<pre><code>")
|
327
|
+
end
|
328
|
+
|
314
329
|
def test_that_headers_are_linkable
|
315
330
|
markdown = @markdown.render('### Hello [GitHub](http://github.com)')
|
316
331
|
html_equal "<h3>Hello <a href=\"http://github.com\">GitHub</a></h3>", markdown
|
@@ -327,6 +342,14 @@ text
|
|
327
342
|
rd = render_with({:space_after_headers => true}, "#123 a header yes\n")
|
328
343
|
assert rd !~ /<h1>/
|
329
344
|
end
|
345
|
+
|
346
|
+
def test_proper_intra_emphasis
|
347
|
+
md = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :no_intra_emphasis => true)
|
348
|
+
assert render_with({:no_intra_emphasis => true}, "http://en.wikipedia.org/wiki/Dave_Allen_(comedian)") !~ /<em>/
|
349
|
+
assert render_with({:no_intra_emphasis => true}, "this fails: hello_world_") !~ /<em>/
|
350
|
+
assert render_with({:no_intra_emphasis => true}, "this also fails: hello_world_#bye") !~ /<em>/
|
351
|
+
assert render_with({:no_intra_emphasis => true}, "this works: hello_my_world") !~ /<em>/
|
352
|
+
end
|
330
353
|
end
|
331
354
|
|
332
355
|
class CustomRenderTest < Test::Unit::TestCase
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redcarpet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 2.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 2.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Natacha Port\xC3\xA9"
|
@@ -16,10 +16,11 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date:
|
19
|
+
date: 2012-10-11 00:00:00 +02:00
|
20
|
+
default_executable:
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
23
|
+
name: nokogiri
|
23
24
|
prerelease: false
|
24
25
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
26
|
none: false
|
@@ -32,6 +33,20 @@ dependencies:
|
|
32
33
|
version: "0"
|
33
34
|
type: :development
|
34
35
|
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake-compiler
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
35
50
|
description: A fast, safe and extensible Markdown to (X)HTML parser
|
36
51
|
email: vicent@github.com
|
37
52
|
executables:
|
@@ -42,6 +57,8 @@ extra_rdoc_files:
|
|
42
57
|
- COPYING
|
43
58
|
files:
|
44
59
|
- COPYING
|
60
|
+
- Gemfile
|
61
|
+
- Gemfile.lock
|
45
62
|
- README.markdown
|
46
63
|
- Rakefile
|
47
64
|
- bin/redcarpet
|
@@ -70,7 +87,8 @@ files:
|
|
70
87
|
- lib/redcarpet/render_strip.rb
|
71
88
|
- redcarpet.gemspec
|
72
89
|
- test/redcarpet_test.rb
|
73
|
-
|
90
|
+
has_rdoc: true
|
91
|
+
homepage: http://github.com/vmg/redcarpet
|
74
92
|
licenses: []
|
75
93
|
|
76
94
|
post_install_message:
|
@@ -99,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
117
|
requirements: []
|
100
118
|
|
101
119
|
rubyforge_project:
|
102
|
-
rubygems_version: 1.
|
120
|
+
rubygems_version: 1.6.2
|
103
121
|
signing_key:
|
104
122
|
specification_version: 3
|
105
123
|
summary: Markdown that smells nice
|