diff options
author | Linnnus <[email protected]> | 2024-03-07 21:30:29 +0100 |
---|---|---|
committer | Linnnus <[email protected]> | 2024-03-07 21:30:29 +0100 |
commit | 7af40dac48281448e000e65918d7aec6bd1aa8dc (patch) | |
tree | 8e25a6b3a574ad371a2d308916e006af2ea7d65d | |
parent | 89be2e2cc472b8b6303e7a3f4350467edd4f70ad (diff) |
feat(creole): Add nowiki blocks
-rw-r--r-- | src/creole.c | 32 | ||||
-rw-r--r-- | src/creole_test_main.c | 23 |
2 files changed, 52 insertions, 3 deletions
diff --git a/src/creole.c b/src/creole.c index 56edbd8..2a16205 100644 --- a/src/creole.c +++ b/src/creole.c @@ -21,10 +21,15 @@ long do_raw_url(const char *begin, const char *end, bool new_block, FILE *out); long do_emphasis(const char *begin, const char *end, bool new_block, FILE *out); long do_bold(const char *begin, const char *end, bool new_block, FILE *out); long do_nowiki_inline(const char *begin, const char *end, bool new_block, FILE *out); +long do_nowiki_block(const char *begin, const char *end, bool new_block, FILE *out); -// Prints string escaped. +// Prints string with special HTML characters escaped. +// +// Unlike many other functions, this function does not assume that (end >= +// begin). This simplifies some logic in callers since bracket-matching is prone +// to off-by-one errors when the brackets are empty. void hprint(FILE *out, const char *begin, const char *end) { - for (const char *p = begin; p != end; p++) { + for (const char *p = begin; p < end; p++) { if (*p == '&') { fputs("&", out); } else if (*p == '"') { @@ -59,6 +64,7 @@ typedef long (* parser_t)(const char *begin, const char *end, bool new_block, FI static parser_t parsers[] = { // Block-level elements do_headers, + do_nowiki_block, do_paragraph, // <p> should be last as it eats anything // Inline-level elements @@ -356,7 +362,7 @@ long do_nowiki_inline(const char *begin, const char *end, bool new_block, FILE * trim_start += 1; } const char *trim_stop = stop; - while (isspace(trim_stop[-1])) { + while (isspace(trim_stop[-1]) && trim_start <= trim_stop - 1) { trim_stop -= 1; } @@ -367,7 +373,27 @@ long do_nowiki_inline(const char *begin, const char *end, bool new_block, FILE * return 3 + (stop - start) + 3; /* {{{...}}} */ } +long do_nowiki_block(const char *begin, const char *end, bool new_block, FILE *out) { + if (!(new_block && starts_with(begin, end, "{{{\n"))) { + return 0; + } + const char *start = begin + 4; + + const char *stop = strnstr(start - 1, "\n}}}", end - (start - 1)); + if (stop == NULL) { + return 0; + } + + fputs("<pre><code>", out); + hprint(out, start, stop); + fputs("</code></pre>", out); + + return -(stop - start + 8); +} + void process(const char *begin, const char *end, bool new_block, FILE *out) { + assert(begin <= end); + const char *p = begin; while (p < end) { // Eat all newlines if we're starting a block. diff --git a/src/creole_test_main.c b/src/creole_test_main.c index 8d531c7..4f71087 100644 --- a/src/creole_test_main.c +++ b/src/creole_test_main.c @@ -223,6 +223,29 @@ struct { .input = "Creole: Inline nowiki with closing braces: {{{if (a>b) { b = a; }}}}.", .output = "<p>Creole: Inline nowiki with closing braces: <tt>if (a>b) { b = a; }</tt>.</p>" }, + { + .name = "Nowiki block", + .input = "Here is some stuff:\n\n{{{\nwad\n}}}", + .output = "<p>Here is some stuff:</p>" + "<pre><code>wad</code></pre>" + }, + { + .name = "Non-closed nowiki block", + .input = "Here is some stuff:\n\n{{{\nwad", + .output = "<p>Here is some stuff:</p>" + "<p>{{{\nwad</p>" + }, + { + .name = "Empty nowiki block", + .input = "{{{\n}}}", + .output = "<pre><code></code></pre>" + }, + { // Spec: In preformatted blocks, since markers must not be preceded by leading spaces, lines with three closing braces + // which belong to the preformatted block must follow at least one space. In the rendered output, one leading space is removed. + .name = "", + .input = "{{{\nif (x != NULL) {\n for (i = 0; i < size; i++) {\n if (x[i] > 0) {\n x[i]--;\n }}}\n}}}\n", + .output = "<pre><code>if (x != NULL) {\n for (i = 0; i < size; i++) {\n if (x[i] > 0) {\n x[i]--;\n }}}</code></pre>", + }, #if 0 { .name = "Simple unordered list", |