-/* $Id: mdoc_markdown.c,v 1.6 2017/03/07 13:28:02 schwarze Exp $ */
+/* $Id: mdoc_markdown.c,v 1.10 2017/03/08 15:08:36 schwarze Exp $ */
/*
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
*
#define ESC_PAR (1 << 3) /* ")" when "(" is open. */
#define ESC_SQU (1 << 4) /* "]" when "[" is open. */
#define ESC_FON (1 << 5) /* "*" immediately after unrelated "*". */
+#define ESC_EOL (1 << 6) /* " " at the and of a line. */
static int code_blocks, quote_blocks, list_blocks;
static int outcount;
static void
md_preword(void)
{
+ const char *cp;
+
/*
* If a list block is nested inside a code block or a blockquote,
* blank lines for paragraph breaks no longer work; instead,
* they terminate the list. Work around this markdown issue
* by using mere line breaks instead.
*/
+
if (list_blocks && outflags & MD_sp) {
outflags &= ~MD_sp;
outflags |= MD_br;
}
- /* End the old line if requested. */
+ /*
+ * End the old line if requested.
+ * Escape whitespace at the end of the markdown line
+ * such that it won't look like an output line break.
+ */
if (outflags & MD_sp)
putchar('\n');
else if (outflags & MD_br) {
putchar(' ');
putchar(' ');
-#ifdef DEBUG
- putchar(':');
- putchar(':');
- putchar(' ');
- putchar(' ');
-#endif
- }
+ } else if (outflags & MD_nl && escflags & ESC_EOL)
+ md_named("zwnj");
/* Start a new line if necessary. */
if (outflags & (MD_nl | MD_br | MD_sp)) {
putchar('\n');
- fputs(md_stack('\0'), stdout);
+ for (cp = md_stack('\0'); *cp != '\0'; cp++) {
+ putchar(*cp);
+ if (*cp == '>')
+ putchar(' ');
+ }
outflags &= ~(MD_nl | MD_br | MD_sp);
escflags = ESC_BOL;
outcount = 0;
{
md_preword();
- if (*s == 0)
+ if (*s == '\0')
return;
if (escflags & ESC_FON) {
}
md_char(*s++);
}
+ if (s[-1] == ' ')
+ escflags |= ESC_EOL;
+ else
+ escflags &= ~ESC_EOL;
}
/*
md_preword();
+ if (*s == '\0')
+ return;
+
/* No spacing after opening delimiters. */
if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
outflags &= ~MD_spc;
if (*currfont != '\0') {
outflags &= ~MD_spc;
md_rawword(currfont);
- }
+ } else if (s[-2] == ' ')
+ escflags |= ESC_EOL;
+ else
+ escflags &= ~ESC_EOL;
}
/*
md_named(const char *s)
{
printf("&%s;", s);
- escflags &= ~ESC_FON;
+ escflags &= ~(ESC_FON | ESC_EOL);
outcount++;
}
static void
md_post_Eo(struct roff_node *n)
{
- int body, tail;
-
if (n->end != ENDBODY_NOT) {
outflags |= MD_spc;
return;
}
- body = n->child != NULL || n->parent->head->child != NULL;
- tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+ if (n->child == NULL && n->parent->head->child == NULL)
+ return;
- if (body && tail)
+ if (n->parent->tail != NULL && n->parent->tail->child != NULL)
outflags &= ~MD_spc;
- else if ( ! (body || tail))
- md_preword();
- else if ( ! tail)
+ else
outflags |= MD_spc;
}
case ROFFT_HEAD:
bln = n->parent->parent;
- if (bln->norm->Bl.comp == 0)
+ if (bln->norm->Bl.comp == 0 &&
+ bln->norm->Bl.type != LIST_column)
outflags |= MD_sp;
outflags |= MD_nl;
printf("%d.\t", ++bln->norm->Bl.count);
escflags &= ~ESC_FON;
break;
+ case LIST_column:
+ outflags |= MD_br;
+ return 0;
default:
return 0;
}