summaryrefslogtreecommitdiff
path: root/src/latex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/latex.c')
-rw-r--r--src/latex.c780
1 files changed, 379 insertions, 401 deletions
diff --git a/src/latex.c b/src/latex.c
index 782b0c0..146062e 100644
--- a/src/latex.c
+++ b/src/latex.c
@@ -18,413 +18,391 @@
#define CR() renderer->cr(renderer)
#define BLANKLINE() renderer->blankline(renderer)
-static inline void outc(cmark_renderer *renderer,
- cmark_escaping escape,
- int32_t c,
- unsigned char nextc)
-{
- if (escape == LITERAL) {
- cmark_render_code_point(renderer, c);
- return;
- }
-
- switch(c) {
- case 123: // '{'
- case 125: // '}'
- case 35: // '#'
- case 37: // '%'
- case 38: // '&'
- cmark_render_ascii(renderer, "\\");
- cmark_render_code_point(renderer, c);
- break;
- case 36: // '$'
- case 95: // '_'
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "\\");
- }
- cmark_render_code_point(renderer, c);
- break;
- case 45 : // '-'
- if (nextc == 45) { // prevent ligature
- cmark_render_ascii(renderer, "\\-");
- } else {
- cmark_render_ascii(renderer, "-");
- }
- break;
- case 126: // '~'
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "\\textasciitilde{}");
- } else {
- cmark_render_code_point(renderer, c);
- }
- break;
- case 94: // '^'
- cmark_render_ascii(renderer, "\\^{}");
- break;
- case 92: // '\\'
- if (escape == URL) {
- // / acts as path sep even on windows:
- cmark_render_ascii(renderer, "/");
- } else {
- cmark_render_ascii(renderer, "\\textbackslash{}");
- }
- break;
- case 124: // '|'
- cmark_render_ascii(renderer, "\\textbar{}");
- break;
- case 60: // '<'
- cmark_render_ascii(renderer, "\\textless{}");
- break;
- case 62: // '>'
- cmark_render_ascii(renderer, "\\textgreater{}");
- break;
- case 91: // '['
- case 93: // ']'
- cmark_render_ascii(renderer, "{");
- cmark_render_code_point(renderer, c);
- cmark_render_ascii(renderer, "}");
- break;
- case 34: // '"'
- cmark_render_ascii(renderer, "\\textquotedbl{}");
- // requires \usepackage[T1]{fontenc}
- break;
- case 39: // '\''
- cmark_render_ascii(renderer, "\\textquotesingle{}");
- // requires \usepackage{textcomp}
- break;
- case 160: // nbsp
- cmark_render_ascii(renderer, "~");
- break;
- case 8230: // hellip
- cmark_render_ascii(renderer, "\\ldots{}");
- break;
- case 8216: // lsquo
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "`");
- } else {
- cmark_render_code_point(renderer, c);
- }
- break;
- case 8217: // rsquo
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "\'");
- } else {
- cmark_render_code_point(renderer, c);
- }
- break;
- case 8220: // ldquo
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "``");
- } else {
- cmark_render_code_point(renderer, c);
- }
- break;
- case 8221: // rdquo
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "''");
- } else {
- cmark_render_code_point(renderer, c);
- }
- break;
- case 8212: // emdash
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "---");
- } else {
- cmark_render_code_point(renderer, c);
- }
- break;
- case 8211: // endash
- if (escape == NORMAL) {
- cmark_render_ascii(renderer, "--");
- } else {
- cmark_render_code_point(renderer, c);
- }
- break;
- default:
- cmark_render_code_point(renderer, c);
- }
+static inline void outc(cmark_renderer *renderer, cmark_escaping escape,
+ int32_t c, unsigned char nextc) {
+ if (escape == LITERAL) {
+ cmark_render_code_point(renderer, c);
+ return;
+ }
+
+ switch (c) {
+ case 123: // '{'
+ case 125: // '}'
+ case 35: // '#'
+ case 37: // '%'
+ case 38: // '&'
+ cmark_render_ascii(renderer, "\\");
+ cmark_render_code_point(renderer, c);
+ break;
+ case 36: // '$'
+ case 95: // '_'
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "\\");
+ }
+ cmark_render_code_point(renderer, c);
+ break;
+ case 45: // '-'
+ if (nextc == 45) { // prevent ligature
+ cmark_render_ascii(renderer, "\\-");
+ } else {
+ cmark_render_ascii(renderer, "-");
+ }
+ break;
+ case 126: // '~'
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "\\textasciitilde{}");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 94: // '^'
+ cmark_render_ascii(renderer, "\\^{}");
+ break;
+ case 92: // '\\'
+ if (escape == URL) {
+ // / acts as path sep even on windows:
+ cmark_render_ascii(renderer, "/");
+ } else {
+ cmark_render_ascii(renderer, "\\textbackslash{}");
+ }
+ break;
+ case 124: // '|'
+ cmark_render_ascii(renderer, "\\textbar{}");
+ break;
+ case 60: // '<'
+ cmark_render_ascii(renderer, "\\textless{}");
+ break;
+ case 62: // '>'
+ cmark_render_ascii(renderer, "\\textgreater{}");
+ break;
+ case 91: // '['
+ case 93: // ']'
+ cmark_render_ascii(renderer, "{");
+ cmark_render_code_point(renderer, c);
+ cmark_render_ascii(renderer, "}");
+ break;
+ case 34: // '"'
+ cmark_render_ascii(renderer, "\\textquotedbl{}");
+ // requires \usepackage[T1]{fontenc}
+ break;
+ case 39: // '\''
+ cmark_render_ascii(renderer, "\\textquotesingle{}");
+ // requires \usepackage{textcomp}
+ break;
+ case 160: // nbsp
+ cmark_render_ascii(renderer, "~");
+ break;
+ case 8230: // hellip
+ cmark_render_ascii(renderer, "\\ldots{}");
+ break;
+ case 8216: // lsquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "`");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8217: // rsquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "\'");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8220: // ldquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "``");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8221: // rdquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "''");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8212: // emdash
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "---");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8211: // endash
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "--");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ default:
+ cmark_render_code_point(renderer, c);
+ }
}
-typedef enum {
- NO_LINK,
- URL_AUTOLINK,
- EMAIL_AUTOLINK,
- NORMAL_LINK
-} link_type;
-
-static link_type
-get_link_type(cmark_node *node)
-{
- size_t title_len, url_len;
- cmark_node *link_text;
- char *realurl;
- int realurllen;
- bool isemail = false;
-
- if (node->type != CMARK_NODE_LINK) {
- return NO_LINK;
- }
-
- const char* url = cmark_node_get_url(node);
- cmark_chunk url_chunk = cmark_chunk_literal(url);
-
- url_len = safe_strlen(url);
- if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) {
- return NO_LINK;
- }
-
- const char* title = cmark_node_get_title(node);
- title_len = safe_strlen(title);
- // if it has a title, we can't treat it as an autolink:
- if (title_len > 0) {
- return NORMAL_LINK;
- }
-
- link_text = node->first_child;
- cmark_consolidate_text_nodes(link_text);
- realurl = (char*)url;
- realurllen = url_len;
- if (strncmp(realurl, "mailto:", 7) == 0) {
- realurl += 7;
- realurllen -= 7;
- isemail = true;
- }
- if (realurllen == link_text->as.literal.len &&
- strncmp(realurl,
- (char*)link_text->as.literal.data,
- link_text->as.literal.len) == 0) {
- if (isemail) {
- return EMAIL_AUTOLINK;
- } else {
- return URL_AUTOLINK;
- }
- } else {
- return NORMAL_LINK;
- }
+typedef enum { NO_LINK, URL_AUTOLINK, EMAIL_AUTOLINK, NORMAL_LINK } link_type;
+
+static link_type get_link_type(cmark_node *node) {
+ size_t title_len, url_len;
+ cmark_node *link_text;
+ char *realurl;
+ int realurllen;
+ bool isemail = false;
+
+ if (node->type != CMARK_NODE_LINK) {
+ return NO_LINK;
+ }
+
+ const char *url = cmark_node_get_url(node);
+ cmark_chunk url_chunk = cmark_chunk_literal(url);
+
+ url_len = safe_strlen(url);
+ if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) {
+ return NO_LINK;
+ }
+
+ const char *title = cmark_node_get_title(node);
+ title_len = safe_strlen(title);
+ // if it has a title, we can't treat it as an autolink:
+ if (title_len > 0) {
+ return NORMAL_LINK;
+ }
+
+ link_text = node->first_child;
+ cmark_consolidate_text_nodes(link_text);
+ realurl = (char *)url;
+ realurllen = url_len;
+ if (strncmp(realurl, "mailto:", 7) == 0) {
+ realurl += 7;
+ realurllen -= 7;
+ isemail = true;
+ }
+ if (realurllen == link_text->as.literal.len &&
+ strncmp(realurl, (char *)link_text->as.literal.data,
+ link_text->as.literal.len) == 0) {
+ if (isemail) {
+ return EMAIL_AUTOLINK;
+ } else {
+ return URL_AUTOLINK;
+ }
+ } else {
+ return NORMAL_LINK;
+ }
}
-static int
-S_get_enumlevel(cmark_node *node)
-{
- int enumlevel = 0;
- cmark_node *tmp = node;
- while (tmp) {
- if (tmp->type == CMARK_NODE_LIST &&
- cmark_node_get_list_type(node) == CMARK_ORDERED_LIST) {
- enumlevel++;
- }
- tmp = tmp->parent;
- }
- return enumlevel;
+static int S_get_enumlevel(cmark_node *node) {
+ int enumlevel = 0;
+ cmark_node *tmp = node;
+ while (tmp) {
+ if (tmp->type == CMARK_NODE_LIST &&
+ cmark_node_get_list_type(node) == CMARK_ORDERED_LIST) {
+ enumlevel++;
+ }
+ tmp = tmp->parent;
+ }
+ return enumlevel;
}
-static int
-S_render_node(cmark_renderer *renderer,
- cmark_node *node,
- cmark_event_type ev_type,
- int options)
-{
- int list_number;
- char list_number_string[20];
- bool entering = (ev_type == CMARK_EVENT_ENTER);
- cmark_list_type list_type;
- const char* roman_numerals[] = { "", "i", "ii", "iii", "iv", "v",
- "vi", "vii", "viii", "ix", "x"
- };
-
- // avoid warning about unused parameter:
- (void)(options);
-
- switch (node->type) {
- case CMARK_NODE_DOCUMENT:
- break;
-
- case CMARK_NODE_BLOCK_QUOTE:
- if (entering) {
- LIT("\\begin{quote}");
- CR();
- } else {
- LIT("\\end{quote}");
- BLANKLINE();
- }
- break;
-
- case CMARK_NODE_LIST:
- list_type = cmark_node_get_list_type(node);
- if (entering) {
- LIT("\\begin{");
- LIT(list_type == CMARK_ORDERED_LIST ?
- "enumerate" : "itemize");
- LIT("}");
- CR();
- list_number = cmark_node_get_list_start(node);
- if (list_number > 1) {
- sprintf(list_number_string,
- "%d", list_number);
- LIT("\\setcounter{enum");
- LIT((char *)roman_numerals[S_get_enumlevel(node)]);
- LIT("}{");
- OUT(list_number_string, false, NORMAL);
- LIT("}");
- CR();
- }
- } else {
- LIT("\\end{");
- LIT(list_type == CMARK_ORDERED_LIST ?
- "enumerate" : "itemize");
- LIT("}");
- BLANKLINE();
- }
- break;
-
- case CMARK_NODE_ITEM:
- if (entering) {
- LIT("\\item ");
- } else {
- CR();
- }
- break;
-
- case CMARK_NODE_HEADER:
- if (entering) {
- switch (cmark_node_get_header_level(node)) {
- case 1:
- LIT("\\section");
- break;
- case 2:
- LIT("\\subsection");
- break;
- case 3:
- LIT("\\subsubsection");
- break;
- case 4:
- LIT("\\paragraph");
- break;
- case 5:
- LIT("\\subparagraph");
- break;
- }
- LIT("{");
- } else {
- LIT("}");
- BLANKLINE();
- }
- break;
-
- case CMARK_NODE_CODE_BLOCK:
- CR();
- LIT("\\begin{verbatim}");
- CR();
- OUT(cmark_node_get_literal(node), false, LITERAL);
- CR();
- LIT("\\end{verbatim}");
- BLANKLINE();
- break;
-
- case CMARK_NODE_HTML:
- break;
-
- case CMARK_NODE_HRULE:
- BLANKLINE();
- LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}");
- BLANKLINE();
- break;
-
- case CMARK_NODE_PARAGRAPH:
- if (!entering) {
- BLANKLINE();
- }
- break;
-
- case CMARK_NODE_TEXT:
- OUT(cmark_node_get_literal(node), true, NORMAL);
- break;
-
- case CMARK_NODE_LINEBREAK:
- LIT("\\\\");
- CR();
- break;
-
- case CMARK_NODE_SOFTBREAK:
- if (renderer->width == 0) {
- CR();
- } else {
- OUT(" ", true, NORMAL);
- }
- break;
-
- case CMARK_NODE_CODE:
- LIT("\\texttt{");
- OUT(cmark_node_get_literal(node), false, NORMAL);
- LIT("}");
- break;
-
- case CMARK_NODE_INLINE_HTML:
- break;
-
- case CMARK_NODE_STRONG:
- if (entering) {
- LIT("\\textbf{");
- } else {
- LIT("}");
- }
- break;
-
- case CMARK_NODE_EMPH:
- if (entering) {
- LIT("\\emph{");
- } else {
- LIT("}");
- }
- break;
-
- case CMARK_NODE_LINK:
- if (entering) {
- const char* url = cmark_node_get_url(node);
- // requires \usepackage{hyperref}
- switch(get_link_type(node)) {
- case URL_AUTOLINK:
- LIT("\\url{");
- OUT(url, false, URL);
- break;
- case EMAIL_AUTOLINK:
- LIT("\\href{");
- OUT(url, false, URL);
- LIT("}\\nolinkurl{");
- break;
- case NORMAL_LINK:
- LIT("\\href{");
- OUT(url, false, URL);
- LIT("}{");
- break;
- case NO_LINK:
- LIT("{"); // error?
- }
- } else {
- LIT("}");
- }
-
- break;
-
- case CMARK_NODE_IMAGE:
- if (entering) {
- LIT("\\protect\\includegraphics{");
- // requires \include{graphicx}
- OUT(cmark_node_get_url(node), false, URL);
- LIT("}");
- return 0;
- }
- break;
-
- default:
- assert(false);
- break;
- }
-
- return 1;
+static int S_render_node(cmark_renderer *renderer, cmark_node *node,
+ cmark_event_type ev_type, int options) {
+ int list_number;
+ char list_number_string[20];
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
+ cmark_list_type list_type;
+ const char *roman_numerals[] = {"", "i", "ii", "iii", "iv", "v",
+ "vi", "vii", "viii", "ix", "x"};
+
+ // avoid warning about unused parameter:
+ (void)(options);
+
+ switch (node->type) {
+ case CMARK_NODE_DOCUMENT:
+ break;
+
+ case CMARK_NODE_BLOCK_QUOTE:
+ if (entering) {
+ LIT("\\begin{quote}");
+ CR();
+ } else {
+ LIT("\\end{quote}");
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_LIST:
+ list_type = cmark_node_get_list_type(node);
+ if (entering) {
+ LIT("\\begin{");
+ LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
+ LIT("}");
+ CR();
+ list_number = cmark_node_get_list_start(node);
+ if (list_number > 1) {
+ sprintf(list_number_string, "%d", list_number);
+ LIT("\\setcounter{enum");
+ LIT((char *)roman_numerals[S_get_enumlevel(node)]);
+ LIT("}{");
+ OUT(list_number_string, false, NORMAL);
+ LIT("}");
+ CR();
+ }
+ } else {
+ LIT("\\end{");
+ LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
+ LIT("}");
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_ITEM:
+ if (entering) {
+ LIT("\\item ");
+ } else {
+ CR();
+ }
+ break;
+
+ case CMARK_NODE_HEADER:
+ if (entering) {
+ switch (cmark_node_get_header_level(node)) {
+ case 1:
+ LIT("\\section");
+ break;
+ case 2:
+ LIT("\\subsection");
+ break;
+ case 3:
+ LIT("\\subsubsection");
+ break;
+ case 4:
+ LIT("\\paragraph");
+ break;
+ case 5:
+ LIT("\\subparagraph");
+ break;
+ }
+ LIT("{");
+ } else {
+ LIT("}");
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_CODE_BLOCK:
+ CR();
+ LIT("\\begin{verbatim}");
+ CR();
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ CR();
+ LIT("\\end{verbatim}");
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_HTML:
+ break;
+
+ case CMARK_NODE_HRULE:
+ BLANKLINE();
+ LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}");
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_PARAGRAPH:
+ if (!entering) {
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_TEXT:
+ OUT(cmark_node_get_literal(node), true, NORMAL);
+ break;
+
+ case CMARK_NODE_LINEBREAK:
+ LIT("\\\\");
+ CR();
+ break;
+
+ case CMARK_NODE_SOFTBREAK:
+ if (renderer->width == 0) {
+ CR();
+ } else {
+ OUT(" ", true, NORMAL);
+ }
+ break;
+
+ case CMARK_NODE_CODE:
+ LIT("\\texttt{");
+ OUT(cmark_node_get_literal(node), false, NORMAL);
+ LIT("}");
+ break;
+
+ case CMARK_NODE_INLINE_HTML:
+ break;
+
+ case CMARK_NODE_STRONG:
+ if (entering) {
+ LIT("\\textbf{");
+ } else {
+ LIT("}");
+ }
+ break;
+
+ case CMARK_NODE_EMPH:
+ if (entering) {
+ LIT("\\emph{");
+ } else {
+ LIT("}");
+ }
+ break;
+
+ case CMARK_NODE_LINK:
+ if (entering) {
+ const char *url = cmark_node_get_url(node);
+ // requires \usepackage{hyperref}
+ switch (get_link_type(node)) {
+ case URL_AUTOLINK:
+ LIT("\\url{");
+ OUT(url, false, URL);
+ break;
+ case EMAIL_AUTOLINK:
+ LIT("\\href{");
+ OUT(url, false, URL);
+ LIT("}\\nolinkurl{");
+ break;
+ case NORMAL_LINK:
+ LIT("\\href{");
+ OUT(url, false, URL);
+ LIT("}{");
+ break;
+ case NO_LINK:
+ LIT("{"); // error?
+ }
+ } else {
+ LIT("}");
+ }
+
+ break;
+
+ case CMARK_NODE_IMAGE:
+ if (entering) {
+ LIT("\\protect\\includegraphics{");
+ // requires \include{graphicx}
+ OUT(cmark_node_get_url(node), false, URL);
+ LIT("}");
+ return 0;
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ return 1;
}
-char *cmark_render_latex(cmark_node *root, int options, int width)
-{
- return cmark_render(root, options, width, outc, S_render_node);
+char *cmark_render_latex(cmark_node *root, int options, int width) {
+ return cmark_render(root, options, width, outc, S_render_node);
}