qiita_marker 0.23.2.0 → 0.23.2.1
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
- data/LICENSE.txt +1 -1
- data/README.md +27 -1
- data/ext/qiita_marker/core-extensions.c +2 -0
- data/ext/qiita_marker/html.c +13 -0
- data/ext/qiita_marker/inlines.c +17 -5
- data/ext/qiita_marker/qfm.h +19 -0
- data/ext/qiita_marker/qfm_custom_block.c +278 -0
- data/ext/qiita_marker/qfm_custom_block.h +10 -0
- data/ext/qiita_marker/qfm_mention_no_emphasis.c +37 -0
- data/ext/qiita_marker/qfm_mention_no_emphasis.h +8 -0
- data/ext/qiita_marker/qfm_scanners.c +291 -0
- data/ext/qiita_marker/qfm_scanners.h +20 -0
- data/ext/qiita_marker/qfm_scanners.re +50 -0
- data/lib/qiita_marker/config.rb +5 -2
- data/lib/qiita_marker/renderer/html_renderer.rb +4 -0
- data/lib/qiita_marker/version.rb +1 -1
- data/qiita_marker.gemspec +1 -1
- data/test/test_qfm_code_data_metadata.rb +26 -0
- data/test/test_qfm_custom_block.rb +23 -0
- data/test/test_qfm_mention_no_emphasis.rb +60 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0579157ad4abb4038246ef4dc4752fd1de6cd281daa619b2ef42adec5b147982'
|
4
|
+
data.tar.gz: c671815ff61ab460fcf6c3a42a614018a250c62ceaa41ee0aa3e899f34c12b16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32f16ce193b82d6a7214c851fdd81126d42d872fdd4508b798ccfc4faba4668793274f88f9ef25e61ae57545041d1062c65169b05cd756eec55df0aa042d0140
|
7
|
+
data.tar.gz: da050452749a3eee8d998db24aa45d6a8b1a282672283e427f8deca374405bfaebe572e954c7906ceb84bea2ff08ad737da05707b2ed5d378158d2738ac0e318
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Qiita Marker
|
2
2
|
|
3
|
-
[](https://github.com/increments/qiita-marker/actions/workflows/test.yml)
|
3
|
+
[](https://github.com/increments/qiita-marker/actions/workflows/test.yml) [](https://badge.fury.io/rb/qiita_marker)
|
4
4
|
|
5
5
|
:warning: This library is still in the testing phase. As such, development may be halted.
|
6
6
|
|
@@ -11,6 +11,27 @@ It will be a core module of [Qiita Markdown](https://github.com/increments/qiita
|
|
11
11
|
|
12
12
|
Please see [CommonMarker's Usage](https://github.com/gjtorikian/commonmarker#usage).
|
13
13
|
|
14
|
+
In addition to CommonMarker's options and extensions, the following are available in Qiita Marker.
|
15
|
+
|
16
|
+
### Original options
|
17
|
+
|
18
|
+
#### Parse options
|
19
|
+
|
20
|
+
| Name | Description |
|
21
|
+
| --- | --- |
|
22
|
+
| `:MENTION_NO_EMPHASIS` | Prevent parsing mentions as emphasis. |
|
23
|
+
|
24
|
+
#### Render options
|
25
|
+
|
26
|
+
| Name | Description |
|
27
|
+
| --- | --- |
|
28
|
+
| `:CODE_DATA_METADATA` | Use `<code data-metadata>` for fenced code blocks. |
|
29
|
+
| `:MENTION_NO_EMPHASIS` | Prevent parsing mentions as emphasis. |
|
30
|
+
|
31
|
+
### Original extensions
|
32
|
+
|
33
|
+
- `:custom_block` - This provides support for customizable blocks.
|
34
|
+
|
14
35
|
## Contributing
|
15
36
|
|
16
37
|
If you have suggestion or modification to this repository, please create an Issue or Pull Request.
|
@@ -45,6 +66,11 @@ $ docker compose run --rm app ./script/bootstrap
|
|
45
66
|
$ docker compose run --rm rake test
|
46
67
|
```
|
47
68
|
|
69
|
+
### Versioning policy
|
70
|
+
|
71
|
+
Qiita Marker follows CommonMarker's updates by merging the upstream changes.
|
72
|
+
The version format is `MAJOR.MINOR.PATCH.FORK`. `MAJOR.MINOR.PATCH` is the same as the version of CommonMarker that Qiita Marker is based on. `FORK` is incremented on each release of Qiita Marker itself and reset to zero when any of `MAJOR.MINOR.PATCH` is bumped.
|
73
|
+
|
48
74
|
## License
|
49
75
|
|
50
76
|
Please see [LICENSE.txt](/LICENSE.txt).
|
@@ -6,6 +6,7 @@
|
|
6
6
|
#include "tasklist.h"
|
7
7
|
#include "registry.h"
|
8
8
|
#include "plugin.h"
|
9
|
+
#include "qfm_custom_block.h"
|
9
10
|
|
10
11
|
static int core_extensions_registration(cmark_plugin *plugin) {
|
11
12
|
cmark_plugin_register_syntax_extension(plugin, create_table_extension());
|
@@ -14,6 +15,7 @@ static int core_extensions_registration(cmark_plugin *plugin) {
|
|
14
15
|
cmark_plugin_register_syntax_extension(plugin, create_autolink_extension());
|
15
16
|
cmark_plugin_register_syntax_extension(plugin, create_tagfilter_extension());
|
16
17
|
cmark_plugin_register_syntax_extension(plugin, create_tasklist_extension());
|
18
|
+
cmark_plugin_register_syntax_extension(plugin, create_qfm_custom_block_extension());
|
17
19
|
return 1;
|
18
20
|
}
|
19
21
|
|
data/ext/qiita_marker/html.c
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
#include "syntax_extension.h"
|
11
11
|
#include "html.h"
|
12
12
|
#include "render.h"
|
13
|
+
#include "qfm.h"
|
13
14
|
|
14
15
|
// Functions to convert cmark_nodes to HTML strings.
|
15
16
|
|
@@ -222,6 +223,18 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
|
222
223
|
escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1);
|
223
224
|
}
|
224
225
|
cmark_strbuf_puts(html, "\"><code>");
|
226
|
+
} else if (options & CMARK_OPT_CODE_DATA_METADATA) {
|
227
|
+
cmark_strbuf_puts(html, "<pre");
|
228
|
+
cmark_html_render_sourcepos(node, html, options);
|
229
|
+
cmark_strbuf_puts(html, "><code data-metadata=\"");
|
230
|
+
escape_html(html, node->as.code.info.data, first_tag);
|
231
|
+
if (first_tag < node->as.code.info.len &&
|
232
|
+
(options & CMARK_OPT_FULL_INFO_STRING)) {
|
233
|
+
cmark_strbuf_puts(html, "\" data-meta=\"");
|
234
|
+
escape_html(html, node->as.code.info.data + first_tag + 1,
|
235
|
+
node->as.code.info.len - first_tag - 1);
|
236
|
+
}
|
237
|
+
cmark_strbuf_puts(html, "\">");
|
225
238
|
} else {
|
226
239
|
cmark_strbuf_puts(html, "<pre");
|
227
240
|
cmark_html_render_sourcepos(node, html, options);
|
data/ext/qiita_marker/inlines.c
CHANGED
@@ -13,6 +13,8 @@
|
|
13
13
|
#include "scanners.h"
|
14
14
|
#include "inlines.h"
|
15
15
|
#include "syntax_extension.h"
|
16
|
+
#include "qfm.h"
|
17
|
+
#include "qfm_mention_no_emphasis.h"
|
16
18
|
|
17
19
|
static const char *EMDASH = "\xE2\x80\x94";
|
18
20
|
static const char *ENDASH = "\xE2\x80\x93";
|
@@ -381,11 +383,10 @@ static cmark_node *handle_backticks(subject *subj, int options) {
|
|
381
383
|
}
|
382
384
|
}
|
383
385
|
|
384
|
-
|
385
386
|
// Scan ***, **, or * and return number scanned, or 0.
|
386
387
|
// Advances position.
|
387
388
|
static int scan_delims(subject *subj, unsigned char c, bool *can_open,
|
388
|
-
bool *can_close) {
|
389
|
+
bool *can_close, bool mention_no_emphasis) {
|
389
390
|
int numdelims = 0;
|
390
391
|
bufsize_t before_char_pos, after_char_pos;
|
391
392
|
int32_t after_char = 0;
|
@@ -393,6 +394,15 @@ static int scan_delims(subject *subj, unsigned char c, bool *can_open,
|
|
393
394
|
int len;
|
394
395
|
bool left_flanking, right_flanking;
|
395
396
|
|
397
|
+
if (mention_no_emphasis &&
|
398
|
+
is_part_of_mention(subj->input.data + subj->pos, subj->pos)) {
|
399
|
+
numdelims++;
|
400
|
+
advance(subj);
|
401
|
+
*can_open = false;
|
402
|
+
*can_close = false;
|
403
|
+
return numdelims;
|
404
|
+
}
|
405
|
+
|
396
406
|
if (subj->pos == 0) {
|
397
407
|
before_char = 10;
|
398
408
|
} else {
|
@@ -528,13 +538,14 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
|
|
528
538
|
}
|
529
539
|
|
530
540
|
// Assumes the subject has a c at the current position.
|
531
|
-
static cmark_node *handle_delim(subject *subj, unsigned char c, bool smart
|
541
|
+
static cmark_node *handle_delim(subject *subj, unsigned char c, bool smart,
|
542
|
+
bool mention_no_emphasis) {
|
532
543
|
bufsize_t numdelims;
|
533
544
|
cmark_node *inl_text;
|
534
545
|
bool can_open, can_close;
|
535
546
|
cmark_chunk contents;
|
536
547
|
|
537
|
-
numdelims = scan_delims(subj, c, &can_open, &can_close);
|
548
|
+
numdelims = scan_delims(subj, c, &can_open, &can_close, mention_no_emphasis);
|
538
549
|
|
539
550
|
if (c == '\'' && smart) {
|
540
551
|
contents = cmark_chunk_literal(RIGHTSINGLEQUOTE);
|
@@ -1387,7 +1398,8 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
|
|
1387
1398
|
case '_':
|
1388
1399
|
case '\'':
|
1389
1400
|
case '"':
|
1390
|
-
new_inl = handle_delim(subj, c, (options & CMARK_OPT_SMART) != 0
|
1401
|
+
new_inl = handle_delim(subj, c, (options & CMARK_OPT_SMART) != 0,
|
1402
|
+
(options & CMARK_OPT_MENTION_NO_EMPHASIS) != 0);
|
1391
1403
|
break;
|
1392
1404
|
case '-':
|
1393
1405
|
new_inl = handle_hyphen(subj, (options & CMARK_OPT_SMART) != 0);
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#ifndef QFM_H
|
2
|
+
#define QFM_H
|
3
|
+
|
4
|
+
#ifdef __cplusplus
|
5
|
+
extern "C" {
|
6
|
+
#endif
|
7
|
+
|
8
|
+
/** Use <pre><code data-metadata="x"> tags for code blocks instead of <pre><code
|
9
|
+
* class="language-x">. **/
|
10
|
+
#define CMARK_OPT_CODE_DATA_METADATA (1 << 25)
|
11
|
+
|
12
|
+
/* Prevent parsing Qiita-style Mentions as emphasis. */
|
13
|
+
#define CMARK_OPT_MENTION_NO_EMPHASIS (1 << 26)
|
14
|
+
|
15
|
+
#ifdef __cplusplus
|
16
|
+
}
|
17
|
+
#endif
|
18
|
+
|
19
|
+
#endif
|
@@ -0,0 +1,278 @@
|
|
1
|
+
#include <html.h>
|
2
|
+
#include <parser.h>
|
3
|
+
#include <render.h>
|
4
|
+
|
5
|
+
#include "cmark-gfm-core-extensions.h"
|
6
|
+
#include "houdini.h"
|
7
|
+
#include "qfm_custom_block.h"
|
8
|
+
#include "qfm_scanners.h"
|
9
|
+
#include "strikethrough.h"
|
10
|
+
|
11
|
+
cmark_node_type CMARK_NODE_QFM_CUSTOM_BLOCK;
|
12
|
+
|
13
|
+
typedef struct {
|
14
|
+
cmark_chunk info;
|
15
|
+
bool opening;
|
16
|
+
cmark_strbuf *xml_attr_buff;
|
17
|
+
} node_qfm_custom_block;
|
18
|
+
|
19
|
+
static void escape_html(cmark_strbuf *dest, const unsigned char *source,
|
20
|
+
bufsize_t length) {
|
21
|
+
houdini_escape_html0(dest, source, length, 0);
|
22
|
+
}
|
23
|
+
|
24
|
+
static bool get_qfm_custom_block_opening(cmark_node *node) {
|
25
|
+
if (node == NULL) {
|
26
|
+
return false;
|
27
|
+
}
|
28
|
+
|
29
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
30
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
31
|
+
return ((node_qfm_custom_block *)node->as.opaque)->opening;
|
32
|
+
} else {
|
33
|
+
return false;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
static bool set_qfm_custom_block_opening(cmark_node *node, bool opening) {
|
38
|
+
if (node == NULL) {
|
39
|
+
return false;
|
40
|
+
}
|
41
|
+
|
42
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
43
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
44
|
+
((node_qfm_custom_block *)node->as.opaque)->opening = opening;
|
45
|
+
return true;
|
46
|
+
} else {
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
static cmark_chunk *get_qfm_custom_block_info(cmark_node *node) {
|
52
|
+
if (node == NULL) {
|
53
|
+
return NULL;
|
54
|
+
}
|
55
|
+
|
56
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
57
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
58
|
+
return &((node_qfm_custom_block *)node->as.opaque)->info;
|
59
|
+
} else {
|
60
|
+
return NULL;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
static bool set_qfm_custom_block_info(cmark_node *node, const char *info) {
|
65
|
+
if (node == NULL) {
|
66
|
+
return false;
|
67
|
+
}
|
68
|
+
|
69
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
70
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
71
|
+
cmark_chunk_set_cstr(cmark_node_mem(node),
|
72
|
+
&((node_qfm_custom_block *)node->as.opaque)->info,
|
73
|
+
info);
|
74
|
+
return true;
|
75
|
+
} else {
|
76
|
+
return false;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
static void free_node_qfm_custom_block(cmark_mem *mem, void *ptr) {
|
81
|
+
node_qfm_custom_block *cb = (node_qfm_custom_block *)ptr;
|
82
|
+
|
83
|
+
cmark_chunk_free(mem, &cb->info);
|
84
|
+
cmark_strbuf_free(cb->xml_attr_buff);
|
85
|
+
mem->free(cb);
|
86
|
+
}
|
87
|
+
|
88
|
+
static int matches(cmark_syntax_extension *self, cmark_parser *parser,
|
89
|
+
unsigned char *input, int len,
|
90
|
+
cmark_node *parent_container) {
|
91
|
+
int res = 0;
|
92
|
+
|
93
|
+
if (get_qfm_custom_block_opening(parent_container)) {
|
94
|
+
bufsize_t matched = scan_close_qfm_custom_block_fence(
|
95
|
+
input, len, cmark_parser_get_first_nonspace(parser));
|
96
|
+
|
97
|
+
if (matched > 0) {
|
98
|
+
set_qfm_custom_block_opening(parent_container, false);
|
99
|
+
cmark_parser_advance_offset(parser, (char *)input,
|
100
|
+
len - cmark_parser_get_offset(parser), 0);
|
101
|
+
} else {
|
102
|
+
res = 1;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
return res;
|
107
|
+
}
|
108
|
+
|
109
|
+
static cmark_node *try_opening_qfm_custom_block_block(
|
110
|
+
cmark_syntax_extension *self, int indented, cmark_parser *parser,
|
111
|
+
cmark_node *parent_container, unsigned char *input, int len) {
|
112
|
+
cmark_node_type parent_type = cmark_node_get_type(parent_container);
|
113
|
+
|
114
|
+
if (!indented && parent_type != CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
115
|
+
bufsize_t matched = scan_open_qfm_custom_block_fence(
|
116
|
+
input, len, cmark_parser_get_first_nonspace(parser));
|
117
|
+
if (!matched) {
|
118
|
+
return NULL;
|
119
|
+
}
|
120
|
+
|
121
|
+
cmark_node *custom_block_node = cmark_parser_add_child(
|
122
|
+
parser, parent_container, CMARK_NODE_QFM_CUSTOM_BLOCK,
|
123
|
+
parser->first_nonspace_column);
|
124
|
+
custom_block_node->as.opaque = (node_qfm_custom_block *)parser->mem->calloc(
|
125
|
+
1, sizeof(node_qfm_custom_block));
|
126
|
+
|
127
|
+
cmark_strbuf *info = parser->mem->calloc(1, sizeof(cmark_strbuf));
|
128
|
+
cmark_strbuf_init(parser->mem, info, len - matched);
|
129
|
+
cmark_strbuf_put(info, input + matched, len - matched);
|
130
|
+
cmark_strbuf_trim(info);
|
131
|
+
|
132
|
+
set_qfm_custom_block_opening(custom_block_node, true);
|
133
|
+
set_qfm_custom_block_info(custom_block_node, (char *)info->ptr);
|
134
|
+
|
135
|
+
cmark_node_set_syntax_extension(custom_block_node, self);
|
136
|
+
cmark_parser_advance_offset(parser, (char *)input,
|
137
|
+
len - cmark_parser_get_offset(parser), 0);
|
138
|
+
|
139
|
+
return custom_block_node;
|
140
|
+
}
|
141
|
+
|
142
|
+
return NULL;
|
143
|
+
}
|
144
|
+
|
145
|
+
static const char *get_type_string(cmark_syntax_extension *self,
|
146
|
+
cmark_node *node) {
|
147
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
148
|
+
|
149
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
150
|
+
return "qfm_custom_block";
|
151
|
+
}
|
152
|
+
|
153
|
+
return "<unknown>";
|
154
|
+
}
|
155
|
+
|
156
|
+
static int can_contain(cmark_syntax_extension *self, cmark_node *node,
|
157
|
+
cmark_node_type child_type) {
|
158
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
159
|
+
|
160
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
161
|
+
return
|
162
|
+
// Block
|
163
|
+
child_type == CMARK_NODE_LIST || child_type == CMARK_NODE_PARAGRAPH ||
|
164
|
+
// Inline
|
165
|
+
child_type == CMARK_NODE_TEXT || child_type == CMARK_NODE_CODE ||
|
166
|
+
child_type == CMARK_NODE_HTML_INLINE || child_type == CMARK_NODE_EMPH ||
|
167
|
+
child_type == CMARK_NODE_STRONG || child_type == CMARK_NODE_LINK ||
|
168
|
+
child_type == CMARK_NODE_IMAGE ||
|
169
|
+
child_type == CMARK_NODE_FOOTNOTE_REFERENCE ||
|
170
|
+
child_type == CMARK_NODE_STRIKETHROUGH;
|
171
|
+
}
|
172
|
+
|
173
|
+
return 0;
|
174
|
+
}
|
175
|
+
|
176
|
+
static int contains_inlines(cmark_syntax_extension *self, cmark_node *node) {
|
177
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
178
|
+
|
179
|
+
return node_type == CMARK_NODE_QFM_CUSTOM_BLOCK;
|
180
|
+
}
|
181
|
+
|
182
|
+
static void plaintext_render(cmark_syntax_extension *self,
|
183
|
+
cmark_renderer *renderer, cmark_node *node,
|
184
|
+
cmark_event_type ev_type, int options) {
|
185
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
186
|
+
|
187
|
+
if (node_type != CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
188
|
+
assert(false);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
static void html_render(cmark_syntax_extension *self,
|
193
|
+
cmark_html_renderer *renderer, cmark_node *node,
|
194
|
+
cmark_event_type ev_type, int options) {
|
195
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
196
|
+
|
197
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
198
|
+
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
199
|
+
cmark_strbuf *html = renderer->html;
|
200
|
+
|
201
|
+
if (entering) {
|
202
|
+
cmark_html_render_cr(html);
|
203
|
+
cmark_strbuf_puts(html,
|
204
|
+
"<div data-type=\"customblock\" data-metadata=\"");
|
205
|
+
cmark_chunk *info = get_qfm_custom_block_info(node);
|
206
|
+
escape_html(html, info->data, info->len);
|
207
|
+
cmark_strbuf_putc(html, '"');
|
208
|
+
cmark_html_render_sourcepos(node, html, options);
|
209
|
+
cmark_strbuf_putc(html, '>');
|
210
|
+
} else {
|
211
|
+
cmark_html_render_cr(html);
|
212
|
+
cmark_strbuf_puts(html, "</div>");
|
213
|
+
cmark_html_render_cr(html);
|
214
|
+
}
|
215
|
+
} else {
|
216
|
+
assert(false);
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
static const char *xml_attr(cmark_syntax_extension *self, cmark_node *node) {
|
221
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
222
|
+
|
223
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
224
|
+
cmark_chunk *info = get_qfm_custom_block_info(node);
|
225
|
+
cmark_mem *mem = node->content.mem;
|
226
|
+
|
227
|
+
cmark_strbuf *xml_attr_buff = mem->calloc(1, sizeof(cmark_strbuf));
|
228
|
+
((node_qfm_custom_block *)node->as.opaque)->xml_attr_buff = xml_attr_buff;
|
229
|
+
cmark_strbuf_init(
|
230
|
+
mem, xml_attr_buff,
|
231
|
+
17 + info->len); // `17` is length of ` data-metadata="` and `"`.
|
232
|
+
cmark_strbuf_puts(xml_attr_buff, " data-metadata=\"");
|
233
|
+
cmark_strbuf_puts(xml_attr_buff, (char *)info->data);
|
234
|
+
cmark_strbuf_putc(xml_attr_buff, '"');
|
235
|
+
|
236
|
+
return (char *)xml_attr_buff->ptr;
|
237
|
+
}
|
238
|
+
|
239
|
+
return NULL;
|
240
|
+
}
|
241
|
+
|
242
|
+
static void opaque_alloc(cmark_syntax_extension *self, cmark_mem *mem,
|
243
|
+
cmark_node *node) {
|
244
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
245
|
+
|
246
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
247
|
+
node->as.opaque = mem->calloc(1, sizeof(node_qfm_custom_block));
|
248
|
+
}
|
249
|
+
}
|
250
|
+
|
251
|
+
static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem,
|
252
|
+
cmark_node *node) {
|
253
|
+
cmark_node_type node_type = cmark_node_get_type(node);
|
254
|
+
|
255
|
+
if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
|
256
|
+
free_node_qfm_custom_block(mem, node->as.opaque);
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
cmark_syntax_extension *create_qfm_custom_block_extension(void) {
|
261
|
+
cmark_syntax_extension *self = cmark_syntax_extension_new("custom_block");
|
262
|
+
|
263
|
+
cmark_syntax_extension_set_match_block_func(self, matches);
|
264
|
+
cmark_syntax_extension_set_open_block_func(
|
265
|
+
self, try_opening_qfm_custom_block_block);
|
266
|
+
cmark_syntax_extension_set_get_type_string_func(self, get_type_string);
|
267
|
+
cmark_syntax_extension_set_can_contain_func(self, can_contain);
|
268
|
+
cmark_syntax_extension_set_contains_inlines_func(self, contains_inlines);
|
269
|
+
cmark_syntax_extension_set_commonmark_render_func(self, plaintext_render);
|
270
|
+
cmark_syntax_extension_set_plaintext_render_func(self, plaintext_render);
|
271
|
+
cmark_syntax_extension_set_xml_attr_func(self, xml_attr);
|
272
|
+
cmark_syntax_extension_set_html_render_func(self, html_render);
|
273
|
+
cmark_syntax_extension_set_opaque_alloc_func(self, opaque_alloc);
|
274
|
+
cmark_syntax_extension_set_opaque_free_func(self, opaque_free);
|
275
|
+
CMARK_NODE_QFM_CUSTOM_BLOCK = cmark_syntax_extension_add_node(0);
|
276
|
+
|
277
|
+
return self;
|
278
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#include "cmark_ctype.h"
|
2
|
+
#include "cmark-gfm.h"
|
3
|
+
#include "config.h"
|
4
|
+
|
5
|
+
static bool is_wordchar(char c) {
|
6
|
+
return cmark_isalnum(c) || c == '_' || c == '-';
|
7
|
+
}
|
8
|
+
|
9
|
+
bool is_part_of_mention(unsigned char *data, bufsize_t offset) {
|
10
|
+
int i;
|
11
|
+
int lookbehind_limit = (int)-offset;
|
12
|
+
char character;
|
13
|
+
|
14
|
+
for (i = 0; i >= lookbehind_limit; i--) {
|
15
|
+
character = data[i];
|
16
|
+
|
17
|
+
if (is_wordchar(character)) {
|
18
|
+
// Continue lookbehind.
|
19
|
+
} else if (character == '@') {
|
20
|
+
if (i == offset) {
|
21
|
+
// The "@" is at beginning of the text. (e.g. "@foo")
|
22
|
+
return true;
|
23
|
+
} else {
|
24
|
+
// Check if the previous character of the "@" is alphanumeric or not.
|
25
|
+
// " @foo" and "あ@foo" are mentions.
|
26
|
+
// "a@foo" is not a mention.
|
27
|
+
char prev_character = data[i - 1];
|
28
|
+
return !cmark_isalnum(prev_character);
|
29
|
+
}
|
30
|
+
} else {
|
31
|
+
// Found non-mention character, so this is not a mention.
|
32
|
+
return false;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
return false;
|
37
|
+
}
|
@@ -0,0 +1,291 @@
|
|
1
|
+
/* Generated by re2c 1.3 */
|
2
|
+
|
3
|
+
#include "qfm_scanners.h"
|
4
|
+
#include <stdlib.h>
|
5
|
+
|
6
|
+
bufsize_t _qfm_scan_at(bufsize_t (*scanner)(const unsigned char *),
|
7
|
+
unsigned char *ptr, int len, bufsize_t offset) {
|
8
|
+
bufsize_t res;
|
9
|
+
|
10
|
+
if (ptr == NULL || offset >= len) {
|
11
|
+
return 0;
|
12
|
+
} else {
|
13
|
+
unsigned char lim = ptr[len];
|
14
|
+
|
15
|
+
ptr[len] = '\0';
|
16
|
+
res = scanner(ptr + offset);
|
17
|
+
ptr[len] = lim;
|
18
|
+
}
|
19
|
+
|
20
|
+
return res;
|
21
|
+
}
|
22
|
+
|
23
|
+
// Scan an opening qfm_custom_block fence.
|
24
|
+
bufsize_t _scan_open_qfm_custom_block_fence(const unsigned char *p) {
|
25
|
+
const unsigned char *marker = NULL;
|
26
|
+
const unsigned char *start = p;
|
27
|
+
|
28
|
+
{
|
29
|
+
unsigned char yych;
|
30
|
+
static const unsigned char yybm[] = {
|
31
|
+
0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 128, 128, 0,
|
32
|
+
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
33
|
+
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
34
|
+
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
35
|
+
128, 128, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
36
|
+
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
37
|
+
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
38
|
+
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
39
|
+
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
40
|
+
128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
41
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
42
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
43
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
44
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
45
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
46
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
47
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
48
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
49
|
+
0, 0, 0, 0,
|
50
|
+
};
|
51
|
+
yych = *p;
|
52
|
+
if (yych == ':')
|
53
|
+
goto yy4;
|
54
|
+
++p;
|
55
|
+
yy3 : { return 0; }
|
56
|
+
yy4:
|
57
|
+
yych = *(marker = ++p);
|
58
|
+
if (yych != ':')
|
59
|
+
goto yy3;
|
60
|
+
yych = *++p;
|
61
|
+
if (yybm[0 + yych] & 64) {
|
62
|
+
goto yy7;
|
63
|
+
}
|
64
|
+
yy6:
|
65
|
+
p = marker;
|
66
|
+
goto yy3;
|
67
|
+
yy7:
|
68
|
+
yych = *++p;
|
69
|
+
if (yybm[0 + yych] & 64) {
|
70
|
+
goto yy7;
|
71
|
+
}
|
72
|
+
if (yych <= 0xDF) {
|
73
|
+
if (yych <= '\f') {
|
74
|
+
if (yych <= 0x00)
|
75
|
+
goto yy6;
|
76
|
+
if (yych == '\n') {
|
77
|
+
marker = p;
|
78
|
+
goto yy11;
|
79
|
+
}
|
80
|
+
marker = p;
|
81
|
+
} else {
|
82
|
+
if (yych <= '\r') {
|
83
|
+
marker = p;
|
84
|
+
goto yy11;
|
85
|
+
}
|
86
|
+
if (yych <= 0x7F) {
|
87
|
+
marker = p;
|
88
|
+
goto yy9;
|
89
|
+
}
|
90
|
+
if (yych <= 0xC1)
|
91
|
+
goto yy6;
|
92
|
+
marker = p;
|
93
|
+
goto yy13;
|
94
|
+
}
|
95
|
+
} else {
|
96
|
+
if (yych <= 0xEF) {
|
97
|
+
if (yych <= 0xE0) {
|
98
|
+
marker = p;
|
99
|
+
goto yy14;
|
100
|
+
}
|
101
|
+
if (yych == 0xED) {
|
102
|
+
marker = p;
|
103
|
+
goto yy16;
|
104
|
+
}
|
105
|
+
marker = p;
|
106
|
+
goto yy15;
|
107
|
+
} else {
|
108
|
+
if (yych <= 0xF0) {
|
109
|
+
marker = p;
|
110
|
+
goto yy17;
|
111
|
+
}
|
112
|
+
if (yych <= 0xF3) {
|
113
|
+
marker = p;
|
114
|
+
goto yy18;
|
115
|
+
}
|
116
|
+
if (yych <= 0xF4) {
|
117
|
+
marker = p;
|
118
|
+
goto yy19;
|
119
|
+
}
|
120
|
+
goto yy6;
|
121
|
+
}
|
122
|
+
}
|
123
|
+
yy9:
|
124
|
+
yych = *++p;
|
125
|
+
if (yybm[0 + yych] & 128) {
|
126
|
+
goto yy9;
|
127
|
+
}
|
128
|
+
if (yych <= 0xEC) {
|
129
|
+
if (yych <= 0xC1) {
|
130
|
+
if (yych <= 0x00)
|
131
|
+
goto yy6;
|
132
|
+
if (yych >= 0x0E)
|
133
|
+
goto yy6;
|
134
|
+
} else {
|
135
|
+
if (yych <= 0xDF)
|
136
|
+
goto yy13;
|
137
|
+
if (yych <= 0xE0)
|
138
|
+
goto yy14;
|
139
|
+
goto yy15;
|
140
|
+
}
|
141
|
+
} else {
|
142
|
+
if (yych <= 0xF0) {
|
143
|
+
if (yych <= 0xED)
|
144
|
+
goto yy16;
|
145
|
+
if (yych <= 0xEF)
|
146
|
+
goto yy15;
|
147
|
+
goto yy17;
|
148
|
+
} else {
|
149
|
+
if (yych <= 0xF3)
|
150
|
+
goto yy18;
|
151
|
+
if (yych <= 0xF4)
|
152
|
+
goto yy19;
|
153
|
+
goto yy6;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
yy11:
|
157
|
+
++p;
|
158
|
+
p = marker;
|
159
|
+
{ return (bufsize_t)(p - start); }
|
160
|
+
yy13:
|
161
|
+
yych = *++p;
|
162
|
+
if (yych <= 0x7F)
|
163
|
+
goto yy6;
|
164
|
+
if (yych <= 0xBF)
|
165
|
+
goto yy9;
|
166
|
+
goto yy6;
|
167
|
+
yy14:
|
168
|
+
yych = *++p;
|
169
|
+
if (yych <= 0x9F)
|
170
|
+
goto yy6;
|
171
|
+
if (yych <= 0xBF)
|
172
|
+
goto yy13;
|
173
|
+
goto yy6;
|
174
|
+
yy15:
|
175
|
+
yych = *++p;
|
176
|
+
if (yych <= 0x7F)
|
177
|
+
goto yy6;
|
178
|
+
if (yych <= 0xBF)
|
179
|
+
goto yy13;
|
180
|
+
goto yy6;
|
181
|
+
yy16:
|
182
|
+
yych = *++p;
|
183
|
+
if (yych <= 0x7F)
|
184
|
+
goto yy6;
|
185
|
+
if (yych <= 0x9F)
|
186
|
+
goto yy13;
|
187
|
+
goto yy6;
|
188
|
+
yy17:
|
189
|
+
yych = *++p;
|
190
|
+
if (yych <= 0x8F)
|
191
|
+
goto yy6;
|
192
|
+
if (yych <= 0xBF)
|
193
|
+
goto yy15;
|
194
|
+
goto yy6;
|
195
|
+
yy18:
|
196
|
+
yych = *++p;
|
197
|
+
if (yych <= 0x7F)
|
198
|
+
goto yy6;
|
199
|
+
if (yych <= 0xBF)
|
200
|
+
goto yy15;
|
201
|
+
goto yy6;
|
202
|
+
yy19:
|
203
|
+
yych = *++p;
|
204
|
+
if (yych <= 0x7F)
|
205
|
+
goto yy6;
|
206
|
+
if (yych <= 0x8F)
|
207
|
+
goto yy15;
|
208
|
+
goto yy6;
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
// Scan a closing qfm_custom_block fence with length at least len.
|
213
|
+
bufsize_t _scan_close_qfm_custom_block_fence(const unsigned char *p) {
|
214
|
+
const unsigned char *marker = NULL;
|
215
|
+
const unsigned char *start = p;
|
216
|
+
|
217
|
+
{
|
218
|
+
unsigned char yych;
|
219
|
+
static const unsigned char yybm[] = {
|
220
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
221
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
222
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0,
|
223
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
224
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
225
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
226
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
227
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
228
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
229
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
230
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
231
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
232
|
+
};
|
233
|
+
yych = *p;
|
234
|
+
if (yych == ':')
|
235
|
+
goto yy24;
|
236
|
+
++p;
|
237
|
+
yy23 : { return 0; }
|
238
|
+
yy24:
|
239
|
+
yych = *(marker = ++p);
|
240
|
+
if (yych != ':')
|
241
|
+
goto yy23;
|
242
|
+
yych = *++p;
|
243
|
+
if (yybm[0 + yych] & 64) {
|
244
|
+
goto yy27;
|
245
|
+
}
|
246
|
+
yy26:
|
247
|
+
p = marker;
|
248
|
+
goto yy23;
|
249
|
+
yy27:
|
250
|
+
yych = *++p;
|
251
|
+
if (yybm[0 + yych] & 64) {
|
252
|
+
goto yy27;
|
253
|
+
}
|
254
|
+
if (yych <= '\f') {
|
255
|
+
if (yych <= 0x08)
|
256
|
+
goto yy26;
|
257
|
+
if (yych <= '\t') {
|
258
|
+
marker = p;
|
259
|
+
goto yy29;
|
260
|
+
}
|
261
|
+
if (yych <= '\n') {
|
262
|
+
marker = p;
|
263
|
+
goto yy31;
|
264
|
+
}
|
265
|
+
goto yy26;
|
266
|
+
} else {
|
267
|
+
if (yych <= '\r') {
|
268
|
+
marker = p;
|
269
|
+
goto yy31;
|
270
|
+
}
|
271
|
+
if (yych != ' ')
|
272
|
+
goto yy26;
|
273
|
+
marker = p;
|
274
|
+
}
|
275
|
+
yy29:
|
276
|
+
yych = *++p;
|
277
|
+
if (yybm[0 + yych] & 128) {
|
278
|
+
goto yy29;
|
279
|
+
}
|
280
|
+
if (yych <= 0x08)
|
281
|
+
goto yy26;
|
282
|
+
if (yych <= '\n')
|
283
|
+
goto yy31;
|
284
|
+
if (yych != '\r')
|
285
|
+
goto yy26;
|
286
|
+
yy31:
|
287
|
+
++p;
|
288
|
+
p = marker;
|
289
|
+
{ return (bufsize_t)(p - start); }
|
290
|
+
}
|
291
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#include "chunk.h"
|
2
|
+
#include "cmark-gfm.h"
|
3
|
+
|
4
|
+
#ifdef __cplusplus
|
5
|
+
extern "C" {
|
6
|
+
#endif
|
7
|
+
|
8
|
+
bufsize_t _qfm_scan_at(bufsize_t (*scanner)(const unsigned char *),
|
9
|
+
unsigned char *ptr, int len, bufsize_t offset);
|
10
|
+
bufsize_t _scan_open_qfm_custom_block_fence(const unsigned char *p);
|
11
|
+
bufsize_t _scan_close_qfm_custom_block_fence(const unsigned char *p);
|
12
|
+
|
13
|
+
#define scan_open_qfm_custom_block_fence(c, l, n) \
|
14
|
+
_qfm_scan_at(&_scan_open_qfm_custom_block_fence, c, l, n)
|
15
|
+
#define scan_close_qfm_custom_block_fence(c, l, n) \
|
16
|
+
_qfm_scan_at(&_scan_close_qfm_custom_block_fence, c, l, n)
|
17
|
+
|
18
|
+
#ifdef __cplusplus
|
19
|
+
}
|
20
|
+
#endif
|
@@ -0,0 +1,50 @@
|
|
1
|
+
/*!re2c re2c:flags:no-debug-info = 1; */
|
2
|
+
/*!re2c re2c:indent:string = ' '; */
|
3
|
+
|
4
|
+
#include "qfm_scanners.h"
|
5
|
+
#include <stdlib.h>
|
6
|
+
|
7
|
+
bufsize_t _qfm_scan_at(bufsize_t (*scanner)(const unsigned char *),
|
8
|
+
unsigned char *ptr, int len, bufsize_t offset) {
|
9
|
+
bufsize_t res;
|
10
|
+
|
11
|
+
if (ptr == NULL || offset >= len) {
|
12
|
+
return 0;
|
13
|
+
} else {
|
14
|
+
unsigned char lim = ptr[len];
|
15
|
+
|
16
|
+
ptr[len] = '\0';
|
17
|
+
res = scanner(ptr + offset);
|
18
|
+
ptr[len] = lim;
|
19
|
+
}
|
20
|
+
|
21
|
+
return res;
|
22
|
+
}
|
23
|
+
|
24
|
+
/*!re2c
|
25
|
+
re2c:define:YYCTYPE = "unsigned char";
|
26
|
+
re2c:define:YYCURSOR = p;
|
27
|
+
re2c:define:YYMARKER = marker;
|
28
|
+
re2c:define:YYCTXMARKER = marker;
|
29
|
+
re2c:yyfill:enable = 0;
|
30
|
+
*/
|
31
|
+
|
32
|
+
// Scan an opening qfm_custom_block fence.
|
33
|
+
bufsize_t _scan_open_qfm_custom_block_fence(const unsigned char *p) {
|
34
|
+
const unsigned char *marker = NULL;
|
35
|
+
const unsigned char *start = p;
|
36
|
+
/*!re2c
|
37
|
+
[:]{3,} / [^:\r\n\x00]*[\r\n] { return (bufsize_t)(p - start); }
|
38
|
+
* { return 0; }
|
39
|
+
*/
|
40
|
+
}
|
41
|
+
|
42
|
+
// Scan a closing qfm_custom_block fence with length at least len.
|
43
|
+
bufsize_t _scan_close_qfm_custom_block_fence(const unsigned char *p) {
|
44
|
+
const unsigned char *marker = NULL;
|
45
|
+
const unsigned char *start = p;
|
46
|
+
/*!re2c
|
47
|
+
[:]{3,} / [ \t]*[\r\n] { return (bufsize_t)(p - start); }
|
48
|
+
* { return 0; }
|
49
|
+
*/
|
50
|
+
}
|
data/lib/qiita_marker/config.rb
CHANGED
@@ -13,7 +13,8 @@ module QiitaMarker
|
|
13
13
|
SMART: (1 << 10),
|
14
14
|
LIBERAL_HTML_TAG: (1 << 12),
|
15
15
|
FOOTNOTES: (1 << 13),
|
16
|
-
STRIKETHROUGH_DOUBLE_TILDE: (1 << 14)
|
16
|
+
STRIKETHROUGH_DOUBLE_TILDE: (1 << 14),
|
17
|
+
MENTION_NO_EMPHASIS: (1 << 26)
|
17
18
|
}.freeze,
|
18
19
|
render: {
|
19
20
|
DEFAULT: 0,
|
@@ -28,7 +29,9 @@ module QiitaMarker
|
|
28
29
|
FOOTNOTES: (1 << 13),
|
29
30
|
STRIKETHROUGH_DOUBLE_TILDE: (1 << 14),
|
30
31
|
TABLE_PREFER_STYLE_ATTRIBUTES: (1 << 15),
|
31
|
-
FULL_INFO_STRING: (1 << 16)
|
32
|
+
FULL_INFO_STRING: (1 << 16),
|
33
|
+
CODE_DATA_METADATA: (1 << 25),
|
34
|
+
MENTION_NO_EMPHASIS: (1 << 26)
|
32
35
|
}.freeze,
|
33
36
|
format: %i[html xml commonmark plaintext].freeze
|
34
37
|
}.freeze
|
@@ -94,6 +94,10 @@ module QiitaMarker
|
|
94
94
|
out("<pre#{sourcepos(node)}")
|
95
95
|
out(' lang="', node.fence_info.split(/\s+/)[0], '"') if node.fence_info && !node.fence_info.empty?
|
96
96
|
out('><code>')
|
97
|
+
elsif option_enabled?(:CODE_DATA_METADATA)
|
98
|
+
out("<pre#{sourcepos(node)}><code")
|
99
|
+
out(' data-metadata="', node.fence_info.split(/\s+/)[0], '"') if node.fence_info && !node.fence_info.empty?
|
100
|
+
out('>')
|
97
101
|
else
|
98
102
|
out("<pre#{sourcepos(node)}><code")
|
99
103
|
if node.fence_info && !node.fence_info.empty?
|
data/lib/qiita_marker/version.rb
CHANGED
data/qiita_marker.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.version = QiitaMarker::VERSION
|
10
10
|
s.summary = 'Qiita Marker is a Ruby library for Markdown processing, based on CommonMarker.'
|
11
11
|
s.description = 'A Ruby library that is the core module of the Qiita-specified markdown processor.'
|
12
|
-
s.authors = ['
|
12
|
+
s.authors = ['Qiita Inc.']
|
13
13
|
s.homepage = 'https://github.com/increments/qiita_marker'
|
14
14
|
s.license = 'MIT'
|
15
15
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require('test_helper')
|
4
|
+
|
5
|
+
class TestQfmCodeDataMetadata < Minitest::Test
|
6
|
+
def setup
|
7
|
+
text = <<~MD
|
8
|
+
```ruby:example.rb
|
9
|
+
puts :foo
|
10
|
+
```
|
11
|
+
MD
|
12
|
+
@doc = QiitaMarker.render_doc(text, :DEFAULT, [])
|
13
|
+
@expected = <<~HTML
|
14
|
+
<pre><code data-metadata="ruby:example.rb">puts :foo
|
15
|
+
</code></pre>
|
16
|
+
HTML
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_to_html
|
20
|
+
assert_equal(@expected, @doc.to_html(:CODE_DATA_METADATA))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_html_renderer
|
24
|
+
assert_equal(@expected, QiitaMarker::HtmlRenderer.new(options: :CODE_DATA_METADATA).render(@doc))
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require('test_helper')
|
4
|
+
|
5
|
+
class TestQfmCustomBlock < Minitest::Test
|
6
|
+
def setup
|
7
|
+
text = <<~MD
|
8
|
+
:::foo bar
|
9
|
+
message
|
10
|
+
:::
|
11
|
+
MD
|
12
|
+
@doc = QiitaMarker.render_doc(text, :DEFAULT, %i[custom_block])
|
13
|
+
@expected = <<~HTML
|
14
|
+
<div data-type="customblock" data-metadata="foo bar">
|
15
|
+
<p>message</p>
|
16
|
+
</div>
|
17
|
+
HTML
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_to_html
|
21
|
+
assert_equal(@expected, @doc.to_html(:DEFAULT, %i[custom_block]))
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestQfmMentionNoEmphasis < Minitest::Test
|
6
|
+
describe 'with mention_no_emphasis option' do
|
7
|
+
[
|
8
|
+
['@_username_', false],
|
9
|
+
['@__username__', false],
|
10
|
+
['@___username___', false],
|
11
|
+
['@user__name__', false],
|
12
|
+
['@some__user__name__', false],
|
13
|
+
[' @_username_', false],
|
14
|
+
['あ@_username_', false],
|
15
|
+
['A@_username_', true],
|
16
|
+
['@*username*', true],
|
17
|
+
['_foo_', true],
|
18
|
+
['_', false],
|
19
|
+
['_foo @username_', false],
|
20
|
+
['__foo @username__', false],
|
21
|
+
['___foo @username___', false]
|
22
|
+
].each do |text, emphasize|
|
23
|
+
describe "with text #{text.inspect}" do
|
24
|
+
if emphasize
|
25
|
+
it 'emphasizes the text' do
|
26
|
+
QiitaMarker.render_html(text, :MENTION_NO_EMPHASIS).tap do |out|
|
27
|
+
assert_match(/(<em>|<strong>)/, out.chomp)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
it 'does not emphasize the text' do
|
32
|
+
QiitaMarker.render_html(text, :MENTION_NO_EMPHASIS).tap do |out|
|
33
|
+
assert_match "<p>#{text.strip}</p>", out.chomp
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'without mention_no_emphasis option' do
|
42
|
+
describe 'with text "@_username_"' do
|
43
|
+
text = '@_username_'
|
44
|
+
it 'emphasizes the text' do
|
45
|
+
QiitaMarker.render_html(text, :DEFAULT, %i[]).tap do |out|
|
46
|
+
assert_match(/<em>/, out.chomp)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'with text "_foo @username_"' do
|
52
|
+
text = '_foo @username_'
|
53
|
+
it 'emphasizes the text' do
|
54
|
+
QiitaMarker.render_html(text, :DEFAULT, %i[]).tap do |out|
|
55
|
+
assert_match(/<em>/, out.chomp)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qiita_marker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.23.2.
|
4
|
+
version: 0.23.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Qiita Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -196,6 +196,14 @@ files:
|
|
196
196
|
- ext/qiita_marker/plaintext.c
|
197
197
|
- ext/qiita_marker/plugin.c
|
198
198
|
- ext/qiita_marker/plugin.h
|
199
|
+
- ext/qiita_marker/qfm.h
|
200
|
+
- ext/qiita_marker/qfm_custom_block.c
|
201
|
+
- ext/qiita_marker/qfm_custom_block.h
|
202
|
+
- ext/qiita_marker/qfm_mention_no_emphasis.c
|
203
|
+
- ext/qiita_marker/qfm_mention_no_emphasis.h
|
204
|
+
- ext/qiita_marker/qfm_scanners.c
|
205
|
+
- ext/qiita_marker/qfm_scanners.h
|
206
|
+
- ext/qiita_marker/qfm_scanners.re
|
199
207
|
- ext/qiita_marker/qiita_marker.c
|
200
208
|
- ext/qiita_marker/qiita_marker.h
|
201
209
|
- ext/qiita_marker/references.c
|
@@ -249,6 +257,9 @@ files:
|
|
249
257
|
- test/test_options.rb
|
250
258
|
- test/test_pathological_inputs.rb
|
251
259
|
- test/test_plaintext.rb
|
260
|
+
- test/test_qfm_code_data_metadata.rb
|
261
|
+
- test/test_qfm_custom_block.rb
|
262
|
+
- test/test_qfm_mention_no_emphasis.rb
|
252
263
|
- test/test_renderer.rb
|
253
264
|
- test/test_smartpunct.rb
|
254
265
|
- test/test_spec.rb
|
@@ -306,6 +317,9 @@ test_files:
|
|
306
317
|
- test/test_options.rb
|
307
318
|
- test/test_pathological_inputs.rb
|
308
319
|
- test/test_plaintext.rb
|
320
|
+
- test/test_qfm_code_data_metadata.rb
|
321
|
+
- test/test_qfm_custom_block.rb
|
322
|
+
- test/test_qfm_mention_no_emphasis.rb
|
309
323
|
- test/test_renderer.rb
|
310
324
|
- test/test_smartpunct.rb
|
311
325
|
- test/test_spec.rb
|