change the external code block formatting option into an actual external code block formatter

This commit is contained in:
david parsons
2022-08-01 13:41:33 -07:00
parent 26ba488a8a
commit 5b6e5b0e07
2 changed files with 126 additions and 76 deletions
+70 -46
View File
@@ -1663,21 +1663,75 @@ printtable(Paragraph *pp, MMIOT *f)
return 1;
}
/* external formatter caller for code blocks
*/
static int
code_callback(Line *t, char *lang, int fenced, Line **ret, MMIOT *f)
{
if ( f->cb->e_codefmt ) {
/* external code block formatter; copy the text into a buffer,
* call the formatter to style it, then dump that styled text
* directly to the queue
*/
char *text;
char *fmt;
int size, copy_p;
Line *p;
for (size=0, p = t; p && (fenced ? p->is_fenced : 1); p = p->next )
size += 1+S(p->text);
text = malloc(1+size);
for ( copy_p = 0; t && (fenced ? t->is_fenced : 1); t = t->next ) {
memcpy(text+copy_p, T(t->text), S(t->text));
copy_p += S(t->text);
text[copy_p++] = '\n';
}
text[copy_p] = 0;
fmt = (*(f->cb->e_codefmt))(text, copy_p, (lang && lang[0]) ? lang : 0);
free(text);
if ( fmt ) {
Qwrite(fmt, strlen(fmt), f);
if ( f->cb->e_free )
(*(f->cb->e_free))(fmt, f->cb->e_data);
*ret = t;
return 1;
}
}
/* either the external formatter failed or doesn't exist,
* so fall back to the traditional codeblock format
*/
*ret = 0;
return 0;
}
static Line *
printfenced(Line *t, MMIOT *f)
{
Line *ret;
Qstring("<pre><code", f);
if ( t->fence_class )
Qprintf(f, " class=\"%s\"", t->fence_class);
Qchar('>', f);
while ( (t = t->next) && t->is_fenced ) {
code(f, T(t->text), S(t->text));
Qchar('\n', f);
if ( !code_callback(t, t->fence_class, 1, &ret, f) ) {
while ( (t = t->next) && t->is_fenced ) {
code(f, T(t->text), S(t->text));
Qchar('\n', f);
}
ret = t;
}
Qstring("</code></pre>\n", f);
return t;
return ret;
}
@@ -1713,6 +1767,7 @@ printblock(Paragraph *pp, MMIOT *f)
} while (t && (t = t->next) );
text(f);
Qstring(End[align], f);
return 1;
}
@@ -1721,42 +1776,8 @@ static void
printcode(Line *t, char *lang, MMIOT *f)
{
int blanks;
Line *ret;
if ( f->cb->e_codefmt ) {
/* external code block formatter; copy the text into a buffer,
* call the formatter to style it, then dump that styled text
* directly to the queue
*/
char *text;
char *fmt;
int size, copy_p;
Line *p;
for (size=0, p = t; p; p = p->next )
size += 1+S(p->text);
text = malloc(1+size);
for ( copy_p = 0; t ; t = t->next ) {
memcpy(text+copy_p, T(t->text), S(t->text));
copy_p += S(t->text);
text[copy_p++] = '\n';
}
text[copy_p] = 0;
fmt = (*(f->cb->e_codefmt))(text, copy_p, (lang && lang[0]) ? lang : 0);
free(text);
if ( fmt ) {
Qwrite(fmt, strlen(fmt), f);
if ( f->cb->e_free )
(*(f->cb->e_free))(fmt, f->cb->e_data);
return;
}
/* otherwise the external formatter failed and we need to
* fall back to the traditional codeblock format
*/
}
Qstring("<pre><code", f);
if (lang && lang[0]) {
@@ -1765,16 +1786,19 @@ printcode(Line *t, char *lang, MMIOT *f)
Qstring("\"", f);
}
Qstring(">", f);
for ( blanks = 0; t ; t = t->next ) {
if ( S(t->text) > t->dle ) {
while ( blanks ) {
if ( !code_callback(t, lang, 0, &ret, f) ) {
for ( blanks = 0; t ; t = t->next ) {
if ( S(t->text) > t->dle ) {
while ( blanks ) {
Qchar('\n', f);
--blanks;
}
code(f, T(t->text), S(t->text));
Qchar('\n', f);
--blanks;
}
code(f, T(t->text), S(t->text));
Qchar('\n', f);
else blanks++;
}
else blanks++;
}
Qstring("</code></pre>", f);
}
+56 -30
View File
@@ -14,6 +14,7 @@
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <unistd.h>
#include "config.h"
#include "amalloc.h"
@@ -97,46 +98,67 @@ free_it(char *object, void *ctx)
free(object);
}
char *external_formatter = 0;
#define RECEIVER 0
#define SENDER 1
char *
external_codefmt(char *src, int len, char *lang)
{
int extra = 0;
int i, x;
int child_status;
int size, bufsize, curr;
char *res;
if ( lang == 0 )
lang = "generic_code";
pid_t child;
for ( i=0; i < len; i++) {
if ( src[i] == '&' )
extra += 5;
else if ( src[i] == '<' || src[i] == '>' )
extra += 4;
int tochild[2], toparent[2];
if ( pipe(tochild) != 0 || pipe(toparent) != 0 ) {
perror("external_codefmt (pipe)");
res = malloc(len+1);
strcpy(res, src);
return res;
}
/* 80 characters for the format wrappers */
if ( (res = malloc(len+extra+80+strlen(lang))) ==0 )
/* out of memory? drat! */
return 0;
if ( (child = fork()) > 0 ) {
sprintf(res, "<pre><code class=\"%s\">\n", lang);
x = strlen(res);
for ( i=0; i < len; i++ ) {
switch (src[i]) {
case '&': strcpy(&src[x], "&amp;");
x += 5 /*strlen(&amp;)*/ ;
break;
case '<': strcpy(&src[x], "&lt;");
x += 4 /*strlen(&lt;)*/ ;
break;
case '>': strcpy(&src[x], "&gt;");
x += 4 /*strlen(&gt;)*/ ;
break;
default: res[x++] = src[i];
break;
close(tochild[RECEIVER]);
close(toparent[SENDER]);
bufsize = 1000;
res = malloc(1+bufsize);
curr = 0;
/* parent */
write(tochild[SENDER], src, len);
close(tochild[SENDER]);
while ( (size = read(toparent[RECEIVER], res+curr, 1000)) > 0 ) {
curr += size;
res = realloc(res, bufsize += 1000);
}
res[curr] = 0;
waitpid(child, &child_status, WNOHANG);
close(toparent[RECEIVER]);
return res;
}
strcpy(&res[x], "</code></pre>\n");
else if ( child == 0 ) {
close(tochild[SENDER]);
close(toparent[RECEIVER]);
close(1); dup2(toparent[SENDER], 1);
close(0); dup2(tochild[RECEIVER], 0);
system(external_formatter);
close(0); close(tochild[RECEIVER]);
close(1); close(toparent[SENDER]);
exit(0);
}
res = malloc(len+1);
strcpy(res, src);
return res;
}
@@ -158,11 +180,12 @@ struct h_opt opts[] = {
{ 0, 0, 'C', "prefix", "prefix for markdown extra footnotes" },
{ 0, 0, 'o', "file", "write output to file" },
{ 0, "squash", 'x', 0, "squash toc labels to be more like github" },
{ 0, "codefmt",'X', 0, "use an external code formatter" },
{ 0, "codefmt",'X', "command", "use an external code formatter" },
{ 0, "help", '?', 0, "print a detailed usage message" },
};
#define NROPTS (sizeof opts/sizeof opts[0])
int
main(int argc, char **argv)
{
@@ -268,6 +291,8 @@ main(int argc, char **argv)
break;
case 'X': use_e_codefmt = 1;
mkd_set_flag_num(flags, MKD_FENCEDCODE);
external_formatter = hoptarg(&blob);
fprintf(stderr, "selected external formatter (%s)\n", external_formatter);
break;
case '?': hoptdescribe(pgm, opts, NROPTS, "[file]", 1);
return 0;
@@ -323,6 +348,7 @@ main(int argc, char **argv)
}
if ( squash )
mkd_e_anchor(doc, (mkd_callback_t) anchor_format);
if ( use_e_codefmt )
mkd_e_code_format(doc, (mkd_callback_t)external_codefmt);