From 832c68a5c596c24e85e0e340735bdaa51413b569 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Mon, 30 Jan 2012 13:39:54 -0600 Subject: [PATCH] v1.7: added `--no-source` option, foxpro, SQL support. * Added `--no-source` option. By default JLP copies the original source code into the output directory. THis option disables that behavior. * Added basic error handling after parsing input files: input files that do not parse correctly are ignored. Beforehand they were causing null pointer exceptions in the second parse phase of the processor. * Made the top-level support directories hidden in the output root (ie. `/.css` instead of `/css`. * Added configuration to handle Visual FoxPro files (no syntax highlighter available) and SQL files. * Expanded the list of binary file types. Binary and unknown file types are not parsed. --- project.properties | 6 +- src/main/com/jdblabs/jlp/JLPMain.groovy | 14 +++- src/main/com/jdblabs/jlp/JLPPegParser.java | 13 ++++ .../jlp/LiterateMarkdownGenerator.groovy | 10 +-- src/main/com/jdblabs/jlp/Processor.groovy | 77 +++++++++++++++---- 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/project.properties b/project.properties index f9970fe..0b4c5cd 100644 --- a/project.properties +++ b/project.properties @@ -1,7 +1,7 @@ -#Tue, 10 Jan 2012 10:00:20 -0600 +#Fri, 27 Jan 2012 18:21:58 -0600 name=jlp -version=1.6 -build.number=5 +version=1.7 +build.number=24 lib.local=true release.dir=release main.class=com.jdblabs.jlp.JLPMain diff --git a/src/main/com/jdblabs/jlp/JLPMain.groovy b/src/main/com/jdblabs/jlp/JLPMain.groovy index 90e5a61..9cbe756 100644 --- a/src/main/com/jdblabs/jlp/JLPMain.groovy +++ b/src/main/com/jdblabs/jlp/JLPMain.groovy @@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory */ public class JLPMain { - public static final String VERSION = "1.6" + public static final String VERSION = "1.7" private static Logger log = LoggerFactory.getLogger(JLPMain.class) @@ -60,6 +60,12 @@ public class JLPMain { /// : Display JLP versioning information. cli._(longOpt: 'version', 'Display the JLP version information.') + /// --no-source + /// : Do not copy the source files into the output directory alongside + /// the documentation. + cli._(longOpt: 'no-source', 'Do not copy the source files into the' + + ' output directory alongside the documentation.') + /// #### Parse the options. def opts = cli.parse(args) @@ -121,6 +127,9 @@ public class JLPMain { "${cssFile.canonicalPath}'." println " Using the default CSS." }} + /// Look for our `--no-source` option. + def includeSource = !opts."no-source" + /// #### Create the input file list. /// We will start with the filenames passed as arguments on the command @@ -151,7 +160,8 @@ public class JLPMain { else { inputFiles << file } } /// #### Process the files. - Processor.process(outputDir, css, inputFiles) + log.trace("Starting JLP processor.") + Processor.process(outputDir, css, inputFiles, includeSource) } } diff --git a/src/main/com/jdblabs/jlp/JLPPegParser.java b/src/main/com/jdblabs/jlp/JLPPegParser.java index 86292a1..75971e3 100644 --- a/src/main/com/jdblabs/jlp/JLPPegParser.java +++ b/src/main/com/jdblabs/jlp/JLPPegParser.java @@ -65,6 +65,19 @@ public class JLPPegParser extends BaseParser implements JLPParser { MDOC_END = NOTHING; SDOC_START = String(sdocStart).label("SDOC_START"); } + /** + * #### Single-line comments only constructor. + * This is the same as the previous constructor except it allows the caller + * to define several different syntax for single-line comments. This is + * useful for languages that support several different syntaxes for comment + * lines (e.g. bash, Visual FoxPro). + */ + public JLPPegParser(List sdocStarts) { + MDOC_START = NOTHING; + MDOC_LINE_START = NOTHING; + MDOC_END = NOTHING; + SDOC_START = FirstOf(sdocStarts.toArray()).label("SDOC_START"); } + /** * #### Default constructor. * The default constructor creates a JLPPegParser configured to recognize diff --git a/src/main/com/jdblabs/jlp/LiterateMarkdownGenerator.groovy b/src/main/com/jdblabs/jlp/LiterateMarkdownGenerator.groovy index 9677a22..d110a0a 100644 --- a/src/main/com/jdblabs/jlp/LiterateMarkdownGenerator.groovy +++ b/src/main/com/jdblabs/jlp/LiterateMarkdownGenerator.groovy @@ -142,15 +142,15 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator { ${escape(processor.currentDocId)} + href="${resolveLink('/.css/jlp.css')}"> + href="${resolveLink('/.sh/styles/shCoreDefault.css')}"> + src="${resolveLink('/.sh/scripts/XRegExp.js')}"> """) + src="${resolveLink('/.sh/scripts/shCore.js')}">""") /// If there is a language-specific brush, include it def shBrush = processor.shBrushForSourceType( @@ -159,7 +159,7 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator { if (shBrush) { sb.append(""" """) } + src="${resolveLink('/.sh/scripts/' + shBrush + '.js')}">""") } /// Finish our header and begin the body. sb.append(""" diff --git a/src/main/com/jdblabs/jlp/Processor.groovy b/src/main/com/jdblabs/jlp/Processor.groovy index 40e0e6b..855ff8c 100644 --- a/src/main/com/jdblabs/jlp/Processor.groovy +++ b/src/main/com/jdblabs/jlp/Processor.groovy @@ -46,6 +46,10 @@ public class Processor { /// A shortcut for `docs[currentDocId]` public TargetDoc currentDoc + /// Setting to control whether the source code is copied into the final + /// documentation directory or not. + public boolean includeSource + /// ### Non-public State /// @org jlp.jdb-labs.com/Processor/non-public-state @@ -67,7 +71,7 @@ public class Processor { * to the directory named in `outputDir`, using the CSS given in `css` */ public static void process(File outputDir, def css, - List inputFiles) { + List inputFiles, boolean includeSource) { /// Find the closest common parent folder to all of the files given. /// This will be our input root for the parsing process. @@ -78,7 +82,8 @@ public class Processor { Processor inst = new Processor( inputRoot: inputDir, outputRoot: outputDir, - css: css) + css: css, + includeSource: includeSource) /// Run the process. inst.process(inputFiles) } @@ -96,17 +101,24 @@ public class Processor { /// constructor. /// * Write the CSS file to our output directory. - File cssFile = new File(outputRoot, "css/jlp.css") + File cssFile = new File(outputRoot, ".css/jlp.css") cssFile.parentFile.mkdirs() cssFile.text = css.text /// * Extract the syntax highlighter files to the output directory. File shFile = new File(outputRoot, "temp.jar") + File shDir = new File(outputRoot, "sh") + File metaDir = new File(outputRoot, "META-INF") getClass().getResourceAsStream("/syntax-highlighter.jar").withStream { is -> shFile.withOutputStream { os -> while (is.available()) { os.write(is.read()) }}} JarUtils.extract(shFile, outputRoot) + shDir.renameTo(new File(outputRoot, '.sh')) + + /// * Delete our temporary jar file and the META-INF directory extracted + /// from it. shFile.delete() + metaDir.deleteDir() /// * Create the processing context for each input file. We are using /// the name of the file (including the extension) as the id. If there @@ -118,6 +130,12 @@ public class Processor { def relPath = getRelativeFilepath(inputRoot, file) def pathParts = relPath.split('/') as List + // Get our file type. + def fileType = sourceTypeForFile(file) + + // We will skip binary files and files we know nothing about. + if (fileType == 'binary' || fileType == 'unknown') { return; } + // Start with just the file name. def docId = pathParts.pop() @@ -137,11 +155,20 @@ public class Processor { /// * Run the parse phase on each of the files. For each file, we load /// the parser for that file type and parse the file into an abstract /// syntax tree (AST). + def badDocs = [] processDocs { log.trace("Parsing '{}'.", currentDocId) def parser = getParser(currentDoc.sourceType) - // TODO: error detection - currentDoc.sourceAST = parser.parse(currentDoc.sourceFile.text) } + + // TODO: better error detection and handling + currentDoc.sourceAST = parser.parse(currentDoc.sourceFile.text) + + if (currentDoc.sourceAST == null) { + log.warn("Unable to parse '{}'. Ignoring this document.", currentDocId) + badDocs << currentDocId }} + + /// * Remove all the documents we could not parse from our doc list. + docs = docs.findAll { docId, doc -> !badDocs.contains(docId) } /// * Run our generator parse phase (see /// [`JLPBaseGenerator`](jlp://com.jdb-labs.jlp.JLPBaseGenerator/phases) @@ -176,9 +203,9 @@ public class Processor { if (!outputDir.exists()) { outputDir.mkdirs() } /// Copy the source file over. - // TODO: make this behavior customizable. - (new File(outputRoot, relativePath)).withWriter { - it.print currentDoc.sourceFile.text } + if (includeSource) { + (new File(outputRoot, relativePath)).withWriter { + it.print currentDoc.sourceFile.text }} /// Write the output to the file. outputFile.withWriter { it.println currentDoc.output } } } @@ -338,15 +365,22 @@ public class Processor { /// Lookup the file type by extension switch (extension) { - case 'c': case 'h': return 'c'; - case 'c++': case 'h++': case 'cpp': case 'hpp': return 'cpp'; - case 'erl': case 'hrl': return 'erlang'; - case 'groovy': return 'groovy'; - case 'java': return 'java'; - case 'js': return 'javascript'; - case 'md': return 'markdown'; - case 'html': return 'html'; - case 'xml': case 'xhtml': return 'xml'; + case 'c': case 'h': return 'c' + case 'c++': case 'h++': case 'cpp': case 'hpp': return 'cpp' + case 'erl': case 'hrl': return 'erlang' + case 'groovy': return 'groovy' + case 'java': return 'java' + case 'js': return 'javascript' + case 'md': return 'markdown' + case 'html': return 'html' + case 'xml': case 'xhtml': return 'xml' + case 'prg': return 'foxpro' + case 'sql': return 'sql' + + // binary file types + case 'bin': case 'com': case 'exe': case 'o': + case 'bz2': case 'tar': case 'tgz': case 'zip': case 'jar': + return 'binary' default: return 'unknown'; }} /** @@ -362,6 +396,7 @@ public class Processor { case 'java': return 'shBrushJava' case 'javascript': return 'shBrushJScript' case 'html': case 'xml': return 'shBrushXml' + case 'sql': return 'shBrushSql' default: return null }} /** @@ -396,6 +431,10 @@ public class Processor { parsers[sourceType] = Parboiled.createParser( JLPPegParser, '%%') break + case 'foxpro': + parsers[sourceType] = Parboiled.createParser( + JLPPegParser, ['**', '&&&']) + break case 'markdown': parsers[sourceType] = new MarkdownParser() break @@ -404,6 +443,10 @@ public class Processor { JLPPegParser, '', '#$%^&*()_-+=|;:\'",<>?~`', '<?~`', '---') + break case 'c': case 'cpp': case 'groovy':