All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.mmm.code.api.doc.CodeDocFormat Maven / Gradle / Ivy

There is a newer version: 1.0.0-beta7
Show newest version
/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0 */
package net.sf.mmm.code.api.doc;

import java.util.function.Supplier;

import net.sf.mmm.util.xml.base.XmlUtilImpl;

/**
 * Definition of format(s) to be able to convert {@link CodeDoc} to.
 *
 * @see CodeDoc#getFormatted(CodeDocFormat)
 *
 * @author Joerg Hohwiller (hohwille at users.sourceforge.net)
 * @since 1.0.0
 */
public abstract class CodeDocFormat {

  /** {@link CodeDocFormat} for documentation as HTML fragment. */
  public static final CodeDocFormat HTML = new CodeDocFormatHtml();

  /** {@link CodeDocFormat} for documentation as AsciiDoc fragment. */
  public static final CodeDocFormat ASCII_DOC = new CodeDocFormatAsciiDoc();

  /** {@link CodeDocFormat} for documentation as plain text (all markup removed). */
  public static final CodeDocFormat PLAIN_TEXT = new CodeDocFormatPlainText();

  /**
   * {@link CodeDocFormat} for documentation as raw text in its original source format (e.g. JavaDoc or
   * JSDoc).
   */
  public static final CodeDocFormat RAW = new CodeDocFormatRaw();

  private static final String CODE_START = "";

  private static final String CODE_END = "";

  /**
   * @return {@code true} if XML tags shall be parsed and {@link #replaceXmlTag(Tag) replaced}, {@code false}
   *         otherwise (if they shall be kept unmodified).
   */
  public abstract boolean isReplaceXmlTags();

  /**
   * @param tag the XML {@link Tag} to replace.
   * @return the replacement.
   */
  public abstract String replaceXmlTag(Tag tag);

  /**
   * @param tag the documentation tag such as {@link CodeDoc#TAG_CODE} or {@link CodeDoc#TAG_LINK}.
   * @param link the optional {@link Supplier} used to resolve a {@link CodeDocLink} in case of
   *        {@link CodeDoc#TAG_LINK link}, {@link CodeDoc#TAG_LINKPLAIN linkplain}, or
   *        {@link CodeDoc#TAG_VALUE value} {@code tag}. Otherwise {@code null}.
   * @param text the plain text.
   * @return the tag converted to this format.
   */
  public abstract String replaceDocTag(String tag, Supplier link, String text);

  @Override
  public abstract String toString();

  private static int getListLevel(Tag tag) {

    Tag parent = tag.getParent();
    if (parent == null) {
      return 0;
    }
    int level = getListLevel(parent);
    String name = tag.getName();
    if (name.equals("ul")) {
      if (level == 0) {
        level = -1;
      } else if (level > 0) {
        level = -level;
      }
    } else if (name.equals("ol")) {
      if (level == 0) {
        level = 1;
      } else if (level < 0) {
        level = -level;
      }
    } else if (name.equals("li")) {
      if (level > 0) {
        level++;
      } else {
        level--;
      }
    }
    return level;
  }

  /** {@link CodeDocFormat} for {@link CodeDocFormat#HTML}. */
  protected static class CodeDocFormatHtml extends CodeDocFormat {

    @Override
    public boolean isReplaceXmlTags() {

      return false;
    }

    @Override
    public String replaceXmlTag(Tag tag) {

      throw new IllegalStateException();
    }

    @Override
    public String replaceDocTag(String tag, Supplier link, String text) {

      StringBuilder buffer = new StringBuilder(text.length() + 16);
      if (CodeDoc.TAG_LINK.equals(tag)) {
        buffer.append(CODE_START);
        appendLink(buffer, link.get(), text);
        buffer.append(CODE_END);
      } else if (CodeDoc.TAG_LINKPLAIN.equals(tag)) {
        appendLink(buffer, link.get(), text);
      } else if (CodeDoc.TAG_CODE.equals(tag)) {
        buffer.append(CODE_START);
        appendText(buffer, text);
        buffer.append(CODE_END);
      } else if (CodeDoc.TAG_LITERAL.equals(tag)) {
        appendText(buffer, text);
      } else if (CodeDoc.TAG_VALUE.equals(tag)) {
        appendValue(buffer, link.get());
      } else {
        // unknown tag...
        appendText(buffer, text);
      }
      return buffer.toString();
    }

    private void appendValue(StringBuilder buffer, CodeDocLink link) {

      buffer.append(CODE_START);
      appendText(buffer, link.getLinkedValueAsString());
      buffer.append(CODE_END);
    }

    private void appendLink(StringBuilder buffer, CodeDocLink link, String text) {

      buffer.append("");
      appendText(buffer, link.getText());
      buffer.append("");
    }

    private void appendText(StringBuilder buffer, String text) {

      if ((text == null) || (text.isEmpty())) {
        return;
      }
      buffer.append(XmlUtilImpl.getInstance().escapeXml(text.trim(), false));
    }

    @Override
    public String toString() {

      return "html";
    }
  }

  /** {@link CodeDocFormat} for {@link CodeDocFormat#ASCII_DOC}. */
  protected static class CodeDocFormatAsciiDoc extends CodeDocFormat {

    @Override
    public boolean isReplaceXmlTags() {

      return true;
    }

    @Override
    public String replaceXmlTag(Tag tag) {

      String name = tag.getName();
      if (tag.isOpening() && tag.isClosing()) {
        if ("br".equals(name)) {
          return "\n";
        } else if ("p".equals(name)) {
          return "\n<<<<\n";
        } else if ("hr".equals(name)) {
          return "\n'''\n";
        }
        return "";
      }
      if (CodeDoc.TAG_CODE.equals(name)) {
        return "`";
      } else if ("b".equals(name) || "strong".equals(name)) {
        return "*";
      } else if ("i".equals(name) || "em".equals(name)) {
        return "_";
      } else if (tag.getName().equals("ol") || tag.getName().equals("ul")) {
        return "\n";
      } else if (tag.isOpening() && !tag.isClosing()) {
        if ("li".equals(name)) {
          if (tag.isOpening()) {
            int level = getListLevel(tag);
            int indent = level;
            String bullet;
            if (indent < 0) {
              indent = -indent;
              bullet = "*";
            } else {
              bullet = ".";
            }
            StringBuilder buffer = new StringBuilder(indent + 2);
            buffer.append('\n');
            for (int i = 0; i < indent; i++) {
              buffer.append(bullet);
            }
            buffer.append(' ');
            return buffer.toString();
          }
        } else if ("h1".equals(name)) {
          return "\n= ";
        } else if ("h2".equals(name)) {
          return "\n== ";
        } else if ("h3".equals(name)) {
          return "\n=== ";
        } else if ("h4".equals(name)) {
          return "\n==== ";
        }
      }
      // unknown tag...
      return "";
    }

    @Override
    public String replaceDocTag(String tag, Supplier link, String text) {

      StringBuilder buffer = new StringBuilder(text.length() + 16);
      if (CodeDoc.TAG_LINK.equals(tag)) {
        buffer.append('`');
        appendLink(buffer, link.get(), text);
        buffer.append('`');
      } else if (CodeDoc.TAG_LINKPLAIN.equals(tag)) {
        appendLink(buffer, link.get(), text);
      } else if (CodeDoc.TAG_CODE.equals(tag)) {
        buffer.append('`');
        appendText(buffer, text);
        buffer.append('`');
      } else if (CodeDoc.TAG_LITERAL.equals(tag)) {
        appendText(buffer, text);
      } else if (CodeDoc.TAG_VALUE.equals(tag)) {
        appendValue(buffer, link.get());
      } else {
        // unknown tag...
        appendText(buffer, text);
      }
      return buffer.toString();
    }

    private void appendValue(StringBuilder buffer, CodeDocLink link) {

      buffer.append('`');
      appendText(buffer, link.getLinkedValueAsString());
      buffer.append('`');
    }

    private void appendLink(StringBuilder buffer, CodeDocLink link, String text) {

      String url = link.getLinkUrl();
      if (!url.contains("://")) {
        buffer.append("link:");
      }
      buffer.append(url);
      buffer.append('[');
      appendText(buffer, link.getText());
      buffer.append(']');
    }

    private void appendText(StringBuilder buffer, String text) {

      if ((text == null) || (text.isEmpty())) {
        return;
      }
      buffer.append(text.trim());
    }

    @Override
    public String toString() {

      return "ascii-doc";
    }

  }

  /** {@link CodeDocFormat} for {@link CodeDocFormat#PLAIN_TEXT}. */
  protected static class CodeDocFormatPlainText extends CodeDocFormat {

    @Override
    public boolean isReplaceXmlTags() {

      return true;
    }

    @Override
    public String replaceXmlTag(Tag tag) {

      if (tag.getName().equals("li")) {
        if (tag.isOpening()) {
          int level = getListLevel(tag);
          int indent = level;
          String bullet;
          if (indent < 0) {
            indent = -indent;
            bullet = "* ";
          } else {
            bullet = ". ";
          }
          StringBuilder buffer = new StringBuilder(2 * (indent - 1) + 3);
          buffer.append('\n');
          for (int i = 1; i < indent; i++) {
            buffer.append("  ");
          }
          buffer.append(bullet);
          return buffer.toString();
        }
      } else if (tag.isClosing()) {
        if (tag.getName().equals("ol") || tag.getName().equals("ul")) {
          return "\n";
        }
      }
      return "";
    }

    @Override
    public String replaceDocTag(String tag, Supplier link, String text) {

      if (link != null) {
        return link.get().getText();
      }
      return text;
    }

    @Override
    public String toString() {

      return "plain-text";
    }
  }

  /** {@link CodeDocFormat} for {@link CodeDocFormat#RAW}. */
  protected static class CodeDocFormatRaw extends CodeDocFormat {

    @Override
    public boolean isReplaceXmlTags() {

      return false;
    }

    @Override
    public String replaceXmlTag(Tag tag) {

      throw new IllegalStateException();
    }

    @Override
    public String replaceDocTag(String tag, Supplier link, String text) {

      throw new IllegalStateException();
    }

    @Override
    public String toString() {

      return "raw";
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy