From 168cf05300cec2bb4c0607711b752609976b2901 Mon Sep 17 00:00:00 2001 From: Svjatoslav Agejenko Date: Fri, 2 Oct 2020 17:45:00 +0300 Subject: [PATCH] Misc fixes: Fixed last content element and list title continuation detections. Properly handle list depth decrease. Better parsing of multiline list title. --- .../sixth/core/document/Heading.java | 55 ++++++------------- .../svjatoslav/sixth/core/document/Utils.java | 31 ++++++++++- .../core/document/content/ListElement.java | 25 ++++++--- 3 files changed, 63 insertions(+), 48 deletions(-) diff --git a/src/main/java/eu/svjatoslav/sixth/core/document/Heading.java b/src/main/java/eu/svjatoslav/sixth/core/document/Heading.java index ca72321..8a80d9c 100644 --- a/src/main/java/eu/svjatoslav/sixth/core/document/Heading.java +++ b/src/main/java/eu/svjatoslav/sixth/core/document/Heading.java @@ -1,7 +1,6 @@ package eu.svjatoslav.sixth.core.document; import eu.svjatoslav.commons.string.String2; -import eu.svjatoslav.commons.string.tokenizer.Tokenizer; import eu.svjatoslav.commons.string.tokenizer.TokenizerMatch; import eu.svjatoslav.sixth.core.document.content.ListElement; import eu.svjatoslav.sixth.core.document.text.FormattedText; @@ -58,6 +57,9 @@ public class Heading { public void parse(TokenizerMatch tm){ + int indent = Utils.getLineIndent(tm.token); + if (indent > -1 && indent <= currentListElement.indent) handleListDepthDecrease(indent); + if (tm.isGroup(TG_LIST)){ parseList(tm); return; @@ -66,11 +68,22 @@ public class Heading { currentListElement.parse(tm); } + private void handleListDepthDecrease(int indent) { + while (true){ + if (currentListElement.parent.indent <= indent){ + currentListElement = currentListElement.parent; + return; + } + currentListElement = currentListElement.parent; + } + } + private void parseList(TokenizerMatch tm) { String[] listSections = tm.getRegExpGroups(); int indent = listSections[0].length(); String type = listSections[1]; - FormattedText title = FormattedText.fromOrg(parseFullListTitle(getPartialTitle(listSections), tm.getTokenizer(), indent)); + + String title = getPartialTitle(listSections); if (indent > currentListElement.indent){ // list dept increases @@ -88,47 +101,11 @@ public class Heading { return; } - // list dept decreases - while (true){ - if (currentListElement.parent.indent <= indent){ - ListElement newElement = new ListElement(title, indent, currentListElement.parent.parent, type); - currentListElement.parent.parent.addContent(newElement); - currentListElement = newElement; - return; - } - currentListElement = currentListElement.parent; - } - + throw new RuntimeException("Impossible condition reached. Must be a bug!"); } private String getPartialTitle(String[] listSections) { return listSections.length > 2 ? listSections[2] : ""; } - private String parseFullListTitle(String partialTitle, Tokenizer tokenizer, int listIndent){ - StringBuilder sb = new StringBuilder(); - sb.append(partialTitle); - - while (tokenizer.hasMoreContent()){ - final TokenizerMatch tm = tokenizer.getNextToken(); - - if (isContentContinuation(tm, listIndent, Helper.TG_NORMAL_TEXT)){ - String titleContinuation = tm.token.substring(listIndent).trim(); - sb.append("\n").append(titleContinuation); - continue; - } - - tokenizer.unreadToken(); - break; - } - - return sb.toString(); - } - - public static boolean isContentContinuation(TokenizerMatch tm, int requiredIndent, String requiredGroup) { - if (tm.token.length() <= requiredIndent) return false; - - return tm.isGroup(requiredGroup) && tm.token.substring(0, requiredIndent +1).trim().length() == 0; - } - } diff --git a/src/main/java/eu/svjatoslav/sixth/core/document/Utils.java b/src/main/java/eu/svjatoslav/sixth/core/document/Utils.java index 00166ef..4883d1d 100644 --- a/src/main/java/eu/svjatoslav/sixth/core/document/Utils.java +++ b/src/main/java/eu/svjatoslav/sixth/core/document/Utils.java @@ -4,6 +4,8 @@ import eu.svjatoslav.commons.string.String2; public class Utils { + public static final char[] whitespace = new char[]{'\n', '\r', ' ', '\t'}; + public static String addIndentExceptFirstLine(String input, int indent) { String[] lines = input.split("\\r?\\n"); @@ -21,7 +23,34 @@ public class Utils { } public static boolean isBlank(String s){ - return s.trim().length() == 0; + for (char c : s.toCharArray()) + if (!isWhitespaceChar(c)) return false; + + return true; + } + + /** + * @return line indent in characters or -1 if line is blank or empty + */ + public static int getLineIndent(String line){ + for (int i = 0; i < line.length(); i++) { + if (!isWhitespaceChar(line.charAt(i))) + return i; + } + return -1; + } + + public static boolean isWhitespaceChar(char c){ + for (char whitespaceChar : whitespace) + if (whitespaceChar == c) return true; + + return false; + } + + public static String removePrefix(String string, int charsToRemove){ + String2 s = new String2(string); + s.trimPrefix(charsToRemove); + return s.toString(); } } diff --git a/src/main/java/eu/svjatoslav/sixth/core/document/content/ListElement.java b/src/main/java/eu/svjatoslav/sixth/core/document/content/ListElement.java index 0db636f..5cfc791 100644 --- a/src/main/java/eu/svjatoslav/sixth/core/document/content/ListElement.java +++ b/src/main/java/eu/svjatoslav/sixth/core/document/content/ListElement.java @@ -9,17 +9,18 @@ import java.util.List; import static eu.svjatoslav.sixth.core.document.Helper.*; import static eu.svjatoslav.sixth.core.document.Utils.isBlank; +import static eu.svjatoslav.sixth.core.document.Utils.removePrefix; public class ListElement implements Content { - public final FormattedText name; + StringBuilder nameInOrg = new StringBuilder(); public final int indent; public final ListElement parent; private final String type; private final List content = new ArrayList<>(); - public ListElement(FormattedText name, int indent, ListElement parent, String type) { + public ListElement(String nameInOrg, int indent, ListElement parent, String type) { this.indent = indent; - this.name = name; + this.nameInOrg.append(nameInOrg); this.type = type; this.parent = parent; } @@ -33,7 +34,7 @@ public class ListElement implements Content { Content contentElement = findCurrentContentElement(); if (contentElement == null) return false; - return contentElement.getClass().isInstance(aClass); + return aClass.isInstance(contentElement); } public void addContent(Content contentElement){ @@ -86,12 +87,16 @@ public class ListElement implements Content { TextBlock textBlock; if (isLastContentElement(TextBlock.class)) { textBlock = ((TextBlock) findCurrentContentElement()); + } if (content.isEmpty()){ + // list title continuation + nameInOrg.append("\n").append(removePrefix(tm.token, indent + 2)); + return; } else { textBlock = new TextBlock(); content.add(textBlock); } - textBlock.addContent(tm.token + "\n"); + textBlock.addContent(tm.token); } private void parseDocumentProperty(TokenizerMatch tm) { @@ -123,7 +128,7 @@ public class ListElement implements Content { if (this.indent >= 0) { String2 s = new String2(); - s.append(" ", indent).append(type).append(" ").append(name.toMD(indent + 2)).append("\n"); + s.append(" ", indent).append(type).append(" ").append(getName().toMD(indent + 2)).append("\n"); sb.append(s.toString()); } @@ -132,18 +137,22 @@ public class ListElement implements Content { } } + private FormattedText getName(){ + return FormattedText.fromOrg(nameInOrg.toString()); + } + private void disablePlantUmlExport() { for (int i = 0; i< (content.size()-2); i++){ if (!(content.get(i) instanceof MultilineCode)) continue; MultilineCode code = (MultilineCode) content.get(i); - if (!"plantuml".equalsIgnoreCase(code.language)) continue;; + if (!"plantuml".equalsIgnoreCase(code.language)) continue; if (!(content.get(i+1) instanceof DocumentPropertyCollection)) continue; DocumentPropertyCollection property = (DocumentPropertyCollection) content.get(i+1); - if (!property.hasProperty("results")) continue;; + if (!property.hasProperty("results")) continue; if (!(content.get(i+2) instanceof TextBlock)) continue; TextBlock textBlock = (TextBlock) content.get(i+2); -- 2.20.1