+++ /dev/null
-package eu.svjatoslav.sixth.core.document;
-
-import eu.svjatoslav.commons.string.tokenizer.InvalidSyntaxException;
-import eu.svjatoslav.commons.string.tokenizer.Tokenizer;
-import eu.svjatoslav.commons.string.tokenizer.TokenizerMatch;
-import eu.svjatoslav.sixth.core.document.text.FormattedText;
-
-import static eu.svjatoslav.commons.string.tokenizer.Terminator.TerminationStrategy.PRESERVE;
-import static eu.svjatoslav.sixth.core.document.Helper.*;
-import static eu.svjatoslav.sixth.core.document.text.FormattedText.fromOrg;
-
-public class Document {
- public final Heading rootHeading = new Heading( null , 0, null);
- private Heading currentHeading = rootHeading;
-
- public Heading createHeading(FormattedText name, int targetLevel){
- if (currentHeading.level == (targetLevel - 1)){
- Heading newHeading = new Heading(name, targetLevel, currentHeading);
- currentHeading.addChild(newHeading);
- currentHeading = newHeading;
- return newHeading;
- }
-
- if (currentHeading.level > (targetLevel - 1)){
- currentHeading = currentHeading.parent;
- return createHeading(name, targetLevel);
- }
-
- Heading missingIntermediate = new Heading(fromOrg("<noname>"), currentHeading.level + 1, currentHeading);
- currentHeading.addChild(missingIntermediate);
- currentHeading = missingIntermediate;
- return createHeading(name, targetLevel);
- }
-
- public Heading getCurrentHeading(){
- return currentHeading;
- }
-
- private void parseHeading(TokenizerMatch token) throws InvalidSyntaxException {
- String[] headingSections = token.getRegExpGroups();
- int level = headingSections[0].length();
- String title = headingSections[1];
- createHeading(fromOrg(title), level);
- }
-
- public void parse(String fileContentsAsString) throws InvalidSyntaxException {
- final Tokenizer tokenizer = new Tokenizer(fileContentsAsString);
-
- // Org heading:
- // "*** Example Heading 1234"
- tokenizer.addTerminator(PRESERVE, "(\\*+)[ \\t](.*)\\r?\\n", TG_HEADING);
-
- // Org list. Examples:
- // " + my list title"
- // " - my list title"
- tokenizer.addTerminator(PRESERVE, "([ \\t]*)(\\+|-)[ \\t]+(.*)?\\r?\\n", TG_LIST);
-
- // " * my list title"
- tokenizer.addTerminator(PRESERVE, "([ \\t]+)(\\*)[ \\t]+(.*)?\\r?\\n", TG_LIST);
-
- // TODO: add numbered list
-
- // DocumentProperty:
- // "#+OPTIONS: H:20 num:20"
- tokenizer.addTerminator(PRESERVE, "#\\+([^\\s]+):(.*)\\r?\\n", TG_DOCUMENT_PROPERTY);
-
- // Drawer property:
- // " :ID: 533734b9-0456-4448-9830-a43646345615"
- tokenizer.addTerminator(PRESERVE, "([ \\t]*):([^\\s]+):(.*)\\r?\\n", TG_DRAWER_PROPERTY);
-
-
- // multiline code block
- tokenizer.addTerminator(PRESERVE,
- "([ \\t]*)#\\+BEGIN_SRC" + // source begin identifier
- "(([ \\t]+)(.*))?(\\r?\\n)" + // source block parameters
- "((?:.|\\n|\\r)*?)" + // source content
- "(\\r?\\n)([ \\t]*)#\\+END_SRC(.*)\\r?\\n" // source end identifier
- , TG_MULTILINE_CODE);
-
- // verse
- tokenizer.addTerminator(PRESERVE,
- "([ \\t]*)#\\+BEGIN_VERSE" + // verse begin identifier
- "(([ \\t]+)(.*))?(\\r?\\n)" + // verse block parameters
- "((?:.|\\n|\\r)*?)" + // verse
- "(\\r?\\n)([ \\t]*)#\\+END_VERSE(.*)\\r?\\n" // verse end identifier
- , TG_VERSE);
-
-
- // TODO: add support for export blocks:
- // #+begin_export latex
- // \clearpage
- //#+end_export
-
-
- // normal text
- tokenizer.addTerminator(PRESERVE,".*\\r?\\n", TG_NORMAL_TEXT);
-
- while (tokenizer.hasMoreContent()) {
- final TokenizerMatch tm = tokenizer.getNextToken();
-
- if (tm.isGroup(TG_HEADING)){
- parseHeading(tm);
- continue;
- }
-
- currentHeading.parse(tm);
- }
-
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document;
-
-import eu.svjatoslav.commons.string.String2;
-import eu.svjatoslav.commons.string.tokenizer.TokenizerMatch;
-import eu.svjatoslav.sixth.core.document.content.ListElement;
-import eu.svjatoslav.sixth.core.document.text.FormattedText;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static eu.svjatoslav.sixth.core.document.Helper.TG_LIST;
-
-public class Heading {
- public final FormattedText name;
- public final int level;
- public final Heading parent;
- private final List<Heading> children = new ArrayList<>();
-
- public final ListElement rootListElement = new ListElement(null, -2, null, "");
- private ListElement currentListElement = rootListElement;
-
- public Heading(FormattedText name, int level, Heading parent){
- this.level = level;
- this.name = name;
- this.parent = parent;
- }
-
- public void addChild(Heading heading){
- children.add(heading);
- }
-
- public List<Heading> getChildren(){
- return children;
- }
-
- public String toMD () {
- StringBuilder sb = new StringBuilder();
-
- if (level > 0) sb.append(enlistTitleInMD());
-
- rootListElement.toMD(sb, -2);
-
- children.stream().map(Heading::toMD).forEach(sb::append);
-
- return sb.toString();
- }
-
- private String enlistTitleInMD() {
- String2 s = new String2();
- s.append("#", level).append(" ").append(name.toMD(0)).append("\n");
- return s.toString();
- }
-
- public ListElement getCurrentHeading(){
- return currentListElement;
- }
-
- 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;
- }
-
- 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];
-
- String title = getPartialTitle(listSections);
-
- if (indent > currentListElement.indent){
- // list dept increases
- ListElement newElement = new ListElement(title, indent, currentListElement, type);
- currentListElement.addContent(newElement);
- currentListElement = newElement;
- return;
- }
-
- if (indent > currentListElement.parent.indent){
- // list depth is the same
- ListElement newElement = new ListElement(title, indent, currentListElement.parent, type);
- currentListElement.parent.addContent(newElement);
- currentListElement = newElement;
- return;
- }
-
- throw new RuntimeException("Impossible condition reached. Must be a bug!");
- }
-
- private String getPartialTitle(String[] listSections) {
- return listSections.length > 2 ? listSections[2] : "";
- }
-
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document;
-
-public class Helper {
-
- public static final String TG_NORMAL_TEXT = "normaltext";
- public static final String TG_MULTILINE_CODE = "multiline code";
- public static final String TG_VERSE = "verse";
- public static final String TG_HYPERLINK = "hyperlink";
- public static final String TG_HEADING = "heading";
- public static final String TG_LIST = "list";
-
- public static final String TG_DOCUMENT_PROPERTY = "document property";
- public static final String TG_DRAWER_PROPERTY = "drawer property";
-
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document;
-
-import java.io.File;
-import java.io.IOException;
-
-import static eu.svjatoslav.commons.file.IOHelper.saveToFile;
-
-public class MdGenerator {
-
- private StringBuilder sb;
-
- public void generate(Document document, File file) throws IOException {
- sb = new StringBuilder();
-
- sb.append(document.rootHeading.toMD());
-
- saveToFile(file, sb.toString());
- }
-
-
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document;
-
-import eu.svjatoslav.commons.string.tokenizer.InvalidSyntaxException;
-
-import java.io.File;
-import java.io.IOException;
-
-import static eu.svjatoslav.commons.file.IOHelper.getFileContentsAsString;
-
-public class OrgParser {
-
- private Document document;
-
- public Document parse(File file) throws IOException, InvalidSyntaxException {
- document = new Document();
-
- String fileContentsAsString = getFileContentsAsString(file);
-
- document.parse(fileContentsAsString);
-
- return document;
- }
-
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document;
-
-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");
-
- StringBuilder sb = new StringBuilder();
-
- if (lines.length >0 ) sb.append(lines[0]);
-
- for (int i = 1; i< lines.length; i++) {
- sb.append("\n");
- sb.append(new String2(" ").repeat(indent).toString());
- sb.append(lines[i]);
- }
-
- return sb.toString();
- }
-
- public static boolean isBlank(String s){
- 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();
- }
-
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.content;
-
-public interface Content {
- void toMD(StringBuilder sb, int indent);
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.content;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Things like:
- * #+RESULTS:
- * #+LATEX_HEADER: \\usepackage{parskip}
- * #+OPTIONS: H:20 num:20
- * #+attr_latex: :width 300px
- */
-
-public class DocumentPropertyCollection implements Content {
- private Map<String, List<String>> keyToValue = new HashMap<>();
-
- @Override
- public void toMD(StringBuilder sb, int indent) {
- }
-
- public void addProperty(String key, String value){
- getOrCreateValueList(key).add(value);
- }
-
- private List<String> getOrCreateValueList(String key){
- String actualKey = key.toLowerCase();
- if (keyToValue.containsKey(actualKey))
- return keyToValue.get(actualKey);
-
- List valueList = new ArrayList<String>();
- keyToValue.put(actualKey, valueList);
- return valueList;
- }
-
- public boolean hasProperty(String key){
- return keyToValue.containsKey(key.toLowerCase());
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.content;
-
-import eu.svjatoslav.commons.string.String2;
-import eu.svjatoslav.commons.string.tokenizer.TokenizerMatch;
-import eu.svjatoslav.sixth.core.document.text.FormattedText;
-
-import java.util.ArrayList;
-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 {
- StringBuilder nameInOrg = new StringBuilder();
- public final int indent;
- public final ListElement parent;
- private final String type;
- private final List<Content> content = new ArrayList<>();
-
- public ListElement(String nameInOrg, int indent, ListElement parent, String type) {
- this.indent = indent;
- this.nameInOrg.append(nameInOrg);
- this.type = type;
- this.parent = parent;
- }
-
- private Content findCurrentContentElement(){
- if (content.isEmpty()) return null;
- return content.get(content.size()-1);
- }
-
- private boolean isLastContentElement(Class aClass){
- Content contentElement = findCurrentContentElement();
- if (contentElement == null) return false;
-
- return aClass.isInstance(contentElement);
- }
-
- public void addContent(Content contentElement){
- content.add(contentElement);
- }
-
- public void parse(TokenizerMatch tm) {
-
- if (tm.isGroup(TG_DOCUMENT_PROPERTY)) {
- parseDocumentProperty(tm);
- return;
- }
-
- if (tm.isGroup(TG_DRAWER_PROPERTY)) {
- // TODO
- // System.out.println("DOCUMENT PROPERTY!!!: " + tm.token);
- return;
- }
-
- if (tm.isGroup(TG_NORMAL_TEXT)) {
- if (isBlank(tm.token)){
- parseSeparator();
- return;
- }
-
- parseTextBlock(tm);
- return;
- }
-
- if (tm.isGroup(TG_MULTILINE_CODE)){
- // System.out.println(tm.toString());
- String[] groups = tm.getRegExpGroups();
- content.add(new MultilineCode(
- groups[3], // language
- groups[5] // code
- ));
- return;
- }
-
- if (tm.isGroup(TG_VERSE)){
- String[] groups = tm.getRegExpGroups();
- content.add(new Verse(groups[5]));
- return;
- }
-
- System.out.println("ERROR!!!! Unable to handle: " + tm);
- }
-
- private void parseTextBlock(TokenizerMatch tm) {
- 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);
- }
-
- private void parseDocumentProperty(TokenizerMatch tm) {
- DocumentPropertyCollection documentPropertyCollection;
-
- if (isLastContentElement(DocumentPropertyCollection.class)){
- documentPropertyCollection = (DocumentPropertyCollection)findCurrentContentElement();
- } else {
- documentPropertyCollection = new DocumentPropertyCollection();
- content.add(documentPropertyCollection);
- }
-
- documentPropertyCollection.addProperty(
- tm.getRegExpGroups()[0],
- tm.getRegExpGroups()[1]);
- }
-
- private void parseSeparator() {
- if (isLastContentElement(Separator.class)){
- ((Separator)findCurrentContentElement()).addLine();
- } else {
- content.add(new Separator());
- }
- }
-
-
- public void toMD(StringBuilder sb, int indent) {
- disablePlantUmlExport();
-
- if (this.indent >= 0) {
- String2 s = new String2();
- s.append(" ", indent).append(type).append(" ").append(getName().toMD(indent + 2)).append("\n");
- sb.append(s.toString());
- }
-
- for (Content c : content) {
- c.toMD(sb, this.indent + 2);
- }
- }
-
- 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 (!(content.get(i+1) instanceof DocumentPropertyCollection)) continue;
- DocumentPropertyCollection property = (DocumentPropertyCollection) content.get(i+1);
-
- if (!property.hasProperty("results")) continue;
-
- if (!(content.get(i+2) instanceof TextBlock)) continue;
- TextBlock textBlock = (TextBlock) content.get(i+2);
-
- textBlock.disableForExport();
- }
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.content;
-
-import eu.svjatoslav.commons.string.String2;
-import eu.svjatoslav.commons.string.tokenizer.Tokenizer;
-
-import static eu.svjatoslav.commons.string.tokenizer.Terminator.TerminationStrategy.DROP;
-
-public class MultilineCode implements Content {
- public final String language;
- public final String code;
-
- public MultilineCode(String languageAndParams, String code) {
-
- final Tokenizer tokenizer = new Tokenizer(languageAndParams);
- tokenizer.addTerminator(DROP, "[ \\t]+", "whitespace");
- if (tokenizer.hasMoreContent()){
- language = tokenizer.getNextToken().token;
- } else {
- language = null;
- }
-
- this.code = code;
- }
-
- @Override
- public void toMD(StringBuilder sb, int indent) {
- String2 s = new String2();
- s.append(" ", indent).append("```" + getMDlanguage() + "\n");
- // TODO: ensure that required indent is present
- s.append(code + "\n");
- s.append(" ", indent).append("```\n");
- sb.append(s.toString());
- }
-
- public String getMDlanguage(){
- if (language == null) return "";
- return language;
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.content;
-
-public class Separator implements Content {
-
- private int numLines = 1;
-
- public Separator(){
- }
-
- @Override
- public void toMD(StringBuilder sb, int indent) {
- for (int i = 0; i < numLines; i++) {
- sb.append("\n");
- }
- }
-
- public void addLine(){
- numLines++;
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.content;
-
-import eu.svjatoslav.sixth.core.document.text.FormattedText;
-
-public class TextBlock implements Content {
- private StringBuilder orgAccumulator = new StringBuilder();
- private boolean enabledForExport = true;
-
- public TextBlock (){
- }
-
- public void addContent(String content){
- orgAccumulator.append(content);
- }
-
- @Override
- public void toMD(StringBuilder sb, int indent) {
- if (!enabledForExport) return;
-
- FormattedText text = FormattedText.fromOrg(orgAccumulator.toString());
- sb.append(text.toMD(indent) + "\n");
- }
-
- public void disableForExport(){
- enabledForExport = false;
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.content;
-
-import eu.svjatoslav.commons.string.String2;
-
-public class Verse implements Content {
- public final String verse;
-
- public Verse(String verse) {
- this.verse = verse;
- }
-
- @Override
- public void toMD(StringBuilder sb, int indent) {
- String2 s = new String2();
- s.append(" ", indent).append("```\n");
- // TODO: ensure that required indent is present
- s.append(verse + "\n");
- s.append(" ", indent).append("```\n");
- sb.append(s.toString());
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.text;
-
-import eu.svjatoslav.commons.string.tokenizer.Tokenizer;
-import eu.svjatoslav.commons.string.tokenizer.TokenizerMatch;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static eu.svjatoslav.sixth.core.document.Helper.TG_HYPERLINK;
-import static eu.svjatoslav.sixth.core.document.Utils.addIndentExceptFirstLine;
-
-public class FormattedText {
- List<FormattedTextElement> elements = new ArrayList<>();
-
- public void parseOrgSyntax(String orgText) {
-
- Tokenizer tokenizer = getTokenizer(orgText);
- while (tokenizer.hasMoreContent()) {
- final TokenizerMatch token = tokenizer.getNextToken();
-
- if (token.isGroup(TG_HYPERLINK)){
- elements.add(Hyperlink.fromOrg(token));
- continue;
- }
-
- PlainText plainText = new PlainText(token.token);
- elements.add(plainText);
- }
-
- }
-
- public static FormattedText fromOrg(String orgText){
- FormattedText formattedText = new FormattedText();
- formattedText.parseOrgSyntax(orgText);
- return formattedText;
- }
-
- public String toMD(int indent){
- StringBuilder sb = new StringBuilder();
-
- for (FormattedTextElement element : elements)
- sb.append(element.toMD());
-
- return addIndentExceptFirstLine(sb.toString(), indent);
- }
-
- private Tokenizer getTokenizer(String contents) {
- final Tokenizer tokenizer = new Tokenizer(contents);
- tokenizer.addTerminator(Hyperlink.orgTerminator);
- tokenizer.addTerminator(Hyperlink.orgTerminator2);
- return tokenizer;
- }
-
-
- public String toString(){
- return toMD(0);
- }
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.text;
-
-public interface FormattedTextElement {
- String toMD();
-}
-
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.text;
-
-import eu.svjatoslav.commons.string.tokenizer.Terminator;
-import eu.svjatoslav.commons.string.tokenizer.TokenizerMatch;
-
-import static eu.svjatoslav.commons.string.tokenizer.Terminator.TerminationStrategy.PRESERVE;
-import static eu.svjatoslav.sixth.core.document.Helper.TG_HYPERLINK;
-
-public class Hyperlink implements FormattedTextElement {
-
- public static final Terminator orgTerminator =
- new Terminator(PRESERVE, "\\[\\[([\\s\\S]+)\\][ \\t\\r\\n]*\\[([\\s\\S]+)\\]\\]", TG_HYPERLINK);
-
- public static final Terminator orgTerminator2 =
- new Terminator(PRESERVE, "\\[\\[([\\s\\S]+)\\]\\]", TG_HYPERLINK);
-
- private String label;
- private String URL;
-
- @Override
- public String toMD() {
-
- if (URL.startsWith("id:"))
- return label; // TODO
-
- return "[" + label + "]("+ URL + ")";
- }
-
- public static Hyperlink fromOrg(TokenizerMatch tokenizerMatch) {
- Hyperlink hyperlink = new Hyperlink();
- hyperlink.parseOrg(tokenizerMatch);
- return hyperlink;
- }
-
- private void parseOrg(TokenizerMatch tokenizerMatch) {
- String[] regExpGroups = tokenizerMatch.getRegExpGroups();
- URL = regExpGroups[0];
- if (tokenizerMatch.terminator == orgTerminator){
- label = regExpGroups[1];
- }
-
- }
-
-}
+++ /dev/null
-package eu.svjatoslav.sixth.core.document.text;
-
-public class PlainText implements FormattedTextElement {
-
- private String content;
-
- public PlainText(String content){
- this.content = content;
- }
-
- @Override
- public String toMD() {
- return content;
- }
-}
-
-