markly 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/getting-started.md +36 -0
- data/ext/markly/cmark-gfm-extension_api.h +10 -0
- data/ext/markly/cmark-gfm.h +22 -0
- data/ext/markly/cmark-gfm_export.h +1 -0
- data/ext/markly/cmark-gfm_version.h +2 -2
- data/ext/markly/cmark_ctype.c +9 -0
- data/ext/markly/cmark_ctype.h +5 -0
- data/ext/markly/commonmark.c +10 -3
- data/ext/markly/config.h +0 -4
- data/ext/markly/extensions/table.c +24 -0
- data/ext/markly/html.c +47 -25
- data/ext/markly/inlines.c +85 -3
- data/ext/markly/iterator.c +6 -1
- data/ext/markly/markly.c +298 -201
- data/ext/markly/node.c +194 -3
- data/ext/markly/syntax_extension.c +5 -0
- data/ext/markly/syntax_extension.h +1 -0
- data/ext/markly/xml.c +12 -1
- data/lib/markly/flags.rb +4 -1
- data/lib/markly/node/inspect.rb +10 -3
- data/lib/markly/node.rb +54 -37
- data/lib/markly/renderer/generic.rb +42 -12
- data/lib/markly/renderer/headings.rb +24 -19
- data/lib/markly/renderer/html.rb +111 -10
- data/lib/markly/version.rb +3 -1
- data/lib/markly.rb +14 -13
- data/readme.md +15 -1
- data/releases.md +15 -1
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a6df3d157ca441e13f840de336bf04408669aae72ff791d35be091ee008da87c
|
|
4
|
+
data.tar.gz: 682356cc37b69d2a486624ffd0e0c02f75a717b07f32c0a41d838e2032730223
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70315346cac721d22cbc67c0efaee8bd6a035198fec894388a827136c3710d60844c24e29a26a4374a899af01212618412d929acfd840db03ce887f79e2b80ef
|
|
7
|
+
data.tar.gz: 895682bb5cd75d95306c2e60b9bb446b4459ade9800d8a29e5ecd13b4fb9f8e1caa33518ac1d3f6779143af9f213d50a0c17460ded2fc94eea57872e7aba9c26
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/context/getting-started.md
CHANGED
|
@@ -42,7 +42,9 @@ Markly accepts integer flags which control how the Markdown is parsed and render
|
|
|
42
42
|
| ------------------------------------ | -----------
|
|
43
43
|
| `Markly::DEFAULT` | The default parsing system.
|
|
44
44
|
| `Markly::UNSAFE` | Allow raw/custom HTML and unsafe links.
|
|
45
|
+
| `Markly::FRONT_MATTER` | Parse front matter at the start of the document.
|
|
45
46
|
| `Markly::FOOTNOTES` | Parse footnotes.
|
|
47
|
+
| `Markly::INLINE_CODE_INFO` | Parse language prefixes such as `ruby:` on inline code spans.
|
|
46
48
|
| `Markly::LIBERAL_HTML_TAG` | Support liberal parsing of inline HTML tags.
|
|
47
49
|
| `Markly::SMART` | Use smart punctuation (curly quotes, etc.).
|
|
48
50
|
| `Markly::STRIKETHROUGH_DOUBLE_TILDE` | Parse strikethroughs by double tildes (compatibility with [redcarpet](https://github.com/vmg/redcarpet))
|
|
@@ -76,6 +78,40 @@ To have multiple options applied, `|` (or) the flags together:
|
|
|
76
78
|
Markly.render_html("\"'Shelob' is my name.\"", flags: Markly::HARD_BREAKS|Markly::SOURCE_POSITION)
|
|
77
79
|
```
|
|
78
80
|
|
|
81
|
+
Inline code language prefixes are opt-in. The language is available through
|
|
82
|
+
`Node#code_info` and is rendered as a `language-...` class:
|
|
83
|
+
|
|
84
|
+
``` ruby
|
|
85
|
+
document = Markly.parse("ruby:`Object.new`", flags: Markly::INLINE_CODE_INFO)
|
|
86
|
+
code = document.first_child.first_child
|
|
87
|
+
|
|
88
|
+
code.code_info
|
|
89
|
+
# => "ruby"
|
|
90
|
+
|
|
91
|
+
code.code_language
|
|
92
|
+
# => "ruby"
|
|
93
|
+
|
|
94
|
+
document.to_html
|
|
95
|
+
# => <p><code class="language-ruby">Object.new</code></p>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`Node#code_info` is also the general info-string accessor for fenced code
|
|
99
|
+
blocks and front matter. `Node#code_language` returns the first token of that
|
|
100
|
+
info string, while `Node#fence_info` remains available for compatibility on
|
|
101
|
+
those block nodes.
|
|
102
|
+
|
|
103
|
+
For a fenced code block, `Node#fence` returns a `Node::Fence` structure with
|
|
104
|
+
the fence character, length, and indentation:
|
|
105
|
+
|
|
106
|
+
``` ruby
|
|
107
|
+
block = Markly.parse(" ~~~~ ruby\n Object.new\n ~~~~").first_child
|
|
108
|
+
|
|
109
|
+
block.fence
|
|
110
|
+
# => #<struct Markly::Node::Fence character="~", length=4, indent=2>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Indented code blocks and other node types return `nil`.
|
|
114
|
+
|
|
79
115
|
## Extensions
|
|
80
116
|
|
|
81
117
|
Both `render_html` and `parse` take an optional `extensions:` argument defining the extensions you want enabled as your CommonMark document is being processed:
|
|
@@ -264,6 +264,10 @@ typedef void (*cmark_opaque_free_func) (cmark_syntax_extension *extension,
|
|
|
264
264
|
cmark_mem *mem,
|
|
265
265
|
cmark_node *node);
|
|
266
266
|
|
|
267
|
+
typedef void (*cmark_opaque_copy_func)(cmark_syntax_extension *extension,
|
|
268
|
+
cmark_mem *mem, cmark_node *node,
|
|
269
|
+
cmark_node *source);
|
|
270
|
+
|
|
267
271
|
/** Free a cmark_syntax_extension.
|
|
268
272
|
*/
|
|
269
273
|
CMARK_GFM_EXPORT
|
|
@@ -406,6 +410,12 @@ CMARK_GFM_EXPORT
|
|
|
406
410
|
void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extension,
|
|
407
411
|
cmark_opaque_free_func func);
|
|
408
412
|
|
|
413
|
+
/** See the documentation for 'cmark_syntax_extension'
|
|
414
|
+
*/
|
|
415
|
+
CMARK_GFM_EXPORT
|
|
416
|
+
void cmark_syntax_extension_set_opaque_copy_func(
|
|
417
|
+
cmark_syntax_extension *extension, cmark_opaque_copy_func func);
|
|
418
|
+
|
|
409
419
|
/** See the documentation for 'cmark_syntax_extension'
|
|
410
420
|
*/
|
|
411
421
|
CMARK_GFM_EXPORT
|
data/ext/markly/cmark-gfm.h
CHANGED
|
@@ -196,6 +196,12 @@ CMARK_GFM_EXPORT cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type typ
|
|
|
196
196
|
cmark_mem *mem,
|
|
197
197
|
cmark_syntax_extension *extension);
|
|
198
198
|
|
|
199
|
+
/** Creates an independent deep copy of 'node' and all its children.
|
|
200
|
+
* User data is not copied. Returns NULL when extension-specific node data
|
|
201
|
+
* cannot be copied.
|
|
202
|
+
*/
|
|
203
|
+
CMARK_GFM_EXPORT cmark_node *cmark_node_clone(cmark_node *node);
|
|
204
|
+
|
|
199
205
|
/** Frees the memory allocated for a node and any children.
|
|
200
206
|
*/
|
|
201
207
|
CMARK_GFM_EXPORT void cmark_node_free(cmark_node *node);
|
|
@@ -425,6 +431,18 @@ CMARK_GFM_EXPORT int cmark_node_get_item_index(cmark_node *node);
|
|
|
425
431
|
*/
|
|
426
432
|
CMARK_GFM_EXPORT int cmark_node_set_item_index(cmark_node *node, int idx);
|
|
427
433
|
|
|
434
|
+
/** Returns the info string from a code block or the language identifier from
|
|
435
|
+
* an inline code span.
|
|
436
|
+
*/
|
|
437
|
+
CMARK_GFM_EXPORT const char *cmark_node_get_code_info(cmark_node *node);
|
|
438
|
+
|
|
439
|
+
/** Sets the info string in a code block or the language identifier on an
|
|
440
|
+
* inline code span, returning 1 on success and 0 on failure. Inline code
|
|
441
|
+
* language identifiers must begin with an alphanumeric character and may
|
|
442
|
+
* additionally contain '_', '-', '+', '#', and '.'.
|
|
443
|
+
*/
|
|
444
|
+
CMARK_GFM_EXPORT int cmark_node_set_code_info(cmark_node *node, const char *info);
|
|
445
|
+
|
|
428
446
|
/** Returns the info string from a fenced code block.
|
|
429
447
|
*/
|
|
430
448
|
CMARK_GFM_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);
|
|
@@ -776,6 +794,10 @@ char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmar
|
|
|
776
794
|
*/
|
|
777
795
|
#define CMARK_OPT_FRONT_MATTER (1 << 18)
|
|
778
796
|
|
|
797
|
+
/** Parse inline code language prefixes, e.g. ruby:`code`.
|
|
798
|
+
*/
|
|
799
|
+
#define CMARK_OPT_INLINE_CODE_INFO (1 << 19)
|
|
800
|
+
|
|
779
801
|
/**
|
|
780
802
|
* ## Version information
|
|
781
803
|
*/
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
# define CMARK_GFM_DEPRECATED_NO_EXPORT CMARK_GFM_NO_EXPORT CMARK_GFM_DEPRECATED
|
|
34
34
|
#endif
|
|
35
35
|
|
|
36
|
+
/* NOLINTNEXTLINE(readability-avoid-unconditional-preprocessor-if) */
|
|
36
37
|
#if 0 /* DEFINE_NO_DEPRECATED */
|
|
37
38
|
# ifndef CMARK_GFM_NO_DEPRECATED
|
|
38
39
|
# define CMARK_GFM_NO_DEPRECATED
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#ifndef CMARK_GFM_VERSION_H
|
|
2
2
|
#define CMARK_GFM_VERSION_H
|
|
3
3
|
|
|
4
|
-
#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) |
|
|
5
|
-
#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.
|
|
4
|
+
#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 13)
|
|
5
|
+
#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.13"
|
|
6
6
|
|
|
7
7
|
#endif
|
data/ext/markly/cmark_ctype.c
CHANGED
|
@@ -42,3 +42,12 @@ int cmark_isalnum(char c) {
|
|
|
42
42
|
int cmark_isdigit(char c) { return cmark_ctype_class[(uint8_t)c] == 3; }
|
|
43
43
|
|
|
44
44
|
int cmark_isalpha(char c) { return cmark_ctype_class[(uint8_t)c] == 4; }
|
|
45
|
+
|
|
46
|
+
int cmark_is_inline_code_info_start_char(char c) {
|
|
47
|
+
return cmark_isalnum(c);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
int cmark_is_inline_code_info_char(char c) {
|
|
51
|
+
return cmark_is_inline_code_info_start_char(c) || c == '_' || c == '-' ||
|
|
52
|
+
c == '+' || c == '#' || c == '.';
|
|
53
|
+
}
|
data/ext/markly/cmark_ctype.h
CHANGED
|
@@ -26,6 +26,11 @@ int cmark_isdigit(char c);
|
|
|
26
26
|
CMARK_GFM_EXPORT
|
|
27
27
|
int cmark_isalpha(char c);
|
|
28
28
|
|
|
29
|
+
/* Character classes for inline code info identifiers. */
|
|
30
|
+
int cmark_is_inline_code_info_start_char(char c);
|
|
31
|
+
|
|
32
|
+
int cmark_is_inline_code_info_char(char c);
|
|
33
|
+
|
|
29
34
|
#ifdef __cplusplus
|
|
30
35
|
}
|
|
31
36
|
#endif
|
data/ext/markly/commonmark.c
CHANGED
|
@@ -271,7 +271,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
|
271
271
|
if (!first_in_list_item) {
|
|
272
272
|
BLANKLINE();
|
|
273
273
|
}
|
|
274
|
-
info =
|
|
274
|
+
info = cmark_node_get_code_info(node);
|
|
275
275
|
info_len = strlen(info);
|
|
276
276
|
fencechar[0] = strchr(info, '`') == NULL ? '`' : '~';
|
|
277
277
|
code = cmark_node_get_literal(node);
|
|
@@ -363,6 +363,10 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
|
363
363
|
extra_spaces = code_len == 0 ||
|
|
364
364
|
code[0] == '`' || code[code_len - 1] == '`' ||
|
|
365
365
|
code[0] == ' ' || code[code_len - 1] == ' ';
|
|
366
|
+
if (node->as.code.info.len > 0) {
|
|
367
|
+
OUT(cmark_node_get_code_info(node), false, LITERAL);
|
|
368
|
+
LIT(":");
|
|
369
|
+
}
|
|
366
370
|
for (i = 0; i < numticks; i++) {
|
|
367
371
|
LIT("`");
|
|
368
372
|
}
|
|
@@ -494,10 +498,13 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
|
494
498
|
|
|
495
499
|
case CMARK_NODE_FRONT_MATTER:
|
|
496
500
|
if (entering) {
|
|
497
|
-
const char *
|
|
501
|
+
const char *front_matter_info = cmark_node_get_fence_info(node);
|
|
498
502
|
BLANKLINE();
|
|
499
503
|
LIT("---");
|
|
500
|
-
if (
|
|
504
|
+
if (front_matter_info && *front_matter_info) {
|
|
505
|
+
LIT(" ");
|
|
506
|
+
OUT(front_matter_info, false, LITERAL);
|
|
507
|
+
}
|
|
501
508
|
LIT("\n");
|
|
502
509
|
OUT(cmark_node_get_literal(node), false, LITERAL);
|
|
503
510
|
LIT("---\n");
|
data/ext/markly/config.h
CHANGED
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
extern "C" {
|
|
6
6
|
#endif
|
|
7
7
|
|
|
8
|
-
#ifndef HAVE_STDBOOL_H
|
|
9
8
|
#define HAVE_STDBOOL_H
|
|
10
|
-
#endif
|
|
11
9
|
|
|
12
10
|
#ifdef HAVE_STDBOOL_H
|
|
13
11
|
#include <stdbool.h>
|
|
@@ -71,8 +69,6 @@ CMARK_INLINE int c99_snprintf(char *outBuf, size_t size, const char *format, ...
|
|
|
71
69
|
|
|
72
70
|
#endif
|
|
73
71
|
|
|
74
|
-
#define CMARK_DEBUG_NODES 0
|
|
75
|
-
|
|
76
72
|
#ifdef __cplusplus
|
|
77
73
|
}
|
|
78
74
|
#endif
|
|
@@ -842,6 +842,29 @@ static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem, cmark_node
|
|
|
842
842
|
}
|
|
843
843
|
}
|
|
844
844
|
|
|
845
|
+
static void opaque_copy(cmark_syntax_extension *self, cmark_mem *mem,
|
|
846
|
+
cmark_node *node, cmark_node *source) {
|
|
847
|
+
if (node->type == CMARK_NODE_TABLE) {
|
|
848
|
+
node_table *table = (node_table *)node->as.opaque;
|
|
849
|
+
node_table *source_table = (node_table *)source->as.opaque;
|
|
850
|
+
|
|
851
|
+
table->n_columns = source_table->n_columns;
|
|
852
|
+
table->n_rows = source_table->n_rows;
|
|
853
|
+
table->n_nonempty_cells = source_table->n_nonempty_cells;
|
|
854
|
+
|
|
855
|
+
if (source_table->alignments) {
|
|
856
|
+
table->alignments = mem->calloc(source_table->n_columns, sizeof(uint8_t));
|
|
857
|
+
memcpy(table->alignments, source_table->alignments,
|
|
858
|
+
source_table->n_columns * sizeof(uint8_t));
|
|
859
|
+
}
|
|
860
|
+
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
|
861
|
+
*(node_table_row *)node->as.opaque = *(node_table_row *)source->as.opaque;
|
|
862
|
+
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
|
863
|
+
mem->free(node->as.opaque);
|
|
864
|
+
node->as.cell_index = source->as.cell_index;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
845
868
|
static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
|
|
846
869
|
return
|
|
847
870
|
node->type != CMARK_NODE_TABLE &&
|
|
@@ -867,6 +890,7 @@ cmark_syntax_extension *create_table_extension(void) {
|
|
|
867
890
|
cmark_syntax_extension_set_html_render_func(self, html_render);
|
|
868
891
|
cmark_syntax_extension_set_opaque_alloc_func(self, opaque_alloc);
|
|
869
892
|
cmark_syntax_extension_set_opaque_free_func(self, opaque_free);
|
|
893
|
+
cmark_syntax_extension_set_opaque_copy_func(self, opaque_copy);
|
|
870
894
|
cmark_syntax_extension_set_commonmark_escape_func(self, escape);
|
|
871
895
|
CMARK_NODE_TABLE = cmark_syntax_extension_add_node(0);
|
|
872
896
|
CMARK_NODE_TABLE_ROW = cmark_syntax_extension_add_node(0);
|
data/ext/markly/html.c
CHANGED
|
@@ -18,6 +18,34 @@ static void escape_html(cmark_strbuf *dest, const unsigned char *source,
|
|
|
18
18
|
houdini_escape_html0(dest, source, length, 0);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
static bufsize_t first_code_info_tag(cmark_chunk *info) {
|
|
22
|
+
bufsize_t first_tag = 0;
|
|
23
|
+
while (first_tag < info->len && !cmark_isspace(info->data[first_tag])) {
|
|
24
|
+
first_tag += 1;
|
|
25
|
+
}
|
|
26
|
+
return first_tag;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static void render_code_info_attrs(cmark_strbuf *html, cmark_chunk *info,
|
|
30
|
+
int options, bool pre_lang) {
|
|
31
|
+
bufsize_t first_tag = first_code_info_tag(info);
|
|
32
|
+
|
|
33
|
+
if (pre_lang) {
|
|
34
|
+
cmark_strbuf_puts(html, " lang=\"");
|
|
35
|
+
} else {
|
|
36
|
+
cmark_strbuf_puts(html, " class=\"language-");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
escape_html(html, info->data, first_tag);
|
|
40
|
+
|
|
41
|
+
if (first_tag < info->len && (options & CMARK_OPT_FULL_INFO_STRING)) {
|
|
42
|
+
cmark_strbuf_puts(html, "\" data-meta=\"");
|
|
43
|
+
escape_html(html, info->data + first_tag + 1, info->len - first_tag - 1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
cmark_strbuf_putc(html, '"');
|
|
47
|
+
}
|
|
48
|
+
|
|
21
49
|
static void filter_html_block(cmark_html_renderer *renderer, uint8_t *data, size_t len) {
|
|
22
50
|
cmark_strbuf *html = renderer->html;
|
|
23
51
|
cmark_llist *it;
|
|
@@ -125,7 +153,11 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
|
|
125
153
|
case CMARK_NODE_TEXT:
|
|
126
154
|
case CMARK_NODE_CODE:
|
|
127
155
|
case CMARK_NODE_HTML_INLINE:
|
|
128
|
-
|
|
156
|
+
if (node->type == CMARK_NODE_CODE) {
|
|
157
|
+
escape_html(html, node->as.code.literal.data, node->as.code.literal.len);
|
|
158
|
+
} else {
|
|
159
|
+
escape_html(html, node->as.literal.data, node->as.literal.len);
|
|
160
|
+
}
|
|
129
161
|
break;
|
|
130
162
|
|
|
131
163
|
case CMARK_NODE_LINEBREAK:
|
|
@@ -220,32 +252,17 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
|
|
220
252
|
cmark_html_render_sourcepos(node, html, options);
|
|
221
253
|
cmark_strbuf_puts(html, "><code>");
|
|
222
254
|
} else {
|
|
223
|
-
bufsize_t first_tag = 0;
|
|
224
|
-
while (first_tag < node->as.code.info.len &&
|
|
225
|
-
!cmark_isspace(node->as.code.info.data[first_tag])) {
|
|
226
|
-
first_tag += 1;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
255
|
if (options & CMARK_OPT_GITHUB_PRE_LANG) {
|
|
230
256
|
cmark_strbuf_puts(html, "<pre");
|
|
231
257
|
cmark_html_render_sourcepos(node, html, options);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) {
|
|
235
|
-
cmark_strbuf_puts(html, "\" data-meta=\"");
|
|
236
|
-
escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1);
|
|
237
|
-
}
|
|
238
|
-
cmark_strbuf_puts(html, "\"><code>");
|
|
258
|
+
render_code_info_attrs(html, &node->as.code.info, options, true);
|
|
259
|
+
cmark_strbuf_puts(html, "><code>");
|
|
239
260
|
} else {
|
|
240
261
|
cmark_strbuf_puts(html, "<pre");
|
|
241
262
|
cmark_html_render_sourcepos(node, html, options);
|
|
242
|
-
cmark_strbuf_puts(html, "><code
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
cmark_strbuf_puts(html, "\" data-meta=\"");
|
|
246
|
-
escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1);
|
|
247
|
-
}
|
|
248
|
-
cmark_strbuf_puts(html, "\">");
|
|
263
|
+
cmark_strbuf_puts(html, "><code");
|
|
264
|
+
render_code_info_attrs(html, &node->as.code.info, options, false);
|
|
265
|
+
cmark_strbuf_putc(html, '>');
|
|
249
266
|
}
|
|
250
267
|
}
|
|
251
268
|
|
|
@@ -286,7 +303,7 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
|
|
286
303
|
|
|
287
304
|
case CMARK_NODE_PARAGRAPH:
|
|
288
305
|
parent = cmark_node_parent(node);
|
|
289
|
-
grandparent = cmark_node_parent(parent);
|
|
306
|
+
grandparent = parent ? cmark_node_parent(parent) : NULL;
|
|
290
307
|
if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) {
|
|
291
308
|
tight = grandparent->as.list.tight;
|
|
292
309
|
} else {
|
|
@@ -299,7 +316,8 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
|
|
299
316
|
cmark_html_render_sourcepos(node, html, options);
|
|
300
317
|
cmark_strbuf_putc(html, '>');
|
|
301
318
|
} else {
|
|
302
|
-
if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION &&
|
|
319
|
+
if (parent && parent->type == CMARK_NODE_FOOTNOTE_DEFINITION &&
|
|
320
|
+
node->next == NULL) {
|
|
303
321
|
cmark_strbuf_putc(html, ' ');
|
|
304
322
|
S_put_footnote_backref(renderer, html, parent);
|
|
305
323
|
}
|
|
@@ -327,8 +345,12 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
|
|
327
345
|
break;
|
|
328
346
|
|
|
329
347
|
case CMARK_NODE_CODE:
|
|
330
|
-
cmark_strbuf_puts(html, "<code
|
|
331
|
-
|
|
348
|
+
cmark_strbuf_puts(html, "<code");
|
|
349
|
+
if (node->as.code.info.len > 0) {
|
|
350
|
+
render_code_info_attrs(html, &node->as.code.info, options, false);
|
|
351
|
+
}
|
|
352
|
+
cmark_strbuf_putc(html, '>');
|
|
353
|
+
escape_html(html, node->as.code.literal.data, node->as.code.literal.len);
|
|
332
354
|
cmark_strbuf_puts(html, "</code>");
|
|
333
355
|
break;
|
|
334
356
|
|
data/ext/markly/inlines.c
CHANGED
|
@@ -24,7 +24,6 @@ static const char *RIGHTSINGLEQUOTE = "\xE2\x80\x99";
|
|
|
24
24
|
|
|
25
25
|
// Macros for creating various kinds of simple.
|
|
26
26
|
#define make_str(subj, sc, ec, s) make_literal(subj, CMARK_NODE_TEXT, sc, ec, s)
|
|
27
|
-
#define make_code(subj, sc, ec, s) make_literal(subj, CMARK_NODE_CODE, sc, ec, s)
|
|
28
27
|
#define make_raw_html(subj, sc, ec, s) make_literal(subj, CMARK_NODE_HTML_INLINE, sc, ec, s)
|
|
29
28
|
#define make_linebreak(mem) make_simple(mem, CMARK_NODE_LINEBREAK)
|
|
30
29
|
#define make_softbreak(mem) make_simple(mem, CMARK_NODE_SOFTBREAK)
|
|
@@ -104,6 +103,18 @@ static CMARK_INLINE cmark_node *make_simple(cmark_mem *mem, cmark_node_type t) {
|
|
|
104
103
|
return e;
|
|
105
104
|
}
|
|
106
105
|
|
|
106
|
+
static CMARK_INLINE cmark_node *make_code(subject *subj, int start_column,
|
|
107
|
+
int end_column, cmark_chunk literal) {
|
|
108
|
+
cmark_node *e = (cmark_node *)subj->mem->calloc(1, sizeof(*e));
|
|
109
|
+
cmark_strbuf_init(subj->mem, &e->content, 0);
|
|
110
|
+
e->type = CMARK_NODE_CODE;
|
|
111
|
+
e->as.code.literal = literal;
|
|
112
|
+
e->start_line = e->end_line = subj->line;
|
|
113
|
+
e->start_column = start_column + 1 + subj->column_offset + subj->block_offset;
|
|
114
|
+
e->end_column = end_column + 1 + subj->column_offset + subj->block_offset;
|
|
115
|
+
return e;
|
|
116
|
+
}
|
|
117
|
+
|
|
107
118
|
// Like make_str, but parses entities.
|
|
108
119
|
static cmark_node *make_str_with_entities(subject *subj,
|
|
109
120
|
int start_column, int end_column,
|
|
@@ -385,6 +396,39 @@ static void S_normalize_code(cmark_strbuf *s) {
|
|
|
385
396
|
|
|
386
397
|
}
|
|
387
398
|
|
|
399
|
+
static bufsize_t scan_inline_code_info_prefix(subject *subj, bufsize_t start) {
|
|
400
|
+
if (start >= subj->input.len ||
|
|
401
|
+
!cmark_is_inline_code_info_start_char((char)subj->input.data[start]) ||
|
|
402
|
+
(start > 0 && cmark_is_inline_code_info_char(
|
|
403
|
+
(char)subj->input.data[start - 1]))) {
|
|
404
|
+
return 0;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
bufsize_t pos = start + 1;
|
|
408
|
+
while (pos < subj->input.len && cmark_is_inline_code_info_char(
|
|
409
|
+
(char)subj->input.data[pos])) {
|
|
410
|
+
pos++;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (pos + 1 < subj->input.len && subj->input.data[pos] == ':' &&
|
|
414
|
+
subj->input.data[pos + 1] == '`') {
|
|
415
|
+
return pos;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
static bufsize_t find_inline_code_info_prefix(subject *subj, bufsize_t start,
|
|
422
|
+
bufsize_t limit) {
|
|
423
|
+
while (start < limit) {
|
|
424
|
+
if (scan_inline_code_info_prefix(subj, start)) {
|
|
425
|
+
return start;
|
|
426
|
+
}
|
|
427
|
+
start++;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return 0;
|
|
431
|
+
}
|
|
388
432
|
|
|
389
433
|
// Parse backtick code section or raw backticks, return an inline.
|
|
390
434
|
// Assumes that the subject has a backtick at the current position.
|
|
@@ -403,12 +447,35 @@ static cmark_node *handle_backticks(subject *subj, int options) {
|
|
|
403
447
|
endpos - startpos - openticks.len);
|
|
404
448
|
S_normalize_code(&buf);
|
|
405
449
|
|
|
406
|
-
cmark_node *node = make_code(subj, startpos, endpos - openticks.len - 1,
|
|
407
|
-
|
|
450
|
+
cmark_node *node = make_code(subj, startpos, endpos - openticks.len - 1,
|
|
451
|
+
cmark_chunk_buf_detach(&buf));
|
|
452
|
+
adjust_subj_node_newlines(subj, node, endpos - startpos, openticks.len,
|
|
453
|
+
options);
|
|
408
454
|
return node;
|
|
409
455
|
}
|
|
410
456
|
}
|
|
411
457
|
|
|
458
|
+
static cmark_node *handle_inline_code_info(subject *subj, int options) {
|
|
459
|
+
bufsize_t startpos = subj->pos;
|
|
460
|
+
bufsize_t colonpos = scan_inline_code_info_prefix(subj, startpos);
|
|
461
|
+
if (colonpos == 0) {
|
|
462
|
+
return NULL;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
cmark_chunk info =
|
|
466
|
+
cmark_chunk_dup(&subj->input, startpos, colonpos - startpos);
|
|
467
|
+
subj->pos = colonpos + 1;
|
|
468
|
+
|
|
469
|
+
cmark_node *node = handle_backticks(subj, options);
|
|
470
|
+
if (node->type != CMARK_NODE_CODE) {
|
|
471
|
+
cmark_node_free(node);
|
|
472
|
+
subj->pos = startpos;
|
|
473
|
+
return NULL;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
node->as.code.info = chunk_clone(subj->mem, &info);
|
|
477
|
+
return node;
|
|
478
|
+
}
|
|
412
479
|
|
|
413
480
|
// Scan ***, **, or * and return number scanned, or 0.
|
|
414
481
|
// Advances position.
|
|
@@ -1458,6 +1525,14 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
|
|
|
1458
1525
|
if (c == 0) {
|
|
1459
1526
|
return 0;
|
|
1460
1527
|
}
|
|
1528
|
+
if (options & CMARK_OPT_INLINE_CODE_INFO) {
|
|
1529
|
+
new_inl = handle_inline_code_info(subj, options);
|
|
1530
|
+
}
|
|
1531
|
+
if (new_inl != NULL) {
|
|
1532
|
+
append_child(parent, new_inl);
|
|
1533
|
+
return 1;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1461
1536
|
switch (c) {
|
|
1462
1537
|
case '\r':
|
|
1463
1538
|
case '\n':
|
|
@@ -1511,6 +1586,13 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
|
|
|
1511
1586
|
break;
|
|
1512
1587
|
|
|
1513
1588
|
endpos = subject_find_special_char(subj, options);
|
|
1589
|
+
if (options & CMARK_OPT_INLINE_CODE_INFO) {
|
|
1590
|
+
bufsize_t info_start =
|
|
1591
|
+
find_inline_code_info_prefix(subj, subj->pos + 1, endpos);
|
|
1592
|
+
if (info_start > 0 && info_start < endpos) {
|
|
1593
|
+
endpos = info_start;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1514
1596
|
contents = cmark_chunk_dup(&subj->input, subj->pos, endpos - subj->pos);
|
|
1515
1597
|
startpos = subj->pos;
|
|
1516
1598
|
subj->pos = endpos;
|
data/ext/markly/iterator.c
CHANGED
|
@@ -139,10 +139,15 @@ void cmark_node_own(cmark_node *root) {
|
|
|
139
139
|
switch (cur->type) {
|
|
140
140
|
case CMARK_NODE_TEXT:
|
|
141
141
|
case CMARK_NODE_HTML_INLINE:
|
|
142
|
-
case CMARK_NODE_CODE:
|
|
143
142
|
case CMARK_NODE_HTML_BLOCK:
|
|
144
143
|
cmark_chunk_to_cstr(iter->mem, &cur->as.literal);
|
|
145
144
|
break;
|
|
145
|
+
case CMARK_NODE_CODE:
|
|
146
|
+
cmark_chunk_to_cstr(iter->mem, &cur->as.code.literal);
|
|
147
|
+
if (cur->as.code.info.len > 0) {
|
|
148
|
+
cmark_chunk_to_cstr(iter->mem, &cur->as.code.info);
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
146
151
|
case CMARK_NODE_LINK:
|
|
147
152
|
cmark_chunk_to_cstr(iter->mem, &cur->as.link.url);
|
|
148
153
|
cmark_chunk_to_cstr(iter->mem, &cur->as.link.title);
|