/*
* Copyright 2013 eXo Platform SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package juzu.impl.common;
import juzu.impl.compiler.CompilationError;
import juzu.io.UndeclaredIOException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Various utilities for formatting stuff.
*
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
*/
public class Formatting {
/**
* Append a script section that will add a <code>stylesheet</code> element in the head section of
* the document.
*
* @param buffer the buffer
*/
public static void renderStyleSheet(StringBuilder buffer) {
try {
renderStyleSheet((Appendable)buffer);
}
catch (IOException e) {
throw new UndeclaredIOException(e);
}
}
/**
* Append a script section that will add a <code>stylesheet</code> element in the head section of
* the document.
*
* @param appendable the appendable
* @throws IOException any io exception
*/
public static void renderStyleSheet(Appendable appendable) throws IOException {
URL cssURL = Formatting.class.getResource("juzu.css");
String css = Tools.read(cssURL);
css = css.replace("\"", "\\\"");
css = css.replace("'", "\\'");
css = css.replace("\n", "\\n");
appendable.append("<script type='text/javascript'>\n");
appendable.append("var styleElement = document.createElement('style');\n");
appendable.append("var css = '");
appendable.append(css);
appendable.append("';\n");
appendable.append("styleElement.type = 'text/css';\n");
appendable.append("if (styleElement.styleSheet) {;\n");
appendable.append("styleElement.styleSheet.cssText = css;\n");
appendable.append("} else {\n");
appendable.append("styleElement.appendChild(document.createTextNode(css));\n");
appendable.append("}\n");
appendable.append("document.getElementsByTagName(\"head\")[0].appendChild(styleElement);\n");
appendable.append("</script>\n");
}
/**
* Renders the throwable in the specified writer.
*
* @param buffer the writer
* @param t the throwable
*/
public static void renderThrowable(Class<?> stop, StringBuilder buffer, Throwable t) {
try {
renderThrowable(stop, (Appendable)buffer, t);
}
catch (IOException e) {
throw new UndeclaredIOException(e);
}
}
/**
* Renders the throwable in the specified writer.
*
* @param appendable the writer
* @param t the throwable
* @throws IOException any io exception
*/
public static void renderThrowable(Class<?> stop, Appendable appendable, Throwable t) throws IOException {
// Trim the stack trace to remove stuff we don't want to see
int size = 0;
StackTraceElement[] trace = t.getStackTrace();
for (StackTraceElement element : trace) {
if (stop != null && element.getClassName().equals(stop.getName())) {
break;
}
else {
size++;
}
}
StackTraceElement[] ourTrace = new StackTraceElement[size];
System.arraycopy(trace, 0, ourTrace, 0, ourTrace.length);
t.setStackTrace(ourTrace);
// We hack a bit
final AtomicBoolean open = new AtomicBoolean(false);
PrintWriter formatter = new PrintWriter(new AppendableWriter(appendable)) {
@Override
public void println(Object x) {
if (open.get()) {
super.append("</ul></div>");
}
super.append("<p>");
super.append(String.valueOf(x));
super.append("</p>");
open.set(false);
}
@Override
public void println(String x) {
if (!open.get()) {
super.append("<div class=\"code\"><ul>");
open.set(true);
}
super.append("<li><p>");
super.append(x);
super.append("</p></li>");
}
@Override
public void println() {
// Do nothing
}
};
//
appendable.append("<section>");
// We hack a bit with our formatter
t.printStackTrace(formatter);
//
if (open.get()) {
appendable.append("</ul></div>");
}
//
appendable.append("</section>");
}
/**
* Renders an iterable of {@link CompilationError} in the specified buffer.
*
* @param buffer the buffer
* @param errors the errors
*/
public static void renderErrors(StringBuilder buffer, Iterable<CompilationError> errors) {
try {
renderErrors((Appendable)buffer, errors);
}
catch (IOException e) {
throw new UndeclaredIOException(e);
}
}
/**
* Renders an iterable of {@link CompilationError} in the specified appendable.
*
* @param appendable the appendable
* @param errors the errors
* @throws IOException any io exception
*/
public static void renderErrors(Appendable appendable, Iterable<CompilationError> errors) throws IOException {
renderStyleSheet(appendable);
//
for (CompilationError error : errors) {
appendable.append("<section>");
appendable.append("<p>").append(error.getMessage()).append("</p>");
// Display the source code
File source = error.getSourceFile();
if (source != null) {
int line = error.getLocation().getLine();
int from = line - 2;
int to = line + 3;
BufferedReader reader = new BufferedReader(new FileReader(source));
int count = 1;
appendable.append("<div class=\"code\"><ol start=\"").append(String.valueOf(from)).append("\">");
for (String s = reader.readLine();s != null;s = reader.readLine()) {
if (count >= from && count < to) {
if (count == line) {
appendable.append("<li><p class=\"error\">").append(s).append("</p></li>");
}
else {
appendable.append("<li><p>").append(s).append("</p></li>");
}
}
count++;
}
appendable.append("</ol></div>");
}
appendable.append("</section>");
}
}
}