com.redhat.ceylon.common.tools.help.HtmlVisitor Maven / Gradle / Ivy
/*
* Copyright Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the authors tag. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*
* This particular file is subject to the "Classpath" exception as provided in the
* LICENSE file that accompanied this code.
*
* This program is distributed in the hope that it will be useful, but WITHOUT A
* 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 this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.redhat.ceylon.common.tools.help;
import java.util.ResourceBundle;
import org.tautua.markdownpapers.ast.Node;
import com.redhat.ceylon.common.tool.ArgumentModel;
import com.redhat.ceylon.common.tool.OptionModel;
import com.redhat.ceylon.common.tool.OptionModel.ArgumentType;
import com.redhat.ceylon.common.tools.help.model.DescribedSection;
import com.redhat.ceylon.common.tools.help.model.Doc;
import com.redhat.ceylon.common.tools.help.model.Option;
import com.redhat.ceylon.common.tools.help.model.OptionsSection;
import com.redhat.ceylon.common.tools.help.model.SubtoolVisitor;
import com.redhat.ceylon.common.tools.help.model.SummarySection;
import com.redhat.ceylon.common.tools.help.model.SynopsesSection;
import com.redhat.ceylon.common.tools.help.model.Synopsis;
import com.redhat.ceylon.common.tools.help.model.Visitor;
import com.redhat.ceylon.common.tools.help.model.DescribedSection.Role;
import com.redhat.ceylon.common.tool.ToolModel;
public class HtmlVisitor implements Visitor {
private final Html html;
private boolean hadFirstArgument;
private boolean hadOptions;
private Doc doc;
private int optionsDepth = 0;
private final boolean omitDoctype;
HtmlVisitor(Appendable out, boolean omitDoctype) {
this.html = new Html(out);
this.omitDoctype = omitDoctype;
}
AbstractMl getHtml() {
return html;
}
@Override
public void start(Doc doc) {
this.doc = doc;
ResourceBundle bundle = CeylonHelpToolMessages.RESOURCE_BUNDLE;
if (!omitDoctype) {
html.doctype("html").text("\n");
}
html.open("html", "head");
html.tag("meta charset='UTF-8'").text("\n");
html.open("title").text(doc.getInvocation()).close("title").text("\n");
html.tag("link rel='stylesheet' type='text/css' href='bootstrap.min.css'").text("\n");
html.tag("link rel='stylesheet' type='text/css' href='doc-tool.css'").text("\n");
html.close("head").text("\n");
html.open("body").text("\n");
html.open("div class='navbar navbar-inverse navbar-static-top'").text("\n");
html.open("div class='navbar-inner'").text("\n");
html.open("a class='tool-header' href='index.html'").text("\n");
html.open("i class='tool-logo'").close("i").text("\n");
html.open("span class='tool-label'").text(bundle.getString("index.title")).close("span").text("\n");
html.open("span", "code class='tool-name'").text(doc.getInvocation()).close("code", "span").text("\n");
html.open("span class='tool-version'").text(doc.getVersion()).close("span").text("\n");
html.close("a").text("\n");
html.open("ul class='nav pull-right'");
html.tag("li class='divider-vertical'");
html.open("li id='infoDropdown' class='dropdown'");
html.open("a href='#' title='Show keyboard shortcuts [Shortcut: ?]' role='button' class='dropdown-toggle' data-toggle='dropdown'");
html.open("i class='icon-info'").close("i");
html.close("a");
html.open("ul id='info-dropdown-panel' class='dropdown-menu'");
html.open("h4").text("Keyboard Shortcuts").close("h4");
html.open("li class='divider'").close("li");
html.open("div id='info-common-shortcuts'");
shortcutInfo(html, "?", "Open this information panel");
shortcutInfo(html, "i", "Jump to tool index");
shortcutInfo(html, "s", "Jump to synopsis");
shortcutInfo(html, "d", "Jump to description");
shortcutInfo(html, "o", "Jump to options");
html.close("div", "ul", "li", "ul");
html.close("div").text("\n");
html.close("div").text("\n");
}
private static void shortcutInfo(AbstractMl html, String key, String description) {
html.open("div id='"+key+"'").open("span class='key badge'").text(key).close("span");
html.open("span class='info muted'").text(description).close("span", "div");
}
@Override
public void end(Doc doc) {
html.close("div");
html.open("script type='text/javascript' src='jquery-1.8.2.min.js'").close("script");
html.open("script type='text/javascript' src='bootstrap.min.js'").close("script");
html.open("script type='text/javascript' src='doc-tool.js'").close("script");
html.open("script type='text/javascript'").unescaped("init();").close("script");
html.close("body", "html");
}
private static void addTableStart(AbstractMl html, String section, String title, int cols) {
addTableStart(html, section, Markdown.markdown("##" + title), cols);
}
private static void addTableStart(AbstractMl html, String sectionId, Node title, int cols) {
html.open("table class='table table-condensed table-bordered'").text("\n");
html.open("thead").text("\n");
html.open("tr class='table-header' title='Click for expand/collapse'");
html.open("td colspan='" + cols + "'" + (sectionId != null ? " id='" + sectionId + "'" : ""));
html.open("i class='icon-expand'").close("i");
html.markdown(title).close("td", "tr").text("\n");
html.close("thead").text("\n");
html.open("tbody").text("\n");
}
private static void addTableEnd(AbstractMl html) {
html.close("tbody", "table");
}
@Override
public void visitAdditionalSection(DescribedSection describedSection) {
describedSection(0, describedSection);
}
private void describedSection(int depth, DescribedSection describedSection) {
String sectionId = null;
if (depth == 0) {
if (describedSection.getRole() == Role.DESCRIPTION) {
html.open("div class='section section-description'").text("\n");
sectionId = "section-description";
} else {
html.open("div class='section'").text("\n");
}
addTableStart(html, sectionId, describedSection.getTitle(), 1);
html.open("tr", "td").markdown(describedSection.getDescription());
} else {
if (describedSection.getAbout() instanceof ToolModel) {
html.open("div id='" + idSubtool((ToolModel>)describedSection.getAbout()) + "'");
} else {
html.open("div");
}
html.markdown(describedSection.getTitle());
html.markdown(describedSection.getDescription());
}
for (DescribedSection subsection : describedSection.getSubsections()) {
describedSection(depth+1, subsection);
}
if (depth != 0) {
html.close("div");
} else {
html.close("td", "tr");
addTableEnd(html);
html.close("div").text("\n");
}
}
@Override
public void startOptions(OptionsSection optionsSection) {
if (optionsDepth == 0) {
html.open("div class='section section-options'").text("\n");
addTableStart(html, "section-options", optionsSection.getTitle(), 2);
} else {
html.open("tr class='table-header'", "td colspan='2'");
html.markdown(optionsSection.getTitle());
html.close("td", "tr");
}
optionsDepth++;
}
private String idLongOption(OptionModel> option) {
// TODO Could be ambiguous need to use whole path from root
return "option--" + option.getLongName();
}
private String idShortOption(OptionModel> option) {
// TODO Could be ambiguous need to use whole path from root
return "option-" + option.getShortName();
}
private String idSubtool(ToolModel> model) {
// TODO Could be ambiguous need to use whole path from root
return "subtool-" + model.getName();
}
@Override
public void visitOption(Option option) {
String longName = option.getLongName();
String shortName = option.getShortName();
String argumentName = option.getArgumentName();
ArgumentType argumentType = option.getOption().getArgumentType();
html.open("tr");
html.open("td class='span3' id='" + idLongOption(option.getOption()) + "'", "code").text(longName);
if (argumentType == ArgumentType.OPTIONAL) {
html.text("[");
}
if (argumentType != ArgumentType.NOT_ALLOWED) {
html.text("=").text(argumentName);
}
if (argumentType == ArgumentType.OPTIONAL) {
html.text("]");
}
html.close("code");
if (shortName != null) {
html.text(", ");
html.open("code id='" + idShortOption(option.getOption()) + "'").text(shortName);
if (argumentType == ArgumentType.REQUIRED) {
html.text(" ");
html.text(argumentName);
}
html.close("code");
}
html.close("td").text("\n");
html.open("td class='option-description'");
html.markdown(option.getDescription());
html.close("td").text("\n");
html.close("tr");
}
@Override
public void endOptions(OptionsSection optionsSection) {
optionsDepth--;
if (optionsDepth == 0) {
addTableEnd(html);
html.close("div");
}
}
@Override
public void visitSummary(SummarySection summarySection) {
html.open("div class='sub-navbar'").text("\n");
html.open("div class='sub-navbar-inner'");
html.open("div", "code class='sub-navbar-tool'").text(doc.getInvocation()).close("code", "div").text("\n");
html.open("div class='sub-navbar-summary'").markdown(Markdown.markdown(summarySection.getSummary())).close("div").text("\n");
html.close("div");
html.open("div class='sub-navbar-menu'").text("\n");
addShortcutKey(html, "index.html", "Jump to tool index", "I", "ndex");
addShortcutKey(html, "#section-synopsis", "Jump to tool synopsis", "S", "ynopsis");
addShortcutKey(html, "#section-description", "Jump to tool description", "D", "escription");
addShortcutKey(html, "#section-options", "Jump to tool options", "O", "ptions");
html.close("div", "div").text("\n");
html.open("div class='container-fluid'").text("\n");
}
private static void addShortcutKey(AbstractMl html, String url, String title, String key, String rest) {
html.open("a href='" + url + "'");
html.open("span title='" + title + " [Shortcut: "+key+"]'");
html.open("span class='accesskey'").text(key).close("span").text(rest).close("span", "a");
}
@Override
public void startSynopses(SynopsesSection synopsesSection) {
html.open("div class='section section-synopsis'").text("\n");
addTableStart(html, "section-synopsis", synopsesSection.getTitle(), 1);
}
private void longOptionSynopsis(OptionModel> option) {
String string = "--" + option.getLongName();
html.link(string, "#" + idLongOption(option));
}
private void shortOptionSynopsis(OptionModel> option) {
String string = "-" + option.getShortName();
html.link(string, "#" + idShortOption(option));
}
private void argumentSynopsis(String name) {
html.link(name, "#arg" + name);
}
private void subtoolSynopsis(SubtoolVisitor.ToolModelAndSubtoolModel nast) {
String name = nast.getName();
if (nast.getModel().getSubtoolModel() == null) {
html.link(name, "#" + idSubtool(nast.getModel()));
} else {
html.text(name);
}
}
private String multiplicity(ArgumentModel> argument, String name) {
name = "<" + name + ">";
if (argument.getMultiplicity().isMultivalued()) {
name += "...";
}
return name;
}
@Override
public void startSynopsis(Synopsis synopsis) {
hadFirstArgument = false;
hadOptions = false;
html.open("tr", "td");
html.open("div class='synopsis'", "code");
html.text(synopsis.getInvocation() + " ");
}
@Override
public void endSynopsis(Synopsis synopsis) {
html.close("code", "div").text("\n");
html.close("td", "tr");
}
@Override
public void visitSynopsisArgument(ArgumentModel> argument) {
if (!hadFirstArgument) {
html.text(" [--]");
hadFirstArgument = true;
}
html.text(" ");
String name = argument.getName();
if (!argument.getMultiplicity().isRequired()) {
html.text("[");
}
// don't generate a # link because arguments have no name or id
html.text("<").text(name);
if (argument.getMultiplicity().isMultivalued()) {
html.text("...");
}
html.text(">");
if (!argument.getMultiplicity().isRequired()) {
html.text("]");
}
}
@Override
public void visitSynopsisOption(OptionModel> option) {
hadOptions = true;
html.text(" ");
final ArgumentModel> argument = option.getArgument();
if (!argument.getMultiplicity().isRequired()) {
html.text("[");
}
if (option.getLongName() != null) {
longOptionSynopsis(option);
if (option.getArgumentType() == ArgumentType.REQUIRED) {
html.text("=");
html.text(multiplicity(argument, argument.getName()));
} else if (option.getArgumentType() == ArgumentType.OPTIONAL) {
html.text("[=");
html.text(multiplicity(argument, argument.getName()));
html.text("]");
}
} else {
shortOptionSynopsis(option);
if (option.getArgumentType() == ArgumentType.REQUIRED) {
html.text(" ");
html.text(multiplicity(argument, argument.getName()));
}
}
if (!argument.getMultiplicity().isRequired()) {
html.text("]");
}
}
@Override
public void endSynopses(SynopsesSection synopsesSection) {
addTableEnd(html);
html.close("div").text("\n\n");
}
@Override
public void visitDescription(DescribedSection descriptionSection) {
describedSection(0, descriptionSection);
}
@Override
public void visitSynopsisSubtool(SubtoolVisitor.ToolModelAndSubtoolModel option) {
html.text(" ");
subtoolSynopsis(option);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy