Skip to content

Commit f10d17d

Browse files
wip: half of the 'superscript' extension
1 parent 1e705e9 commit f10d17d

File tree

5 files changed

+197
-0
lines changed

5 files changed

+197
-0
lines changed

extensions/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(LIBRARY_SOURCES
1111
ext_scanners.re
1212
ext_scanners.h
1313
tasklist.c
14+
superscript.c
1415
)
1516

1617
include_directories(

extensions/core-extensions.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "tasklist.h"
88
#include "registry.h"
99
#include "plugin.h"
10+
#include "superscript.h"
1011

1112
static int core_extensions_registration(cmark_plugin *plugin) {
1213
cmark_plugin_register_syntax_extension(plugin, create_table_extension());
@@ -15,6 +16,7 @@ static int core_extensions_registration(cmark_plugin *plugin) {
1516
cmark_plugin_register_syntax_extension(plugin, create_autolink_extension());
1617
cmark_plugin_register_syntax_extension(plugin, create_tagfilter_extension());
1718
cmark_plugin_register_syntax_extension(plugin, create_tasklist_extension());
19+
cmark_plugin_register_syntax_extension(plugin, create_superscript_extension());
1820
return 1;
1921
}
2022

extensions/superscript.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#include "superscript.h"
2+
#include <inlines.h>
3+
#include <parser.h>
4+
#include <render.h>
5+
6+
cmark_node_type CMARK_NODE_SUPERSCRIPT;
7+
8+
static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser,
9+
cmark_node *parent, unsigned char character,
10+
cmark_inline_parser *inline_parser) {
11+
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;
21+
22+
cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
23+
bufsize_t len = chunk->len;
24+
25+
while (endpos < len && !cmark_isspace(cmark_inline_parser_peek_at(inline_parser, endpos)))
26+
endpos++;
27+
28+
int nodelen = endpos - startpos;
29+
30+
// don't emit an empty node
31+
if (nodelen == 0)
32+
return NULL;
33+
34+
cmark_inline_parser_set_offset(inline_parser, startpos);
35+
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);
40+
41+
cmark_inline_parser_set_offset(inline_parser, endpos);
42+
43+
res->end_line = cmark_inline_parser_get_line(inline_parser);
44+
res->end_column = cmark_inline_parser_get_column(inline_parser);
45+
46+
const char *text = cmark_chunk_to_cstr(parser->mem, &res->as.literal);
47+
cmark_node_set_string_content(res, text);
48+
49+
cmark_parse_inlines(parser, res, parser->refmap, parser->options);
50+
51+
return res;
52+
}
53+
54+
static const char *get_type_string(cmark_syntax_extension *extension,
55+
cmark_node *node) {
56+
return node->type == CMARK_NODE_SUPERSCRIPT ? "superscript" : "<unknown>";
57+
}
58+
59+
static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
60+
cmark_node_type child_type) {
61+
if (node->type != CMARK_NODE_SUPERSCRIPT)
62+
return false;
63+
64+
return CMARK_NODE_TYPE_INLINE_P(child_type);
65+
}
66+
67+
static void commonmark_render(cmark_syntax_extension *extension,
68+
cmark_renderer *renderer, cmark_node *node,
69+
cmark_event_type ev_type, int options) {
70+
bool should_wrap = (cmark_strbuf_strchr(&node->content, ' ', 0) != -1);
71+
bool entering = (ev_type == CMARK_EVENT_ENTER);
72+
if (entering) {
73+
if (should_wrap)
74+
renderer->out(renderer, node, "^(", false, LITERAL);
75+
else
76+
renderer->out(renderer, node, "^", false, LITERAL);
77+
} else if (!entering && should_wrap) {
78+
renderer->out(renderer, node, ")", false, LITERAL);
79+
}
80+
}
81+
82+
static void latex_render(cmark_syntax_extension *extension,
83+
cmark_renderer *renderer, cmark_node *node,
84+
cmark_event_type ev_type, int options) {
85+
bool entering = (ev_type == CMARK_EVENT_ENTER);
86+
if (entering) {
87+
renderer->out(renderer, node, "^{", false, LITERAL);
88+
} else {
89+
renderer->out(renderer, node, "}", false, LITERAL);
90+
}
91+
}
92+
93+
static void man_render(cmark_syntax_extension *extension,
94+
cmark_renderer *renderer, cmark_node *node,
95+
cmark_event_type ev_type, int options) {
96+
// requires MOM
97+
bool entering = (ev_type == CMARK_EVENT_ENTER);
98+
if (entering) {
99+
renderer->cr(renderer);
100+
renderer->out(renderer, node, "\\*[SUP]", false, LITERAL);
101+
} else {
102+
renderer->out(renderer, node, "\\*[SUPX]", false, LITERAL);
103+
renderer->cr(renderer);
104+
}
105+
}
106+
107+
static void html_render(cmark_syntax_extension *extension,
108+
cmark_html_renderer *renderer, cmark_node *node,
109+
cmark_event_type ev_type, int options) {
110+
bool entering = (ev_type == CMARK_EVENT_ENTER);
111+
if (entering) {
112+
cmark_strbuf_puts(renderer->html, "<sup>");
113+
} else {
114+
cmark_strbuf_puts(renderer->html, "</sup>");
115+
}
116+
}
117+
118+
cmark_syntax_extension *create_superscript_extension(void) {
119+
cmark_syntax_extension *ext = cmark_syntax_extension_new("superscript");
120+
cmark_llist *special_chars = NULL;
121+
122+
cmark_syntax_extension_set_get_type_string_func(ext, get_type_string);
123+
cmark_syntax_extension_set_can_contain_func(ext, can_contain);
124+
cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render);
125+
cmark_syntax_extension_set_plaintext_render_func(ext, commonmark_render);
126+
cmark_syntax_extension_set_latex_render_func(ext, latex_render);
127+
cmark_syntax_extension_set_man_render_func(ext, man_render);
128+
cmark_syntax_extension_set_html_render_func(ext, html_render);
129+
CMARK_NODE_SUPERSCRIPT = cmark_syntax_extension_add_node(1);
130+
131+
cmark_syntax_extension_set_match_inline_func(ext, match);
132+
// cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
133+
134+
cmark_mem *mem = cmark_get_default_mem_allocator();
135+
special_chars = cmark_llist_append(mem, special_chars, (void *)'^');
136+
cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
137+
138+
cmark_syntax_extension_set_emphasis(ext, 1);
139+
140+
return ext;
141+
}

extensions/superscript.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef CMARK_GFM_SUPERSCRIPT_H
2+
#define CMARK_GFM_SUPERSCRIPT_H
3+
4+
#include "cmark-gfm-core-extensions.h"
5+
6+
extern cmark_node_type CMARK_NODE_SUPERSCRIPT;
7+
cmark_syntax_extension *create_superscript_extension(void);
8+
9+
#endif /* CMARK_GFM_SUPERSCRIPT_H */

test/spec.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7734,6 +7734,50 @@ new paragraph~~.
77347734

77357735
</div>
77367736

7737+
<div class="extension">
7738+
7739+
## Superscript (extension)
7740+
7741+
GFM provides the `superscript` extension, which adds "superscript" spans.
7742+
7743+
There are two ways to write superscripts. For simple uses, you can use a
7744+
caret (`^`) to style the text between it and the next space (or the end of
7745+
the line):
7746+
7747+
```````````````````````````````` example superscript
7748+
y = x^2 + 2
7749+
7750+
Superscripting a whole ^word
7751+
.
7752+
<p>y = x<sup>2</sup> + 2</p>
7753+
<p>Superscripting a whole <sup>word</sup></p>
7754+
````````````````````````````````
7755+
7756+
In addition, if you would like to raise more than one word, you can add
7757+
parentheses around the text you would like to style in a superscript:
7758+
7759+
```````````````````````````````` example superscript disabled
7760+
I would like to ^(raise this whole phrase), please.
7761+
.
7762+
<p>I would like to <sup>raise this whole phrase</sup>, please.</p>
7763+
````````````````````````````````
7764+
7765+
Superscripts can be nested, by adding additional carets:
7766+
7767+
```````````````````````````````` example superscript
7768+
z = t^x^2
7769+
.
7770+
<p>z = t<sup>x<sup>2</sup></sup></p>
7771+
````````````````````````````````
7772+
7773+
```````````````````````````````` example superscript disabled
7774+
For my next trick, I will ^(raise my text ^(twice)), at the same time!
7775+
.
7776+
<p>For my next trick, I will <sup>raise my text<sup>twice</sup></sup>, at the same time!</p>
7777+
````````````````````````````````
7778+
7779+
</div>
7780+
77377781
## Links
77387782

77397783
A link contains [link text] (the visible text), a [link destination]

0 commit comments

Comments
 (0)