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

Reply via email to