Hi Branden, Dave, and others, I've been playing a bit with neatroff lately, and tried separating alignment from adjustment that we've discussed here before. I am attaching the (mostly complete) patch below.[1]
It adds new request .al (align) with possible arguments l, c, r, while .ad now takes only b, p, k.[2] I am looking for your opinions regarding this alternative behavior, mostly in relation to https://savannah.gnu.org/bugs/?65954. I assume the old behavior would be retained in compatibility mode, but that isn't part of the patch yet. I personally find it intriguing, but am not sure if it's worth the breaking change. To test it: git clone https://github.com/aligrudi/neatroff_make cd neatroff_make make init cd neatroff git apply path/to/patch cd .. make neat neatroff/roff -F. INPUT.tr | neatpost/pdf -F. -pa4 > OUTPUT.pdf ~ onf [1] If anyone is wondering why not patch groff, besides the fact that I have zero experience with C++, neatroff's code base is just an order of magnitude easier to understand and navigate through. [2] p = paragraph-at-once adjustment k = keshideh adjustment (used for Arabic script) ---8<--------------------------------------------------8<------------ >From 84cad1ef5d0ff568e3bbfe51f2134517ee1aa726 Mon Sep 17 00:00:00 2001 From: onf <o...@disroot.org> Date: Fri, 10 Jan 2025 16:15:56 +0100 Subject: [PATCH neatroff] decouple alignment from adjustment (new request .al), remove .na mode TODO: check behavior of \p TODO: commit message TODO: backwards compatibility --- fmt.c | 4 ++-- reg.c | 8 +++++--- ren.c | 38 +++++++++++++++++++++---------------- roff.h | 19 ++++++++++++------- tr.c | 60 ++++++++++++++++++++++++++++++++++------------------------ 5 files changed, 76 insertions(+), 53 deletions(-) diff --git a/fmt.c b/fmt.c index ce48cb4..bf499b0 100644 --- a/fmt.c +++ b/fmt.c @@ -18,7 +18,7 @@ #define FMT_LLEN(f) MAX(0, (f)->ll - (f)->li - (f)->lI) #define FMT_FILL(f) (!n_ce && n_u) -#define FMT_ADJ(f) (n_u && !n_na && !n_ce && (n_j & AD_B) == AD_B) +#define FMT_ADJ(f) (n_u && !n_ce && n_j) static int fmt_fillwords(struct fmt *f, int br); @@ -194,7 +194,7 @@ static int fmt_extractline(struct fmt *f, int beg, int end, int str) return 1; llen = FMT_LLEN(f); w = fmt_wordslen(f, beg, end); - if (str && FMT_ADJ(f) && n_j & AD_K) { + if (str && FMT_ADJ(f) && n_j == AD_K) { fmt_keshideh(f, beg, end, llen - w); w = fmt_wordslen(f, beg, end); } diff --git a/reg.c b/reg.c index e817de7..00d5d53 100644 --- a/reg.c +++ b/reg.c @@ -33,11 +33,11 @@ static int env_id; /* current environment id */ static int eregs_idx[NREGS]; /* register environment index in eregs[] */ static char *eregs[] = { /* environment-specific number registers */ - "ln", ".f", ".i", ".j", ".l", + "ln", ".al", ".f", ".i", ".j", ".l", ".L", ".nI", ".nm", ".nM", ".nn", ".nS", ".m", ".s", ".u", ".v", ".it", ".itn", ".mc", ".mcn", - ".ce", ".f0", ".i0", ".l0", + ".ce", ".al0", ".f0", ".i0", ".j0", ".l0", ".hy", ".hycost", ".hycost2", ".hycost3", ".hlm", ".L0", ".m0", ".n0", ".s0", ".ss", ".ssh", ".sss", ".pmll", ".pmllcost", ".ti", ".lt", ".lt0", ".v0", @@ -229,10 +229,13 @@ static void env_set(int id) if (!env) { envs[id] = env_alloc(); env = envs[id]; + n_al = AL_L; + n_al0 = AL_L; n_f = 1; n_i = 0; n_I = 0; n_j = AD_B; + n_j0 = AD_B; n_l = SC_IN * 65 / 10; n_L = 1; n_s = 10; @@ -240,7 +243,6 @@ static void env_set(int id) n_v = 12 * SC_PT; n_s0 = n_s; n_f0 = n_f; - n_na = 0; n_lt = SC_IN * 65 / 10; n_hy = 1; n_ss = 12; diff --git a/ren.c b/ren.c index 8a9a204..4e532ed 100644 --- a/ren.c +++ b/ren.c @@ -236,15 +236,15 @@ static int down(int n) return ren_pagelimit(0); } -/* line adjustment */ -static int ren_ljust(struct sbuf *spre, int w, int ad, int li, int lI, int ll) +/* line alignment */ +static int ren_ljust(struct sbuf *spre, int w, int al, int li, int lI, int ll) { int ljust = li; int llen = ll - lI - li; n_n = w; - if ((ad & AD_B) == AD_C) + if (al == AL_C) ljust += llen > w ? (llen - w) / 2 : 0; - if ((ad & AD_B) == AD_R) + if (al == AL_R) ljust += llen - w; if (ljust) sbuf_printf(spre, "%ch'%du'", c_ec, ljust); @@ -326,7 +326,7 @@ static void ren_mc(struct sbuf *sbuf, int w, int ljust) } /* process a line and print it with ren_out() */ -static int ren_line(char *line, int w, int ad, int body, +static int ren_line(char *line, int w, int al, int body, int li, int lI, int ll, int els_neg, int els_pos) { struct sbuf sbeg, send, sbuf; @@ -336,7 +336,7 @@ static int ren_line(char *line, int w, int ad, int body, sbuf_init(&send); sbuf_init(&sbuf); sbuf_append(&sbuf, line); - lspc = MAX(1, n_L) * n_v; /* line space, ignoreing \x */ + lspc = MAX(1, n_L) * n_v; /* line space, ignoring \x */ prev_d = n_d; if (!n_ns || line[0] || els_neg || els_pos) { if (els_neg) @@ -346,7 +346,7 @@ static int ren_line(char *line, int w, int ad, int body, ren_lnum(&sbeg); if (!ren_div && dir_do) ren_dir(&sbuf); - ljust = ren_ljust(&sbeg, w, ad, li, lI, ll); + ljust = ren_ljust(&sbeg, w, al, li, lI, ll); if (line[0] && body && n_mc) ren_mc(&send, w, ljust); ren_out(sbuf_buf(&sbeg), sbuf_buf(&sbuf), sbuf_buf(&send)); @@ -373,18 +373,16 @@ static int ren_passline(struct fmt *fmt) { char *buf; int ll, li, lI, els_neg, els_pos, w, ret; - int ad = n_j; + int al = n_al; ren_first(); if (!fmt_morewords(fmt)) return 0; buf = fmt_nextline(fmt, &w, &li, &lI, &ll, &els_neg, &els_pos); - if ((n_cp && !n_u) || n_na) - ad = AD_L; - else if ((ad & AD_B) == AD_B) - ad = n_td > 0 ? AD_R : AD_L; + if (n_cp && !n_u) + al = AL_L; if (n_ce) - ad = AD_C; - ret = ren_line(buf, w, ad, 1, li, lI, ll, els_neg, els_pos); + al = AL_C; + ret = ren_line(buf, w, al, 1, li, lI, ll, els_neg, els_pos); free(buf); return ret; } @@ -568,6 +566,10 @@ void tr_l2r(char **args) dir_do = 1; if (args[0][0] == c_cc) ren_br(); + if (n_td) { + if (n_al != AL_C) n_al = AL_C - n_al; + if (n_al0 != AL_C) n_al0 = AL_C - n_al0; + } n_td = 0; n_cd = 0; } @@ -577,6 +579,10 @@ void tr_r2l(char **args) dir_do = 1; if (args[0][0] == c_cc) ren_br(); + if (!n_td) { + if (n_al != AL_C) n_al = AL_C - n_al; + if (n_al0 != AL_C) n_al0 = AL_C - n_al0; + } n_td = 1; n_cd = 1; } @@ -932,7 +938,7 @@ void ren_tl(int (*next)(void), void (*back)(int)) ren_untilmap(&wb2, next, back, delim, c_pc, pgnum); wb_cpy(&wb, &wb2, n_lt - wb_wid(&wb2)); /* flushing the line */ - ren_line(wb_buf(&wb), wb_wid(&wb), AD_L, 0, + ren_line(wb_buf(&wb), wb_wid(&wb), AL_L, 0, 0, 0, n_lt, wb.els_neg, wb.els_pos); wb_done(&wb2); wb_done(&wb); @@ -1021,7 +1027,7 @@ void tr_popren(char **args) ren_level = args[1] ? atoi(args[1]) : 0; } -#define FMT_PAR() (n_u && !n_na && !n_ce && (n_j & AD_P) == AD_P) +#define FMT_PAR() (n_u && !n_ce && n_j == AD_P) /* read characters from tr.c and pass the rendered lines to out.c */ static int render_rec(int level) diff --git a/roff.h b/roff.h index ac7fd62..e27df90 100644 --- a/roff.h +++ b/roff.h @@ -308,13 +308,16 @@ int hy_cput(char *d, char *s); void hyph_init(void); void hyph_done(void); +/* alignment types */ +#define AL_L 1 /* flush left (flag) */ +#define AL_R 2 /* flush right (flag) */ +#define AL_C 3 /* center (mask) */ + /* adjustment types */ -#define AD_C 0 /* center */ -#define AD_L 1 /* adjust left margin (flag) */ -#define AD_R 2 /* adjust right margin (flag) */ -#define AD_B 3 /* adjust both margin (mask) */ -#define AD_P 4 /* paragraph-at-once adjustment (flag) */ -#define AD_K 8 /* keshideh adjustment (flag) */ +#define AD_0 0 /* adjustment off */ +#define AD_B 1 /* adjust separate lines (flag) */ +#define AD_P 2 /* adjust entire paragraph (flag) */ +#define AD_K 3 /* keshideh adjustment (mask) */ /* line formatting */ struct fmt *fmt_alloc(void); @@ -458,6 +461,8 @@ int clr_get(char *s); /* builtin number registers; n_X for .X register */ #define n_a (*nreg(DOTMAP('a'))) +#define n_al (*nreg(map(".al"))) +#define n_al0 (*nreg(map(".al0"))) #define n_cp (*nreg(DOTMAP('C'))) #define n_d (*nreg(DOTMAP('d'))) #define n_f (*nreg(DOTMAP('f'))) @@ -467,6 +472,7 @@ int clr_get(char *s); #define n_itn (*nreg(map(".itn"))) /* .it lines left */ #define n_I (*nreg(DOTMAP('I'))) /* base indent */ #define n_j (*nreg(DOTMAP('j'))) +#define n_j0 (*nreg(map(".j0"))) #define n_l (*nreg(DOTMAP('l'))) #define n_L (*nreg(DOTMAP('L'))) #define n_lsn (*nreg(map("lsn"))) /* for .lsm */ @@ -513,7 +519,6 @@ int clr_get(char *s); #define n_L0 (*nreg(map(".L0"))) /* last .L */ #define n_m0 (*nreg(map(".m0"))) /* last .m */ #define n_mk (*nreg(map(".mk"))) /* .mk internal register */ -#define n_na (*nreg(map(".na"))) /* .na mode */ #define n_ns (*nreg(map(".ns"))) /* .ns mode */ #define n_o0 (*nreg(map(".o0"))) /* last .o */ #define n_pmll (*nreg(map(".pmll"))) /* minimum line length (.pmll) */ diff --git a/tr.c b/tr.c index 7aa6b7a..b0f8ca1 100644 --- a/tr.c +++ b/tr.c @@ -322,39 +322,48 @@ static void tr_el(char **args) cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1); } -static void tr_na(char **args) -{ - n_na = 1; -} - -static int adjmode(int c, int def) +static void tr_al(char **args) { - switch (c) { - case 'l': - return AD_L; - case 'r': - return AD_R; - case 'c': - return AD_C; - case 'b': - case 'n': - return AD_B; - case 'k': - return AD_B | AD_K; - } - return def; + char *s = args[1]; + int al = n_al; + if (!s) + n_al = n_al0; + else if (*s == 'l') + n_al = AL_L; + else if (*s == 'r') + n_al = AL_R; + else if (*s == 'c') + n_al = AL_C; + else if (isdigit((unsigned char) *s)) + n_al = MIN(1, atoi(s) & 3); + else + return; + n_al0 = al; } static void tr_ad(char **args) { char *s = args[1]; - n_na = 0; + int j = n_j; if (!s) - return; - if (isdigit((unsigned char) s[0])) - n_j = atoi(s) & 15; + n_j = n_j0; + else if (*s == 'b') + n_j = AD_B; + else if (*s == 'p') + n_j = AD_P; + else if (*s == 'k') + n_j = AD_K; + else if (isdigit((unsigned char) *s)) + n_j = atoi(s) & 3; else - n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], n_j); + return; + n_j0 = j; +} + +static void tr_na(char **args) +{ + args = (char*[NARGS]){ ".na", "0" }; + tr_ad(args); } static void tr_tm(char **args) @@ -1107,6 +1116,7 @@ static struct cmd { {"ab", tr_ab, mkargs_eol}, {"ad", tr_ad}, {"af", tr_af}, + {"al", tr_al}, {"am", tr_de, mkargs_reg1}, {"as", tr_as, mkargs_ds}, {"bd", tr_bd}, -- 2.47.1