gbranden pushed a commit to branch master in repository groff. commit 06a1368ca954dabc07e7c45d2ac68bebb44f7b5e Author: G. Branden Robinson <g.branden.robin...@gmail.com> AuthorDate: Sat Mar 15 15:13:39 2025 -0500
[troff]: Revise `pline` output style. Use more JSON/YAML-ish syntax. Present node properties in a consistent order: first, general node properties (read: member variables of the `node` abstract class); next, type-specific properties (read: member variables of classes derived from `node`); then, general node properties used only by MTSM/grohtml, which I hope one day to refactor away. * src/roff/troff/node.cpp (glyph_node::dump_node) (node::dump_node, node::dump_node_list) (composite_node::dump_node) (dbreak_node::dump_node): Do it. (node::dump_node): Report the `is_special_node` Boolean property. (glyph_node::dump_node, composite_node::dump_node): Write string values with JSON-valid escaped characters. --- ChangeLog | 17 +++++++ src/roff/troff/node.cpp | 133 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 114 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index c7512f7f4..74066b114 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2025-03-02 G. Branden Robinson <g.branden.robin...@gmail.com> + + [troff]: Revise `pline` output style. Use more JSON/YAML-ish + syntax. Present node properties in a consistent order: first, + general node properties (read: member variables of the `node` + abstract class); next, type-specific properties (read: member + variables of classes derived from `node`); then, general node + properties used only by MTSM/grohtml, which I hope one day to + refactor away. + + * src/roff/troff/node.cpp (glyph_node::dump_node) + (node::dump_node, node::dump_node_list) + (composite_node::dump_node, dbreak_node::dump_node): Do it. + (node::dump_node): Report the `is_special` Boolean property. + (glyph_node::dump_node, composite_node::dump_node): Write string + values with JSON-valid escaped characters. + 2025-03-04 G. Branden Robinson <g.branden.robin...@gmail.com> [libgroff]: Add `json_length()`, `json_extract()`, and diff --git a/src/roff/troff/node.cpp b/src/roff/troff/node.cpp index 547b23953..0bd007e7b 100644 --- a/src/roff/troff/node.cpp +++ b/src/roff/troff/node.cpp @@ -2214,19 +2214,41 @@ void glyph_node::ascii_print(ascii_output_file *ascii) // presumably has several different solutions for this. Pick one. void glyph_node::dump_node() { + fprintf(stderr, "{\"type\": \"%s\"", type()); + // GNU troff multiplexes the distinction of ordinary vs. special + // characters though the special character code zero. unsigned char c = ci->get_ascii_code(); - fprintf(stderr, "{type: %s, character: ", type()); - if (c) - fprintf(stderr, "\"%c\"", c); - else - fprintf(stderr, "\"\\%s\"", ci->nm.contents()); - if (push_state) - fprintf(stderr, ", push_state"); + if (c) { + fputs(", \"character\": ", stderr); + fputc('\"', stderr); + // JSON-encode the (printable Basic Latin) character. + switch (c) { + case '"': + case '\\': + case '/': + fputc('\\', stderr); + // fall through + default: + fputc(c, stderr); + break; + } + fputc('\"', stderr); + } + else { + fputs(", \"special character\": ", stderr); + ci->nm.json_dump(); + } + fprintf(stderr, ", \"diversion level\": %d", div_nest_level); + fprintf(stderr, ", \"is_special_node\": %s", + is_special ? "true" : "false"); + if (push_state) { + fputs(", \"push_state\": ", stderr); + push_state->display_state(); + } if (state) { - fprintf(stderr, ", state: "); + fputs(", \"state\": ", stderr); state->display_state(); } - fprintf(stderr, ", diversion level: %d", div_nest_level); fputs("}", stderr); fflush(stderr); } @@ -2589,12 +2611,18 @@ units node::size() void node::dump_node() { - fprintf(stderr, "{type: %s", type()); - if (push_state) - fputs(", <push_state>", stderr); - if (state) - fputs(", <state>", stderr); - fprintf(stderr, ", diversion level: %d", div_nest_level); + fprintf(stderr, "{\"type\": \"%s\"", type()); + fprintf(stderr, ", \"diversion level\": %d", div_nest_level); + fprintf(stderr, ", \"is_special_node\": %s", + is_special ? "true" : "false"); + if (push_state) { + fputs(", \"push_state\": ", stderr); + push_state->display_state(); + } + if (state) { + fputs(", \"state\": ", stderr); + state->display_state(); + } fputs("}", stderr); fflush(stderr); } @@ -2604,13 +2632,14 @@ void node::dump_node_list() // It's stored in reverse order already; this puts it forward again. std::stack<node *> reversed_node_list; node *n = next; - bool need_comma = false; assert(next != 0 /* nullptr */); do { reversed_node_list.push(n); n = n->next; } while (n != 0 /* nullptr */); + fputc('[', stderr); + bool need_comma = false; while (!reversed_node_list.empty()) { if (need_comma) fputs(",\n", stderr); @@ -2618,7 +2647,11 @@ void node::dump_node_list() reversed_node_list.pop(); need_comma = true; } - fputc('\n', stderr); + // !need_comma implies that the list was empty. JSON convention is to + // put a space between an empty pair of square brackets. + if (!need_comma) + fputc(' ', stderr); + fputs("]\n", stderr); fflush(stderr); } @@ -4994,19 +5027,41 @@ void composite_node::tprint(troff_output_file *out) // presumably has several different solutions for this. Pick one. void composite_node::dump_node() { + fprintf(stderr, "{\"type\": \"%s\"", type()); + // GNU troff multiplexes the distinction of ordinary vs. special + // characters though the special character code zero. unsigned char c = ci->get_ascii_code(); - fprintf(stderr, "{type: %s, character: ", type()); - if (c) - fprintf(stderr, "\"%c\"", c); - else - fprintf(stderr, "\"\\%s\"", ci->nm.contents()); - if (push_state) - fprintf(stderr, ", push_state, "); + if (c) { + fputs(", \"character\": ", stderr); + fputc('\"', stderr); + // JSON-encode the (printable Basic Latin) character. + switch (c) { + case '"': + case '\\': + case '/': + fputc('\\', stderr); + // fall through + default: + fputc(c, stderr); + break; + } + fputc('\"', stderr); + } + else { + fputs(", \"special character\": ", stderr); + ci->nm.json_dump(); + } + fprintf(stderr, ", \"diversion level\": %d", div_nest_level); + fprintf(stderr, ", \"is_special_node\": %s", + is_special ? "true" : "false"); + if (push_state) { + fputs(", \"push_state\": ", stderr); + push_state->display_state(); + } if (state) { - fprintf(stderr, ", state: "); + fputs(", \"state\": ", stderr); state->display_state(); } - fprintf(stderr, ", diversion level: %d", div_nest_level); fputs("}", stderr); fflush(stderr); } @@ -5890,25 +5945,31 @@ bool dbreak_node::is_tag() void dbreak_node::dump_node() { - fprintf(stderr, "{type: %s", type()); - if (push_state) - fprintf(stderr, ", <push_state>"); - if (state) - fprintf(stderr, ", <state>"); - fprintf(stderr, ", diversion level: %d", div_nest_level); + fprintf(stderr, "{\"type\": \"%s\"", type()); if (none != 0 /* nullptr */) { - fputs(", none: ", stderr); + fputs(", \"none\": ", stderr); none->dump_node(); } if (pre != 0 /* nullptr */) { - fputs(", pre: ", stderr); + fputs(", \"pre\": ", stderr); pre->dump_node(); } if (post != 0 /* nullptr */) { - fputs(", post: ", stderr); + fputs(", \"post\": ", stderr); post->dump_node(); } - fprintf(stderr, "}"); + fprintf(stderr, ", \"diversion level\": %d", div_nest_level); + fprintf(stderr, ", \"is_special_node\": %s", + is_special ? "true" : "false"); + if (push_state) { + fputs(", \"push_state\": ", stderr); + push_state->display_state(); + } + if (state) { + fputs(", \"state\": ", stderr); + state->display_state(); + } + fputs("}", stderr); fflush(stderr); } _______________________________________________ groff-commit mailing list groff-commit@gnu.org https://lists.gnu.org/mailman/listinfo/groff-commit