Skip to content

Commit 42ce137

Browse files
committed
🐛 Fix rendering of nested tables (loot)
1 parent b8b6bbb commit 42ce137

4 files changed

Lines changed: 86 additions & 31 deletions

File tree

src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,4 +528,18 @@ default void appendToArray(JsonNode target, String value) {
528528
ArrayNode array = ensureArrayIn(target).add(value);
529529
setIn(target, array);
530530
}
531+
532+
/** Destructive! */
533+
default void appendToArray(JsonNode target, JsonNode value) {
534+
if (target == null || value == null) {
535+
return;
536+
}
537+
ArrayNode array = ensureArrayIn(target);
538+
if (value.isArray()) {
539+
array.addAll((ArrayNode) value);
540+
} else {
541+
array.add(value);
542+
}
543+
setIn(target, array);
544+
}
531545
}

src/main/java/dev/ebullient/convert/tools/ParseState.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ public boolean pushHtmlTable(boolean inTable) {
233233
}
234234

235235
public boolean pushMarkdownTable(boolean inTable) {
236+
ParseStateInfo current = stack.peek();
237+
if (current != null && current.inMarkdownTable == inTable) {
238+
return false;
239+
}
236240
stack.addFirst(ParseStateInfo.inMarkdownTable(stack.peek(), inTable));
237241
return true;
238242
}

src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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) {

src/test/java/dev/ebullient/convert/Tools5eDataConvertTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public void clear() throws IOException {
7272
Path filePath = testOutput.resolve(logFile);
7373
Files.move(logFile, filePath, StandardCopyOption.REPLACE_EXISTING);
7474

75-
if (content.contains("Exception")) {
75+
if (content.matches(".*?Exception(\\s.*|$)")) {
7676
tui.errorf("Exception found in %s", filePath);
7777
}
7878
}

0 commit comments

Comments
 (0)