Package ch.raffael.doclets.pegdown

Source Code of ch.raffael.doclets.pegdown.Options

/*
* Copyright 2013 Raffael Herzog
*
* This file is part of pegdown-doclet.
*
* pegdown-doclet is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pegdown-doclet is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pegdown-doclet.  If not, see <http://www.gnu.org/licenses/>.
*/
package ch.raffael.doclets.pegdown;

import java.io.File;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import com.google.common.base.Splitter;
import com.google.common.collect.Ordering;
import com.sun.javadoc.DocErrorReporter;
import com.sun.tools.doclets.standard.Standard;
import org.pegdown.Extensions;
import org.pegdown.LinkRenderer;
import org.pegdown.PegDownProcessor;
import org.pegdown.ToHtmlSerializer;

import static com.google.common.base.MoreObjects.*;


/**
* Processes and stores the command line options.
*
* @author <p><a href="mailto:herzog@raffael.ch">Raffael Herzog</a></p>
*/
public class Options {

    public static final String OPT_EXTENSIONS = "-extensions";
    public static final String OPT_DISABLE_HIGHLIGHT = "-disable-highlight";
    public static final String OPT_ENABLE_AUTO_HIGHLIGHT = "-enable-auto-highlight";
    public static final String OPT_HIGHLIGHT_STYLE = "-highlight-style";
    public static final String OPT_PLANTUML_CONFIG = "-plantuml-config";
    public static final String OPT_PARSE_TIMEOUT = "-parse-timeout";
    public static final String OPT_ENCODING = "-encoding";
    public static final String OPT_OVERVIEW = "-overview";
    public static final String OPT_OUTPUT_DIR = "-d";
    public static final String OPT_STYLESHEETFILE = "-stylesheetfile";
    public static final String OPT_TODO_TITLE = "-todo-title";

    private static final Pattern LINE_START = Pattern.compile("^ ", Pattern.MULTILINE);
    private static final Pattern MARKERS = Pattern.compile("\\020[et]");

    /**
     * The default extensions for Pegdown. This includes the following extensions:
     *
     * * {@link Extensions#AUTOLINKS}
     * * {@link Extensions#DEFINITIONS}
     * * {@link Extensions#FENCED_CODE_BLOCKS}
     * * {@link Extensions#SMARTYPANTS}
     * * {@link Extensions#TABLES}
     * * {@link Extensions#WIKILINKS}
     */
    public static final int DEFAULT_PEGDOWN_EXTENSIONS =
            Extensions.AUTOLINKS
            | Extensions.DEFINITIONS
            | Extensions.FENCED_CODE_BLOCKS
            | Extensions.SMARTYPANTS
            | Extensions.TABLES
            | Extensions.WIKILINKS;

    private String[][] forwardedOptions = new String[0][];

    private Integer pegdownExtensions = null;
    private File overviewFile = null;
    private Charset encoding = null;
    private File destinationDir = null;
    private File stylesheetFile = null;
    private File plantUmlConfigFile = null;
    private boolean highlightEnabled = true;
    private boolean autoHighlightEnabled = false;
    private String highlightStyle = null;
    private Long parseTimeout;
    private String todoTitle = null;

    private LinkRenderer linkRenderer = null;
    private PegDownProcessor processor = null;

    private Set<Integer> consumedOptions = new HashSet<>();

    public Options() {
    }

    /**
     * Retrieves the options to be forwarded to the standard Doclet.
     *
     * @return The options for the standard Doclet.
     */
    public String[][] forwardedOptions() {
        return forwardedOptions;
    }

    /**
     * Loads the options from the command line.
     *
     * @param options          The command line options.
     * @param errorReporter    The error reporter for printing messages.
     *
     * @return `true` if the options are valid.
     */
    public boolean load(String[][] options, DocErrorReporter errorReporter) {
        this.forwardedOptions = options;
        consumedOptions.clear();
        for ( int i = 0; i < options.length; i++ ) {
            String[] opt = options[i];
            if ( opt[0].equals(OPT_EXTENSIONS) ) {
                if ( pegdownExtensions != null ) {
                    errorReporter.printError("Only one " + OPT_EXTENSIONS + " option allowed");
                    return false;
                }
                try {
                    setPegdownExtensions(toExtensions(opt[1]));
                }
                catch ( IllegalArgumentException e ) {
                    errorReporter.printError(e.getMessage());
                    return false;
                }
                consumeOption(i);
            }
            else if ( opt[0].equals(OPT_DISABLE_HIGHLIGHT) ) {
                highlightEnabled = false;
                consumeOption(i);
            }
            else if ( opt[0].equals(OPT_ENABLE_AUTO_HIGHLIGHT) ) {
                autoHighlightEnabled = true;
                consumeOption(i);
            }
            else if ( opt[0].equals(OPT_HIGHLIGHT_STYLE) ) {
                if ( highlightStyle != null ) {
                    errorReporter.printError("Only one " + OPT_HIGHLIGHT_STYLE + " option allowed");
                    return false;
                }
                highlightStyle = opt[1];
                consumeOption(i);
            }
            else if ( opt[0].equals(OPT_PLANTUML_CONFIG) ) {
                if ( plantUmlConfigFile != null ) {
                    errorReporter.printError("Only one " + OPT_PLANTUML_CONFIG + " option allowed");
                    return false;
                }
                setPlantUmlConfigFile(new File(opt[1]));
                consumeOption(i);
            }
            else if ( opt[0].equals(OPT_PARSE_TIMEOUT) ) {
                if ( parseTimeout != null ) {
                    errorReporter.printError("Only one -parse-timeout option allowed");
                    return false;
                }
                BigDecimal millis = new BigDecimal(opt[1]).movePointRight(3);
                if ( millis.compareTo(BigDecimal.ZERO) <= 0 || millis.compareTo(new BigDecimal(Long.MAX_VALUE)) > 0 ) {
                    errorReporter.printError("Invalid timeout value: " + opt[1]);
                    return false;
                }
                parseTimeout = millis.longValue();
                consumeOption(i);
            }
            else if ( opt[0].equals(OPT_ENCODING) ) {
                try {
                    encoding = Charset.forName(opt[1]);
                }
                catch ( IllegalCharsetNameException e ) {
                    errorReporter.printError("Illegal charset: " + opt[1]);
                    return false;
                }
            }
            else if ( opt[0].equals(OPT_OVERVIEW) ) {
                if ( getOverviewFile() != null ) {
                    errorReporter.printError(OPT_OVERVIEW + " may only be specified once");
                    return false;
                }
                setOverviewFile(new File(opt[1]));
                consumeOption(i);
            }
            else if ( opt[0].equals(OPT_OUTPUT_DIR) ) {
                if ( destinationDir != null ) {
                    errorReporter.printError(OPT_OUTPUT_DIR + " may only be specified once");
                }
                setDestinationDir(new File(opt[1]));
            }
            else if ( opt[0].equals(OPT_STYLESHEETFILE) ) {
                if ( stylesheetFile != null ) {
                    errorReporter.printError(OPT_STYLESHEETFILE + " may only specified once");
                }
                setStylesheetFile(new File(opt[1]));
            }
            else if ( opt[0].equals(OPT_TODO_TITLE) ) {
                if ( todoTitle != null ) {
                    errorReporter.printError(OPT_TODO_TITLE + " may only specified once");
                }
                setTodoTitle(todoTitle);
                consumeOption(i);
            }
        }
        if ( !customLoad(options, errorReporter) ) {
            return false;
        }
        if ( pegdownExtensions == null ) {
            setPegdownExtensions(DEFAULT_PEGDOWN_EXTENSIONS);
        }
        if ( !consumedOptions.isEmpty() ) {
            ArrayList<String[]> consuming = new ArrayList<>(Arrays.asList(options));
            for ( int i : Ordering.natural().reverse().sortedCopy(consumedOptions) ) {
                consuming.remove(i);
            }
            forwardedOptions = consuming.toArray(new String[consuming.size()][]);
            consumedOptions.clear();
        }
        return Standard.validOptions(forwardedOptions, errorReporter);
    }

    /**
     * Hook to do some custom option processing.
     *
     * @param options          The command line options.
     * @param errorReporter    An error reporter for printing messages.
     *
     * @return `true` if the options are valid.
     */
    protected boolean customLoad(String[][] options, DocErrorReporter errorReporter) {
        return true;
    }

    /**
     * Consumes an option. The option will then be excluded from the result of
     * {@link #forwardedOptions()}.
     *
     * @param index    The index of the consumed option.
     */
    protected void consumeOption(int index) {
        consumedOptions.add(index);
    }

    /**
     * Gets the Pegdown extension flags.
     *
     * @return The Pegdown extension flags.
     *
     * @see Extensions
     */
    public int getPegdownExtensions() {
        return pegdownExtensions != null ? pegdownExtensions : DEFAULT_PEGDOWN_EXTENSIONS;
    }

    /**
     * Sets the Pegdown extension flags.
     *
     * @param pegdownExtensions    The Pegdown extension flags.
     *
     * @see Extensions
     */
    public void setPegdownExtensions(int pegdownExtensions) {
        this.pegdownExtensions = pegdownExtensions;
        processor = null;
    }

    /**
     * Gets the overview file.
     *
     * @return The overview file.
     */
    public File getOverviewFile() {
        return overviewFile;
    }

    /**
     * Sets the overview file.
     *
     * @param overviewFile The overview file.
     */
    public void setOverviewFile(File overviewFile) {
        this.overviewFile = overviewFile;
    }

    /**
     * Gets the source encoding.
     *
     * @return The source encoding.
     */
    public Charset getEncoding() {
        return firstNonNull(encoding, Charset.defaultCharset());
    }

    /**
     * Sets the source encoding.
     *
     * @param encoding The source encoding.
     */
    public void setEncoding(Charset encoding) {
        this.encoding = encoding;
    }

    /**
     * Gets the destination directory.
     *
     * @return The destination directory.
     */
    public File getDestinationDir() {
        if ( destinationDir == null ) {
            destinationDir = new File(System.getProperty("user.dir"));
        }
        return destinationDir;
    }

    /**
     * Sets the destination directory.
     *
     * @param destinationDir    The destination directory
     */
    public void setDestinationDir(File destinationDir) {
        this.destinationDir = destinationDir;
    }

    /**
     * Gets the CSS stylesheet file.
     *
     * @return The stylesheet file.
     */
    public File getStylesheetFile() {
        return stylesheetFile;
    }

    /**
     * Sets the CSS stylesheet file.
     *
     * @param stylesheetFile The stylesheet file.
     */
    public void setStylesheetFile(File stylesheetFile) {
        this.stylesheetFile = stylesheetFile;
    }

    /**
     * Gets the PlantUML configuration file.
     *
     * @return The PlantUML configuration file.
     */
    public File getPlantUmlConfigFile() {
        return plantUmlConfigFile;
    }

    /**
     * Sets the PlantUML configuration file.
     *
     * @param plantUmlConfigFile    The PlantUML configuration file.
     */
    public void setPlantUmlConfigFile(File plantUmlConfigFile) {
        this.plantUmlConfigFile = plantUmlConfigFile;
    }

    /**
     * Gets the link renderer.
     *
     * @return The link renderer.
     */
    public LinkRenderer getLinkRenderer() {
        if ( linkRenderer == null ) {
            linkRenderer = new DocletLinkRenderer();
        }
        return linkRenderer;
    }

    /**
     * Sets the link renderer.
     *
     * @param linkRenderer The link renderer.
     */
    public void setLinkRenderer(LinkRenderer linkRenderer) {
        this.linkRenderer = linkRenderer;
    }

    public boolean isHighlightEnabled() {
        return highlightEnabled;
    }

    public void setHighlightEnabled(boolean highlightEnabled) {
        this.highlightEnabled = highlightEnabled;
    }

    public boolean isAutoHighlightEnabled() {
        return autoHighlightEnabled;
    }

    public void setAutoHighlightEnabled(boolean autoHighlightEnabled) {
        this.autoHighlightEnabled = autoHighlightEnabled;
    }

    public String getHighlightStyle() {
        return firstNonNull(highlightStyle, "default");
    }

    public void setHighlightStyle(String highlightStyle) {
        this.highlightStyle = highlightStyle;
    }

    public String getTodoTitle() {
        return firstNonNull(todoTitle, "To Do");
    }

    public void setTodoTitle(String todoTitle) {
        this.todoTitle = todoTitle;
    }

    /**
     * Gets the parse timeout in milliseconds for the Pegdown processor.
     *
     * @return The parse timeout.
     *
     * @see PegDownProcessor#PegDownProcessor(int, long)
     */
    public long getParseTimeout() {
        processor = null;
        return parseTimeout != null ? parseTimeout : PegDownProcessor.DEFAULT_MAX_PARSING_TIME;
    }

    /**
     * Sets the parse timeout in milliseconds for the Pegdown processor.
     *
     * @param parseTimeout    The new parse timeout.
     *
     * @see PegDownProcessor#PegDownProcessor(int, long)
     */
    public void setParseTimeout(long parseTimeout) {
        this.parseTimeout = parseTimeout;
    }

    /**
     * Converts Markdown source to HTML according to this options object. Leading spaces
     * will be fixed.
     *
     * @param markup    The Markdown source.
     *
     * @return The resulting HTML.
     *
     * @see #toHtml(String, boolean)
     */
    public String toHtml(String markup) {
        return toHtml(markup, true);
    }

    /**
     * Converts Markdown source to HTML according to this options object. If
     * `fixLeadingSpaces` is `true`, exactly one leading whitespace character ('\\u0020')
     * will be removed, if it exists.
     *
     * @todo This method doesn't belong here, move it to {@link PegdownDoclet}.
     *
     * @param markup           The Markdown source.
     * @param fixLeadingSpaces `true` if leading spaces should be fixed.
     *
     * @return The resulting HTML.
     */
    public String toHtml(String markup, boolean fixLeadingSpaces) {
        if ( processor == null ) {
            processor = createProcessor();
        }
        if ( fixLeadingSpaces ) {
            markup = LINE_START.matcher(markup).replaceAll("");
        }
        List<String> tags = new ArrayList<>();
        String html = createDocletSerializer().toHtml(processor.parseMarkdown(Tags.extractInlineTags(markup, tags).toCharArray()));
        return Tags.insertInlineTags(html, tags);
    }

    /**
     * Create a new processor. If you need to further customise the markup processing,
     * you can override this method.
     *
     * @return A (possibly customised) Pegdown processor.
     */
    protected PegDownProcessor createProcessor() {
        return new PegDownProcessor(firstNonNull(pegdownExtensions, DEFAULT_PEGDOWN_EXTENSIONS), getParseTimeout());
    }

    /**
     * Create a new serializer. If you need to further customize the HTML rendering, you
     * can override this method.
     *
     * @return A (possibly customised) ToHtmlSerializer.
     */
    protected ToHtmlSerializer createDocletSerializer() {
        return new DocletSerializer(this, getLinkRenderer());
    }

    public static int optionLength(String option) {
        switch ( option ) {
            case OPT_EXTENSIONS:
            case OPT_PLANTUML_CONFIG:
            case OPT_HIGHLIGHT_STYLE:
            case OPT_PARSE_TIMEOUT:
            case OPT_TODO_TITLE:
                return 2;
            case OPT_DISABLE_HIGHLIGHT:
            case OPT_ENABLE_AUTO_HIGHLIGHT:
                return 1;
            default:
                return Standard.optionLength(option);
        }
    }

    /**
     * As specified by the Doclet specification.
     *
     * @param options          The command line options.
     * @param errorReporter    An error reporter to print messages.
     *
     * @return `true` if the options are valid.
     *
     * @see com.sun.javadoc.Doclet#validOptions(String[][], com.sun.javadoc.DocErrorReporter)
     */
    public static boolean validOptions(String[][] options, DocErrorReporter errorReporter) {
        return new Options().load(options, errorReporter);
    }

    /**
     * Convert a comma separated list of extension names to an int. Each name is
     * converted to upper case, any '-' is replaced by '_'. The result is expected to
     * be a flag from {@link Extensions}.
     *
     * @param extensions    A comma separated list of PegDown extensions.
     *
     * @return An `int` representing the enabled Pegdown extensions.
     */
    public static int toExtensions(String extensions) {
        int result = 0;
        for ( String ext : Splitter.on(',').trimResults().omitEmptyStrings().split(extensions) ) {
            try {
                Field f = Extensions.class.getField(ext.replace('-', '_').toUpperCase());
                result |= (int)f.get(null);
            }
            catch ( NoSuchFieldException e ) {
                throw new IllegalArgumentException("No such extension: " + ext);
            }
            catch ( IllegalAccessException e ) {
                throw new IllegalArgumentException("Cannot read int value for extension " + ext + ": " + e, e);
            }
        }
        return result;
    }

}
TOP

Related Classes of ch.raffael.doclets.pegdown.Options

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.