/** * Copyright 2010-2014 Three Crickets LLC. * <p> * The contents of this file are subject to the terms of a BSD license. See * attached license.txt. * <p> * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly from Three Crickets * at http://threecrickets.com/ */ package org.sikuli.syntaxhighlight.contrib; import java.io.IOException; import java.io.Writer; import java.util.List; import java.util.Map; import org.sikuli.syntaxhighlight.ResolutionException; import org.sikuli.syntaxhighlight.Util; import org.sikuli.syntaxhighlight.format.Formatter; import org.sikuli.syntaxhighlight.grammar.Token; import org.sikuli.syntaxhighlight.grammar.TokenType; import org.sikuli.syntaxhighlight.style.ColorStyleElement; import org.sikuli.syntaxhighlight.style.EffectStyleElement; import org.sikuli.syntaxhighlight.style.FontStyleElement; import org.sikuli.syntaxhighlight.style.Style; import org.sikuli.syntaxhighlight.style.StyleElement; /** * @author Tal Liron */ public class HtmlFormatter extends Formatter { // // Construction // public HtmlFormatter() throws ResolutionException { this( Style.getByName( "default" ), false, null, null ); } public HtmlFormatter( Style style, boolean full, String title, String encoding ) { super( style, full, title, encoding ); } // // Formatter // @Override public void format( Iterable<Token> tokenSource, Writer writer ) throws IOException { writer.write( getDocHeader1() ); writer.write( " <title>" ); writer.write( Util.escapeHtml( getTitle() ) ); writer.write( "</title>\n" ); writer.write( getDocHeader2() ); writer.write( getEncoding() ); writer.write( getDocHeader3() ); writer.write( getCssFileTemplate() ); formatStyleSheet( writer ); writer.write( getDocHeader4() ); if( getTitle().length() > 0 ) { writer.write( "<h2>" ); writer.write( Util.escapeHtml( getTitle() ) ); writer.write( "</h2>\n" ); } writer.write( "<div><pre>\n" ); StringBuilder line = new StringBuilder(); int line_no = 1; for( Token token : tokenSource ) { String[] toks = token.getValue().split("\n", -1); for(int i = 0; i < toks.length - 1; i++) { format_partial_token(token, toks[i], line); format_line(line.toString(), writer, line_no++); line = new StringBuilder(); } format_partial_token(token, toks[toks.length-1], line); } if(line.length() > 0) format_line(line.toString(), writer, line_no++); writer.write( "</pre></div>\n" ); writer.write( getDocFooter() ); writer.flush(); } private void format_partial_token(Token token, String part_tok, StringBuilder line) { if( token.getType().getShortName().length() > 0 ) { line.append( "<span class=\"" ); line.append( token.getType().getShortName() ); line.append( "\">" ); line.append( Util.escapeHtml( part_tok ) ); line.append( "</span>" ); } else line.append( Util.escapeHtml( part_tok ) ); } public void format_line(String line, Writer writer, int line_no) throws IOException { writer.write(line); writer.write("\n"); } // ////////////////////////////////////////////////////////////////////////// // Protected protected String getClassPrefix() { return ""; } protected String getCssFileTemplate() { return " td.linenos { background-color: #f0f0f0; padding-right: 10px; }\n" + " span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }\n" + " pre { line-height: 125%; }\n"; } protected String getDocHeader1() { return "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n" + "<html>\n" + "<head>\n"; } protected String getDocHeader2() { return " <meta http-equiv=\"content-type\" content=\"text/html; charset="; } protected String getDocHeader3() { return "\">\n" + " <style type=\"text/css\">\n"; } protected String getDocHeader4() { return " </style>\n" + "</head>\n" + "<body>\n"; } /* * private static final String DOC_HEADER_EXTERNAL_CSS = * "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n" + * " \"http://www.w3.org/TR/html4/strict.dtd\">\n" + "\n" + "<html>\n" + * "<head>\n" + " <title>%(title)s</title>\n" + * " <meta http-equiv=\"content-type\" content=\"text/html; charset=%(encoding)s\">\n" * + " <link rel=\"stylesheet\" href=\"%(cssfile)s\" type=\"text/css\">\n" * + "</head>\n" + "<body>\n" + "<h2>%(title)s</h2>\n"; */ protected String getDocFooter() { return "</body>\n" + "</html>\n"; } // ////////////////////////////////////////////////////////////////////////// // Private private void formatStyleSheet( Writer writer ) throws IOException { for( Map.Entry<TokenType, List<StyleElement>> entry : getStyle().getStyleElements().entrySet() ) { TokenType tokenType = entry.getKey(); List<StyleElement> styleElementsForTokenType = entry.getValue(); writer.write( " ." ); writer.write( getClassPrefix() ); writer.write( tokenType.getShortName() ); writer.write( " { " ); for( StyleElement styleElement : styleElementsForTokenType ) { if( styleElement instanceof ColorStyleElement ) { ColorStyleElement colorStyleElement = (ColorStyleElement) styleElement; if( colorStyleElement.getType() == ColorStyleElement.Type.Foreground ) writer.write( "color: " ); else if( colorStyleElement.getType() == ColorStyleElement.Type.Background ) writer.write( "background-color: " ); else if( colorStyleElement.getType() == ColorStyleElement.Type.Border ) writer.write( "border: 1px solid " ); writer.write( colorStyleElement.getColor() ); writer.write( "; " ); } else if( styleElement instanceof EffectStyleElement ) { if( styleElement == EffectStyleElement.Bold ) writer.write( "font-weight: bold; " ); else if( styleElement == EffectStyleElement.Italic ) writer.write( "font-style: italic; " ); else if( styleElement == EffectStyleElement.Underline ) writer.write( "text-decoration: underline; " ); } else if( styleElement instanceof FontStyleElement ) { // We don't want to set fonts in this formatter } } writer.write( "} /* " ); writer.write( tokenType.getName() ); writer.write( " */\n" ); } } }