1 #include "strikethrough.h"
2 #include <parser.h>
3 #include <render.h>
4
5 cmark_node_type CMARK_NODE_STRIKETHROUGH;
6
match(cmark_syntax_extension * self,cmark_parser * parser,cmark_node * parent,unsigned char character,cmark_inline_parser * inline_parser)7 static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser,
8 cmark_node *parent, unsigned char character,
9 cmark_inline_parser *inline_parser) {
10 cmark_node *res = NULL;
11 int left_flanking, right_flanking, punct_before, punct_after, delims;
12 char buffer[101];
13
14 if (character != '~')
15 return NULL;
16
17 delims = cmark_inline_parser_scan_delimiters(
18 inline_parser, sizeof(buffer) - 1, '~',
19 &left_flanking,
20 &right_flanking, &punct_before, &punct_after);
21
22 memset(buffer, '~', delims);
23 buffer[delims] = 0;
24
25 res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
26 cmark_node_set_literal(res, buffer);
27 res->start_line = res->end_line = cmark_inline_parser_get_line(inline_parser);
28 res->start_column = cmark_inline_parser_get_column(inline_parser) - delims;
29
30 if ((left_flanking || right_flanking) &&
31 (delims == 2 || (!(parser->options & CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE) && delims == 1))) {
32 cmark_inline_parser_push_delimiter(inline_parser, character, left_flanking,
33 right_flanking, res);
34 }
35
36 return res;
37 }
38
insert(cmark_syntax_extension * self,cmark_parser * parser,cmark_inline_parser * inline_parser,delimiter * opener,delimiter * closer)39 static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
40 cmark_inline_parser *inline_parser, delimiter *opener,
41 delimiter *closer) {
42 cmark_node *strikethrough;
43 cmark_node *tmp, *next;
44 delimiter *delim, *tmp_delim;
45 delimiter *res = closer->next;
46
47 strikethrough = opener->inl_text;
48
49 if (opener->inl_text->as.literal.len != closer->inl_text->as.literal.len)
50 goto done;
51
52 if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH))
53 goto done;
54
55 cmark_node_set_syntax_extension(strikethrough, self);
56
57 tmp = cmark_node_next(opener->inl_text);
58
59 while (tmp) {
60 if (tmp == closer->inl_text)
61 break;
62 next = cmark_node_next(tmp);
63 cmark_node_append_child(strikethrough, tmp);
64 tmp = next;
65 }
66
67 strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
68 cmark_node_free(closer->inl_text);
69
70 delim = closer;
71 while (delim != NULL && delim != opener) {
72 tmp_delim = delim->previous;
73 cmark_inline_parser_remove_delimiter(inline_parser, delim);
74 delim = tmp_delim;
75 }
76
77 cmark_inline_parser_remove_delimiter(inline_parser, opener);
78
79 done:
80 return res;
81 }
82
get_type_string(cmark_syntax_extension * extension,cmark_node * node)83 static const char *get_type_string(cmark_syntax_extension *extension,
84 cmark_node *node) {
85 return node->type == CMARK_NODE_STRIKETHROUGH ? "strikethrough" : "<unknown>";
86 }
87
can_contain(cmark_syntax_extension * extension,cmark_node * node,cmark_node_type child_type)88 static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
89 cmark_node_type child_type) {
90 if (node->type != CMARK_NODE_STRIKETHROUGH)
91 return false;
92
93 return CMARK_NODE_TYPE_INLINE_P(child_type);
94 }
95
commonmark_render(cmark_syntax_extension * extension,cmark_renderer * renderer,cmark_node * node,cmark_event_type ev_type,int options)96 static void commonmark_render(cmark_syntax_extension *extension,
97 cmark_renderer *renderer, cmark_node *node,
98 cmark_event_type ev_type, int options) {
99 renderer->out(renderer, node, "~~", false, LITERAL);
100 }
101
latex_render(cmark_syntax_extension * extension,cmark_renderer * renderer,cmark_node * node,cmark_event_type ev_type,int options)102 static void latex_render(cmark_syntax_extension *extension,
103 cmark_renderer *renderer, cmark_node *node,
104 cmark_event_type ev_type, int options) {
105 // requires \usepackage{ulem}
106 bool entering = (ev_type == CMARK_EVENT_ENTER);
107 if (entering) {
108 renderer->out(renderer, node, "\\sout{", false, LITERAL);
109 } else {
110 renderer->out(renderer, node, "}", false, LITERAL);
111 }
112 }
113
man_render(cmark_syntax_extension * extension,cmark_renderer * renderer,cmark_node * node,cmark_event_type ev_type,int options)114 static void man_render(cmark_syntax_extension *extension,
115 cmark_renderer *renderer, cmark_node *node,
116 cmark_event_type ev_type, int options) {
117 bool entering = (ev_type == CMARK_EVENT_ENTER);
118 if (entering) {
119 renderer->cr(renderer);
120 renderer->out(renderer, node, ".ST \"", false, LITERAL);
121 } else {
122 renderer->out(renderer, node, "\"", false, LITERAL);
123 renderer->cr(renderer);
124 }
125 }
126
html_render(cmark_syntax_extension * extension,cmark_html_renderer * renderer,cmark_node * node,cmark_event_type ev_type,int options)127 static void html_render(cmark_syntax_extension *extension,
128 cmark_html_renderer *renderer, cmark_node *node,
129 cmark_event_type ev_type, int options) {
130 bool entering = (ev_type == CMARK_EVENT_ENTER);
131 if (entering) {
132 cmark_strbuf_puts(renderer->html, "<del>");
133 } else {
134 cmark_strbuf_puts(renderer->html, "</del>");
135 }
136 }
137
plaintext_render(cmark_syntax_extension * extension,cmark_renderer * renderer,cmark_node * node,cmark_event_type ev_type,int options)138 static void plaintext_render(cmark_syntax_extension *extension,
139 cmark_renderer *renderer, cmark_node *node,
140 cmark_event_type ev_type, int options) {
141 renderer->out(renderer, node, "~", false, LITERAL);
142 }
143
create_strikethrough_extension(void)144 cmark_syntax_extension *create_strikethrough_extension(void) {
145 cmark_syntax_extension *ext = cmark_syntax_extension_new("strikethrough");
146 cmark_llist *special_chars = NULL;
147
148 cmark_syntax_extension_set_get_type_string_func(ext, get_type_string);
149 cmark_syntax_extension_set_can_contain_func(ext, can_contain);
150 cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render);
151 cmark_syntax_extension_set_latex_render_func(ext, latex_render);
152 cmark_syntax_extension_set_man_render_func(ext, man_render);
153 cmark_syntax_extension_set_html_render_func(ext, html_render);
154 cmark_syntax_extension_set_plaintext_render_func(ext, plaintext_render);
155 CMARK_NODE_STRIKETHROUGH = cmark_syntax_extension_add_node(1);
156
157 cmark_syntax_extension_set_match_inline_func(ext, match);
158 cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
159
160 cmark_mem *mem = cmark_get_default_mem_allocator();
161 special_chars = cmark_llist_append(mem, special_chars, (void *)'~');
162 cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
163
164 cmark_syntax_extension_set_emphasis(ext, 1);
165
166 return ext;
167 }
168