diff -Nru lowdown-1.0.2/LICENSE.md lowdown-1.1.0/LICENSE.md --- lowdown-1.0.2/LICENSE.md 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/LICENSE.md 2023-11-08 01:32:58.000000000 +0000 @@ -1,7 +1,7 @@ Copyright (c) 2008, Natacha Porté Copyright (c) 2011, Vicent Martí Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors -Copyright (c) 2016, Kristaps Dzonsons +Copyright (c) 2016--2023, Kristaps Dzonsons Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice diff -Nru lowdown-1.0.2/Makefile lowdown-1.1.0/Makefile --- lowdown-1.0.2/Makefile 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/Makefile 2023-11-08 01:32:58.000000000 +0000 @@ -3,8 +3,15 @@ include Makefile.configure -VERSION = 1.0.2 -LIBVER = 3 +# Follows semver. +# This is complex because lowdown is both a program and a library; and +# while libraries have well-defined semantics of semver change, programs +# do not. Let the library guide our versioning until a better way is +# thought out. +VERSION = 1.1.0 +# This is the major number of VERSION. It might later become +# MAJOR.MINOR, if the library moves a lot. +LIBVER = 1 OBJS = autolink.o \ buffer.o \ diff.o \ @@ -107,13 +114,17 @@ screen-term.thumb.jpg VALGRINDS != for f in `find regress -name \*.md` ; do echo `dirname $$f`/`basename $$f .md`.valgrind ; done VALGRINDDIFFS != for f in `find regress/diff -name \*.old.md` ; do echo `dirname $$f`/`basename $$f .old.md`.diff-valgrind ; done +# Because the objects will be compiled into a shared library: CFLAGS += -fPIC +# To avoid exporting internal functions (lowdown.h has default visibility). +CFLAGS += -fvisibility=hidden # Only for MarkdownTestv1.0.3 in regress/original. REGRESS_ARGS = "--out-no-smarty" REGRESS_ARGS += "--parse-no-img-ext" REGRESS_ARGS += "--parse-no-metadata" +REGRESS_ARGS += "--parse-super-short" REGRESS_ARGS += "--html-no-head-ids" REGRESS_ARGS += "--html-no-skiphtml" REGRESS_ARGS += "--html-no-escapehtml" @@ -186,6 +197,15 @@ $(CC) -shared -o $@.$(LIBVER) $(OBJS) $(COMPAT_OBJS) $(LDFLAGS) $(LDADD_MD5) -lm -Wl,${LINKER_SONAME},$@.$(LIBVER) $(LDLIBS) ln -sf $@.$(LIBVER) $@ +uninstall: + rm -rf $(SHAREDIR)/lowdown + rm -f $(BINDIR)/lowdown $(BINDIR)/lowdown-diff + for f in $(MAN1S) $(MAN5S) ; do \ + name=`basename $$f .html` ; \ + section=$${name##*.} ; \ + rm -f $(MANDIR)/man$$section/$$name ; \ + done + install: bins mkdir -p $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(MANDIR)/man1 @@ -200,6 +220,15 @@ $(INSTALL_MAN) man/$$name $(DESTDIR)$(MANDIR)/man$$section ; \ done +uninstall_lib_common: + rm -f $(LIBDIR)/pkgconfig/lowdown.pc + rm -f $(INCLUDEDIR)/lowdown.h + for f in $(MAN3S) ; do \ + name=`basename $$f .html` ; \ + section=$${name##*.} ; \ + rm -f $(MANDIR)/man$$section/$$name ; \ + done + install_lib_common: lowdown.pc mkdir -p $(DESTDIR)$(MANDIR)/man3 mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig @@ -212,13 +241,21 @@ $(INSTALL_MAN) man/$$name $(DESTDIR)$(MANDIR)/man$$section ; \ done +uninstall_shared: uninstall_lib_common + rm -f $(LIBDIR)/liblowdown.so.$(LIBVER) $(LIBDIR)/liblowdown.so + install_shared: liblowdown.so install_lib_common $(INSTALL_LIB) liblowdown.so.$(LIBVER) $(DESTDIR)$(LIBDIR) ( cd $(DESTDIR)$(LIBDIR) && ln -sf liblowdown.so.$(LIBVER) liblowdown.so ) +uninstall_static: uninstall_lib_common + rm -f $(LIBDIR)/liblowdown.a + install_static: liblowdown.a install_lib_common $(INSTALL_LIB) liblowdown.a $(DESTDIR)$(LIBDIR) +uninstall_libs: uninstall_shared uninstall_static + install_libs: install_shared install_static distcheck: lowdown.tar.gz.sha512 diff -Nru lowdown-1.0.2/autolink.c lowdown-1.1.0/autolink.c --- lowdown-1.0.2/autolink.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/autolink.c 2023-11-08 01:32:57.000000000 +0000 @@ -1,9 +1,8 @@ -/* $Id$ */ /* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors - * Copyright (c) 2016--2017, 2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/buffer.c lowdown-1.1.0/buffer.c --- lowdown-1.0.2/buffer.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/buffer.c 2023-11-08 01:32:57.000000000 +0000 @@ -1,9 +1,8 @@ -/* $Id$ */ /* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors - * Copyright (c) 2016, 2021, Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/debian/changelog lowdown-1.1.0/debian/changelog --- lowdown-1.0.2/debian/changelog 2023-10-27 14:24:44.000000000 +0000 +++ lowdown-1.1.0/debian/changelog 2023-11-08 06:33:19.000000000 +0000 @@ -1,3 +1,12 @@ +lowdown (1.1.0-1) unstable; urgency=medium + + * New upstream release. + - Drop previously backported upstream patches related to the roff + constant-width problem. + - Drop patch "revet-soname", upstream has now reverted LIBVER to 1. + + -- Faidon Liambotis Wed, 08 Nov 2023 08:33:19 +0200 + lowdown (1.0.2-2) unstable; urgency=medium * Backport upstream commits to address the roff constant-width problem, i.e. diff -Nru lowdown-1.0.2/debian/patches/Attempt-to-solve-the-roff-constant-width-problem.patch lowdown-1.1.0/debian/patches/Attempt-to-solve-the-roff-constant-width-problem.patch --- lowdown-1.0.2/debian/patches/Attempt-to-solve-the-roff-constant-width-problem.patch 2023-10-27 14:24:15.000000000 +0000 +++ lowdown-1.1.0/debian/patches/Attempt-to-solve-the-roff-constant-width-problem.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,379 +0,0 @@ -From 9f3a5d707287c245ec65bd7fc2511612fa457f2e Mon Sep 17 00:00:00 2001 -From: Kristaps Dz -Date: Tue, 12 Sep 2023 12:42:35 -0700 -Subject: [PATCH] Attempt to solve the roff constant-width problem. - -This has been many-times discussed online, e.g.: - -https://github.com/jgm/pandoc/issues/9020 - -The issue at heart is that the "C" font for roff (mandoc, groff, etc.) -is non-standard across output devices. Prior to this change, lowdown -was emitting the "C" font for constant-width fonts (those `in -backticks`). These were being discarded by mandoc and groff when on the -terminal, where "C" is unnecessary because everything is "C". Mandoc -warned about it, but groff just silently let it go by until a recent -version displayed a warning message. - -This introduces some changes. First, "C" is retained by default for --tms, although output as "CR" instead of "C". The rationale is that --ms is mostly used for formatting PDF/PS, which have the "C" font. -Second, "C" is no longer used for -tman: instead, a bold font is used. - -However, the user can override this behaviour. (This will be documented -in subsequent checkins.) The --nroff-code-font (not yet finalised) -accepts a 4-tuple describing the constant width fonts, specifically -"regular,bold,italic,bold-italic". This lets the user override the font -that will be coded into the output. Three aliases exist: "none", -"bold", and "code". "None" does not render a constant-width font at -all, and simply uses the regular font. "Bold" uses a bold font -(obviously if it's a **`situation like this`**, the bold is kept as-is). -Finally, "code" uses the constant-width variants. - -References #123 - -Bug: https://github.com/kristapsdz/lowdown/issues/123 -Origin: upstream, https://github.com/kristapsdz/lowdown/commit/9f3a5d707287c245ec65bd7fc2511612fa457f2e ---- - lowdown.h | 8 +++ - main.c | 59 +++++++++++++++++++++- - nroff.c | 121 ++++++++++++++++++++++++++++++--------------- - regress/simple.man | 2 +- - regress/simple.ms | 2 +- - 5 files changed, 148 insertions(+), 44 deletions(-) - -diff --git a/lowdown.h b/lowdown.h -index d54179d..2bf4b02 100644 ---- a/lowdown.h -+++ b/lowdown.h -@@ -284,10 +284,18 @@ struct lowdown_opts_odt { - const char *sty; - }; - -+struct lowdown_opts_nroff { -+ const char *cr; -+ const char *cb; -+ const char *ci; -+ const char *cbi; -+}; -+ - struct lowdown_opts { - enum lowdown_type type; - union { - struct lowdown_opts_odt odt; -+ struct lowdown_opts_nroff nroff; - }; - size_t maxdepth; - size_t cols; -diff --git a/main.c b/main.c -index 1d192be..ecd99d1 100644 ---- a/main.c -+++ b/main.c -@@ -235,7 +235,8 @@ main(int argc, char *argv[]) - int c, diff = 0, fd, status = 0, afl = 0, - rfl = 0, aifl = 0, rifl = 0, - centre = 0, list = 0; -- char *ret = NULL, *cp, *odtsty = NULL; -+ char *ret = NULL, *cp, *odtsty = NULL, -+ *nroffcodefn = NULL; - size_t i, retsz = 0, rcols, sz; - ssize_t ssz; - struct lowdown_meta *m; -@@ -271,6 +272,7 @@ main(int argc, char *argv[]) - { "nroff-no-shortlinks",no_argument, &rfl, LOWDOWN_NROFF_SHORTLINK }, - { "nroff-skiphtml", no_argument, &afl, LOWDOWN_NROFF_SKIP_HTML }, - { "nroff-no-skiphtml", no_argument, &rfl, LOWDOWN_NROFF_SKIP_HTML }, -+ { "nroff-code-font", required_argument, NULL, 7 }, - - { "odt-skiphtml", no_argument, &afl, LOWDOWN_ODT_SKIP_HTML }, - { "odt-no-skiphtml", no_argument, &rfl, LOWDOWN_ODT_SKIP_HTML }, -@@ -480,6 +482,18 @@ main(int argc, char *argv[]) - case 6: - odtstyfn = optarg; - break; -+ case 7: -+ if (strcmp(optarg, "none") == 0) -+ nroffcodefn = strdup("R,B,I,BI"); -+ else if (strcmp(optarg, "bold") == 0) -+ nroffcodefn = strdup("B,B,BI,BI"); -+ else if (strcmp(optarg, "code") == 0) -+ nroffcodefn = strdup("CR,CB,CI,CBI"); -+ else -+ nroffcodefn = strdup(optarg); -+ if (nroffcodefn == NULL) -+ err(1, NULL); -+ break; - default: - goto usage; - } -@@ -561,6 +575,48 @@ main(int argc, char *argv[]) - opts.odt.sty = odtsty; - } - -+ /* -+ * If specified and in -tman or -tms, parse the "code" font. As -+ * mentioned in nroff.c, the code font "C" is not portable, so -+ * let the user override it. (If in standalone mode, a useful -+ * default will be provided.) This comes as a comma-separated -+ * sequence of R[,B[,I[,BI]]]. Any of these may inherit the -+ * default by being unspecified or empty, e.g., "CR,CB". -+ */ -+ -+ if ((opts.type == LOWDOWN_MAN || opts.type == LOWDOWN_NROFF) && -+ nroffcodefn != NULL && *nroffcodefn != '\0') { -+ opts.nroff.cr = cp = nroffcodefn; -+ while (*cp != '\0' && *cp != ',') -+ cp++; -+ if (*cp != '\0') { -+ *cp++ = '\0'; -+ opts.nroff.cb = cp; -+ while (*cp != '\0' && *cp != ',') -+ cp++; -+ if (*cp != '\0') { -+ *cp++ = '\0'; -+ opts.nroff.ci = cp; -+ while (*cp != '\0' && *cp != ',') -+ cp++; -+ if (*cp != '\0') { -+ *cp++ = '\0'; -+ opts.nroff.cbi = cp; -+ while (*cp != '\0' && *cp != ',') -+ cp++; -+ } -+ } -+ } -+ if (opts.nroff.cr != NULL && *opts.nroff.cr == '\0') -+ opts.nroff.cr = NULL; -+ if (opts.nroff.cb != NULL && *opts.nroff.cb == '\0') -+ opts.nroff.cb = NULL; -+ if (opts.nroff.ci != NULL && *opts.nroff.ci == '\0') -+ opts.nroff.ci = NULL; -+ if (opts.nroff.cbi != NULL && *opts.nroff.cbi == '\0') -+ opts.nroff.cbi = NULL; -+ } -+ - /* Configure the output file. */ - - if (fnout != NULL && strcmp(fnout, "-") && -@@ -616,6 +672,7 @@ main(int argc, char *argv[]) - - free(ret); - free(odtsty); -+ free(nroffcodefn); - - if (fout != stdout) - fclose(fout); -diff --git a/nroff.c b/nroff.c -index 118a981..aee5fa0 100644 ---- a/nroff.c -+++ b/nroff.c -@@ -50,6 +50,10 @@ struct nroff { - struct bnodeq **foots; /* footnotes */ - size_t footsz; /* footnote size */ - size_t indent; /* indentation width */ -+ const char *cr; /* fixed-width font */ -+ const char *cb; /* fixed-width bold font */ -+ const char *ci; /* fixed-width italic font */ -+ const char *cbi; /* fixed-width bold-italic font */ - }; - - enum bscope { -@@ -205,41 +209,47 @@ nstate_colour_buf(unsigned int ft) - * For compatibility with traditional troff, return non-block font code - * using the correct sequence of \fX, \f(xx, and \f[xxx]. - */ --static const char * --nstate_font_buf(unsigned int ft, int blk) -+static int -+nstate_font(const struct nroff *st, struct lowdown_buf *ob, -+ unsigned int ft, int enclose) - { -- static char fonts[10]; -+ const char *font = NULL; -+ char fonts[3]; - char *cp = fonts; -- size_t len = 0; -- -- if (ft & BFONT_FIXED) -- len++; -- if (ft & BFONT_BOLD) -- len++; -- if (ft & BFONT_ITALIC) -- len++; -- if (ft == 0) -- len++; -- -- if (!blk && len == 3) -- (*cp++) = '['; -- else if (!blk && len == 2) -- (*cp++) = '('; -- -- if (ft & BFONT_FIXED) -- (*cp++) = 'C'; -- if (ft & BFONT_BOLD) -- (*cp++) = 'B'; -- if (ft & BFONT_ITALIC) -- (*cp++) = 'I'; -- if (ft == 0) -- (*cp++) = 'R'; -- -- if (!blk && len == 3) -- (*cp++) = ']'; -- -- (*cp++) = '\0'; -- return fonts; -+ size_t sz; -+ -+ if (ft & BFONT_FIXED) { -+ if ((ft & BFONT_BOLD) && (ft & BFONT_ITALIC)) -+ font = st->cbi; -+ else if (ft & BFONT_BOLD) -+ font = st->cb; -+ else if (ft & BFONT_ITALIC) -+ font = st->ci; -+ else -+ font = st->cr; -+ } else { -+ font = cp = fonts; -+ if (ft & BFONT_BOLD) -+ (*cp++) = 'B'; -+ if (ft & BFONT_ITALIC) -+ (*cp++) = 'I'; -+ if (ft == 0) -+ (*cp++) = 'R'; -+ *cp = '\0'; -+ } -+ -+ assert(font != NULL); -+ sz = strlen(font); -+ assert(sz > 0); -+ -+ if (!enclose || sz == 1) -+ return hbuf_puts(ob, font); -+ -+ if (sz > 2) -+ return HBUF_PUTSL(ob, "[") && -+ hbuf_puts(ob, font) && HBUF_PUTSL(ob, "]"); -+ -+ return HBUF_PUTSL(ob, "(") && hbuf_puts(ob, font); - } - - static int -@@ -354,7 +364,8 @@ bqueue_strip_paras(struct bnodeq *bq) - } - - static int --bqueue_flush(struct lowdown_buf *ob, const struct bnodeq *bq, int esc) -+bqueue_flush(const struct nroff *st, struct lowdown_buf *ob, -+ const struct bnodeq *bq, int esc) - { - const struct bnode *bn, *chk, *next; - const char *cp; -@@ -411,12 +422,14 @@ bqueue_flush(struct lowdown_buf *ob, const struct bnodeq *bq, int esc) - /* Print font and colour escapes. */ - - if (bn->scope == BSCOPE_FONT && nextblk) { -- if (!hbuf_printf(ob, ".ft %s", -- nstate_font_buf(bn->font, nextblk))) -+ if (!HBUF_PUTSL(ob, ".ft ")) -+ return 0; -+ if (!nstate_font(st, ob, bn->font, 0)) - return 0; - } else if (bn->scope == BSCOPE_FONT) { -- if (!hbuf_printf(ob, "\\f%s", -- nstate_font_buf(bn->font, nextblk))) -+ if (!HBUF_PUTSL(ob, "\\f")) -+ return 0; -+ if (!nstate_font(st, ob, bn->font, 1)) - return 0; - } else if (bn->scope == BSCOPE_COLOUR) { - assert(nextblk); -@@ -649,7 +662,7 @@ putlink(struct bnodeq *obq, struct nroff *st, - goto out; - if (bq == NULL && !hbuf_putb(ob, link)) - goto out; -- else if (bq != NULL && !bqueue_flush(ob, bq, 1)) -+ else if (bq != NULL && !bqueue_flush(st, ob, bq, 1)) - goto out; - - /* -@@ -1525,7 +1538,7 @@ rndr_meta(struct nroff *st, const struct bnodeq *bq, - - if ((ob = hbuf_new(32)) == NULL) - return 0; -- if (!bqueue_flush(ob, bq, 1)) { -+ if (!bqueue_flush(st, ob, bq, 1)) { - hbuf_free(ob); - return 0; - } -@@ -1929,7 +1942,7 @@ lowdown_nroff_rndr(struct lowdown_buf *ob, - st->post_para = 0; - - if (rndr(&metaq, st, n, &bq)) { -- if (!bqueue_flush(ob, &bq, 1)) -+ if (!bqueue_flush(st, ob, &bq, 1)) - goto out; - if (ob->size && ob->data[ob->size - 1] != '\n' && - !hbuf_putc(ob, '\n')) -@@ -1963,6 +1976,32 @@ lowdown_nroff_new(const struct lowdown_opts *opts) - p->flags = opts != NULL ? opts->oflags : 0; - p->man = opts != NULL && opts->type == LOWDOWN_MAN; - -+ p->cr = opts != NULL ? opts->nroff.cr : NULL; -+ p->cb = opts != NULL ? opts->nroff.cb : NULL; -+ p->ci = opts != NULL ? opts->nroff.ci : NULL; -+ p->cbi = opts != NULL ? opts->nroff.cbi : NULL; -+ -+ /* -+ * Set the default "code" (fixed-width) fonts. This is complicated -+ * because the "C" fixed-with font is not universally available on all -+ * output media. For example, -Tascii does not carry a "C" font. The -+ * standalone prologue can test whether the font exists, but if we're -+ * not in standalone mode, we need to do someting if the value was not -+ * given. Thus, use bold for -Tman and the fixed-width for -Tms. My -+ * rationale is that -Tman is usually seen in the terminal, which will -+ * either be -Tasci or -Tutf8; while -Tms is usually pushed into PDF/PS, -+ * both of which we have fixed width fonts. -+ */ -+ -+ if (p->cr == NULL) -+ p->cr = p->man ? "B" : "CR"; -+ if (p->cb == NULL) -+ p->cb = p->man ? "B" : "CB"; -+ if (p->ci == NULL) -+ p->ci = p->man ? "BI" : "CI"; -+ if (p->cbi == NULL) -+ p->cbi = p->man ? "BI" : "CBI"; -+ - /* - * Set a default indentation. For -man, we use 3 because we - * want to be efficient with page width. For -ms, use 5 because -diff --git a/regress/simple.man b/regress/simple.man -index d656916..329f7a4 100644 ---- a/regress/simple.man -+++ b/regress/simple.man -@@ -3,7 +3,7 @@ An h1 header - .LP - Paragraphs are separated by a blank line. - .PP --2nd paragraph. \fIItalic\fR, \fBbold\fR, and \fCmonospace\fR. Itemized lists -+2nd paragraph. \fIItalic\fR, \fBbold\fR, and \fBmonospace\fR. Itemized lists - look like: - .IP "\(bu" 3 - this one -diff --git a/regress/simple.ms b/regress/simple.ms -index e8dbb6a..625afc0 100644 ---- a/regress/simple.ms -+++ b/regress/simple.ms -@@ -5,7 +5,7 @@ An h1 header - .LP - Paragraphs are separated by a blank line. - .PP --2nd paragraph. \fIItalic\fR, \fBbold\fR, and \fCmonospace\fR. Itemized lists -+2nd paragraph. \fIItalic\fR, \fBbold\fR, and \f(CRmonospace\fR. Itemized lists - look like: - .IP "\(bu" 5 - this one --- -2.42.0 - diff -Nru lowdown-1.0.2/debian/patches/Default-to-using-CR-unilaterally.patch lowdown-1.1.0/debian/patches/Default-to-using-CR-unilaterally.patch --- lowdown-1.0.2/debian/patches/Default-to-using-CR-unilaterally.patch 2023-10-27 14:24:34.000000000 +0000 +++ lowdown-1.1.0/debian/patches/Default-to-using-CR-unilaterally.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -From 03cab9b8588184f47382cb501e7163cf4607c7ce Mon Sep 17 00:00:00 2001 -From: Kristaps Dz -Date: Wed, 13 Sep 2023 22:51:50 -0700 -Subject: [PATCH] Default to using "CR" unilaterally. - -Like pandoc, use the "C" family of fonts by default, with "CR" for -the roman font. This followed pandoc's usage. - -References #123 - -Bug: https://github.com/kristapsdz/lowdown/issues/123 -Origin: upstream, https://github.com/kristapsdz/lowdown/commit/03cab9b8588184f47382cb501e7163cf4607c7ce ---- - main.c | 16 ++++++++++------ - nroff.c | 22 ++++++++-------------- - regress/simple.man | 2 +- - 3 files changed, 19 insertions(+), 21 deletions(-) - -diff --git a/main.c b/main.c -index ecd99d1..473eb1c 100644 ---- a/main.c -+++ b/main.c -@@ -483,6 +483,10 @@ main(int argc, char *argv[]) - odtstyfn = optarg; - break; - case 7: -+ /* -+ * Break down some aliases here: "none", "bold", -+ * or "code". -+ */ - if (strcmp(optarg, "none") == 0) - nroffcodefn = strdup("R,B,I,BI"); - else if (strcmp(optarg, "bold") == 0) -@@ -576,12 +580,12 @@ main(int argc, char *argv[]) - } - - /* -- * If specified and in -tman or -tms, parse the "code" font. As -- * mentioned in nroff.c, the code font "C" is not portable, so -- * let the user override it. (If in standalone mode, a useful -- * default will be provided.) This comes as a comma-separated -- * sequence of R[,B[,I[,BI]]]. Any of these may inherit the -- * default by being unspecified or empty, e.g., "CR,CB". -+ * If specified and in -tman or -tms, parse the constant width -+ * fonts. As mentioned in nroff.c, the code font "C" is not -+ * portable, so let the user override it. This comes as a -+ * comma-separated sequence of R[,B[,I[,BI]]]. Any of these may -+ * inherit the default by being unspecified or empty, e.g., -+ * "CR,CB". - */ - - if ((opts.type == LOWDOWN_MAN || opts.type == LOWDOWN_NROFF) && -diff --git a/nroff.c b/nroff.c -index aee5fa0..4a6bdaf 100644 ---- a/nroff.c -+++ b/nroff.c -@@ -1975,32 +1975,26 @@ lowdown_nroff_new(const struct lowdown_opts *opts) - - p->flags = opts != NULL ? opts->oflags : 0; - p->man = opts != NULL && opts->type == LOWDOWN_MAN; -- - p->cr = opts != NULL ? opts->nroff.cr : NULL; - p->cb = opts != NULL ? opts->nroff.cb : NULL; - p->ci = opts != NULL ? opts->nroff.ci : NULL; - p->cbi = opts != NULL ? opts->nroff.cbi : NULL; - - /* -- * Set the default "code" (fixed-width) fonts. This is complicated -- * because the "C" fixed-with font is not universally available on all -- * output media. For example, -Tascii does not carry a "C" font. The -- * standalone prologue can test whether the font exists, but if we're -- * not in standalone mode, we need to do someting if the value was not -- * given. Thus, use bold for -Tman and the fixed-width for -Tms. My -- * rationale is that -Tman is usually seen in the terminal, which will -- * either be -Tasci or -Tutf8; while -Tms is usually pushed into PDF/PS, -- * both of which we have fixed width fonts. -+ * Set the default "constant width" fonts. This is complicated -+ * because the "C" fixed-with font is not universally available -+ * on all output media. For example, -Tascii does not carry a -+ * "C" font. However, this is a good enough default. - */ - - if (p->cr == NULL) -- p->cr = p->man ? "B" : "CR"; -+ p->cr = "CR"; - if (p->cb == NULL) -- p->cb = p->man ? "B" : "CB"; -+ p->cb = "CB"; - if (p->ci == NULL) -- p->ci = p->man ? "BI" : "CI"; -+ p->ci = "CI"; - if (p->cbi == NULL) -- p->cbi = p->man ? "BI" : "CBI"; -+ p->cbi = "CBI"; - - /* - * Set a default indentation. For -man, we use 3 because we -diff --git a/regress/simple.man b/regress/simple.man -index 329f7a4..0c356e0 100644 ---- a/regress/simple.man -+++ b/regress/simple.man -@@ -3,7 +3,7 @@ An h1 header - .LP - Paragraphs are separated by a blank line. - .PP --2nd paragraph. \fIItalic\fR, \fBbold\fR, and \fBmonospace\fR. Itemized lists -+2nd paragraph. \fIItalic\fR, \fBbold\fR, and \f(CRmonospace\fR. Itemized lists - look like: - .IP "\(bu" 3 - this one --- -2.42.0 - diff -Nru lowdown-1.0.2/debian/patches/revert-soname.patch lowdown-1.1.0/debian/patches/revert-soname.patch --- lowdown-1.0.2/debian/patches/revert-soname.patch 2023-07-10 14:46:19.000000000 +0000 +++ lowdown-1.1.0/debian/patches/revert-soname.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Description: Revert SONAME to liblowdown.so.1 - The ABI is compatible, so do not force an unnecessary library transition. -Forwarded: https://github.com/kristapsdz/lowdown/issues/121 -Author: Faidon Liambotis -Last-Update: 2023-07-10 - ---- a/Makefile -+++ b/Makefile -@@ -4,7 +4,7 @@ - include Makefile.configure - - VERSION = 1.0.2 --LIBVER = 3 -+LIBVER = 1 - OBJS = autolink.o \ - buffer.o \ - diff.o \ diff -Nru lowdown-1.0.2/debian/patches/series lowdown-1.1.0/debian/patches/series --- lowdown-1.0.2/debian/patches/series 2023-10-27 14:21:48.000000000 +0000 +++ lowdown-1.1.0/debian/patches/series 2023-11-08 06:23:19.000000000 +0000 @@ -1,4 +1 @@ -revert-soname.patch pkg-config-libmd-libbsd.patch -Attempt-to-solve-the-roff-constant-width-problem.patch -Default-to-using-CR-unilaterally.patch diff -Nru lowdown-1.0.2/diff.c lowdown-1.1.0/diff.c --- lowdown-1.0.2/diff.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/diff.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2017--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/document.c lowdown-1.1.0/document.c --- lowdown-1.0.2/document.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/document.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,9 +1,8 @@ -/* $Id$ */ /* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors - * Copyright (c) 2016--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -113,6 +112,7 @@ static ssize_t char_image(struct lowdown_doc *, char *, size_t, size_t); static ssize_t char_superscript(struct lowdown_doc *, char *, size_t, size_t); static ssize_t char_math(struct lowdown_doc *, char *, size_t, size_t); +static ssize_t char_subscript(struct lowdown_doc *, char *, size_t, size_t); enum markdown_char_t { MD_CHAR_NONE = 0, @@ -128,6 +128,7 @@ MD_CHAR_AUTOLINK_EMAIL, MD_CHAR_AUTOLINK_WWW, MD_CHAR_SUPERSCRIPT, + MD_CHAR_SUBSCRIPT, MD_CHAR_QUOTE, MD_CHAR_MATH }; @@ -146,6 +147,7 @@ &char_autolink_email, &char_autolink_www, &char_superscript, + &char_subscript, NULL, &char_math }; @@ -1028,8 +1030,6 @@ /* * Spacing cannot follow an opening emphasis: strikethrough and * highlight only takes '~~'. - * FIXME: don't depend upon the "ret =" as the last part of an - * "or" chain---it's hard to read. */ if (size > 2 && data[1] != c) { @@ -2117,36 +2117,84 @@ return ret > 0 ? (ssize_t)i : ret; } +/* + * Parsing a superscript or subscript. + */ static ssize_t -char_superscript(struct lowdown_doc *doc, - char *data, size_t offset, size_t size) +char_supsubscript(struct lowdown_doc *doc, char *data, size_t offset, + size_t size, char token) { - size_t sup_start, sup_len; - struct lowdown_node *n; + size_t sup_start, sup_len, end; + struct lowdown_node *n; + + assert(token == '^' || token == '~'); if (size < 2) return 0; - if (data[1] == '(') { + /* + * The traditional syntax for superscripts is incompatible with + * pandoc's (from GFM). Calling the traditional syntax "short": + * first check if not using that, then fall back on the + * traditional syntaxes. + */ + + if (!(doc->ext_flags & LOWDOWN_SUPER_SHORT)) { + sup_start = sup_len = 1; + while (sup_len < size && data[sup_len] != token) + if (xisspace(data[sup_len++])) + return 0; + + /* + * FIXME: a standalone "~~" results in noting at all + * being printed instead of the ~~. + */ + if (sup_len == size) + return 0; + end = sup_len + 1; + if (sup_len - sup_start == 0) + return 2; + } else if (data[1] == '(') { sup_start = 2; sup_len = find_emph_char(data + 2, size - 2, ')') + 2; if (sup_len == size) return 0; + end = sup_len + 1; + if (sup_len - sup_start == 0) + return 3; } else { sup_start = sup_len = 1; while (sup_len < size && !xisspace(data[sup_len])) sup_len++; + end = sup_len; + if (sup_len - sup_start == 0) + return 0; } - if (sup_len - sup_start == 0) - return (sup_start == 2) ? 3 : 0; - - if ((n = pushnode(doc, LOWDOWN_SUPERSCRIPT)) == NULL) + if ((n = pushnode(doc, token == '^' ? + LOWDOWN_SUPERSCRIPT : LOWDOWN_SUBSCRIPT)) == NULL) return -1; if (!parse_inline(doc, data + sup_start, sup_len - sup_start)) return -1; popnode(doc, n); - return (sup_start == 2) ? sup_len + 1 : sup_len; + return end; +} + +static ssize_t +char_superscript(struct lowdown_doc *doc, char *data, size_t offset, + size_t size) +{ + return char_supsubscript(doc, data, offset, size, '^'); +} + +static ssize_t +char_subscript(struct lowdown_doc *doc, char *data, size_t offset, + size_t size) +{ + if ((doc->ext_flags & LOWDOWN_STRIKE) && size > 0 && + data[1] == '~') + return char_emphasis(doc, data, offset, size); + return char_supsubscript(doc, data, offset, size, '~'); } static ssize_t @@ -2519,7 +2567,7 @@ { size_t beg = 0, end = 0, pre, work_size = 0; char *work_data = NULL; - struct lowdown_node *n; + struct lowdown_node *n, *nn, *nnn; while (beg < size) { for (end = beg + 1; @@ -2556,6 +2604,59 @@ if (!parse_block(doc, work_data, work_size)) return -1; popnode(doc, n); + + if (!(doc->ext_flags & LOWDOWN_CALLOUTS)) + return end; + + /* + * See if we're a GitHub or MDN admonition. Begin by seeing if + * the first node is a paragraph containing an initial double + * emphasis with a specific word therein. + */ + + if (TAILQ_EMPTY(&n->children)) + return end; + nn = TAILQ_FIRST(&n->children); + if (nn->type != LOWDOWN_PARAGRAPH || + (nn = TAILQ_FIRST(&nn->children)) == NULL) + return end; + if (nn->type != LOWDOWN_DOUBLE_EMPHASIS || + (nnn = TAILQ_FIRST(&nn->children)) == NULL) + return end; + if (nnn->type != LOWDOWN_NORMAL_TEXT || + TAILQ_NEXT(nnn, entries) != NULL) + return end; + + /* + * GitHub uses the term on its own, while MDN uses the word, a + * colon, and more text afterward. Accept both. (GitHub + * doesn't support a "callout" admonition.) + */ + + if (hbuf_streq(&nnn->rndr_normal_text.text, "Note")) + n->rndr_blockquote.admonition = ADMONITION_NOTE; + else if (hbuf_streq(&nnn->rndr_normal_text.text, "Note:")) + n->rndr_blockquote.admonition = ADMONITION_NOTE; + else if (hbuf_streq(&nnn->rndr_normal_text.text, "Callout:")) + n->rndr_blockquote.admonition = ADMONITION_CALLOUT; + else if (hbuf_streq(&nnn->rndr_normal_text.text, "Warning")) + n->rndr_blockquote.admonition = ADMONITION_WARNING; + else if (hbuf_streq(&nnn->rndr_normal_text.text, "Warning:")) + n->rndr_blockquote.admonition = ADMONITION_WARNING; + else + return end; + n->rndr_blockquote.type = BLOCKQUOTE_ADMONITION_BLOCK; + + /* If the starting is just its own paragraph, done. */ + + if ((nn = TAILQ_NEXT(nn, entries)) == NULL) + return end; + + /* ...or on its own line. */ + + if (nn->type == LOWDOWN_NORMAL_TEXT && + hbuf_strprefix(&nn->rndr_normal_text.text, "\n")) + n->rndr_blockquote.type = BLOCKQUOTE_ADMONITION; return end; } @@ -4349,19 +4450,17 @@ lowdown_doc_new(const struct lowdown_opts *opts) { struct lowdown_doc *doc; - unsigned int extensions = opts ? opts->feat : 0; size_t i; doc = calloc(1, sizeof(struct lowdown_doc)); if (doc == NULL) return NULL; + doc->ext_flags = opts == NULL ? 0 : opts->feat; doc->maxdepth = opts == NULL ? 128 : opts->maxdepth; doc->active_char['*'] = MD_CHAR_EMPHASIS; doc->active_char['_'] = MD_CHAR_EMPHASIS; - if (extensions & LOWDOWN_STRIKE) - doc->active_char['~'] = MD_CHAR_EMPHASIS; - if (extensions & LOWDOWN_HILITE) + if (doc->ext_flags & LOWDOWN_HILITE) doc->active_char['='] = MD_CHAR_EMPHASIS; doc->active_char['`'] = MD_CHAR_CODESPAN; doc->active_char['\n'] = MD_CHAR_LINEBREAK; @@ -4370,18 +4469,19 @@ doc->active_char['<'] = MD_CHAR_LANGLE; doc->active_char['\\'] = MD_CHAR_ESCAPE; doc->active_char['&'] = MD_CHAR_ENTITY; - if (extensions & LOWDOWN_AUTOLINK) { + if (doc->ext_flags & LOWDOWN_AUTOLINK) { doc->active_char[':'] = MD_CHAR_AUTOLINK_URL; doc->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; doc->active_char['w'] = MD_CHAR_AUTOLINK_WWW; } - if (extensions & LOWDOWN_SUPER) + if (doc->ext_flags & LOWDOWN_SUPER) { doc->active_char['^'] = MD_CHAR_SUPERSCRIPT; - if (extensions & LOWDOWN_MATH) + doc->active_char['~'] = MD_CHAR_SUBSCRIPT; + } else if (doc->ext_flags & LOWDOWN_STRIKE) + doc->active_char['~'] = MD_CHAR_EMPHASIS; + if (doc->ext_flags & LOWDOWN_MATH) doc->active_char['$'] = MD_CHAR_MATH; - doc->ext_flags = extensions; - if (opts != NULL && opts->metasz > 0) { doc->meta = calloc(opts->metasz, sizeof(char *)); if (doc->meta == NULL) diff -Nru lowdown-1.0.2/entity.c lowdown-1.1.0/entity.c --- lowdown-1.0.2/entity.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/entity.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2020, Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/extern.h lowdown-1.1.0/extern.h --- lowdown-1.0.2/extern.h 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/extern.h 2023-11-08 01:32:57.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2016--2020 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/gemini.c lowdown-1.1.0/gemini.c --- lowdown-1.0.2/gemini.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/gemini.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2020--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -608,7 +607,7 @@ rndr(struct lowdown_buf *ob, struct lowdown_metaq *mq, struct gemini *st, const struct lowdown_node *n) { - const struct lowdown_node *child, *prev; + const struct lowdown_node *child, *prev, *nn; struct link *l; void *pp; struct lowdown_buf *tmpbuf; @@ -678,13 +677,31 @@ break; case LOWDOWN_DEFINITION_TITLE: case LOWDOWN_HRULE: - case LOWDOWN_LINEBREAK: case LOWDOWN_LISTITEM: case LOWDOWN_META: case LOWDOWN_TABLE_ROW: if (!rndr_buf_vspace(st, ob, 1)) return 0; break; + case LOWDOWN_LINEBREAK: + if (!rndr_buf_vspace(st, ob, 1)) + return 0; + + /* + * A linebreak is special if invoked within a + * blockquote, because it means we want to output a + * newline but also continue outputting the blockquote + * marker. + */ + + for (nn = n->parent; nn != NULL; nn = nn->parent) + if (nn->type == LOWDOWN_BLOCKQUOTE) { + if (!HBUF_PUTSL(ob, "> ")) + return 0; + st->last_blank = 0; + break; + } + break; case LOWDOWN_IMAGE: case LOWDOWN_LINK: case LOWDOWN_LINK_AUTO: @@ -704,7 +721,7 @@ case LOWDOWN_TABLE_BLOCK: case LOWDOWN_BLOCKCODE: case LOWDOWN_BLOCKHTML: - if (!HBUF_PUTSL(st->tmp, "```")) + if (!HBUF_PUTSL(st->tmp, "```\n")) return 0; if (!rndr_buf(st, ob, n, st->tmp)) return 0; @@ -774,10 +791,14 @@ return 0; st->last_blank = -1; break; - case LOWDOWN_SUPERSCRIPT: - if (!HBUF_PUTSL(st->tmp, "^")) + case LOWDOWN_SUBSCRIPT: + if (!HBUF_PUTSL(st->tmp, "~") || + !rndr_buf(st, ob, n, st->tmp)) return 0; - if (!rndr_buf(st, ob, n, st->tmp)) + break; + case LOWDOWN_SUPERSCRIPT: + if (!HBUF_PUTSL(st->tmp, "^") || + !rndr_buf(st, ob, n, st->tmp)) return 0; break; default: diff -Nru lowdown-1.0.2/html.c lowdown-1.1.0/html.c --- lowdown-1.0.2/html.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/html.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,9 +1,8 @@ -/* $Id$ */ /* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors - * Copyright (c) 2016--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -230,17 +229,65 @@ } static int -rndr_blockquote(struct lowdown_buf *ob, - const struct lowdown_buf *content) +rndr_blockquote(const struct html *st, + const struct rndr_blockquote *param, + struct lowdown_buf *ob, const struct lowdown_buf *content) { + size_t i; if (!newline(ob)) return 0; - if (!HBUF_PUTSL(ob, "
\n")) + if (param->type == BLOCKQUOTE_REGULAR || !(st->flags & + (LOWDOWN_HTML_CALLOUT_GFM|LOWDOWN_HTML_CALLOUT_MDN))) + return HBUF_PUTSL(ob, "
\n") && + hbuf_putb(ob, content) && + HBUF_PUTSL(ob, "
\n"); + + if (!HBUF_PUTSL(ob, "
flags & LOWDOWN_HTML_CALLOUT_MDN) { + if (!hbuf_printf(ob, "%s", + (param->admonition == ADMONITION_NOTE) ? + "notecard note" : + (param->admonition == ADMONITION_WARNING) ? + "notecard warning" : "callout")) + return 0; + } + if (st->flags & LOWDOWN_HTML_CALLOUT_GFM) { + if (!hbuf_printf(ob, "%smarkdown-alert ", + (st->flags & LOWDOWN_HTML_CALLOUT_MDN) ? " " : "")) + return 0; + if (!hbuf_printf(ob, "markdown-alert-%s", + (param->admonition == ADMONITION_NOTE) ? + "note" : + (param->admonition == ADMONITION_WARNING) ? + "warning" : "callout")) + return 0; + } + + if (!HBUF_PUTSL(ob, "\">\n")) return 0; - if (!hbuf_putb(ob, content)) + + /* + * Weird: content callouts have their initial callout type + * removed. Fortunately, this is hard-coded, so we know its + * exact length. Remove the callout type and any extra spacing + * that follows it. + */ + + if (param->admonition == ADMONITION_CALLOUT && content->size > 28) { + i = 28; + while (i < content->size && content->data[i] == ' ') + i++; + if (!HBUF_PUTSL(ob, "

") || + !hbuf_put(ob, content->data + i, content->size - i)) + return 0; + } else if (!hbuf_putb(ob, content)) return 0; - return HBUF_PUTSL(ob, "

\n"); + return HBUF_PUTSL(ob, "\n"); } static int @@ -801,14 +848,15 @@ static int rndr_superscript(struct lowdown_buf *ob, - const struct lowdown_buf *content) + const struct lowdown_buf *content, enum lowdown_rndrt type) { + const char *elem; - if (!HBUF_PUTSL(ob, "")) - return 0; - if (!hbuf_putb(ob, content)) - return 0; - return HBUF_PUTSL(ob, ""); + elem = (type == LOWDOWN_SUPERSCRIPT) ? "sup" : "sub"; + + return hbuf_printf(ob, "<%s>", elem) && + hbuf_putb(ob, content) && + hbuf_printf(ob, "", elem); } static int @@ -1212,14 +1260,12 @@ } static int -rndr(struct lowdown_buf *ob, - struct lowdown_metaq *mq, void *ref, +rndr(struct lowdown_buf *ob, struct lowdown_metaq *mq, struct html *st, const struct lowdown_node *n) { const struct lowdown_node *child; struct lowdown_buf *tmp; int32_t ent; - struct html *st = ref; int ret = 1, rc = 1; if ((tmp = hbuf_new(64)) == NULL) @@ -1259,7 +1305,7 @@ rc = rndr_blockcode(ob, &n->rndr_blockcode, st); break; case LOWDOWN_BLOCKQUOTE: - rc = rndr_blockquote(ob, tmp); + rc = rndr_blockquote(st, &n->rndr_blockquote, ob, tmp); break; case LOWDOWN_DEFINITION: rc = rndr_definition(ob, tmp); @@ -1342,7 +1388,10 @@ rc = rndr_strikethrough(ob, tmp); break; case LOWDOWN_SUPERSCRIPT: - rc = rndr_superscript(ob, tmp); + rc = rndr_superscript(ob, tmp, n->type); + break; + case LOWDOWN_SUBSCRIPT: + rc = rndr_superscript(ob, tmp, n->type); break; case LOWDOWN_FOOTNOTE: rc = rndr_footnote_ref(ob, tmp, st); diff -Nru lowdown-1.0.2/html_escape.c lowdown-1.1.0/html_escape.c --- lowdown-1.0.2/html_escape.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/html_escape.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,9 +1,8 @@ -/* $Id$ */ /* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors - * Copyright (c) 2016--2017, 2020 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/latex.c lowdown-1.1.0/latex.c --- lowdown-1.0.2/latex.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/latex.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2020--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -645,14 +644,16 @@ static int rndr_superscript(struct lowdown_buf *ob, - const struct lowdown_buf *content) + const struct lowdown_buf *content, + enum lowdown_rndrt type) { + const char *elem; - if (!HBUF_PUTSL(ob, "\\textsuperscript{")) - return 0; - if (!hbuf_putb(ob, content)) - return 0; - return HBUF_PUTSL(ob, "}"); + elem = (type == LOWDOWN_SUPERSCRIPT) ? "super" : "sub"; + + return hbuf_printf(ob, "\\text%sscript{", elem) && + hbuf_putb(ob, content) && + HBUF_PUTSL(ob, "}"); } static int @@ -963,8 +964,12 @@ if (!rndr_triple_emphasis(ob, tmp)) return 0; break; + case LOWDOWN_SUBSCRIPT: + if (!rndr_superscript(ob, tmp, n->type)) + return 0; + break; case LOWDOWN_SUPERSCRIPT: - if (!rndr_superscript(ob, tmp)) + if (!rndr_superscript(ob, tmp, n->type)) return 0; break; case LOWDOWN_FOOTNOTE: diff -Nru lowdown-1.0.2/libdiff.c lowdown-1.1.0/libdiff.c --- lowdown-1.0.2/libdiff.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/libdiff.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 2013 Tatsuhiko Kubo - * Copyright (c) 2018 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff -Nru lowdown-1.0.2/libdiff.h lowdown-1.1.0/libdiff.h --- lowdown-1.0.2/libdiff.h 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/libdiff.h 2023-11-08 01:32:57.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 2013 Tatsuhiko Kubo - * Copyright (c) 2018 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff -Nru lowdown-1.0.2/library.c lowdown-1.1.0/library.c --- lowdown-1.0.2/library.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/library.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2017--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/lowdown.h lowdown-1.1.0/lowdown.h --- lowdown-1.0.2/lowdown.h 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/lowdown.h 2023-11-08 01:32:57.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2017--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,6 +15,10 @@ */ #ifndef LOWDOWN_H #define LOWDOWN_H +/* + * The only visible symbols should be those in this header file. + */ +#pragma GCC visibility push(default) /* * All of this is documented in lowdown.3. @@ -52,9 +55,6 @@ LOWDOWN_NULL }; -/* - * All types of Markdown nodes that lowdown understands. - */ enum lowdown_rndrt { LOWDOWN_ROOT, LOWDOWN_BLOCKCODE, @@ -83,6 +83,7 @@ LOWDOWN_LINK, LOWDOWN_TRIPLE_EMPHASIS, LOWDOWN_STRIKETHROUGH, + LOWDOWN_SUBSCRIPT, LOWDOWN_SUPERSCRIPT, LOWDOWN_FOOTNOTE, LOWDOWN_MATH_BLOCK, @@ -112,6 +113,19 @@ HTBL_FL_HEADER = 4 }; +enum admonition_type { + ADMONITION_NONE, + ADMONITION_NOTE, + ADMONITION_CALLOUT, + ADMONITION_WARNING, +}; + +enum blockquote_type { + BLOCKQUOTE_REGULAR, + BLOCKQUOTE_ADMONITION, + BLOCKQUOTE_ADMONITION_BLOCK +}; + enum halink_type { HALINK_NONE, /* used internally when it is not an autolink */ HALINK_NORMAL, @@ -186,6 +200,11 @@ struct lowdown_buf lang; }; +struct rndr_blockquote { + enum blockquote_type type; + enum admonition_type admonition; +}; + struct rndr_definition { enum hlist_fl flags; }; @@ -266,6 +285,7 @@ struct rndr_raw_html rndr_raw_html; struct rndr_link rndr_link; struct rndr_blockcode rndr_blockcode; + struct rndr_blockquote rndr_blockquote; struct rndr_definition rndr_definition; struct rndr_codespan rndr_codespan; struct rndr_table rndr_table; @@ -284,10 +304,18 @@ const char *sty; }; +struct lowdown_opts_nroff { + const char *cr; + const char *cb; + const char *ci; + const char *cbi; +}; + struct lowdown_opts { enum lowdown_type type; union { struct lowdown_opts_odt odt; + struct lowdown_opts_nroff nroff; }; size_t maxdepth; size_t cols; @@ -303,6 +331,7 @@ #define LOWDOWN_HILITE 0x40 #define LOWDOWN_IMG_EXT 0x20000 /* -> LOWDOWN_ATTRS */ #define LOWDOWN_MANTITLE 0x100000 +#define LOWDOWN_CALLOUTS 0x200000 #define LOWDOWN_MATH 0x200 /* Disabled LOWDOWN_MATHEXP 0x1000 */ #define LOWDOWN_METADATA 0x4000 @@ -310,6 +339,7 @@ #define LOWDOWN_NOINTEM 0x400 #define LOWDOWN_STRIKE 0x10 #define LOWDOWN_SUPER 0x100 +#define LOWDOWN_SUPER_SHORT 0x400000 #define LOWDOWN_TABLES 0x01 #define LOWDOWN_TASKLIST 0x40000 /* Omitted 0x20 */ @@ -327,6 +357,8 @@ #define LOWDOWN_HTML_OWASP 0x800 /* use OWASP escaping */ #define LOWDOWN_HTML_SKIP_HTML 0x01 /* skip all HTML */ #define LOWDOWN_HTML_TITLEBLOCK 0x4000000 /* output title block */ +#define LOWDOWN_HTML_CALLOUT_GFM 0x8000000 /* GFM callouts */ +#define LOWDOWN_HTML_CALLOUT_MDN 0x10000000 /* MDN callouts */ #define LOWDOWN_LATEX_NUMBERED 0x4000 /* numbered sections */ #define LOWDOWN_LATEX_SKIP_HTML 0x2000 /* skip all HTML */ #define LOWDOWN_NROFF_GROFF 0x20 /* use groff extensions */ @@ -342,6 +374,7 @@ #define LOWDOWN_TERM_NOCOLOUR 0x800000 /* no ANSI colours */ #define LOWDOWN_TERM_NOLINK 0x20000 /* don't show URLs */ #define LOWDOWN_TERM_SHORTLINK 0x400 /* shorten URLs */ +#define LOWDOWN_TERM_ALL_META 0x20000000 /* show all metadata */ char **meta; size_t metasz; char **metaovr; @@ -426,4 +459,5 @@ __END_DECLS +#pragma GCC visibility pop /* visibility(default) */ #endif /* !LOWDOWN_H */ diff -Nru lowdown-1.0.2/main.c lowdown-1.1.0/main.c --- lowdown-1.0.2/main.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/main.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2016, 2017, 2020 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -235,7 +234,8 @@ int c, diff = 0, fd, status = 0, afl = 0, rfl = 0, aifl = 0, rifl = 0, centre = 0, list = 0; - char *ret = NULL, *cp, *odtsty = NULL; + char *ret = NULL, *cp, *odtsty = NULL, + *nroffcodefn = NULL; size_t i, retsz = 0, rcols, sz; ssize_t ssz; struct lowdown_meta *m; @@ -255,6 +255,10 @@ { "html-no-skiphtml", no_argument, &rfl, LOWDOWN_HTML_SKIP_HTML }, { "html-titleblock", no_argument, &afl, LOWDOWN_HTML_TITLEBLOCK }, { "html-no-titleblock", no_argument, &rfl, LOWDOWN_HTML_TITLEBLOCK }, + { "html-callout-mdn", no_argument, &afl, LOWDOWN_HTML_CALLOUT_MDN }, + { "html-no-callout-mdn",no_argument, &rfl, LOWDOWN_HTML_CALLOUT_MDN }, + { "html-callout-gfm", no_argument, &afl, LOWDOWN_HTML_CALLOUT_GFM }, + { "html-no-callout-gfm",no_argument, &rfl, LOWDOWN_HTML_CALLOUT_GFM }, { "latex-numbered", no_argument, &afl, LOWDOWN_LATEX_NUMBERED }, { "latex-no-numbered", no_argument, &rfl, LOWDOWN_LATEX_NUMBERED }, @@ -271,6 +275,7 @@ { "nroff-no-shortlinks",no_argument, &rfl, LOWDOWN_NROFF_SHORTLINK }, { "nroff-skiphtml", no_argument, &afl, LOWDOWN_NROFF_SKIP_HTML }, { "nroff-no-skiphtml", no_argument, &rfl, LOWDOWN_NROFF_SKIP_HTML }, + { "nroff-code-font", required_argument, NULL, 7 }, { "odt-skiphtml", no_argument, &afl, LOWDOWN_ODT_SKIP_HTML }, { "odt-no-skiphtml", no_argument, &rfl, LOWDOWN_ODT_SKIP_HTML }, @@ -300,6 +305,8 @@ { "term-no-nolinks", no_argument, &rfl, LOWDOWN_TERM_NOLINK }, { "term-shortlinks", no_argument, &afl, LOWDOWN_TERM_SHORTLINK }, { "term-no-shortlinks", no_argument, &rfl, LOWDOWN_TERM_SHORTLINK }, + { "term-all-meta", no_argument, &afl, LOWDOWN_TERM_ALL_META }, + { "term-no-all-meta", no_argument, &rfl, LOWDOWN_TERM_ALL_META }, { "out-smarty", no_argument, &afl, LOWDOWN_SMARTY }, { "out-no-smarty", no_argument, &rfl, LOWDOWN_SMARTY }, @@ -320,6 +327,8 @@ { "parse-no-strike", no_argument, &rifl, LOWDOWN_STRIKE }, { "parse-super", no_argument, &aifl, LOWDOWN_SUPER }, { "parse-no-super", no_argument, &rifl, LOWDOWN_SUPER }, + { "parse-super-short", no_argument, &aifl, LOWDOWN_SUPER_SHORT }, + { "parse-no-super-short",no_argument, &rifl, LOWDOWN_SUPER_SHORT }, { "parse-math", no_argument, &aifl, LOWDOWN_MATH }, { "parse-no-math", no_argument, &rifl, LOWDOWN_MATH }, { "parse-mantitle", no_argument, &aifl, LOWDOWN_MANTITLE }, @@ -341,6 +350,8 @@ { "parse-no-ext-attrs", no_argument, &rifl, LOWDOWN_ATTRS }, { "parse-tasklists", no_argument, &aifl, LOWDOWN_TASKLIST }, { "parse-no-tasklists", no_argument, &rifl, LOWDOWN_TASKLIST }, + { "parse-callouts", no_argument, &aifl, LOWDOWN_CALLOUTS }, + { "parse-no-callouts", no_argument, &rifl, LOWDOWN_CALLOUTS }, { "parse-maxdepth", required_argument, NULL, 5 }, { NULL, 0, NULL, 0 } @@ -364,6 +375,7 @@ LOWDOWN_DEFLIST | LOWDOWN_FENCED | LOWDOWN_FOOTNOTES | + LOWDOWN_CALLOUTS | LOWDOWN_MANTITLE | LOWDOWN_METADATA | LOWDOWN_STRIKE | @@ -480,6 +492,22 @@ case 6: odtstyfn = optarg; break; + case 7: + /* + * Break down some aliases here: "none", "bold", + * or "code". + */ + if (strcmp(optarg, "none") == 0) + nroffcodefn = strdup("R,B,I,BI"); + else if (strcmp(optarg, "bold") == 0) + nroffcodefn = strdup("B,B,BI,BI"); + else if (strcmp(optarg, "code") == 0) + nroffcodefn = strdup("CR,CB,CI,CBI"); + else + nroffcodefn = strdup(optarg); + if (nroffcodefn == NULL) + err(1, NULL); + break; default: goto usage; } @@ -561,6 +589,48 @@ opts.odt.sty = odtsty; } + /* + * If specified and in -tman or -tms, parse the constant width + * fonts. As mentioned in nroff.c, the code font "C" is not + * portable, so let the user override it. This comes as a + * comma-separated sequence of R[,B[,I[,BI]]]. Any of these may + * inherit the default by being unspecified or empty, e.g., + * "CR,CB". + */ + + if ((opts.type == LOWDOWN_MAN || opts.type == LOWDOWN_NROFF) && + nroffcodefn != NULL && *nroffcodefn != '\0') { + opts.nroff.cr = cp = nroffcodefn; + while (*cp != '\0' && *cp != ',') + cp++; + if (*cp != '\0') { + *cp++ = '\0'; + opts.nroff.cb = cp; + while (*cp != '\0' && *cp != ',') + cp++; + if (*cp != '\0') { + *cp++ = '\0'; + opts.nroff.ci = cp; + while (*cp != '\0' && *cp != ',') + cp++; + if (*cp != '\0') { + *cp++ = '\0'; + opts.nroff.cbi = cp; + while (*cp != '\0' && *cp != ',') + cp++; + } + } + } + if (opts.nroff.cr != NULL && *opts.nroff.cr == '\0') + opts.nroff.cr = NULL; + if (opts.nroff.cb != NULL && *opts.nroff.cb == '\0') + opts.nroff.cb = NULL; + if (opts.nroff.ci != NULL && *opts.nroff.ci == '\0') + opts.nroff.ci = NULL; + if (opts.nroff.cbi != NULL && *opts.nroff.cbi == '\0') + opts.nroff.cbi = NULL; + } + /* Configure the output file. */ if (fnout != NULL && strcmp(fnout, "-") && @@ -616,6 +686,7 @@ free(ret); free(odtsty); + free(nroffcodefn); if (fout != stdout) fclose(fout); diff -Nru lowdown-1.0.2/man/lowdown-diff.1 lowdown-1.1.0/man/lowdown-diff.1 --- lowdown-1.0.2/man/lowdown-diff.1 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown-diff.1 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2016--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -141,6 +139,9 @@ starting all lists at one. .It Fl -parse-no-codeindent Do not parse indented content as code blocks. +.It Fl -parse-no-callouts +Do not parse GFM/MDN callouts +.Pq Qq admonitions . .It Fl -parse-no-deflists Do not parse PHP extra definition lists. .It Fl -parse-no-ext-attrs @@ -169,11 +170,16 @@ .It Fl -parse-no-strike Do not parse strikethroughs. .It Fl -parse-no-super -Do not parse super-scripts. +Do not parse super-scripts or sub-scripts at all. .It Fl -parse-no-tables Do not parse GFM tables. .It Fl -parse-no-tasklists Do not parse GFM task lists. +.It Fl -parse-super-short +If super-script parsing is enabled, use the traditional +non-GFM +.Qq short +syntax. .El .Pp There are many output options. @@ -193,6 +199,8 @@ .Fl t Ns Ar html , these are as follows: .Bl -tag -width Ds +.It Fl -html-callout-mdn , -html-callout-gfm +Output either or both MDN or GFM callout syntaxes. .It Fl -html-hardwrap Hard-wrap paragraph content by outputting line breaks where applicable. .It Fl -html-no-escapehtml @@ -227,6 +235,22 @@ .Fl t Ns Ar ms , the following apply: .Bl -tag -width Ds +.It Fl -nroff-code-font Ns = Ns Ar fonts +Override the default constant-width fonts with a tuple of regular, bold, +italic, and bold-italic variants in that order. +For example, +.Li B,B,BI,BI +uses bold +.Pq Qq B +instead of a constant-width. +Not specifying a font will use the default, as will specifying a +zero-length font name. +Aliases +.Li none , +.Li bold , +and +.Li code +set no special fonts, bold, and the default constant-width. .It Fl -nroff-no-groff Don't use .Xr groff 1 @@ -240,10 +264,6 @@ or Unicode sequence syntax. The output is compatible with traditional .Xr troff 1 . -Applies to -.Fl t Ns Ar man -and -.Fl t Ns Ar ms . .It Fl -nroff-no-numbered Don't output numbered headings. Only applies to @@ -278,6 +298,11 @@ .Fl t Ns Ar term output has the following: .Bl -tag -width Ds +.It Fl -term-all-metadata +If +.Fl s +is specified, output all metadata instead of just the title, author, and +date. .It Fl -term-columns=columns The number of columns in the screen. Useful for when running in a pipe. @@ -498,6 +523,8 @@ statements. .It Fl t Ns Ar man , Fl t Ns Ar ms Prologue macros. +.It Fl t Ns Ar term +Prologue lines. .El .Pp If parsed from the document or as given by @@ -530,8 +557,9 @@ .Fl t Ns Ar fodt , .Fl t Ns Ar html , .Fl t Ns Ar latex , +.Fl t Ns Ar ms , and -.Fl t Ns Ar ms . +.Fl t Ns Ar term . .It Li baseheaderlevel Added to each header level. Deprecated in favour of @@ -560,14 +588,19 @@ .Fl t Ns Ar html , .Fl t Ns Ar latex , .Fl t Ns Ar man , +.Fl t Ns Ar ms , and -.Fl t Ns Ar ms . +.Fl t Ns Ar term . .It Li javascript A JavaScript file included in the HTML5 document head. Multiple script files (in order) may be separated by two or more spaces (including newlines). Only used in .Fl t Ns Ar html . +.It Li lang +Document language in RFC 5646 format. +Only used in +.Fl t Ns Ar html . .It Li rcsauthor Like .Li author , @@ -618,8 +651,9 @@ .Fl t Ns Ar html , .Fl t Ns Ar latex , .Fl t Ns Ar man , +.Fl t Ns Ar ms , and -.Fl t Ns Ar ms . +.Fl t Ns Ar term . .El .Pp Metadata values are parsed and may be used as variables in markdown diff -Nru lowdown-1.0.2/man/lowdown.1 lowdown-1.1.0/man/lowdown.1 --- lowdown-1.0.2/man/lowdown.1 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown.1 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2016--2017, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -159,6 +157,9 @@ starting all lists at one. .It Fl -parse-no-codeindent Do not parse indented content as code blocks. +.It Fl -parse-no-callouts +Do not parse GFM/MDN callouts +.Pq Qq admonitions . .It Fl -parse-no-deflists Do not parse PHP extra definition lists. .It Fl -parse-no-ext-attrs @@ -187,11 +188,16 @@ .It Fl -parse-no-strike Do not parse strikethroughs. .It Fl -parse-no-super -Do not parse super-scripts. +Do not parse super-scripts or sub-scripts at all. .It Fl -parse-no-tables Do not parse GFM tables. .It Fl -parse-no-tasklists Do not parse GFM task lists. +.It Fl -parse-super-short +If super-script parsing is enabled, use the traditional +non-GFM +.Qq short +syntax. .El .Pp There are many output options. @@ -211,6 +217,8 @@ .Fl t Ns Ar html , these are as follows: .Bl -tag -width Ds +.It Fl -html-callout-mdn , -html-callout-gfm +Output either or both MDN or GFM callout syntaxes. .It Fl -html-hardwrap Hard-wrap paragraph content by outputting line breaks where applicable. .It Fl -html-no-escapehtml @@ -245,6 +253,22 @@ .Fl t Ns Ar ms , the following apply: .Bl -tag -width Ds +.It Fl -nroff-code-font Ns = Ns Ar fonts +Override the default constant-width fonts with a tuple of regular, bold, +italic, and bold-italic variants in that order. +For example, +.Li B,B,BI,BI +uses bold +.Pq Qq B +instead of a constant-width. +Not specifying a font will use the default, as will specifying a +zero-length font name. +Aliases +.Li none , +.Li bold , +and +.Li code +set no special fonts, bold, and the default constant-width. .It Fl -nroff-no-groff Don't use .Xr groff 1 @@ -258,10 +282,6 @@ or Unicode sequence syntax. The output is compatible with traditional .Xr troff 1 . -Applies to -.Fl t Ns Ar man -and -.Fl t Ns Ar ms . .It Fl -nroff-no-numbered Don't output numbered headings. Only applies to @@ -296,6 +316,11 @@ .Fl t Ns Ar term output has the following: .Bl -tag -width Ds +.It Fl -term-all-metadata +If +.Fl s +is specified, output all metadata instead of just the title, author, and +date. .It Fl -term-columns=columns The number of columns in the screen. Useful for when running in a pipe. @@ -501,6 +526,8 @@ statements. .It Fl t Ns Ar man , Fl t Ns Ar ms Prologue macros. +.It Fl t Ns Ar term +Prologue lines. .El .Pp If parsed from the document or as given by @@ -533,8 +560,9 @@ .Fl t Ns Ar fodt , .Fl t Ns Ar html , .Fl t Ns Ar latex , +.Fl t Ns Ar ms , and -.Fl t Ns Ar ms . +.Fl t Ns Ar term . .It Li baseheaderlevel Added to each header level. Deprecated in favour of @@ -563,8 +591,9 @@ .Fl t Ns Ar html , .Fl t Ns Ar latex , .Fl t Ns Ar man , +.Fl t Ns Ar ms , and -.Fl t Ns Ar ms . +.Fl t Ns Ar term . .It Li javascript A JavaScript file included in the HTML5 document head. Multiple script files (in order) may be separated by two or more spaces @@ -625,8 +654,9 @@ .Fl t Ns Ar html , .Fl t Ns Ar latex , .Fl t Ns Ar man , +.Fl t Ns Ar ms , and -.Fl t Ns Ar ms . +.Fl t Ns Ar term . .El .Pp Metadata values are parsed and may be used as variables in markdown diff -Nru lowdown-1.0.2/man/lowdown.3 lowdown-1.1.0/man/lowdown.3 --- lowdown-1.0.2/man/lowdown.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -26,7 +24,7 @@ .In sys/queue.h .In stdio.h .In lowdown.h -.Vt "struct lowdown_metadata" +.Vt "struct lowdown_meta" .Vt "struct lowdown_node" .Vt "struct lowdown_opts" .Sh DESCRIPTION @@ -144,18 +142,43 @@ and .Xr lowdown_file 3 : both require access to the stream for reading input. -.Ss Types +.Sh TYPES All .Nm lowdown functions use one or more of the following structures. .Pp -The -.Vt struct lowdown_opts -structure manage features. +The main structure for configuring parsing and output is +.Vt struct lowdown_opts . It has the following fields: -.Bl -tag -width Ds -offset indent +.Bl -tag -width Ds +.It Va enum lowdown_type type +The output medium: +.Pp +.Bl -tag -width Ds -compact +.It Dv LOWDOWN_HTML +HTML5 +.It Dv LOWDOWN_LATEX +LaTeX +.It Dv LOWDOWN_MAN +roff +.Fl m Ns Ar an +macros +.It Dv LOWDOWN_FODT +.Dq flat +OpenDocument +.It Dv LOWDOWN_TERM +ANSI-compatible UTF-8 terminal output +.It Dv LOWDOWN_GEMINI +Gemini format +.It Dv LOWDOWN_NROFF +roff +.Fl m Ns Ar s +macros +.It Dv LOWDOWN_TREE +syntax tree (debugging) +.El .It Va unsigned int feat -Features used during the parse. +Parse-time features. This bit-field may have the following bits OR'd: .Pp .Bl -tag -width Ds -compact @@ -168,6 +191,9 @@ .Li ftp , .Li mailto , and relative links or link fragments. +.It Dv LOWDOWN_CALLOUTS +Parse MDN/GFM callouts +.Pq Dq admonitions . .It Dv LOWDOWN_COMMONMARK Tighten input parsing to the CommonMark specification. This also uses the first ordered list value instead of starting all @@ -184,7 +210,7 @@ .It Dv LOWDOWN_FOOTNOTES Parse MMD style footnotes. This only supports the referenced footnote style, not the -.Qq inline +.Dq inline style. .It Dv LOWDOWN_HILITE Parse highlit sequences. @@ -202,7 +228,7 @@ is also provided. Manpages titles must begin with a non-empty title followed by an open parenthesis, digit or -.Qq n , +.Dq n , optional letters after, then a closing parenthesis. This may be optionally followed by a source and, if a vertical bar is detected, the content after as the volume. @@ -227,6 +253,13 @@ Parse strikethrough sequences. .It Dv LOWDOWN_SUPER Parse super-scripts. +This accepts foo^bar^ GFM super-scripts. +.It Dv LOWDOWN_SUPER_SHORT +If +.Dv LOWDOWN_SUPER +is enabled, instead of the GFM style, accept the +.Dq short +form of superscript. This accepts foo^bar, which puts the parts following the caret until whitespace in superscripts; or foo^(bar), which puts only the parts in parenthesis. @@ -235,18 +268,33 @@ .It Dv LOWDOWN_TASKLIST Parse GFM task list items. .El -.Pp -The default value is zero (none). .It Va unsigned int oflags -Features used by the output generators. -This bit-field may have the following enabled. -Note that bits are by definition specific to an output -.Va type . +Output-time features. +Bit values are specific to the +.Va type +and are not guaranteed to be globally unique. +.Pp +For all types: +.Pp +.Bl -tag -width Ds -compact +.It Dv LOWDOWN_SMARTY +Don't use smart typography formatting. +.It Dv LOWDOWN_STANDALONE +Emit a full document instead of a document fragment. +This envelope is largely populated from metadata if +.Dv LOWDOWN_METADATA +was provided as an option or as given in +.Va meta +or +.Va metaovr . +.El .Pp For .Dv LOWDOWN_HTML : .Pp .Bl -tag -width Ds -compact +.It Dv LOWDOWN_HTML_CALLOUT_MDN , LOWDOWN_HTML_CALLOUT_GFM +Output MDN and/or GFM-style callout syntax. .It Dv LOWDOWN_HTML_ESCAPE If .Dv LOWDOWN_HTML_SKIP_HTML @@ -257,12 +305,12 @@ .It Dv LOWDOWN_HTML_HEAD_IDS Have an identifier written with each header element consisting of an HTML-escaped version of the header contents. -.It Dv LOWDOWN_HTML_OWASP -When escaping text, be extra paranoid in following the OWASP suggestions -for which characters to escape. .It Dv LOWDOWN_HTML_NUM_ENT Convert, when possible, HTML entities to their numeric form. If not set, the entities are used as given in the input. +.It Dv LOWDOWN_HTML_OWASP +When escaping text, be extra paranoid in following the OWASP suggestions +for which characters to escape. .It Dv LOWDOWN_HTML_SKIP_HTML Do not render in-document HTML at all. .It Dv LOWDOWN_HTML_TITLEBLOCK @@ -289,12 +337,14 @@ there are several flags for controlling link placement. By default, links (images, autolinks, and links) are queued when specified in-line then emitted in a block sequence after the nearest -block element. +block node. +(See +.Sx ABSTRACT SYNTAX TREE . ) .Pp .Bl -tag -width Ds -compact .It Dv LOWDOWN_GEMINI_LINK_END Emit the queue of links at the end of the document instead of after the -nearest block element. +nearest block node. .It Dv LOWDOWN_GEMINI_LINK_IN Render all links within the flow of text. This will cause breakage when nested links, such as images within links, @@ -347,7 +397,7 @@ Text within HTML elements remains. .El .Pp -And for +For .Dv LOWDOWN_MAN and .Dv LOWDOWN_NROFF : @@ -372,6 +422,14 @@ and .Dv LOWDOWN_NROFF output types. +.It Dv LOWDOWN_NROFF_NOLINK +Don't show links at all if they have embedded text. +Applies to images and regular links. +Only in +.Dv LOWDOWN_MAN +or when +.Dv LOWDOWN_NROFF_GROFF +is not specified. .It Dv LOWDOWN_NROFF_NUMBERED Use numbered sections if .Dv LOWDOWON_NROFF_GROFF @@ -379,9 +437,6 @@ Only applies to the .Dv LOWDOWN_NROFF output type. -.It Dv LOWDOWN_NROFF_SKIP_HTML -Do not render in-document HTML at all. -Text within HTML elements remains. .It Dv LOWDOWN_NROFF_SHORTLINK Render link URLs in short form. Applies to images, autolinks, and regular links. @@ -390,20 +445,20 @@ or when .Dv LOWDOWN_NROFF_GROFF is not specified. -.It Dv LOWDOWN_NROFF_NOLINK -Don't show links at all if they have embedded text. -Applies to images and regular links. -Only in -.Dv LOWDOWN_MAN -or when -.Dv LOWDOWN_NROFF_GROFF -is not specified. +.It Dv LOWDOWN_NROFF_SKIP_HTML +Do not render in-document HTML at all. +Text within HTML elements remains. .El .Pp For .Dv LOWDOWN_TERM : .Pp .Bl -tag -width Ds -compact +.It Dv LOWDOWN_TERM_ALL_META +If +.Dv LOWDOWN_STANDALONE +is specified, output all metadata instead of just the title, author, and +date. .It Dv LOWDOWN_TERM_NOANSI Don't apply ANSI style codes at all. This implies @@ -426,21 +481,6 @@ .Dv LOWDOWN_TERM_NOLINK to only show shortened autolinks. .El -.Pp -For any mode, you may specify: -.Pp -.Bl -tag -width Ds -compact -.It Dv LOWDOWN_SMARTY -Don't use smart typography formatting. -.It Dv LOWDOWN_STANDALONE -Emit a full document instead of a document fragment. -This envelope is largely populated from metadata if -.Dv LOWDOWN_METADATA -was provided as an option or as given in -.Va meta -or -.Va metaovr . -.El .It Va size_t maxdepth The maximum parse depth before the parser exits. Most documents will have a parse depth in the single digits. @@ -448,7 +488,7 @@ For .Dv LOWDOWN_TERM , the -.Qq soft limit +.Dq soft limit for width of terminal output not including margins. If zero, 80 shall be used. .It Va size_t hmargin @@ -459,31 +499,25 @@ For .Dv LOWDOWN_TERM , the top/bottom margin (newlines). -.It Va enum lowdown_type type -May be set to -.Dv LOWDOWN_HTML -for HTML5 output, -.Dv LOWDOWN_LATEX -for LaTeX, +.It Va struct lowdown_opts_nroff nroff +If +.Va type +is .Dv LOWDOWN_MAN -for -.Fl m Ns Ar an -macros, -.Dv LOWDOWN_FODT -for -.Dq flat -OpenDocument, -.Dv LOWDOWN_TERM -for ANSI-compatible UTF-8 terminal output, -.Dv LOWDOWN_GEMINI -for the Gemini format, or -.Dv LOWDOWN_NROFF -for -.Fl m Ns Ar s -macros. -The -.Dv LOWDOWN_TREE -type causes a debug tree to be written. +or +.Dv LOWDOWN_NROFF , +this contains constant-width font variants: +.Vt "const char *cr" +for roman constant-width, +.Vt "const char *cb" +for bold, +.Vt "const char *ci" +for italic, and +.Vt "const char *cbi" +for bold-italic. +If any of these are +.Dv NULL , +they default to their constant-width variants. .It Va struct lowdown_opts_odt odt If .Va type @@ -524,164 +558,114 @@ .Va metaovr . .El .Pp -Another common structure is -.Vt "struct lowdown_metadata" , -which is used to hold parsed (and output-formatted) metadata keys and -values if +Parsed metadata is held in key-value +.Vt "struct lowdown_meta" +pairs, or collectively as +.Va "struct lowdown_metaq" , +if .Dv LOWDOWN_METADATA -was provided as an input bit. -This structure consists of the following fields: -.Bl -tag -width Ds -offset indent +is set in +.Va feat . +The former structure consists of the following fields: +.Bl -tag -width Ds .It Va char *key -The metadata key in its lowercase, canonical form. +The metadata key in its canonical form: lowercase alphanumerics, hyphen, and +underscore. +Whitespace is removed and other characters replaced by a question mark. .It Va char *value -The metadata value as rendered in the current output format. +The metadata value. This may be an empty string. .El .Pp The abstract syntax tree is encoded in .Vt struct lowdown_node , which consists of the following. -.Bl -tag -width Ds -offset indent +.Bl -tag -width Ds .It Va enum lowdown_rndrt type -The node type. -.Pq Described below. -.It Va size_t id -An identifier unique within the document. -This can be used as a table index since the number is assigned from a -monotonically increasing point during the parse. -.It Va struct lowdown_node *parent -The parent of the node, or -.Dv NULL -at the root. -.It Va enum lowdown_chng chng -Change tracking: whether this node was inserted -.Pq Dv LOWDOWN_CHNG_INSERT , -deleted -.Pq Dv LOWDOWN_CHNG_DELETE , -or neither -.Pq Dv LOWDOWN_CHNG_NONE . -.It Va struct lowdown_nodeq children -A possibly-empty list of child nodes. -.It Va -An anonymous union of type-specific structures. -See below for a description of each one. -.El +The node type, using HTML5 output as an illustration: .Pp -The nodes may be one of the following types, with default rendering in -HTML5 to illustrate functionality. -.Bl -tag -width Ds -offset indent +.Bl -tag -width Ds -compact .It Dv LOWDOWN_BLOCKCODE -A block-level (and possibly language-specific) snippet of code. -Described by the -.Li

-elements.
+A block-level snippet of code described by
+.Li 
 .
 .It Dv LOWDOWN_BLOCKHTML
 A block-level snippet of HTML.
 This is simply opaque HTML content.
-(Only if configured during parse.)
 .It Dv LOWDOWN_BLOCKQUOTE
-A block-level quotation.
-Described by the
-.Li 
-element. +A block-level quotation described by +.Li
. .It Dv LOWDOWN_CODESPAN -A snippet of code. -Described by the -.Li -element. +An inline-level snippet of code described by +.Li . +.It Dv LOWDOWN_DEFINITION +A definition list described by +.Li
. +.It Dv LOWDOWN_DEFINITION_DATA +Definition data described by +.Li
. +.It Dv LOWDOWN_DEFINITION_TITLE +Definition title described by +.Li
. .It Dv LOWDOWN_DOC_HEADER -A header with data gathered from document metadata (if configured). -Described by the -.Li -element. -(Only if configured during parse.) +Container for metadata described by +.Li . .It Dv LOWDOWN_DOUBLE_EMPHASIS -Bold (or otherwise notable) content. -Described by the -.Li -element. +Bold (or otherwise notable) content described by +.Li . .It Dv LOWDOWN_EMPHASIS -Italic (or otherwise notable) content. -Described by the -.Li -element. +Italic (or otherwise notable) content described by +.Li . .It Dv LOWDOWN_ENTITY -An HTML entity, which may either be named or numeric. +Named or numeric HTML entity. .It Dv LOWDOWN_FOOTNOTE -A footnote. -(Only if configured during parse.) +Footnote content. .It Dv LOWDOWN_HEADER -A block-level header. -Described (in the HTML case) by one of +A block-level header described by one of .Li

through .Li

. .It Dv LOWDOWN_HIGHLIGHT -Marked test. -Described by the -.Li -element. -(Only if configured during parse.) +Marked test described by +.Li . .It Dv LOWDOWN_HRULE -A horizontal line. -Described by +A horizontal line described by .Li
. .It Dv LOWDOWN_IMAGE -An image. -Described by the -.Li -element. +An image described by +.Li . .It Dv LOWDOWN_LINEBREAK -A hard line-break within a block context. -Described by the -.Li
-element. +A hard line-break within a block context described by +.Li
. .It Dv LOWDOWN_LINK -A link to external media. -Described by the -.Li -element. +A link to external media described by +.Li . .It Dv LOWDOWN_LINK_AUTO Like .Dv LOWDOWN_LINK , except inferred from text content. -Described by the -.Li -element. -(Only if configured during parse.) .It Dv LOWDOWN_LIST -A block-level list enclosure. -Described by +A list enclosure described by .Li
    or .Li
      . .It Dv LOWDOWN_LISTITEM -A block-level list item, always appearing within a -.Dv LOWDOWN_LIST . -Described by +A list item described by .Li
    1. . .It Dv LOWDOWN_MATH_BLOCK -A block (or inline) of mathematical text in LaTeX format. -Described within +A snippet of mathematical text in LaTeX format described within .Li \e[xx\e] or .Li \e(xx\e) . This is usually (in HTML) externally handled by a JavaScript renderer. -(Only if configured during parse.) .It Dv LOWDOWN_META Meta-data keys and values. -(Only if configured during parse.) -These are described by elements in the -.Li -element. +These are described by elements in +.Li . .It Dv LOWDOWN_NORMAL_TEXT Normal text content. .It Dv LOWDOWN_PARAGRAPH -A block-level paragraph. -Described by the -.Li

      -element. +A block-level paragraph described by +.Li

      . .It Dv LOWDOWN_RAW_HTML An inline of raw HTML. (Only if configured during parse.) @@ -693,64 +677,59 @@ .Dv NULL . .It Dv LOWDOWN_STRIKETHROUGH Content struck through. -Described by the -.Li -element. -(Only if configured during parse.) -.It Dv LOWDOWN_SUPERSCRIPT -A superscript. -Described by the -.Li -element. -(Only if configured during parse.) -.It Dv LOWDOWN_TABLE_BLOCK -A table block. Described by +.Li . +.It Dv LOWDOWN_SUBSCRIPT , Dv LOWDOWN_SUPERSCRIPT +A subscript or superscript described by +.Li +or +.Li , +respectively. +.It Dv LOWDOWN_TABLE_BLOCK +A table block described by .Li . -(Only if configured during parse.) .It Dv LOWDOWN_TABLE_BODY -A table body section. -Described by +A table body section described by .Li . -Parent is always -.Dv LOWDOWN_TABLE_BLOCK . -(Only if configured during parse.) .It Dv LOWDOWN_TABLE_CELL -A table cell. -Described by -.Li . -Parent is always -.Dv LOWDOWN_TABLE_BLOCK . -(Only if configured during parse.) .It Dv LOWDOWN_TABLE_ROW -A table row. -Described by +A table row described by .Li . -Parent is always -.Dv LOWDOWN_TABLE_HEADER -or -.Dv LOWDOWN_TABLE_BODY . -(Only if configured during parse.) .It Dv LOWDOWN_TRIPLE_EMPHASIS Combination of .Dv LOWDOWN_EMPHASIS and .Dv LOWDOWN_DOUBLE_EMPHASIS . .El +.It Va size_t id +An identifier unique within the document. +This can be used as a table index since the number is assigned from a +monotonically increasing point during the parse. +.It Va struct lowdown_node *parent +The parent of the node, or +.Dv NULL +at the root. +.It Va enum lowdown_chng chng +Change tracking: whether this node was inserted +.Pq Dv LOWDOWN_CHNG_INSERT , +deleted +.Pq Dv LOWDOWN_CHNG_DELETE , +or neither +.Pq Dv LOWDOWN_CHNG_NONE . +.It Va struct lowdown_nodeq children +A possibly-empty list of child nodes. +.It Va +An anonymous union of type-specific structures. .Pp -The following anonymous union structures correspond to certain nodes. -Note that all buffers may be zero-length. -.Bl -tag -width Ds -offset indent +.Bl -tag -width Ds -compact .It Va rndr_autolink For .Dv LOWDOWN_LINK_AUTO , @@ -789,7 +768,7 @@ that may be .Dv HLIST_FL_BLOCK if the definition list should be interpreted as containing block -elements. +nodes. .It Va rndr_entity For .Dv LOWDOWN_ENTITY , @@ -873,9 +852,9 @@ .Dv HLIST_FL_UNCHECKED for an unordered .Dq task -list element, and/or +list, and/or .Dv HLIST_FL_BLOCK -for list item output as if containing block elements. +for list item output as if containing block nodes. The .Dv HLIST_FL_BLOCK should not be used: use the parent list (or definition list) flags for @@ -927,7 +906,7 @@ the paragraph has in the input file and .Va beoln , set to non-zero if the paragraph ends with an empty line instead of a -breaking block element. +breaking block node. .It Va rndr_raw_html For .Dv LOWDOWN_RAW_HTML , @@ -987,6 +966,164 @@ .Va rndr_table_cell are the same. .El +.El +.Sh ABSTRACT SYNTAX TREE +A parsed document is a tree of +.Vt struct lowdown_node +nodes. +If a node is +.Dq block , +it may contain other block or inline nodes. +If +.Dq inline, +it may only contain other inline nodes. +.Dq Special +nodes are documented below. +An additional mark of +.Dq void +means that the node will never contain children. +.Pp +.Bl -column "LOWDOWN_DEFINITION_TITLE" "special, void" -offset indent -compact +.It Node Ta Scope +.It Dv LOWDOWN_BLOCKCODE Ta block, void +.It Dv LOWDOWN_BLOCKHTML Ta block, void +.It Dv LOWDOWN_BLOCKQUOTE Ta block +.It Dv LOWDOWN_CODESPAN Ta inline, void +.It Dv LOWDOWN_DEFINITION Ta block +.It Dv LOWDOWN_DEFINITION_DATA Ta special +.It Dv LOWDOWN_DEFINITION_TITLE Ta special +.It Dv LOWDOWN_DOC_HEADER Ta special +.It Dv LOWDOWN_DOUBLE_EMPHASIS Ta inline +.It Dv LOWDOWN_EMPHASIS Ta inline +.It Dv LOWDOWN_ENTITY Ta inline, void +.It Dv LOWDOWN_FOOTNOTE Ta block, special +.It Dv LOWDOWN_HEADER Ta block +.It Dv LOWDOWN_HRULE Ta inline, void +.It Dv LOWDOWN_IMAGE Ta inline, void +.It Dv LOWDOWN_LINEBREAK Ta inline, void +.It Dv LOWDOWN_LINK Ta inline +.It Dv LOWDOWN_LINK_AUTO Ta inline, void +.It Dv LOWDOWN_LIST Ta block +.It Dv LOWDOWN_LISTITEM Ta special +.It Dv LOWDOWN_MATH_BLOCK Ta inline, void +.It Dv LOWDOWN_META Ta special +.It Dv LOWDOWN_NORMAL_TEXT Ta inline, void +.It Dv LOWDOWN_PARAGRAPH Ta block +.It Dv LOWDOWN_RAW_HTML Ta inline, void +.It Dv LOWDOWN_ROOT Ta special +.It Dv LOWDOWN_STRIKETHROUGH Ta inline +.It Dv LOWDOWN_SUBSCRIPT Ta inline +.It Dv LOWDOWN_SUPERSCRIPT Ta inline +.It Dv LOWDOWN_TABLE_BLOCK Ta block +.It Dv LOWDOWN_TABLE_BODY Ta special +.It Dv LOWDOWN_TABLE_CELL Ta special +.It Dv LOWDOWN_TABLE_HEADER Ta special +.It Dv LOWDOWN_TABLE_ROW Ta special +.It Dv LOWDOWN_TRIPLE_EMPHASIS Ta inline +.El +.Pp +The general structure of the AST is as follows. +Nodes have no order imposed on them unless as noted: +.Pp +.Bl -dash -compact +.It +.Dv LOWDOWN_ROOT +.Pq ordered +.Bl -dash -compact +.It +.Dv LOWDOWN_DOC_HEADER +.Bl -dash -compact +.It +.Dv LOWDOWN_META +.Bl -dash -compact +.It +.Dv LOWDOWN_ENTITY +.It +.Dv LOWDOWN_NORMAL_TEXT +.El +.El +.It +.Pq zero or more block nodes +.El +.El +.Pp +Special nodes have specific placement within their parents as follows: +.Bl -dash +.It +.Dv LOWDOWN_DEFINITION +.Pq one or more ordered pairs of... +.Bl -dash -compact +.It +.Dv LOWDOWN_DEFINITION_TITLE +.Bl -dash -compact +.It +.Pq inline nodes +.El +.It +.Dv LOWDOWN_DEFINITION_DATA +.Bl -dash -compact +.It +.Pq block nodes +.El +.El +.It +.Dv LOWDOWN_HEADER +.Bl -dash -compact +.It +.Pq inline nodes +.El +.It +.Dv LOWDOWN_LIST +.Bl -dash -compact +.It +.Dv LOWDOWN_LISTITEM +.Bl -dash -compact +.It +.Pq inline or block nodes, depending +.El +.El +.It +.Dv LOWDOWN_TABLE_BLOCK +.Pq ordered +.Bl -dash -compact +.It +.Dv LOWDOWN_TABLE_HEADER +.Pq zero or more... +.Bl -dash -compact +.It +.Dv LOWDOWN_TABLE_ROW +.Pq one or more... +.Bl -dash -compact +.It +.Dv LOWDOWN_TABLE_CELL +.Bl -dash -compact +.It +.Pq inline nodes +.El +.El +.El +.It +.Dv LOWDOWN_TABLE_BODY +.Pq zero or more... +.Bl -dash -compact +.It +.Dv LOWDOWN_TABLE_ROW +.Pq one or more... +.Bl -dash -compact +.It +.Dv LOWDOWN_TABLE_CELL +.Bl -dash -compact +.It +.Pq inline nodes +.El +.El +.El +.El +.El +.Pp +Lastly, +.Dv LOWDOWN_FOOTNOTE +may appear anywhere in the document and contains block nodes. .Sh SEE ALSO .Xr lowdown 1 , .Xr lowdown_buf 3 , diff -Nru lowdown-1.0.2/man/lowdown.5 lowdown-1.1.0/man/lowdown.5 --- lowdown-1.0.2/man/lowdown.5 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown.5 2023-11-08 01:32:58.000000000 +0000 @@ -1,7 +1,5 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017 Christina Sophonpanich -.\" Copyright (c) 2017--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons +.\" Copyright (c) 2017 Christina Sophonpanich .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -182,6 +180,34 @@ > yes | read engage .Ed . +.Ss Admonitions +Also called +.Qq callouts , +these special block quotes call attention to contents. +These are generally rendered as-is, but some output modes will specially +render admonitions to highlight the content. +.Bd -literal -offset indent +> **Note** +> +> The computer is voiced by Majel Barrett. +.Ed +.Pp +Callouts begin with a double-emphasis +.Qq Note +or +.Qq Warning , +and omitting the initial newline suppresses white-space after the +callout type. +This is GFM syntax. +The MDN syntax includes an initial phrase following the callout type and +colon, and also supports the +.Qq Callout +type: +.Bd -literal -offset indent +> **Warning:** red alert. +> +> Romulan warbird decloaking! +.Ed .Ss Lists Lists may be specified as ordered (numbered) or unordered. Ordered lists are invoked as numbers followed by periods @@ -886,11 +912,21 @@ .Ss Superscripts Uses the caret .Pq Dq \(ha -to start a superscript. -The superscripted material continues to white-space or, if starting with -an open parenthesis, the close parenthesis. +to start a superscript, then another to end it. +Between these, white-space is not allowed. +This is the GFM style. +.Bd -literal -offset indent +Though a great book, Q\(ha2\(ha isn't Star Trek canon. +.Ed +.Pp +If +.Qq short +.Pq traditional +style super-scripts are enabled, start with a caret, continuing to +white-space; or, if starting with an open parenthesis, continuing to the +close parenthesis with possible white-space. .Bd -literal -offset indent -Though a great book, Q\(ha2 (Q\(ha(squared)) isn't Star Trek canon. +Though a great book, Q\(ha2 isn't Star Trek canon. .Ed . .Ss HTML Content diff -Nru lowdown-1.0.2/man/lowdown_buf.3 lowdown-1.1.0/man/lowdown_buf.3 --- lowdown-1.0.2/man/lowdown_buf.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_buf.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_buf_diff.3 lowdown-1.1.0/man/lowdown_buf_diff.3 --- lowdown-1.0.2/man/lowdown_buf_diff.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_buf_diff.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2018, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_buf_free.3 lowdown-1.1.0/man/lowdown_buf_free.3 --- lowdown-1.0.2/man/lowdown_buf_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_buf_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_buf_new.3 lowdown-1.1.0/man/lowdown_buf_new.3 --- lowdown-1.0.2/man/lowdown_buf_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_buf_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_diff.3 lowdown-1.1.0/man/lowdown_diff.3 --- lowdown-1.0.2/man/lowdown_diff.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_diff.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_doc_free.3 lowdown-1.1.0/man/lowdown_doc_free.3 --- lowdown-1.0.2/man/lowdown_doc_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_doc_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_doc_new.3 lowdown-1.1.0/man/lowdown_doc_new.3 --- lowdown-1.0.2/man/lowdown_doc_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_doc_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_doc_parse.3 lowdown-1.1.0/man/lowdown_doc_parse.3 --- lowdown-1.0.2/man/lowdown_doc_parse.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_doc_parse.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_file.3 lowdown-1.1.0/man/lowdown_file.3 --- lowdown-1.0.2/man/lowdown_file.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_file.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_file_diff.3 lowdown-1.1.0/man/lowdown_file_diff.3 --- lowdown-1.0.2/man/lowdown_file_diff.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_file_diff.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2018, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_gemini_free.3 lowdown-1.1.0/man/lowdown_gemini_free.3 --- lowdown-1.0.2/man/lowdown_gemini_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_gemini_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_gemini_new.3 lowdown-1.1.0/man/lowdown_gemini_new.3 --- lowdown-1.0.2/man/lowdown_gemini_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_gemini_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_gemini_rndr.3 lowdown-1.1.0/man/lowdown_gemini_rndr.3 --- lowdown-1.0.2/man/lowdown_gemini_rndr.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_gemini_rndr.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_html_free.3 lowdown-1.1.0/man/lowdown_html_free.3 --- lowdown-1.0.2/man/lowdown_html_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_html_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_html_new.3 lowdown-1.1.0/man/lowdown_html_new.3 --- lowdown-1.0.2/man/lowdown_html_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_html_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -53,6 +51,8 @@ .Dv LOWDOWN_HTML_HARD_WRAP , .Dv LOWDOWN_HTML_SKIP_HTML , .Dv LOWDOWN_HTML_ESCAPE , +.Dv LOWDOWN_HTML_CALLOUT_MDN , +.Dv LOWDOWN_HTML_CALLOUT_GFM , and .Dv LOWDOWN_STANDALONE . .Sh RETURN VALUES diff -Nru lowdown-1.0.2/man/lowdown_html_rndr.3 lowdown-1.1.0/man/lowdown_html_rndr.3 --- lowdown-1.0.2/man/lowdown_html_rndr.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_html_rndr.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017, 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_latex_free.3 lowdown-1.1.0/man/lowdown_latex_free.3 --- lowdown-1.0.2/man/lowdown_latex_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_latex_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_latex_new.3 lowdown-1.1.0/man/lowdown_latex_new.3 --- lowdown-1.0.2/man/lowdown_latex_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_latex_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_latex_rndr.3 lowdown-1.1.0/man/lowdown_latex_rndr.3 --- lowdown-1.0.2/man/lowdown_latex_rndr.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_latex_rndr.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_metaq_free.3 lowdown-1.1.0/man/lowdown_metaq_free.3 --- lowdown-1.0.2/man/lowdown_metaq_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_metaq_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_node_free.3 lowdown-1.1.0/man/lowdown_node_free.3 --- lowdown-1.0.2/man/lowdown_node_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_node_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_nroff_free.3 lowdown-1.1.0/man/lowdown_nroff_free.3 --- lowdown-1.0.2/man/lowdown_nroff_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_nroff_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017, 2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_nroff_new.3 lowdown-1.1.0/man/lowdown_nroff_new.3 --- lowdown-1.0.2/man/lowdown_nroff_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_nroff_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -85,6 +83,20 @@ are used along with .Ar mspdf . These are only supported by groff. +.Pp +The allocated rendered will use constant-width fonts +.Qq CR +.Pq regular , +.Qq CB +.Pq bold , +.Qq CI +.Pq italic , +and +.Qq CBI +.Pq bold-italic . +Override the defaults with variables in the +.Vt "struct lowdown_opts_nroff" +structure. .Sh RETURN VALUES Returns a pointer to the renderer or .Dv NULL @@ -149,3 +161,7 @@ .Qq Portable Document Format Publishing with GNU Troff by Keith Marshall. Neither are implemented in mandoc. +.Sh CAVEATS +The default constant-width fonts may not available for the formatter's +output device (for example, the terminal). +In this case, the formatter may raise a warning and ignore the font. diff -Nru lowdown-1.0.2/man/lowdown_nroff_rndr.3 lowdown-1.1.0/man/lowdown_nroff_rndr.3 --- lowdown-1.0.2/man/lowdown_nroff_rndr.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_nroff_rndr.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017--2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_odt_free.3 lowdown-1.1.0/man/lowdown_odt_free.3 --- lowdown-1.0.2/man/lowdown_odt_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_odt_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_odt_new.3 lowdown-1.1.0/man/lowdown_odt_new.3 --- lowdown-1.0.2/man/lowdown_odt_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_odt_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_odt_rndr.3 lowdown-1.1.0/man/lowdown_odt_rndr.3 --- lowdown-1.0.2/man/lowdown_odt_rndr.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_odt_rndr.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_term_free.3 lowdown-1.1.0/man/lowdown_term_free.3 --- lowdown-1.0.2/man/lowdown_term_free.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_term_free.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_term_new.3 lowdown-1.1.0/man/lowdown_term_new.3 --- lowdown-1.0.2/man/lowdown_term_new.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_term_new.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_term_rndr.3 lowdown-1.1.0/man/lowdown_term_rndr.3 --- lowdown-1.0.2/man/lowdown_term_rndr.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_term_rndr.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2020 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/man/lowdown_tree_rndr.3 lowdown-1.1.0/man/lowdown_tree_rndr.3 --- lowdown-1.0.2/man/lowdown_tree_rndr.3 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/man/lowdown_tree_rndr.3 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,4 @@ -.\" $Id$ -.\" -.\" Copyright (c) 2017, 2021 Kristaps Dzonsons +.\" Copyright (c) Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/nroff.c lowdown-1.1.0/nroff.c --- lowdown-1.0.2/nroff.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/nroff.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,9 +1,8 @@ -/* $Id$ */ /* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * Copyright (c) 2014, Xavier Mendez, Devin Torres and the Hoedown authors - * Copyright (c) 2016--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -50,6 +49,10 @@ struct bnodeq **foots; /* footnotes */ size_t footsz; /* footnote size */ size_t indent; /* indentation width */ + const char *cr; /* fixed-width font */ + const char *cb; /* fixed-width bold font */ + const char *ci; /* fixed-width italic font */ + const char *cbi; /* fixed-width bold-italic font */ }; enum bscope { @@ -205,41 +208,47 @@ * For compatibility with traditional troff, return non-block font code * using the correct sequence of \fX, \f(xx, and \f[xxx]. */ -static const char * -nstate_font_buf(unsigned int ft, int blk) +static int +nstate_font(const struct nroff *st, struct lowdown_buf *ob, + unsigned int ft, int enclose) { - static char fonts[10]; + const char *font = NULL; + char fonts[3]; char *cp = fonts; - size_t len = 0; - - if (ft & BFONT_FIXED) - len++; - if (ft & BFONT_BOLD) - len++; - if (ft & BFONT_ITALIC) - len++; - if (ft == 0) - len++; - - if (!blk && len == 3) - (*cp++) = '['; - else if (!blk && len == 2) - (*cp++) = '('; - - if (ft & BFONT_FIXED) - (*cp++) = 'C'; - if (ft & BFONT_BOLD) - (*cp++) = 'B'; - if (ft & BFONT_ITALIC) - (*cp++) = 'I'; - if (ft == 0) - (*cp++) = 'R'; + size_t sz; - if (!blk && len == 3) - (*cp++) = ']'; + if (ft & BFONT_FIXED) { + if ((ft & BFONT_BOLD) && (ft & BFONT_ITALIC)) + font = st->cbi; + else if (ft & BFONT_BOLD) + font = st->cb; + else if (ft & BFONT_ITALIC) + font = st->ci; + else + font = st->cr; + } else { + font = cp = fonts; + if (ft & BFONT_BOLD) + (*cp++) = 'B'; + if (ft & BFONT_ITALIC) + (*cp++) = 'I'; + if (ft == 0) + (*cp++) = 'R'; + *cp = '\0'; + } + + assert(font != NULL); + sz = strlen(font); + assert(sz > 0); + + if (!enclose || sz == 1) + return hbuf_puts(ob, font); + + if (sz > 2) + return HBUF_PUTSL(ob, "[") && + hbuf_puts(ob, font) && HBUF_PUTSL(ob, "]"); - (*cp++) = '\0'; - return fonts; + return HBUF_PUTSL(ob, "(") && hbuf_puts(ob, font); } static int @@ -354,7 +363,8 @@ } static int -bqueue_flush(struct lowdown_buf *ob, const struct bnodeq *bq, int esc) +bqueue_flush(const struct nroff *st, struct lowdown_buf *ob, + const struct bnodeq *bq, int esc) { const struct bnode *bn, *chk, *next; const char *cp; @@ -411,12 +421,14 @@ /* Print font and colour escapes. */ if (bn->scope == BSCOPE_FONT && nextblk) { - if (!hbuf_printf(ob, ".ft %s", - nstate_font_buf(bn->font, nextblk))) + if (!HBUF_PUTSL(ob, ".ft ")) + return 0; + if (!nstate_font(st, ob, bn->font, 0)) return 0; } else if (bn->scope == BSCOPE_FONT) { - if (!hbuf_printf(ob, "\\f%s", - nstate_font_buf(bn->font, nextblk))) + if (!HBUF_PUTSL(ob, "\\f")) + return 0; + if (!nstate_font(st, ob, bn->font, 1)) return 0; } else if (bn->scope == BSCOPE_COLOUR) { assert(nextblk); @@ -649,7 +661,7 @@ goto out; if (bq == NULL && !hbuf_putb(ob, link)) goto out; - else if (bq != NULL && !bqueue_flush(ob, bq, 1)) + else if (bq != NULL && !bqueue_flush(st, ob, bq, 1)) goto out; /* @@ -1288,13 +1300,23 @@ } static int -rndr_superscript(struct bnodeq *obq, struct bnodeq *bq) +rndr_superscript(struct bnodeq *obq, struct bnodeq *bq, + enum lowdown_rndrt type) { + const char *p1, *p2; - if (bqueue_span(obq, "\\u\\s-3") == NULL) + /* Lift pandoc's way of doing this. */ + + p1 = (type == LOWDOWN_SUPERSCRIPT) ? + "\\v\'-0.3m\'\\s[\\n[.s]*9u/12u]" : + "\\v\'0.3m\'\\s[\\n[.s]*9u/12u]"; + p2 = (type == LOWDOWN_SUPERSCRIPT) ? + "\\s0\\v\'0.3m\'" : + "\\s0\\v\'-0.3m\'"; + if (bqueue_span(obq, p1) == NULL) return 0; TAILQ_CONCAT(obq, bq, entries); - return bqueue_span(obq, "\\s+3\\d") != NULL; + return bqueue_span(obq, p2) != NULL; } static int @@ -1525,7 +1547,7 @@ if ((ob = hbuf_new(32)) == NULL) return 0; - if (!bqueue_flush(ob, bq, 1)) { + if (!bqueue_flush(st, ob, bq, 1)) { hbuf_free(ob); return 0; } @@ -1843,8 +1865,11 @@ case LOWDOWN_LINK: rc = rndr_link(st, obq, &tmpbq, &n->rndr_link); break; + case LOWDOWN_SUBSCRIPT: + rc = rndr_superscript(obq, &tmpbq, n->type); + break; case LOWDOWN_SUPERSCRIPT: - rc = rndr_superscript(obq, &tmpbq); + rc = rndr_superscript(obq, &tmpbq, n->type); break; case LOWDOWN_FOOTNOTE: rc = rndr_footnote_ref(st, obq, &tmpbq); @@ -1929,7 +1954,7 @@ st->post_para = 0; if (rndr(&metaq, st, n, &bq)) { - if (!bqueue_flush(ob, &bq, 1)) + if (!bqueue_flush(st, ob, &bq, 1)) goto out; if (ob->size && ob->data[ob->size - 1] != '\n' && !hbuf_putc(ob, '\n')) @@ -1962,6 +1987,26 @@ p->flags = opts != NULL ? opts->oflags : 0; p->man = opts != NULL && opts->type == LOWDOWN_MAN; + p->cr = opts != NULL ? opts->nroff.cr : NULL; + p->cb = opts != NULL ? opts->nroff.cb : NULL; + p->ci = opts != NULL ? opts->nroff.ci : NULL; + p->cbi = opts != NULL ? opts->nroff.cbi : NULL; + + /* + * Set the default "constant width" fonts. This is complicated + * because the "C" fixed-with font is not universally available + * on all output media. For example, -Tascii does not carry a + * "C" font. However, this is a good enough default. + */ + + if (p->cr == NULL) + p->cr = "CR"; + if (p->cb == NULL) + p->cb = "CB"; + if (p->ci == NULL) + p->ci = "CI"; + if (p->cbi == NULL) + p->cbi = "CBI"; /* * Set a default indentation. For -man, we use 3 because we diff -Nru lowdown-1.0.2/odt.c lowdown-1.1.0/odt.c --- lowdown-1.0.2/odt.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/odt.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -323,6 +323,12 @@ return 0; } break; + case LOWDOWN_SUBSCRIPT: + if (!HBUF_PUTSL(ob, + "\n")) + return 0; + break; case LOWDOWN_SUPERSCRIPT: if (!HBUF_PUTSL(ob, " this is a +> blockquote +> with +> two spaces at the end of +> ever line diff -Nru lowdown-1.0.2/regress/blockquote-linebreaks.html lowdown-1.1.0/regress/blockquote-linebreaks.html --- lowdown-1.0.2/regress/blockquote-linebreaks.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/blockquote-linebreaks.html 2023-11-08 01:32:59.000000000 +0000 @@ -0,0 +1,7 @@ +
      +

      this is a
      +blockquote
      +with
      +two spaces at the end of
      +ever line

      +
      diff -Nru lowdown-1.0.2/regress/blockquote-linebreaks.md lowdown-1.1.0/regress/blockquote-linebreaks.md --- lowdown-1.0.2/regress/blockquote-linebreaks.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/blockquote-linebreaks.md 2023-11-08 01:32:59.000000000 +0000 @@ -0,0 +1,7 @@ + +> this is a +> blockquote +> with +> two spaces at the end of +> ever line + diff -Nru lowdown-1.0.2/regress/blockquote-linebreaks.term lowdown-1.1.0/regress/blockquote-linebreaks.term --- lowdown-1.0.2/regress/blockquote-linebreaks.term 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/blockquote-linebreaks.term 2023-11-08 01:32:59.000000000 +0000 @@ -0,0 +1,5 @@ +  | this is a +  | blockquote +  | with +  | two spaces at the end of +  | ever line diff -Nru lowdown-1.0.2/regress/simple.gemini lowdown-1.1.0/regress/simple.gemini --- lowdown-1.0.2/regress/simple.gemini 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/regress/simple.gemini 2023-11-08 01:33:00.000000000 +0000 @@ -26,20 +26,23 @@ Note again how the actual text starts at 4 columns in (4 characters from the left side). Here’s a code sample: -```# Let me re-iterate ... +``` +# Let me re-iterate ... for i in 1 .. 10 { do-something(i) } ``` As you probably guessed, indented 4 spaces. By the way, instead of indenting the block, you can use delimited blocks, if you like: -```define foobar() { +``` +define foobar() { print "Welcome to flavor country!"; } ``` (which makes copying & pasting easier). You can optionally mark the delimited block for Pandoc to syntax highlight it: -```import time +``` +import time # Quick, count to ten! for i in range(10): # (but not *too* quick) @@ -61,7 +64,8 @@ 3. Dump everything in the pot and follow this algorithm: -```find wooden spoon +``` +find wooden spoon uncover pot stir cover pot @@ -82,7 +86,7 @@ Tables can look like this: -``` +``` size | material | color -----|-------------|------------- 9 | leather | brown diff -Nru lowdown-1.0.2/regress/simple.man lowdown-1.1.0/regress/simple.man --- lowdown-1.0.2/regress/simple.man 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/regress/simple.man 2023-11-08 01:33:00.000000000 +0000 @@ -3,7 +3,7 @@ .LP Paragraphs are separated by a blank line. .PP -2nd paragraph. \fIItalic\fR, \fBbold\fR, and \fCmonospace\fR. Itemized lists +2nd paragraph. \fIItalic\fR, \fBbold\fR, and \f(CRmonospace\fR. Itemized lists look like: .IP "\(bu" 3 this one diff -Nru lowdown-1.0.2/regress/simple.ms lowdown-1.1.0/regress/simple.ms --- lowdown-1.0.2/regress/simple.ms 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/regress/simple.ms 2023-11-08 01:33:00.000000000 +0000 @@ -5,7 +5,7 @@ .LP Paragraphs are separated by a blank line. .PP -2nd paragraph. \fIItalic\fR, \fBbold\fR, and \fCmonospace\fR. Itemized lists +2nd paragraph. \fIItalic\fR, \fBbold\fR, and \f(CRmonospace\fR. Itemized lists look like: .IP "\(bu" 5 this one diff -Nru lowdown-1.0.2/regress/subscript.fodt lowdown-1.1.0/regress/subscript.fodt --- lowdown-1.0.2/regress/subscript.fodt 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript.fodt 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + +abc + + diff -Nru lowdown-1.0.2/regress/subscript.html lowdown-1.1.0/regress/subscript.html --- lowdown-1.0.2/regress/subscript.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      abc

      diff -Nru lowdown-1.0.2/regress/subscript.latex lowdown-1.1.0/regress/subscript.latex --- lowdown-1.0.2/regress/subscript.latex 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript.latex 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1,2 @@ + +a\textsubscript{b}c diff -Nru lowdown-1.0.2/regress/subscript.md lowdown-1.1.0/regress/subscript.md --- lowdown-1.0.2/regress/subscript.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +a~b~c diff -Nru lowdown-1.0.2/regress/subscript.ms lowdown-1.1.0/regress/subscript.ms --- lowdown-1.0.2/regress/subscript.ms 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript.ms 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1,2 @@ +.PP +a\v'0.3m'\s[\n[.s]*9u/12u]b\s0\v'-0.3m'c diff -Nru lowdown-1.0.2/regress/subscript2.html lowdown-1.1.0/regress/subscript2.html --- lowdown-1.0.2/regress/subscript2.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript2.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      a~b

      diff -Nru lowdown-1.0.2/regress/subscript2.md lowdown-1.1.0/regress/subscript2.md --- lowdown-1.0.2/regress/subscript2.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript2.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +a~b diff -Nru lowdown-1.0.2/regress/subscript3.html lowdown-1.1.0/regress/subscript3.html --- lowdown-1.0.2/regress/subscript3.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript3.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      aab

      diff -Nru lowdown-1.0.2/regress/subscript3.md lowdown-1.1.0/regress/subscript3.md --- lowdown-1.0.2/regress/subscript3.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/subscript3.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +~~a~~~a~b diff -Nru lowdown-1.0.2/regress/superscript.fodt lowdown-1.1.0/regress/superscript.fodt --- lowdown-1.0.2/regress/superscript.fodt 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript.fodt 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + +abc + + diff -Nru lowdown-1.0.2/regress/superscript.html lowdown-1.1.0/regress/superscript.html --- lowdown-1.0.2/regress/superscript.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      abc

      diff -Nru lowdown-1.0.2/regress/superscript.latex lowdown-1.1.0/regress/superscript.latex --- lowdown-1.0.2/regress/superscript.latex 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript.latex 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1,2 @@ + +a\textsuperscript{b}c diff -Nru lowdown-1.0.2/regress/superscript.md lowdown-1.1.0/regress/superscript.md --- lowdown-1.0.2/regress/superscript.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +a^b^c diff -Nru lowdown-1.0.2/regress/superscript.ms lowdown-1.1.0/regress/superscript.ms --- lowdown-1.0.2/regress/superscript.ms 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript.ms 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1,2 @@ +.PP +a\v'-0.3m'\s[\n[.s]*9u/12u]b\s0\v'0.3m'c diff -Nru lowdown-1.0.2/regress/superscript2.html lowdown-1.1.0/regress/superscript2.html --- lowdown-1.0.2/regress/superscript2.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript2.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      a^b c

      diff -Nru lowdown-1.0.2/regress/superscript2.md lowdown-1.1.0/regress/superscript2.md --- lowdown-1.0.2/regress/superscript2.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript2.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +a^b c diff -Nru lowdown-1.0.2/regress/superscript3.html lowdown-1.1.0/regress/superscript3.html --- lowdown-1.0.2/regress/superscript3.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript3.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      a^ c

      diff -Nru lowdown-1.0.2/regress/superscript3.md lowdown-1.1.0/regress/superscript3.md --- lowdown-1.0.2/regress/superscript3.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript3.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +a^ c diff -Nru lowdown-1.0.2/regress/superscript4.html lowdown-1.1.0/regress/superscript4.html --- lowdown-1.0.2/regress/superscript4.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript4.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      abc^d

      diff -Nru lowdown-1.0.2/regress/superscript4.md lowdown-1.1.0/regress/superscript4.md --- lowdown-1.0.2/regress/superscript4.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript4.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +a^b^c^d diff -Nru lowdown-1.0.2/regress/superscript5.html lowdown-1.1.0/regress/superscript5.html --- lowdown-1.0.2/regress/superscript5.html 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript5.html 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +

      abcde

      diff -Nru lowdown-1.0.2/regress/superscript5.md lowdown-1.1.0/regress/superscript5.md --- lowdown-1.0.2/regress/superscript5.md 1970-01-01 00:00:00.000000000 +0000 +++ lowdown-1.1.0/regress/superscript5.md 2023-11-08 01:33:01.000000000 +0000 @@ -0,0 +1 @@ +a^b^c^d^e diff -Nru lowdown-1.0.2/smartypants.c lowdown-1.1.0/smartypants.c --- lowdown-1.0.2/smartypants.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/smartypants.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2020 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -144,6 +143,7 @@ TYPE_SPAN, /* LOWDOWN_LINK */ TYPE_SPAN, /* LOWDOWN_TRIPLE_EMPHASIS */ TYPE_SPAN, /* LOWDOWN_STRIKETHROUGH */ + TYPE_SPAN, /* LOWDOWN_SUBSCRIPT */ TYPE_SPAN, /* LOWDOWN_SUPERSCRIPT */ TYPE_BLOCK, /* LOWDOWN_FOOTNOTE */ TYPE_OPAQUE, /* LOWDOWN_MATH_BLOCK */ diff -Nru lowdown-1.0.2/term.c lowdown-1.1.0/term.c --- lowdown-1.0.2/term.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/term.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2020--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -53,6 +52,7 @@ struct lowdown_buf **foots; /* footnotes */ size_t footsz; /* footnotes size */ int footoff; /* don't collect (tables) */ + struct lowdown_metaq metaq; /* metadata */ }; /* @@ -109,6 +109,7 @@ &sty_link, /* LOWDOWN_LINK */ &sty_t_emph, /* LOWDOWN_TRIPLE_EMPHASIS */ &sty_strike, /* LOWDOWN_STRIKETHROUGH */ + NULL, /* LOWDOWN_SUBSCRIPT */ NULL, /* LOWDOWN_SUPERSCRIPT */ NULL, /* LOWDOWN_FOOTNOTE */ NULL, /* LOWDOWN_MATH_BLOCK */ @@ -949,21 +950,21 @@ * Adjust the stack of current nodes we're looking at. */ static int -rndr_stackpos_init(struct term *p, const struct lowdown_node *n) +rndr_stackpos_init(struct term *st, const struct lowdown_node *n) { void *pp; - if (p->stackpos >= p->stackmax) { - p->stackmax += 256; - pp = reallocarray(p->stack, - p->stackmax, sizeof(struct tstack)); + if (st->stackpos >= st->stackmax) { + st->stackmax += 256; + pp = reallocarray(st->stack, + st->stackmax, sizeof(struct tstack)); if (pp == NULL) return 0; - p->stack = pp; + st->stack = pp; } - memset(&p->stack[p->stackpos], 0, sizeof(struct tstack)); - p->stack[p->stackpos].n = n; + memset(&st->stack[st->stackpos], 0, sizeof(struct tstack)); + st->stack[st->stackpos].n = n; return 1; } @@ -971,7 +972,7 @@ * Return zero on failure (memory), non-zero on success. */ static int -rndr_table(struct lowdown_buf *ob, struct term *p, +rndr_table(struct lowdown_buf *ob, struct term *st, const struct lowdown_node *n) { size_t *widths = NULL; @@ -999,9 +1000,9 @@ * keep the current size (which will otherwise advance). */ - assert(!p->footoff); - p->footoff = 1; - footsz = p->footsz; + assert(!st->footoff); + st->footoff = 1; + footsz = st->footsz; TAILQ_FOREACH(top, &n->children, entries) { assert(top->type == LOWDOWN_TABLE_HEADER || @@ -1020,28 +1021,28 @@ * line wrapping. */ - maxcol = p->maxcol; - last_blank = p->last_blank; - col = p->col; - - p->last_blank = 0; - p->maxcol = SIZE_MAX; - p->col = 1; - if (!rndr(celltmp, p, cell)) + maxcol = st->maxcol; + last_blank = st->last_blank; + col = st->col; + + st->last_blank = 0; + st->maxcol = SIZE_MAX; + st->col = 1; + if (!rndr(celltmp, st, cell)) goto out; - if (widths[i] < p->col) - widths[i] = p->col; - p->last_blank = last_blank; - p->col = col; - p->maxcol = maxcol; + if (widths[i] < st->col) + widths[i] = st->col; + st->last_blank = last_blank; + st->col = col; + st->maxcol = maxcol; } } /* Restore footnotes. */ - p->footsz = footsz; - assert(p->footoff); - p->footoff = 0; + st->footsz = footsz; + assert(st->footoff); + st->footoff = 0; /* Now actually print, row-by-row into the output. */ @@ -1053,17 +1054,17 @@ TAILQ_FOREACH(cell, &row->children, entries) { i = cell->rndr_table_cell.col; hbuf_truncate(celltmp); - maxcol = p->maxcol; - last_blank = p->last_blank; - col = p->col; - - p->last_blank = 0; - p->maxcol = SIZE_MAX; - p->col = 1; - if (!rndr(celltmp, p, cell)) + maxcol = st->maxcol; + last_blank = st->last_blank; + col = st->col; + + st->last_blank = 0; + st->maxcol = SIZE_MAX; + st->col = 1; + if (!rndr(celltmp, st, cell)) goto out; - assert(widths[i] >= p->col); - sz = widths[i] - p->col; + assert(widths[i] >= st->col); + sz = widths[i] - st->col; /* * Alignment is either beginning, @@ -1098,16 +1099,16 @@ goto out; } - p->last_blank = last_blank; - p->col = col; - p->maxcol = maxcol; + st->last_blank = last_blank; + st->col = col; + st->maxcol = maxcol; if (TAILQ_NEXT(cell, entries) == NULL) continue; - if (!rndr_buf_style(p, rowtmp, &sty_table) || + if (!rndr_buf_style(st, rowtmp, &sty_table) || !hbuf_printf(rowtmp, " %s ", ifx_table_col) || - !rndr_buf_unstyle(p, rowtmp, &sty_table)) + !rndr_buf_unstyle(st, rowtmp, &sty_table)) goto out; } @@ -1121,26 +1122,26 @@ * our own. Then end the line. */ - p->stackpos++; - if (!rndr_stackpos_init(p, n)) + st->stackpos++; + if (!rndr_stackpos_init(st, n)) goto out; - if (!rndr_buf_startline(p, ob, n, NULL)) + if (!rndr_buf_startline(st, ob, n, NULL)) goto out; if (!hbuf_putb(ob, rowtmp)) goto out; - rndr_buf_advance(p, 1); - if (!rndr_buf_endline(p, ob, n, NULL)) + rndr_buf_advance(st, 1); + if (!rndr_buf_endline(st, ob, n, NULL)) goto out; - if (!rndr_buf_vspace(p, ob, n, 1)) + if (!rndr_buf_vspace(st, ob, n, 1)) goto out; - p->stackpos--; + st->stackpos--; } if (top->type == LOWDOWN_TABLE_HEADER) { - p->stackpos++; - if (!rndr_stackpos_init(p, n)) + st->stackpos++; + if (!rndr_stackpos_init(st, n)) goto out; - if (!rndr_buf_startline(p, ob, n, &sty_table)) + if (!rndr_buf_startline(st, ob, n, &sty_table)) goto out; for (i = 0; i < n->rndr_table.columns; i++) { for (j = 0; j < widths[i]; j++) @@ -1151,12 +1152,12 @@ ifx_table_col, ifx_table_row)) goto out; } - rndr_buf_advance(p, 1); - if (!rndr_buf_endline(p, ob, n, &sty_table)) + rndr_buf_advance(st, 1); + if (!rndr_buf_endline(st, ob, n, &sty_table)) goto out; - if (!rndr_buf_vspace(p, ob, n, 1)) + if (!rndr_buf_vspace(st, ob, n, 1)) goto out; - p->stackpos--; + st->stackpos--; } } @@ -1168,20 +1169,177 @@ return rc; } +/* + * Output a title-value pair. If "multi" is specified, break up into + * multiple title-value lines. + * + * Return zero on failure (memory), non-zero otherwise. + */ +static int +rndr_doc_header_meta(struct lowdown_buf *ob, struct term *st, + const struct lowdown_node *n, const char *title, + const char *value, int multi) +{ + const char *start, *end; + + for (start = value; *start != '\0';) { + if (multi) { + for (end = start + 1; *end != '\0'; end++) + if (isspace((unsigned char)end[0]) && + isspace((unsigned char)end[1])) + break; + } else + end = start + strlen(start); + + if (!rndr_buf_vspace(st, ob, n, 1)) + return 0; + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, title) || + !rndr_buf(st, ob, n, st->tmp, &sty_meta_key)) + return 0; + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, ifx_meta_key) || + !rndr_buf(st, ob, n, st->tmp, &sty_meta_key)) + return 0; + hbuf_truncate(st->tmp); + if (!hbuf_put(st->tmp, start, (size_t)(end - start)) || + !rndr_buf(st, ob, n, st->tmp, NULL)) + return 0; + + start = end; + while (*start != '\0' && isspace((unsigned char)*start)) + start++; + } + + return 1; +} + +/* + * Conditionally emit a document header containing the title, author, + * and date. + */ +static int +rndr_doc_header(struct lowdown_buf *ob, struct term *st, + const struct lowdown_node *n) +{ + const char *title = NULL, *author = NULL, + *date = NULL, *rcsdate = NULL, + *rcsauthor = NULL; + const struct lowdown_meta *m; + + if (!(st->opts & LOWDOWN_STANDALONE)) + return 1; + + if (st->opts & LOWDOWN_TERM_ALL_META) { + TAILQ_FOREACH(m, &st->metaq, entries) + if (!rndr_doc_header_meta(ob, st, n, m->key, + m->value, 0)) + return 0; + return 1; + } + + TAILQ_FOREACH(m, &st->metaq, entries) + if (strcasecmp(m->key, "title") == 0) + title = m->value; + else if (strcasecmp(m->key, "author") == 0) + author = m->value; + else if (strcasecmp(m->key, "date") == 0) + date = m->value; + else if (strcasecmp(m->key, "rcsauthor") == 0) + rcsauthor = rcsauthor2str(m->value); + else if (strcasecmp(m->key, "rcsdate") == 0) + rcsdate = rcsdate2str(m->value); + + /* Overrides. */ + + if (rcsdate != NULL) + date = rcsdate; + if (rcsauthor != NULL) + author = rcsauthor; + + if (title != NULL && + !rndr_doc_header_meta(ob, st, n, "title", title, 0)) + return 0; + if (author != NULL && + !rndr_doc_header_meta(ob, st, n, "author", author, 1)) + return 0; + if (date != NULL && + !rndr_doc_header_meta(ob, st, n, "date", date, 0)) + return 0; + + return 1; +} + +/* + * Extract metadata into "metaq". This avoids calling rndr_buf() + * because of all the line fiddling: because we know the contents of the + * LOWDOWN_META, serialise directly into the metadata value without + * formatting. + * + * This will be serialised to the ouptut buffer in rndr_doc_header(). + * + * Return zero on failure (memory), non-zero otherwise. + */ +static int +rndr_meta(struct term *st, const struct lowdown_node *n) +{ + struct lowdown_meta *m; + const struct lowdown_node *child; + struct lowdown_buf *metatmp; + int32_t entity; + + m = calloc(1, sizeof(struct lowdown_meta)); + if (m == NULL) + return 0; + TAILQ_INSERT_TAIL(&st->metaq, m, entries); + m->key = strndup(n->rndr_meta.key.data, + n->rndr_meta.key.size); + if (m->key == NULL) + return 0; + if ((metatmp = hbuf_new(128)) == NULL) + return 0; + TAILQ_FOREACH(child, &n->children, entries) { + switch (child->type) { + case LOWDOWN_NORMAL_TEXT: + if (!hbuf_putb(metatmp, + &child->rndr_normal_text.text)) + return 0; + break; + case LOWDOWN_ENTITY: + entity = entity_find_iso + (&child->rndr_entity.text); + if (entity == 0) + break; + hbuf_truncate(st->tmp); + if (!rndr_entity(st->tmp, entity) || + !hbuf_putb(metatmp, st->tmp)) + return 0; + break; + default: + abort(); + } + } + m->value = strndup(metatmp->data, metatmp->size); + if (m->value == NULL) + return 0; + hbuf_free(metatmp); + return 1; +} + static int -rndr(struct lowdown_buf *ob, struct term *p, +rndr(struct lowdown_buf *ob, struct term *st, const struct lowdown_node *n) { const struct lowdown_node *child, *nn; struct lowdown_buf *metatmp; void *pp; - int32_t entity; size_t i, col, vs; ssize_t last_blank; + int32_t entity; /* Current nodes we're servicing. */ - if (!rndr_stackpos_init(p, n)) + if (!rndr_stackpos_init(st, n)) return 0; /* @@ -1195,10 +1353,10 @@ vs = 0; switch (n->type) { case LOWDOWN_ROOT: - for (i = 0; i < p->vmargin; i++) + for (i = 0; i < st->vmargin; i++) if (!HBUF_PUTSL(ob, "\n")) return 0; - p->last_blank = -1; + st->last_blank = -1; break; case LOWDOWN_BLOCKCODE: case LOWDOWN_BLOCKHTML: @@ -1223,7 +1381,6 @@ case LOWDOWN_DEFINITION_DATA: case LOWDOWN_HRULE: case LOWDOWN_LINEBREAK: - case LOWDOWN_META: vs = 1; break; case LOWDOWN_LISTITEM: @@ -1240,25 +1397,16 @@ break; } - if (vs > 0 && !rndr_buf_vspace(p, ob, n, vs)) + if (vs > 0 && !rndr_buf_vspace(st, ob, n, vs)) return 0; /* Output leading content. */ switch (n->type) { case LOWDOWN_SUPERSCRIPT: - hbuf_truncate(p->tmp); - if (!hbuf_puts(p->tmp, ifx_super) || - !rndr_buf(p, ob, n, p->tmp, NULL)) - return 0; - break; - case LOWDOWN_META: - if (!rndr_buf(p, ob, n, - &n->rndr_meta.key, &sty_meta_key)) - return 0; - hbuf_truncate(p->tmp); - if (!hbuf_puts(p->tmp, ifx_meta_key) || - !rndr_buf(p, ob, n, p->tmp, &sty_meta_key)) + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, ifx_super) || + !rndr_buf(st, ob, n, st->tmp, NULL)) return 0; break; default: @@ -1269,41 +1417,45 @@ switch (n->type) { case LOWDOWN_FOOTNOTE: - if (p->footoff) { - p->footsz++; + if (st->footoff) { + st->footsz++; break; } - last_blank = p->last_blank; - p->last_blank = -1; - col = p->col; - p->col = 0; + last_blank = st->last_blank; + st->last_blank = -1; + col = st->col; + st->col = 0; if ((metatmp = hbuf_new(128)) == NULL) return 0; TAILQ_FOREACH(child, &n->children, entries) { - p->stackpos++; - if (!rndr(metatmp, p, child)) + st->stackpos++; + if (!rndr(metatmp, st, child)) return 0; - p->stackpos--; + st->stackpos--; } - p->last_blank = last_blank; - p->col = col; - pp = recallocarray(p->foots, p->footsz, - p->footsz + 1, sizeof(struct lowdown_buf *)); + st->last_blank = last_blank; + st->col = col; + pp = recallocarray(st->foots, st->footsz, + st->footsz + 1, sizeof(struct lowdown_buf *)); if (pp == NULL) return 0; - p->foots = pp; - p->foots[p->footsz++] = metatmp; + st->foots = pp; + st->foots[st->footsz++] = metatmp; break; case LOWDOWN_TABLE_BLOCK: - if (!rndr_table(ob, p, n)) + if (!rndr_table(ob, st, n)) + return 0; + break; + case LOWDOWN_META: + if (!rndr_meta(st, n)) return 0; break; default: TAILQ_FOREACH(child, &n->children, entries) { - p->stackpos++; - if (!rndr(ob, p, child)) + st->stackpos++; + if (!rndr(ob, st, child)) return 0; - p->stackpos--; + st->stackpos--; } break; } @@ -1311,136 +1463,140 @@ /* Output content. */ switch (n->type) { + case LOWDOWN_DOC_HEADER: + if (!rndr_doc_header(ob, st, n)) + return 0; + break; case LOWDOWN_HRULE: - hbuf_truncate(p->tmp); - if (!hbuf_puts(p->tmp, ifx_hrule)) + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, ifx_hrule)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, NULL)) + if (!rndr_buf(st, ob, n, st->tmp, NULL)) return 0; break; case LOWDOWN_FOOTNOTE: - hbuf_truncate(p->tmp); - if (!hbuf_printf(p->tmp, "%s%zu%s", ifx_fref_left, - p->footsz, ifx_fref_right)) + hbuf_truncate(st->tmp); + if (!hbuf_printf(st->tmp, "%s%zu%s", ifx_fref_left, + st->footsz, ifx_fref_right)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, &sty_fref)) + if (!rndr_buf(st, ob, n, st->tmp, &sty_fref)) return 0; break; case LOWDOWN_RAW_HTML: - if (!rndr_buf(p, ob, n, &n->rndr_raw_html.text, NULL)) + if (!rndr_buf(st, ob, n, &n->rndr_raw_html.text, NULL)) return 0; break; case LOWDOWN_MATH_BLOCK: - if (!rndr_buf(p, ob, n, &n->rndr_math.text, NULL)) + if (!rndr_buf(st, ob, n, &n->rndr_math.text, NULL)) return 0; break; case LOWDOWN_ENTITY: entity = entity_find_iso(&n->rndr_entity.text); if (entity > 0) { - hbuf_truncate(p->tmp); - if (!rndr_entity(p->tmp, entity)) + hbuf_truncate(st->tmp); + if (!rndr_entity(st->tmp, entity)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, NULL)) + if (!rndr_buf(st, ob, n, st->tmp, NULL)) return 0; } else { - if (!rndr_buf(p, ob, n, + if (!rndr_buf(st, ob, n, &n->rndr_entity.text, &sty_bad_ent)) return 0; } break; case LOWDOWN_BLOCKCODE: - if (!rndr_buf(p, ob, n, &n->rndr_blockcode.text, NULL)) + if (!rndr_buf(st, ob, n, &n->rndr_blockcode.text, NULL)) return 0; break; case LOWDOWN_BLOCKHTML: - if (!rndr_buf(p, ob, n, &n->rndr_blockhtml.text, NULL)) + if (!rndr_buf(st, ob, n, &n->rndr_blockhtml.text, NULL)) return 0; break; case LOWDOWN_CODESPAN: - if (!rndr_buf(p, ob, n, &n->rndr_codespan.text, NULL)) + if (!rndr_buf(st, ob, n, &n->rndr_codespan.text, NULL)) return 0; break; case LOWDOWN_LINK_AUTO: - if (p->opts & LOWDOWN_TERM_SHORTLINK) { - hbuf_truncate(p->tmp); + if (st->opts & LOWDOWN_TERM_SHORTLINK) { + hbuf_truncate(st->tmp); if (!hbuf_shortlink - (p->tmp, &n->rndr_autolink.link)) + (st->tmp, &n->rndr_autolink.link)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, NULL)) + if (!rndr_buf(st, ob, n, st->tmp, NULL)) return 0; } else { - if (!rndr_buf(p, ob, n, + if (!rndr_buf(st, ob, n, &n->rndr_autolink.link, NULL)) return 0; } break; case LOWDOWN_LINK: - if (p->opts & LOWDOWN_TERM_NOLINK) + if (st->opts & LOWDOWN_TERM_NOLINK) break; - hbuf_truncate(p->tmp); - if (!HBUF_PUTSL(p->tmp, " ")) + hbuf_truncate(st->tmp); + if (!HBUF_PUTSL(st->tmp, " ")) return 0; - if (!rndr_buf(p, ob, n, p->tmp, NULL)) + if (!rndr_buf(st, ob, n, st->tmp, NULL)) return 0; - if (p->opts & LOWDOWN_TERM_SHORTLINK) { - hbuf_truncate(p->tmp); + if (st->opts & LOWDOWN_TERM_SHORTLINK) { + hbuf_truncate(st->tmp); if (!hbuf_shortlink - (p->tmp, &n->rndr_link.link)) + (st->tmp, &n->rndr_link.link)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, NULL)) + if (!rndr_buf(st, ob, n, st->tmp, NULL)) return 0; } else { - if (!rndr_buf(p, ob, n, + if (!rndr_buf(st, ob, n, &n->rndr_link.link, NULL)) return 0; } break; case LOWDOWN_IMAGE: - if (!rndr_buf(p, ob, n, &n->rndr_image.alt, NULL)) + if (!rndr_buf(st, ob, n, &n->rndr_image.alt, NULL)) return 0; if (n->rndr_image.alt.size) { - hbuf_truncate(p->tmp); - if (!HBUF_PUTSL(p->tmp, " ")) + hbuf_truncate(st->tmp); + if (!HBUF_PUTSL(st->tmp, " ")) return 0; - if (!rndr_buf(p, ob, n, p->tmp, NULL)) + if (!rndr_buf(st, ob, n, st->tmp, NULL)) return 0; } - if (p->opts & LOWDOWN_TERM_NOLINK) { - hbuf_truncate(p->tmp); - if (!hbuf_puts(p->tmp, ifx_imgbox_left)) + if (st->opts & LOWDOWN_TERM_NOLINK) { + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, ifx_imgbox_left)) return 0; - if (!hbuf_puts(p->tmp, ifx_imgbox_right)) + if (!hbuf_puts(st->tmp, ifx_imgbox_right)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, &sty_imgbox)) + if (!rndr_buf(st, ob, n, st->tmp, &sty_imgbox)) return 0; break; } - hbuf_truncate(p->tmp); - if (!hbuf_puts(p->tmp, ifx_imgbox_left)) + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, ifx_imgbox_left)) return 0; - if (!hbuf_puts(p->tmp, ifx_imgbox_sep)) + if (!hbuf_puts(st->tmp, ifx_imgbox_sep)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, &sty_imgbox)) + if (!rndr_buf(st, ob, n, st->tmp, &sty_imgbox)) return 0; - if (p->opts & LOWDOWN_TERM_SHORTLINK) { - hbuf_truncate(p->tmp); + if (st->opts & LOWDOWN_TERM_SHORTLINK) { + hbuf_truncate(st->tmp); if (!hbuf_shortlink - (p->tmp, &n->rndr_image.link)) + (st->tmp, &n->rndr_image.link)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, &sty_imgurl)) + if (!rndr_buf(st, ob, n, st->tmp, &sty_imgurl)) return 0; } else - if (!rndr_buf(p, ob, n, + if (!rndr_buf(st, ob, n, &n->rndr_image.link, &sty_imgurl)) return 0; - hbuf_truncate(p->tmp); - if (!hbuf_puts(p->tmp, ifx_imgbox_right)) + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, ifx_imgbox_right)) return 0; - if (!rndr_buf(p, ob, n, p->tmp, &sty_imgbox)) + if (!rndr_buf(st, ob, n, st->tmp, &sty_imgbox)) return 0; break; case LOWDOWN_NORMAL_TEXT: - if (!rndr_buf(p, ob, n, + if (!rndr_buf(st, ob, n, &n->rndr_normal_text.text, NULL)) return 0; break; @@ -1451,26 +1607,25 @@ /* Trailing block spaces. */ if (n->type == LOWDOWN_ROOT) { - if (p->footsz) { - if (!rndr_buf_vspace(p, ob, n, 2)) + if (st->footsz) { + if (!rndr_buf_vspace(st, ob, n, 2)) return 0; - hbuf_truncate(p->tmp); - if (!hbuf_puts(p->tmp, pfx_body.text)) + hbuf_truncate(st->tmp); + if (!hbuf_puts(st->tmp, pfx_body.text)) return 0; - if (!hbuf_puts(p->tmp, ifx_foot)) + if (!hbuf_puts(st->tmp, ifx_foot)) return 0; - if (!rndr_buf_literal(p, ob, n, p->tmp, &sty_foot)) + if (!rndr_buf_literal(st, ob, n, st->tmp, + &sty_foot)) return 0; - if (!rndr_buf_vspace(p, ob, n, 2)) + if (!rndr_buf_vspace(st, ob, n, 2)) return 0; - for (i = 0; i < p->footsz; i++) { - if (!hbuf_putb(ob, p->foots[i])) + for (i = 0; i < st->footsz; i++) + if (!hbuf_putb(ob, st->foots[i]) || + !HBUF_PUTSL(ob, "\n")) return 0; - if (!HBUF_PUTSL(ob, "\n")) - return 0; - } } - if (!rndr_buf_vspace(p, ob, n, 1)) + if (!rndr_buf_vspace(st, ob, n, 1)) return 0; while (ob->size && ob->data[ob->size - 1] == '\n') ob->size--; @@ -1479,7 +1634,7 @@ /* Strip breaks but for the vmargin. */ - for (i = 0; i < p->vmargin; i++) + for (i = 0; i < st->vmargin; i++) if (!HBUF_PUTSL(ob, "\n")) return 0; } @@ -1494,48 +1649,49 @@ struct term *st = arg; int rc; + TAILQ_INIT(&st->metaq); st->stackpos = 0; - rc = rndr(ob, st, n); rndr_free_footnotes(st); + lowdown_metaq_free(&st->metaq); return rc; } void * lowdown_term_new(const struct lowdown_opts *opts) { - struct term *p; + struct term *st; - if ((p = calloc(1, sizeof(struct term))) == NULL) + if ((st = calloc(1, sizeof(struct term))) == NULL) return NULL; /* Give us 80 columns by default. */ if (opts != NULL) { - p->maxcol = opts->cols == 0 ? 80 : opts->cols; - p->hmargin = opts->hmargin; - p->vmargin = opts->vmargin; - p->opts = opts->oflags; + st->maxcol = opts->cols == 0 ? 80 : opts->cols; + st->hmargin = opts->hmargin; + st->vmargin = opts->vmargin; + st->opts = opts->oflags; } else - p->maxcol = 80; + st->maxcol = 80; - if ((p->tmp = hbuf_new(32)) == NULL) { - free(p); + if ((st->tmp = hbuf_new(32)) == NULL) { + free(st); return NULL; } - return p; + return st; } void lowdown_term_free(void *arg) { - struct term *p = arg; + struct term *st = arg; - if (p == NULL) + if (st == NULL) return; - hbuf_free(p->tmp); - free(p->buf); - free(p->stack); - free(p); + hbuf_free(st->tmp); + free(st->buf); + free(st->stack); + free(st); } diff -Nru lowdown-1.0.2/term.h lowdown-1.1.0/term.h --- lowdown-1.0.2/term.h 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/term.h 2023-11-08 01:32:57.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff -Nru lowdown-1.0.2/tree.c lowdown-1.1.0/tree.c --- lowdown-1.0.2/tree.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/tree.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2017--2021 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -58,6 +57,7 @@ "LOWDOWN_LINK", /* LOWDOWN_LINK */ "LOWDOWN_TRIPLE_EMPHASIS", /* LOWDOWN_TRIPLE_EMPHASIS */ "LOWDOWN_STRIKETHROUGH", /* LOWDOWN_STRIKETHROUGH */ + "LOWDOWN_SUBSCRIPT", /* LOWDOWN_SUBSCRIPT */ "LOWDOWN_SUPERSCRIPT", /* LOWDOWN_SUPERSCRIPT */ "LOWDOWN_FOOTNOTE", /* LOWDOWN_FOOTNOTE */ "LOWDOWN_MATH_BLOCK", /* LOWDOWN_MATH_BLOCK */ @@ -273,6 +273,20 @@ if (!HBUF_PUTSL(ob, "\n")) return 0; break; + case LOWDOWN_BLOCKQUOTE: + if (root->rndr_blockquote.type == BLOCKQUOTE_REGULAR) + break; + if (!rndr_indent(ob, indent + 1)) + return 0; + if (!hbuf_printf(ob, "admonition (%s): %s\n", + root->rndr_blockquote.type == BLOCKQUOTE_ADMONITION ? + "single-line" : "double-line", + root->rndr_blockquote.admonition == ADMONITION_NOTE ? + "note" : + root->rndr_blockquote.admonition == ADMONITION_WARNING ? + "warning" : "callout")) + return 0; + break; case LOWDOWN_BLOCKCODE: if (!rndr_indent(ob, indent + 1)) return 0; diff -Nru lowdown-1.0.2/util.c lowdown-1.1.0/util.c --- lowdown-1.0.2/util.c 2023-05-20 19:11:09.000000000 +0000 +++ lowdown-1.1.0/util.c 2023-11-08 01:32:58.000000000 +0000 @@ -1,6 +1,5 @@ -/* $Id$ */ /* - * Copyright (c) 2017 Kristaps Dzonsons + * Copyright (c) Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above
      +A table cell described by +.Li , or .Li if in the header. -Parent is always -.Dv LOWDOWN_TABLE_ROW . -(Only if configured during parse.) .It Dv LOWDOWN_TABLE_HEADER -A table header section. -Described by +A table header section described by .Li