Skip to content

Commit c2b9ecb

Browse files
add parenthesis version of superscript
1 parent d5e0f78 commit c2b9ecb

File tree

2 files changed

+138
-33
lines changed

2 files changed

+138
-33
lines changed

extensions/superscript.c

Lines changed: 135 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,154 @@
33
#include <parser.h>
44
#include <render.h>
55

6+
static cmark_chunk *S_get_node_literal_chunk(cmark_node *node) {
7+
if (node == NULL) {
8+
return NULL;
9+
}
10+
11+
switch (node->type) {
12+
case CMARK_NODE_HTML_BLOCK:
13+
case CMARK_NODE_TEXT:
14+
case CMARK_NODE_HTML_INLINE:
15+
case CMARK_NODE_CODE:
16+
case CMARK_NODE_FOOTNOTE_REFERENCE:
17+
return &node->as.literal;
18+
19+
case CMARK_NODE_CODE_BLOCK:
20+
return &node->as.code.literal;
21+
22+
default:
23+
break;
24+
}
25+
26+
return NULL;
27+
}
28+
29+
static bool S_node_contains_space(cmark_node *node) {
30+
cmark_chunk *chunk = S_get_node_literal_chunk(node);
31+
if (chunk)
32+
return (cmark_chunk_strchr(chunk, ' ', 0) != chunk->len);
33+
else
34+
return false;
35+
}
36+
37+
static bool S_children_contain_space(cmark_node *parent) {
38+
cmark_node *node = parent->first_child;
39+
while (node) {
40+
if (S_node_contains_space(node)) {
41+
return true;
42+
}
43+
node = node->next;
44+
}
45+
46+
return false;
47+
}
48+
649
cmark_node_type CMARK_NODE_SUPERSCRIPT;
750

851
static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser,
952
cmark_node *parent, unsigned char character,
1053
cmark_inline_parser *inline_parser) {
1154
cmark_node *res = NULL;
12-
int startpos = cmark_inline_parser_get_offset(inline_parser) + 1;
13-
int endpos = startpos;
14-
15-
if (character != '^')
16-
return NULL;
17-
18-
// TODO: long-form parsing with parens
19-
if (cmark_inline_parser_peek_at(inline_parser, endpos) == '(')
20-
return NULL;
55+
int initpos = cmark_inline_parser_get_offset(inline_parser);
56+
57+
if (character == '^') {
58+
if (cmark_inline_parser_peek_at(inline_parser, initpos + 1) == '(') {
59+
res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
60+
cmark_node_set_literal(res, "^(");
61+
res->start_line = res->end_line = cmark_inline_parser_get_line(inline_parser);
62+
res->start_column = cmark_inline_parser_get_column(inline_parser);
63+
res->end_column = res->start_column + 2;
64+
65+
cmark_inline_parser_set_offset(inline_parser, initpos + 2);
66+
cmark_inline_parser_push_delimiter(inline_parser, '^', true, false, res);
67+
} else {
68+
int startpos = initpos + 1;
69+
int endpos = startpos;
70+
71+
cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
72+
bufsize_t len = chunk->len;
73+
74+
while (endpos < len) {
75+
unsigned char seekchar = cmark_inline_parser_peek_at(inline_parser, endpos);
76+
if (cmark_isspace(seekchar) || (cmark_ispunct(seekchar) && seekchar != '^'))
77+
break;
78+
endpos++;
79+
}
80+
81+
int nodelen = endpos - startpos;
82+
83+
// don't emit an empty node
84+
if (nodelen == 0)
85+
return NULL;
86+
87+
cmark_inline_parser_set_offset(inline_parser, startpos);
88+
89+
res = cmark_node_new_with_mem_and_ext(CMARK_NODE_SUPERSCRIPT, parser->mem, self);
90+
res->as.literal = cmark_chunk_dup(chunk, startpos, nodelen);
91+
res->start_line = cmark_inline_parser_get_line(inline_parser);
92+
res->start_column = cmark_inline_parser_get_column(inline_parser);
93+
94+
cmark_inline_parser_set_offset(inline_parser, endpos);
95+
96+
res->end_line = cmark_inline_parser_get_line(inline_parser);
97+
res->end_column = cmark_inline_parser_get_column(inline_parser);
98+
99+
const char *text = cmark_chunk_to_cstr(parser->mem, &res->as.literal);
100+
cmark_node_set_string_content(res, text);
101+
102+
cmark_parse_inlines(parser, res, parser->refmap, parser->options);
103+
}
104+
} else if (character == ')') {
105+
res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
106+
cmark_node_set_literal(res, ")");
107+
res->start_line = res->end_line = cmark_inline_parser_get_line(inline_parser);
108+
res->start_column = cmark_inline_parser_get_column(inline_parser);
109+
res->end_column = res->start_column + 1;
110+
111+
cmark_inline_parser_set_offset(inline_parser, initpos + 1);
112+
cmark_inline_parser_push_delimiter(inline_parser, '^', false, true, res);
113+
}
21114

22-
cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
23-
bufsize_t len = chunk->len;
115+
return res;
116+
}
24117

25-
while (endpos < len && !cmark_isspace(cmark_inline_parser_peek_at(inline_parser, endpos)))
26-
endpos++;
118+
static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
119+
cmark_inline_parser *inline_parser, delimiter *opener,
120+
delimiter *closer) {
121+
cmark_node *superscript;
122+
cmark_node *tmp, *next;
123+
delimiter *delim, *tmp_delim;
124+
delimiter *res = closer->next;
27125

28-
int nodelen = endpos - startpos;
126+
superscript = opener->inl_text;
29127

30-
// don't emit an empty node
31-
if (nodelen == 0)
32-
return NULL;
128+
if (!cmark_node_set_type(superscript, CMARK_NODE_SUPERSCRIPT))
129+
return res;
33130

34-
cmark_inline_parser_set_offset(inline_parser, startpos);
131+
cmark_node_set_syntax_extension(superscript, self);
35132

36-
res = cmark_node_new_with_mem_and_ext(CMARK_NODE_SUPERSCRIPT, parser->mem, self);
37-
res->as.literal = cmark_chunk_dup(chunk, startpos, nodelen);
38-
res->start_line = cmark_inline_parser_get_line(inline_parser);
39-
res->start_column = cmark_inline_parser_get_column(inline_parser);
133+
tmp = cmark_node_next(opener->inl_text);
40134

41-
cmark_inline_parser_set_offset(inline_parser, endpos);
135+
while (tmp) {
136+
if (tmp == closer->inl_text)
137+
break;
138+
next = cmark_node_next(tmp);
139+
cmark_node_append_child(superscript, tmp);
140+
tmp = next;
141+
}
42142

43-
res->end_line = cmark_inline_parser_get_line(inline_parser);
44-
res->end_column = cmark_inline_parser_get_column(inline_parser);
143+
superscript->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
144+
cmark_node_free(closer->inl_text);
45145

46-
const char *text = cmark_chunk_to_cstr(parser->mem, &res->as.literal);
47-
cmark_node_set_string_content(res, text);
146+
delim = closer;
147+
while (delim != NULL && delim != opener) {
148+
tmp_delim = delim->previous;
149+
cmark_inline_parser_remove_delimiter(inline_parser, delim);
150+
delim = tmp_delim;
151+
}
48152

49-
cmark_parse_inlines(parser, res, parser->refmap, parser->options);
153+
cmark_inline_parser_remove_delimiter(inline_parser, opener);
50154

51155
return res;
52156
}
@@ -67,7 +171,7 @@ static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
67171
static void commonmark_render(cmark_syntax_extension *extension,
68172
cmark_renderer *renderer, cmark_node *node,
69173
cmark_event_type ev_type, int options) {
70-
bool should_wrap = (cmark_strbuf_strchr(&node->content, ' ', 0) != -1);
174+
bool should_wrap = S_children_contain_space(node);
71175
bool entering = (ev_type == CMARK_EVENT_ENTER);
72176
if (entering) {
73177
if (should_wrap)
@@ -129,10 +233,11 @@ cmark_syntax_extension *create_superscript_extension(void) {
129233
CMARK_NODE_SUPERSCRIPT = cmark_syntax_extension_add_node(1);
130234

131235
cmark_syntax_extension_set_match_inline_func(ext, match);
132-
// cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
236+
cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
133237

134238
cmark_mem *mem = cmark_get_default_mem_allocator();
135239
special_chars = cmark_llist_append(mem, special_chars, (void *)'^');
240+
special_chars = cmark_llist_append(mem, special_chars, (void *)')');
136241
cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
137242

138243
cmark_syntax_extension_set_emphasis(ext, 1);

test/spec.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7756,7 +7756,7 @@ Superscripting a whole ^word
77567756
In addition, if you would like to raise more than one word, you can add
77577757
parentheses around the text you would like to style in a superscript:
77587758

7759-
```````````````````````````````` example superscript disabled
7759+
```````````````````````````````` example superscript
77607760
I would like to ^(raise this whole phrase), please.
77617761
.
77627762
<p>I would like to <sup>raise this whole phrase</sup>, please.</p>
@@ -7770,10 +7770,10 @@ z = t^x^2
77707770
<p>z = t<sup>x<sup>2</sup></sup></p>
77717771
````````````````````````````````
77727772

7773-
```````````````````````````````` example superscript disabled
7773+
```````````````````````````````` example superscript
77747774
For my next trick, I will ^(raise my text ^(twice)), at the same time!
77757775
.
7776-
<p>For my next trick, I will <sup>raise my text<sup>twice</sup></sup>, at the same time!</p>
7776+
<p>For my next trick, I will <sup>raise my text <sup>twice</sup></sup>, at the same time!</p>
77777777
````````````````````````````````
77787778

77797779
</div>

0 commit comments

Comments
 (0)