/*
* Copyright 2011 Oliver Buchtala
*
* This file is part of ndogen.
*
* ndogen 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.
*
* ndogen 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 ndogen. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ndogen.converter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.Tree;
import org.ndogen.Fixture;
import org.ndogen.TestUtils;
import org.ndogen.antlr.DebugCharStream;
import org.ndogen.markdown.MarkdownParser;
import org.ndogen.markdown.MarkdownParser.document_return;
import org.ndogen.markdown.MarkdownScanner;
import org.ndogen.watch.task.ContentProvider;
/**
* Converts a Markdown source into html.
* This will not create a standalone html page.
* Use this in combination with a html template file.
*/
public class Markdown2Html implements ContentProvider {
ContentProvider markdownProvider;
// private TemplateProcessor templateProcessor;
public Markdown2Html(ContentProvider markdownProvider) {
super();
this.markdownProvider = markdownProvider;
// templateProcessor = new TemplateProcessor();
}
@Override
public String getContent() {
String input = markdownProvider.getContent();
CharStream lexerInput;
lexerInput = new ANTLRStringStream(input);
lexerInput = new DebugCharStream(lexerInput);
MarkdownScanner lexer = new MarkdownScanner(lexerInput);
CommonTokenStream tokens = new CommonTokenStream(lexer);
MarkdownParser parser = new MarkdownParser(tokens);
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
IndentWriter out = new IndentWriter(pw);
document_return doc = parser.document();
Tree tree = (Tree) doc.getTree();
processTree(out, tree, new State());
return sw.toString();
} catch (RecognitionException e) {
e.printStackTrace();
return "<h1>Parser Error!</h1>";
}
// return "<html><h1>Not implemented yet</h1></html>";
}
protected void processTree(IndentWriter out, Tree node, State state) {
int type = node.getType();
switch(type) {
case 0:
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
break;
case MarkdownParser.SECTION:
state.sectionLevel++;
String title = node.getChild(0).getText();
out.println(String.format("<h%d>%s</h%d>", state.sectionLevel, title, state.sectionLevel));
out.indent();
for (int i = 1; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.dedent();
state.sectionLevel--;
break;
case MarkdownParser.TEXT_BLOCK:
out.println("<p>");
out.indent();
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.dedent();
out.println();
out.println("</p>");
break;
case MarkdownParser.TEXT:
out.print(node.getText());
break;
case MarkdownParser.LIST:
out.println("<ul>");
out.indent();
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.dedent();
out.println("</ul>");
break;
case MarkdownParser.LIST_ITEM:
out.println("<li>");
out.indent();
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.dedent();
out.println();
out.println("</li>");
break;
case MarkdownParser.QUOTE_BLOCK:
out.println("<blockquote><p>");
out.indent();
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.dedent();
out.println();
out.println("</p></blockquote>");
break;
case MarkdownParser.CODE_BLOCK:
out.println("<pre>");
state.insertNL = true;
out.indent();
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.dedent();
state.insertNL = false;
out.println("</pre>");
break;
case MarkdownParser.NL:
if(state.breakLine) {
out.println("<br/>");
} else if (state.insertNL) {
out.println();
} else {
out.print(" ");
}
break;
case MarkdownParser.EL:
// skip this
break;
case MarkdownParser.EMPH:
out.print("<em>");
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.print("</em>");
break;
case MarkdownParser.STRONG:
out.print("<strong>");
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.print("</strong>");
break;
case MarkdownParser.INLINE_CODE:
out.print("<code>");
for (int i = 0; i < node.getChildCount(); i++) {
processTree(out, node.getChild(i), state);
}
out.print("</code>");
break;
case MarkdownParser.LINK:
String text = node.getChild(0).getText();
String link = node.getChild(1).getText();
try {
URL url = new URL(link);
link = url.toString();
} catch (MalformedURLException e) {
System.err.println("Malformed Url: " + link);
out.print(text);
break;
}
out.print("<a href=\""+link+"\">"+text+"</a>");
break;
default:
System.out.println("Skipping unhandled node "+ node.getText());
// skip
}
}
public static class State {
int sectionLevel = 0;
boolean breakLine = false;
boolean insertNL = false;
}
public static void main(String[] args) {
Fixture fixture = TestUtils.getFixture("fixtures/markdown/parser", "links");
final String input = fixture.getInput();
Markdown2Html markdown2Html = new Markdown2Html(new ContentProvider() {
@Override
public String getContent() {
return input;
}
});
String html = markdown2Html.getContent();
System.out.println(html);
}
}