package org.yinwang.pysonar.demos; import org.jetbrains.annotations.NotNull; import org.yinwang.pysonar.FancyProgress; import org.yinwang.pysonar.Indexer; import org.yinwang.pysonar.Util; import java.io.File; import java.util.List; public class Demo { private static File OUTPUT_DIR; private static final String CSS = "body { color: #666666; } \n" + "a {text-decoration: none; color: #5A82F7}\n" + "table, th, td { border: 1px solid lightgrey; padding: 5px; corner: rounded; }\n" + ".builtin {color: #B17E41;}\n" + ".comment, .block-comment {color: #aaaaaa; font-style: italic;}\n" + ".constant {color: #888888;}\n" + ".decorator {color: #778899;}\n" + ".doc-string {color: #aaaaaa;}\n" + ".error {border-bottom: 1px solid red;}\n" + ".field-name {color: #2e8b57;}\n" + ".function {color: #4682b4;}\n" + ".identifier {color: #8b7765;}\n" + ".info {border-bottom: 1px dotted RoyalBlue;}\n" + ".keyword {color: #0000cd;}\n" + ".lineno {color: #aaaaaa;}\n" + ".number {color: #483d8b;}\n" + ".parameter {color: #777777;}\n" + ".string {color: #999999;}\n" + ".type-name {color: #4682b4;}\n" + ".warning {border-bottom: 1px dotted orange;}\n"; private static final String JS = "<script language=\"JavaScript\" type=\"text/javascript\">\n" + "var highlighted = new Array();\n" + "function highlight()\n" + "{\n" + " // clear existing highlights\n" + " for (var i = 0; i < highlighted.length; i++) {\n" + " var elm = document.getElementById(highlighted[i]);\n" + " if (elm != null) {\n" + " elm.style.backgroundColor = 'white';\n" + " }\n" + " }\n" + " highlighted = new Array();\n" + " for (var i = 0; i < arguments.length; i++) {\n" + " var elm = document.getElementById(arguments[i]);\n" + " if (elm != null) {\n" + " elm.style.backgroundColor='gold';\n" + " }\n" + " highlighted.push(arguments[i]);\n" + " }\n" + "} </script>\n"; private Indexer indexer; private String rootPath; private Linker linker; private void makeOutputDir() { if (!OUTPUT_DIR.exists()) { OUTPUT_DIR.mkdirs(); Util.msg("Created directory: " + OUTPUT_DIR.getAbsolutePath()); } } private void start(@NotNull File fileOrDir) throws Exception { File rootDir = fileOrDir.isFile() ? fileOrDir.getParentFile() : fileOrDir; try { rootPath = Util.unifyPath(rootDir); } catch (Exception e) { Util.die("File not found: " + fileOrDir); } indexer = new Indexer(); Util.msg("Loading and analyzing files"); indexer.loadFileRecursive(Util.unifyPath(fileOrDir)); indexer.finish(); generateHtml(); indexer.close(); } private void generateHtml() { Util.msg("\nGenerating HTML"); makeOutputDir(); linker = new Linker(rootPath, OUTPUT_DIR); linker.findLinks(indexer); int rootLength = rootPath.length(); Util.msg("\nGenerating HTML"); int total = 0; for (String path : indexer.getLoadedFiles()) { if (path.startsWith(rootPath)) { total++; } } FancyProgress progress = new FancyProgress(total, 50); for (String path : indexer.getLoadedFiles()) { if (path.startsWith(rootPath)) { progress.tick(); File destFile = Util.joinPath(OUTPUT_DIR, path.substring(rootLength)); destFile.getParentFile().mkdirs(); String destPath = destFile.getAbsolutePath() + ".html"; String html = markup(path); try { Util.writeFile(destPath, html); } catch (Exception e) { Util.msg("Failed to write: " + destPath); } } } Util.msg("\nWrote " + indexer.getLoadedFiles().size() + " files to " + OUTPUT_DIR); } @NotNull private String markup(String path) { String source; try { source = Util.readFile(path); } catch (Exception e) { Util.die("Failed to read file: " + path); return ""; } List<StyleRun> styles = new Styler(indexer, linker).addStyles(path, source); styles.addAll(linker.getStyles(path)); String styledSource = new StyleApplier(path, source, styles).apply(); String outline = new HtmlOutline(indexer).generate(path); StringBuilder sb = new StringBuilder(); sb.append("<html><head title=\"").append(path).append("\">") .append("<style type='text/css'>\n").append(CSS).append("</style>\n") .append(JS) .append("</head>\n<body>\n") .append("<table width=100% border='1px solid gray'><tr><td valign='top'>") .append(outline) .append("</td><td>") .append("<pre>").append(addLineNumbers(styledSource)).append("</pre>") .append("</td></tr></table></body></html>"); return sb.toString(); } @NotNull private String addLineNumbers(@NotNull String source) { StringBuilder result = new StringBuilder((int)(source.length() * 1.2)); int count = 1; for (String line : source.split("\n")) { result.append("<span class='lineno'>"); result.append(count++); result.append("</span> "); result.append(line); result.append("\n"); } return result.toString(); } private static void usage() { Util.msg("Usage: java -jar pysonar-2.0-SNAPSHOT.jar <file-or-dir> <output-dir>"); Util.msg("Example that generates an index for Python 2.7 standard library:"); Util.msg(" java -jar pysonar-2.0-SNAPSHOT.jar /usr/lib/python2.7 ./html"); System.exit(0); } @NotNull private static File checkFile(String path) { File f = new File(path); if (!f.canRead()) { Util.die("Path not found or not readable: " + path); } return f; } public static void main(@NotNull String[] args) throws Exception { if (args.length != 2) { usage(); } File fileOrDir = checkFile(args[0]); OUTPUT_DIR = new File(args[1]); new Demo().start(fileOrDir); Util.msg(Util.printGCStats()); } }