@@ -708,13 +708,17 @@ default void appendTable(List<String> text, JsonNode tableNode) {
708708 ? ""
709709 : "^" + slugify (caption );
710710
711+ String name = findTableName (tableNode );
711712 String known = findTable (Tools5eIndexType .table , tableNode );
712713 if (known != null ) {
713- maybeAddBlankLine (text );
714- text .add (known );
714+ appendTableText (name , List .of (known ), text , tableNode );
715715 return ;
716716 }
717717
718+ // We could be working on a table, or a table nested inside a table.
719+ // Gather text in "inner", then we'll decide how to append it later.
720+ List <String > inner = new ArrayList <>();
721+
718722 boolean pushTable = parseState ().pushMarkdownTable (true );
719723 try {
720724 if (TableFields .colLabels .existsIn (tableNode )) {
@@ -775,8 +779,16 @@ default void appendTable(List<String> text, JsonNode tableNode) {
775779 }
776780 return x ;
777781 })
778- .map (x -> flattenToString (x ).replace ("\n " , "<br />" ))
782+ .map (x -> {
783+ String s = flattenToString (x ).replace ("\n " , "<br />" );
784+ JsonNode nestedTable = TableFields .ttrpgNestedTable .getFrom (x );
785+ if (nestedTable != null ) {
786+ TableFields .ttrpgNestedTable .appendToArray (tableNode , nestedTable );
787+ }
788+ return s ;
789+ })
779790 .collect (Collectors .joining (" | " )) + " |" ;
791+
780792 table .add (row );
781793 }
782794
@@ -790,46 +802,70 @@ default void appendTable(List<String> text, JsonNode tableNode) {
790802 if (header .matches (JsonTextConverter .DICE_TABLE_HEADER ) && !blockid .isBlank ()) {
791803 // prepend a dice roller
792804 String targetFile = getFileName ();
793- table .add (0 , String .format ("`dice: [](%s.md#%s)`" , targetFile , blockid ));
805+ // use dice roller string as name (for use if nested table)
806+ name = String .format ("`dice: [](%s.md#%s)`" , targetFile , blockid );
807+ table .add (0 , name );
794808 table .add (1 , "" );
795809 }
796810 if (!caption .isBlank ()) {
797811 table .add (0 , "" );
798812 table .add (0 , "**" + replaceText (caption ) + "**" );
799813 }
814+
815+ switch (blockid ) {
816+ case "personality-trait" -> Json2QuteBackground .traits .addAll (table );
817+ case "ideal" -> Json2QuteBackground .ideals .addAll (table );
818+ case "bond" -> Json2QuteBackground .bonds .addAll (table );
819+ case "flaw" -> Json2QuteBackground .flaws .addAll (table );
820+ }
821+
822+ JsonNode intro = TableFields .intro .getFrom (tableNode );
823+ if (intro != null ) {
824+ maybeAddBlankLine (inner );
825+ appendToText (inner , intro , null );
826+ }
827+ maybeAddBlankLine (inner );
828+ inner .addAll (table );
829+
830+ JsonNode footnotes = TableFields .footnotes .getFrom (tableNode );
831+ if (footnotes != null ) {
832+ maybeAddBlankLine (inner );
833+ boolean pushF = parseState ().pushFootnotes (true );
834+ appendToText (inner , footnotes , null );
835+ parseState ().pop (pushF );
836+ }
837+ JsonNode outro = TableFields .outro .getFrom (tableNode );
838+ if (outro != null ) {
839+ maybeAddBlankLine (inner );
840+ appendToText (inner , outro , null );
841+ }
800842 } finally {
801843 parseState ().pop (pushTable );
802844 }
803845
804- switch ( blockid ) {
805- case "personality-trait" -> Json2QuteBackground . traits . addAll ( table );
806- case "ideal" -> Json2QuteBackground . ideals . addAll ( table );
807- case "bond" -> Json2QuteBackground . bonds . addAll ( table );
808- case "flaw" -> Json2QuteBackground . flaws . addAll ( table );
809- }
846+ // Add directly to text, or stick in a tableNode for later.
847+ appendTableText ( name , inner , text , tableNode );
848+ } finally {
849+ parseState (). pop ( pushed );
850+ }
851+ }
810852
811- JsonNode intro = TableFields .intro .getFrom (tableNode );
812- if (intro != null ) {
813- maybeAddBlankLine (text );
814- appendToText (text , intro , null );
815- }
853+ default void appendTableText (String name , List <String > inner , List <String > text , JsonNode tableNode ) {
854+ if (parseState ().inMarkdownTable ()) {
855+ // we are inside a table row. Append this text to an element in the tableNode
856+ // that will be rendered after the table.
857+ TableFields .ttrpgNestedTable .appendToArray (tableNode , String .join ("\n " , inner ));
858+ text .add (name );
859+ } else {
816860 maybeAddBlankLine (text );
817- text .addAll (table );
818-
819- JsonNode footnotes = TableFields .footnotes .getFrom (tableNode );
820- if (footnotes != null ) {
821- maybeAddBlankLine (text );
822- boolean pushF = parseState ().pushFootnotes (true );
823- appendToText (text , footnotes , null );
824- parseState ().pop (pushF );
825- }
826- JsonNode outro = TableFields .outro .getFrom (tableNode );
827- if (outro != null ) {
828- maybeAddBlankLine (text );
829- appendToText (text , outro , null );
861+ text .addAll (inner );
862+ if (TableFields .ttrpgNestedTable .existsIn (tableNode )) {
863+ // This table had nested tables! Append them, too (already formatted)
864+ for (JsonNode nested : TableFields .ttrpgNestedTable .iterateArrayFrom (tableNode )) {
865+ maybeAddBlankLine (text );
866+ text .add (nested .asText ());
867+ }
830868 }
831- } finally {
832- parseState ().pop (pushed );
833869 }
834870 }
835871
@@ -1424,6 +1460,7 @@ enum TableFields implements JsonNodeReader {
14241460 outro ,
14251461 style ,
14261462 type ,
1463+ ttrpgNestedTable , // mine, array
14271464 ;
14281465
14291466 static String getFirstRow (JsonNode tableNode ) {
0 commit comments