# HG changeset patch # User Jari-Matti M?kel? # Date 1193751690 -7200 # Node ID 33a4cb255fccecd39a18bc3f87bbf478b6489bff # Parent de2675bc9afad9d6e15d42a80124abfbb8c5b22d Cached images, small fixes, reorganizing. diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/config/configurator.d --- a/trunk/src/docgen/config/configurator.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/config/configurator.d Tue Oct 30 15:41:30 2007 +0200 @@ -1,3 +1,7 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ module docgen.config.configurator; import docgen.config.reader; @@ -5,10 +9,20 @@ import Integer = tango.text.convert.Integer; import tango.io.stream.FileStream; +import tango.io.Stdout; +/** + * Class for handling and merging doc generator options. + */ interface Configurator { + /** + * Merges configuration options from the given file. + */ void mergeConfiguration(char[] cfgFile); + /** + * Returns a hierarchical structure of configuration options. + */ DocGeneratorOptions *getConfiguration(); } @@ -56,19 +70,23 @@ const char[] _parseEnum = `case "` ~ key ~ `":` ~ _wrong(key) ~ `switch(val[0]) {` ~ _parseEnum_!(false, key, V) ~ - `default: err(); }`; + `default: err(); } continue;`; } template _parseEnumList(char[] key, V...) { const char[] _parseEnumList = `case "` ~ key ~ - `":` ~ _wrong(key) ~ `switch(val[0]) {` ~ + `":` ~ `foreach (item; val) switch(item) {` ~ _parseEnum_!(true, key, V) ~ - `default: err(); }`; + `default: err(); } continue;`; } class DefaultConfigurator : Configurator { + private: + DocGeneratorOptions options; + public: + const defaultProfileLocation = "docgen/config/default.cfg"; this() { @@ -129,7 +147,7 @@ _parseEnum!("options.parser.commentFormat", "Doxygen", "CommentFormat.Doxygen", "Ddoc", "CommentFormat.Ddoc" - ) ~ + ) ~ _parseEnumList!("options.outputFormats", "LaTeX", "DocFormat.LaTeX", "HTML", "DocFormat.HTML", diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/config/default.cfg --- a/trunk/src/docgen/config/default.cfg Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/config/default.cfg Tue Oct 30 15:41:30 2007 +0200 @@ -30,6 +30,6 @@ (strRegexps) (commentFormat Doxygen) ) - (outputFormats LaTeX) + (outputFormats LaTeX LaTeX) (outputDir tmp/) ) diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/config/reader.d --- a/trunk/src/docgen/config/reader.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/config/reader.d Tue Oct 30 15:41:30 2007 +0200 @@ -1,7 +1,14 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ module docgen.config.reader; debug import tango.io.Stdout; +/** + * Lexes a s-exp like input + */ char[][] lex(char[] input) { char[][] tokens; @@ -91,6 +98,9 @@ return tokens; } +/** + * Parser a s-exp like input used by the config files. + */ char[][][char[]] parse(char[][] tokens) { char[][][char[]] values; size_t i = 1; diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/docgen.d --- a/trunk/src/docgen/docgen.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/docgen.d Tue Oct 30 15:41:30 2007 +0200 @@ -4,8 +4,10 @@ */ module docgen.docgen; +import docgen.document.generator; + import docgen.sourcelisting.writers; -import docgen.document.writers; +import docgen.page.writers; import docgen.graphutils.writers; import docgen.misc.misc; import docgen.misc.parser; @@ -18,79 +20,6 @@ import tango.io.Stdout; -template DefaultDocGenerator(char[] genDir) { - abstract class DefaultDocGenerator : DocGenerator { - DocGeneratorOptions m_options; - DocumentWriter docWriter; - GraphWriterFactory graphFactory; - - Module[] modules; - Edge[] edges; - Vertex[char[]] vertices; - - this(DocGeneratorOptions options) { - m_options = options; - graphFactory = new DefaultGraphWriterFactory(this); - - // create output dir - (new FilePath(options.outputDir ~ "/" ~ genDir)).create(); - } - - // TODO: constructor for situations where parsing has happened elsewhere - - protected char[] outPath(char[] file) { - return options.outputDir ~ "/" ~ genDir ~ "/" ~ file; - } - - void parseSources() { - int id = 1; - - Parser.loadModules( - options.parser.rootPaths, - options.parser.importPaths, - options.parser.strRegexps, - options.graph.includeUnlocatableModules, - options.graph.depth, - (char[] fqn, char[] path, Module m) { - if (m is null) { - if (fqn in vertices) { - debug Stdout.format("{} already set.\n", fqn); - return; - - } - auto vertex = new Vertex(fqn, path, id++); - vertex.type = VertexType.UnlocatableModule; - vertices[fqn] = vertex; - debug Stdout.format("Setting {} = {}.\n", fqn, path); - - } else { - vertices[m.moduleFQN] = new Vertex(m.moduleFQN, m.filePath, id++); - debug Stdout.format("Setting {} = {}.\n", m.moduleFQN, m.filePath); - } - }, - (Module imported, Module importer) { - debug Stdout.format("Connecting {} - {}.\n", imported.moduleFQN, importer.moduleFQN); - edges ~= vertices[imported.moduleFQN].addChild(vertices[importer.moduleFQN]); - }, - modules - ); - } - - void createDepGraph(char[] depGraphFile) { - auto imgFile = new FileOutput(outPath(depGraphFile)); - - auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot ); - - writer.generateDepGraph(vertices.values, edges, imgFile); - - imgFile.close(); - } - - public DocGeneratorOptions *options() { - return &m_options; - } -} -} class HTMLDocGenerator : DefaultDocGenerator!("html") { this(DocGeneratorOptions options) { @@ -114,7 +43,7 @@ /** * Main routine for LaTeX doc generation. */ -class LaTeXDocGenerator : DefaultDocGenerator!("latex") { +class LaTeXDocGenerator : DefaultCachingDocGenerator!("latex") { this(DocGeneratorOptions options) { super(options); } @@ -123,10 +52,8 @@ * Generates document skeleton. */ void generateDoc(char[] docFileName) { - auto ddf = new DefaultDocumentWriterFactory(this); - auto docFile = new FileOutput(outPath(docFileName)); - docWriter = ddf.createDocumentWriter( [ docFile ], DocFormat.LaTeX ); + docWriter = pageFactory.createPageWriter( [ docFile ], DocFormat.LaTeX ); docWriter.generateFirstPage(); docWriter.generateTOC(modules); @@ -180,9 +107,6 @@ docWriter.setOutput([docFile]); auto writer = dlwf.createListingWriter(docWriter, DocFormat.LaTeX); - /*modules.sort( - (Module a, Module b){ return icompare(a.moduleFQN, b.moduleFQN); } - );*/ foreach(mod; modules) { auto dstFname = replace(mod.moduleFQN.dup, '.', '_') ~ ".d"; @@ -256,31 +180,29 @@ options.outputDir = args[$-1]; foreach(format; options.outputFormats) { + DocGenerator generator; + switch(format) { case DocFormat.LaTeX: - auto generator = new LaTeXDocGenerator(*options); + generator = new LaTeXDocGenerator(*options); Stdout("Generating LaTeX docs.."); - generator.generate(); - Stdout("done.").newline; break; case DocFormat.HTML: - auto generator = new HTMLDocGenerator(*options); + generator = new HTMLDocGenerator(*options); Stdout("Generating HTML docs.."); - generator.generate(); - Stdout("done.").newline; break; case DocFormat.XML: - auto generator = new XMLDocGenerator(*options); + generator = new XMLDocGenerator(*options); Stdout("Generating XML docs.."); - generator.generate(); - Stdout("done.").newline; break; case DocFormat.PlainText: - auto generator = new PlainTextDocGenerator(*options); + generator = new PlainTextDocGenerator(*options); Stdout("Generating plain text docs.."); - generator.generate(); - Stdout("done.").newline; break; + default: throw new Exception("Format not supported"); } + + generator.generate(); + Stdout("done.").newline; } } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/document/generator.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/document/generator.d Tue Oct 30 15:41:30 2007 +0200 @@ -0,0 +1,131 @@ +module docgen.document.generator; + +import docgen.sourcelisting.writers; +import docgen.page.writers; +import docgen.graphutils.writers; +import docgen.misc.misc; +import docgen.misc.parser; +import docgen.config.configurator; +import tango.core.Array; +import tango.io.stream.FileStream; +import tango.text.Ascii; +import tango.text.Util : replace; +import tango.io.FilePath; +debug import tango.io.Stdout; + +template DefaultDocGenerator(char[] genDir) { + abstract class DefaultDocGenerator : DocGenerator { + DocGeneratorOptions m_options; + PageWriter docWriter; + + GraphWriterFactory graphFactory; + PageWriterFactory pageFactory; + + Module[] modules; + Edge[] edges; + Vertex[char[]] vertices; + + this(DocGeneratorOptions options) { + m_options = options; + + createGraphWriterFactory(); + createPageWriterFactory(); + + // create output dir + (new FilePath(options.outputDir ~ "/" ~ genDir)).create(); + } + + // TODO: constructor for situations where parsing has happened elsewhere + + protected void createGraphWriterFactory() { + graphFactory = new DefaultGraphWriterFactory(this); + } + + protected void createPageWriterFactory() { + pageFactory = new DefaultPageWriterFactory(this); + } + + protected char[] outPath(char[] file) { + return options.outputDir ~ "/" ~ genDir ~ "/" ~ file; + } + + protected void parseSources() { + int id = 1; + + Parser.loadModules( + options.parser.rootPaths, + options.parser.importPaths, + options.parser.strRegexps, + options.graph.includeUnlocatableModules, + options.graph.depth, + (char[] fqn, char[] path, Module m) { + if (m is null) { + if (fqn in vertices) { + debug Stdout.format("{} already set.\n", fqn); + return; + + } + auto vertex = new Vertex(fqn, path, id++); + vertex.type = VertexType.UnlocatableModule; + vertices[fqn] = vertex; + debug Stdout.format("Setting {} = {}.\n", fqn, path); + + } else { + vertices[m.moduleFQN] = new Vertex(m.moduleFQN, m.filePath, id++); + debug Stdout.format("Setting {} = {}.\n", m.moduleFQN, m.filePath); + } + }, + (Module imported, Module importer) { + debug Stdout.format("Connecting {} - {}.\n", imported.moduleFQN, importer.moduleFQN); + edges ~= vertices[imported.moduleFQN].addChild(vertices[importer.moduleFQN]); + }, + modules + ); + + modules.sort( + (Module a, Module b){ return icompare(a.moduleFQN, b.moduleFQN); } + ); + } + + void createDepGraph(char[] depGraphFile) { + auto imgFile = new FileOutput(outPath(depGraphFile)); + + auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot ); + + writer.generateDepGraph(vertices.values, edges, imgFile); + + imgFile.close(); + } + + public DocGeneratorOptions *options() { + return &m_options; + } + } +} + +template DefaultCachingDocGenerator(char[] genDir) { + abstract class DefaultCachingDocGenerator : DefaultDocGenerator!(genDir), CachingDocGenerator { + this(DocGeneratorOptions options) { + super(options); + } + + private char[][Object[]][Object[]][GraphFormat] m_graphCache; + + char[] getCachedGraph(Object[] vertices, Object[] edges, GraphFormat format) { + auto lookup1 = format in m_graphCache; + if (lookup1) { + auto lookup2 = edges in *lookup1; + if (lookup2) { + auto lookup3 = vertices in *lookup2; + if (lookup3) + return *lookup3; + } + } + return null; + } + + protected void createGraphWriterFactory() { + graphFactory = new DefaultCachingGraphWriterFactory(this); + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/graphutils/dotwriter.d --- a/trunk/src/docgen/graphutils/dotwriter.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/graphutils/dotwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -9,16 +9,17 @@ import tango.text.convert.Layout : Layout; import tango.io.FilePath; import tango.text.Util; +debug import tango.io.Stdout; /** * Creates a graph rule file for the dot utility. */ class DotWriter : AbstractGraphWriter { - this(GraphWriterFactory factory, DocumentWriter writer) { + this(GraphWriterFactory factory, PageWriter writer) { super(factory, writer); } - void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) { + void generateDepImageFile(Vertex[] vertices, Edge[] edges, OutputStream imageFile) { auto image = new Print!(char)(new Layout!(char), imageFile); Vertex[][char[]] verticesByPckgName; @@ -38,14 +39,6 @@ factory.options.graph.highlightCyclicEdges) findCycles(vertices, edges); - // name of the .dot file - char[] fn = (cast(Object)imageFile.conduit).toUtf8(); - fn = FilePath(fn).file; - - fn = fn[0..$-3] ~ imageFormatExts[factory.options.graph.imageFormat]; - - writer.addGraphics(fn); - image("Digraph ModuleDependencies {\n"); foreach (module_; vertices) { @@ -113,4 +106,44 @@ image("}"); } + + void generateImageTag(OutputStream imageFile) { + // name of the .dot file + char[] fn = (cast(Object)imageFile.conduit).toUtf8(); + fn = FilePath(fn).file; + + fn = fn[0..$-3] ~ imageFormatExts[factory.options.graph.imageFormat]; + + writer.addGraphics(fn); + } + + protected void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) { + generateImageTag(imageFile); + generateDepImageFile(vertices, edges, imageFile); + } } + +class CachingDotWriter : DotWriter { + CachingGraphWriterFactory factory; + + this(CachingGraphWriterFactory factory, PageWriter writer) { + super(factory, writer); + } + + protected void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) { + generateImageTag(imageFile); + + auto cached = factory.getCachedGraph(vertices, edges, GraphFormat.Dot); + + if (cached) { + auto image = new Print!(char)(new Layout!(char), imageFile); + + if (cached) { + debug Stdout("Image cache hit.\n"); + image(cached); + } else + generateDepImageFile(vertices, edges, imageFile); + } + } +} + diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/graphutils/modulenamewriter.d --- a/trunk/src/docgen/graphutils/modulenamewriter.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/graphutils/modulenamewriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -9,7 +9,7 @@ import tango.text.convert.Layout : Layout; class ModuleNameWriter : AbstractGraphWriter { - this(GraphWriterFactory factory, DocumentWriter writer) { + this(GraphWriterFactory factory, PageWriter writer) { super(factory, writer); } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/graphutils/modulepathwriter.d --- a/trunk/src/docgen/graphutils/modulepathwriter.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/graphutils/modulepathwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -9,7 +9,7 @@ import tango.text.convert.Layout : Layout; class ModulePathWriter : AbstractGraphWriter { - this(GraphWriterFactory factory, DocumentWriter writer) { + this(GraphWriterFactory factory, PageWriter writer) { super(factory, writer); } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/graphutils/writer.d --- a/trunk/src/docgen/graphutils/writer.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/graphutils/writer.d Tue Oct 30 15:41:30 2007 +0200 @@ -6,20 +6,28 @@ public import docgen.misc.misc; public import docgen.graphutils.primitives; -public import docgen.document.writer; +public import docgen.page.writer; debug import tango.io.Stdout; interface GraphWriter { void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile); } +interface GraphWriterFactory : WriterFactory { + GraphWriter createGraphWriter(PageWriter writer, GraphFormat outputFormat); +} + +interface CachingGraphWriterFactory : GraphWriterFactory { + char[] getCachedGraph(Vertex[] vertices, Edge[] edges, GraphFormat format); +} + /** * Marks all cycles in the graph. * * May have bugs, but is a bit simpler than the previous version. */ void findCycles(Vertex[] vertices, Edge[] edges) { - debug void p() { + void p() { foreach(e; edges) Stderr(e.type)(" "c); Stderr.newline; } @@ -27,20 +35,20 @@ bool visit(Edge edge) { if (edge.type == EdgeType.Reserved) { edge.type = EdgeType.CyclicDependency; - debug p(); + version(VerboseDebug) p(); return true; } bool wasCyclic = edge.isCyclic(); edge.type = EdgeType.Reserved; - debug p(); + version(VerboseDebug) p(); foreach(edge2; edge.incoming.outgoingEdges) if (visit(edge2)) { if (edge.isCyclic()) { edge.type = EdgeType.Reserved; wasCyclic = true; - debug p(); + version(VerboseDebug) p(); continue; } edge.type = EdgeType.CyclicDependency; @@ -48,7 +56,7 @@ } edge.type = wasCyclic ? EdgeType.CyclicDependency : EdgeType.Dependency; - debug p(); + version(VerboseDebug) p(); return false; } @@ -60,14 +68,10 @@ } } -interface GraphWriterFactory : WriterFactory { - GraphWriter createGraphWriter(DocumentWriter writer, GraphFormat outputFormat); -} - abstract class AbstractGraphWriter : AbstractWriter!(GraphWriterFactory), GraphWriter { - DocumentWriter writer; + PageWriter writer; - this(GraphWriterFactory factory, DocumentWriter writer) { + this(GraphWriterFactory factory, PageWriter writer) { super(factory); this.writer = writer; } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/graphutils/writers.d --- a/trunk/src/docgen/graphutils/writers.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/graphutils/writers.d Tue Oct 30 15:41:30 2007 +0200 @@ -14,7 +14,7 @@ super(generator); } - GraphWriter createGraphWriter(DocumentWriter writer, GraphFormat outputFormat) { + GraphWriter createGraphWriter(PageWriter writer, GraphFormat outputFormat) { switch (outputFormat) { case GraphFormat.Dot: return new DotWriter(this, writer); @@ -27,3 +27,28 @@ } } } + +class DefaultCachingGraphWriterFactory : AbstractWriterFactory, GraphWriterFactory { + CachingDocGenerator generator; + + this(CachingDocGenerator generator) { + super(generator); + } + + char[] getCachedGraph(Vertex[] vertices, Edge[] edges, GraphFormat format) { + return generator.getCachedGraph(vertices, edges, format); + } + + GraphWriter createGraphWriter(PageWriter writer, GraphFormat outputFormat) { + switch (outputFormat) { + case GraphFormat.Dot: + return new DotWriter(this, writer); + case GraphFormat.ModuleNames: + return new ModuleNameWriter(this, writer); + case GraphFormat.ModulePaths: + return new ModulePathWriter(this, writer); + default: + throw new Exception("Graph writer type does not exist!"); + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/misc/misc.d --- a/trunk/src/docgen/misc/misc.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/misc/misc.d Tue Oct 30 15:41:30 2007 +0200 @@ -122,6 +122,10 @@ void generate(); } +interface CachingDocGenerator : DocGenerator { + char[] getCachedGraph(Object[] vertices, Object[] edges, GraphFormat format); +} + interface WriterFactory { DocGeneratorOptions *options(); } @@ -138,6 +142,7 @@ } } + template AbstractWriter(T, int n = 0) { abstract class AbstractWriter { protected T factory; diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/page/htmlwriter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/page/htmlwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -0,0 +1,64 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.page.htmlwriter; + +import docgen.page.writer; +import docgen.misc.textutils; +import tango.io.FileConduit : FileConduit; + +// TODO: this is mostly broken now + +/** + * Writes a HTML document skeleton. + */ +class HTMLWriter : AbstractPageWriter!(2, "html") { + this(PageWriterFactory factory, OutputStream[] outputs) { + super(factory, outputs); + } + + void generateTOC(Module[] modules) { + // TODO + print.format(templates["toc"]); + } + + void generateModuleSection() { + // TODO + print.format(templates["modules"]); + } + + void generateListingSection() { + // TODO + print.format(templates["listings"]); + } + + void generateDepGraphSection() { + // TODO + print.format(templates["dependencies"]); + } + + void generateIndexSection() { } + + void generateLastPage() { } + + void generateFirstPage() { + print.format( + templates["firstpage"], + factory.options.templates.title, + factory.options.templates.copyright, + factory.options.templates.versionString, + docgen_version + ); + } + + void addList(char[][] contents, bool ordered) { + foreach(item; contents) { + switch(item) { + case "(": print(ordered ? "
    " : "
" : ""); continue; + default: print("
  • ")(xml_escape(item))("
  • "); + } + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/page/latexwriter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/page/latexwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -0,0 +1,39 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.page.latexwriter; + +import docgen.page.writer; +import tango.io.FileConduit : FileConduit; + +/** + * Writes a LaTeX document skeleton. + */ +class LaTeXWriter : AbstractPageWriter!(1, "latex") { + this(PageWriterFactory factory, OutputStream[] outputs) { + super(factory, outputs); + } + + void generateFirstPage() { + print.format( + templates["firstpage"], + factory.options.templates.paperSize, + factory.options.templates.title, + factory.options.templates.versionString, + docgen_version, + timeNow(), + factory.options.listing.literateStyle ? "" : "%" + ); + } + + void addList(char[][] contents, bool ordered) { + foreach(item; contents) { + switch(item) { + case "(": print(ordered ? "\\begin{enumerate}" : "\\begin{itemize}"); continue; + case ")": print(ordered ? "\\end{enumerate}" : "\\end{itemize}"); continue; + default: print("\\item")(item)(\n); + } + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/page/plaintextwriter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/page/plaintextwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -0,0 +1,76 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.page.plaintextwriter; + +import docgen.page.writer; +import docgen.misc.textutils; +import tango.io.FileConduit : FileConduit; + +//TODO: this is mostly broken now + +/** + * Writes a plain text document skeleton. + */ +class PlainTextWriter : AbstractPageWriter!(1, "plaintext") { + this(PageWriterFactory factory, OutputStream[] outputs) { + super(factory, outputs); + } + + void generateTOC(Module[] modules) { + // TODO + print.format(templates["toc"]); + } + + void generateModuleSection() { + // TODO + print.format(templates["modules"]); + } + + void generateListingSection() { + // TODO + print.format(templates["listings"]); + } + + void generateDepGraphSection() { + // TODO + print.format(templates["dependencies"]); + } + + void generateIndexSection() { } + + void generateLastPage() { } + + void generateFirstPage() { + print( + plainTextHeading(factory.options.templates.title ~ " Reference Manual") ~ + factory.options.templates.versionString ~ \n ~ + "Generated by " ~ docgen_version ~ \n ~ + timeNow() ~ \n \n \n ~ + plainTextHorizLine() ~ \n \n ~ + plainTextHeading("Table of Contents") ~ \n ~ + plainTextHeading("Module documentation") ~ \n ~ + plainTextHeading("File listings") ~ \n ~ + plainTextHeading("Dependency diagram") ~ \n + ); + } + + void addList(char[][] contents, bool ordered) { + uint[] counters; + foreach(item; contents) { + switch(item) { + case "(": counters ~= 1; continue; + case ")": counters.length = counters.length - 1; continue; + default: + if (counters.length>0) + for (int i=0; i <= counters.length; i++) + print(" "); + if (ordered) + print(++counters[$-1])(". ")(item)(\n); + else + print("* ")(item)(\n); + } + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/page/writer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/page/writer.d Tue Oct 30 15:41:30 2007 +0200 @@ -0,0 +1,197 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.page.writer; + +public import docgen.misc.misc; +import tango.io.model.IConduit : OutputStream; +import tango.util.time.Date; +import tango.util.time.Clock; +import tango.text.convert.Sprint; +import tango.io.stream.FileStream; +import tango.io.Stdout; +import tango.io.Print: Print; +import tango.text.convert.Layout : Layout; +public import docgen.misc.parser; + +const templateDir = "docgen/templates/"; + +// template file names +const templateNames = [ + "firstpage"[], "toc"[], "modules"[], + "listings"[], "dependencies"[], "index"[], + "lastpage"[], "langdef"[], "makefile"[], + "graphics"[], "listing"[] +]; + +/** + * Writes the logical subcomponents of a document, + * e.g. sections, embedded graphics, lists + */ +interface PageWriter { + /** + * Updates the outputstreams. + */ + void setOutput(OutputStream[] outputs); + + /** + * Generates the first page(s). + */ + void generateFirstPage(); + + /** + * Generates table of contents. + */ + void generateTOC(Module[] modules); + + /** + * Generates module documentation section. + */ + void generateModuleSection(); + + /** + * Generates source code listing section. + */ + void generateListingSection(); + + /** + * Generates dependency graph section. + */ + void generateDepGraphSection(); + + /** + * Generates an index section. + */ + void generateIndexSection(); + + /** + * Generates the last page(s). + */ + void generateLastPage(); + + /** + * Generates a language definition file [LaTeX]. + * Could be used for DTD too, I suppose. + */ + void generateLangDef(); + + /** + * Generates a makefile used for document post-processing. + */ + void generateMakeFile(); + + // --- page components + // + /* + * Adds an external graphics file. + */ + void addGraphics(char[] imageFile); + + /** + * Adds a source code listing. + */ + void addListing(char[] moduleName, char[] contents, bool inline = true); + + /** + * Adds a list of items. + */ + void addList(char[][] contents, bool ordered); +} + +interface PageWriterFactory : WriterFactory { + PageWriter createPageWriter(OutputStream[] outputs, DocFormat outputFormat); +} + + +char[] timeNow() { + auto date = Clock.toDate; + auto sprint = new Sprint!(char); + return sprint.format("{0} {1} {2} {3}", + date.asDay(), + date.asMonth(), + date.day, + date.year); +} + +char[] loadTemplate(char[] style, char[] format, char[] templateName) { + char[] fn = templateDir~style~"/"~format~"/"~templateName~".tpl"; + + scope(failure) { + Stderr("Warning: error opening template "~fn~"."); + return null; + } + + auto file = new FileInput(fn); + auto content = new char[file.length]; + auto bytesRead = file.read(content); + + assert(bytesRead == file.length, "Error reading template"); + + file.close(); + + return content; +} + +template AbstractPageWriter(int n, char[] format) { + abstract class AbstractPageWriter : AbstractWriter!(PageWriterFactory, n), PageWriter { + protected char[][char[]] templates; + protected Print!(char) print; + + this(PageWriterFactory factory, OutputStream[] outputs) { + super(factory, outputs); + setOutput(outputs); + + foreach(tpl; templateNames) { + templates[tpl] = loadTemplate(factory.options.templates.templateStyle, format, tpl); + } + } + + void setOutput(OutputStream[] outputs) { + this.outputs = outputs; + + print = new Print!(char)(new Layout!(char), outputs[0]); + } + + void generateTOC(Module[] modules) { + print.format(templates["toc"]); + } + + void generateModuleSection() { + print.format(templates["modules"]); + } + + void generateListingSection() { + print.format(templates["listings"]); + } + + void generateDepGraphSection() { + print.format(templates["dependencies"]); + } + + void generateIndexSection() { + print.format(templates["index"]); + } + + void generateLastPage() { + print.format(templates["lastpage"]); + } + + void generateLangDef() { + print(templates["langdef"]); + } + + void generateMakeFile() { + print(templates["makefile"]); + } + + + void addGraphics(char[] imageFile) { + print.format(templates["graphics"], imageFile); + } + + void addListing(char[] moduleName, char[] contents, bool inline) { + print.format(templates["listing"], moduleName, contents); + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/page/writers.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/page/writers.d Tue Oct 30 15:41:30 2007 +0200 @@ -0,0 +1,32 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.page.writers; + +public import docgen.page.writer; +import docgen.page.htmlwriter; +import docgen.page.xmlwriter; +import docgen.page.plaintextwriter; +import docgen.page.latexwriter; + +class DefaultPageWriterFactory : AbstractWriterFactory, PageWriterFactory { + this(DocGenerator generator) { + super(generator); + } + + PageWriter createPageWriter(OutputStream[] outputs, DocFormat outputFormat) { + switch (outputFormat) { + case DocFormat.LaTeX: + return new LaTeXWriter(this, outputs); + case DocFormat.XML: + return new XMLWriter(this, outputs); + case DocFormat.HTML: + return new HTMLWriter(this, outputs); + case DocFormat.PlainText: + return new PlainTextWriter(this, outputs); + default: + throw new Exception("Document writer type does not exist!"); + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/page/xmlwriter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/page/xmlwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -0,0 +1,56 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.page.xmlwriter; + +import docgen.page.writer; +import docgen.misc.textutils; +import tango.io.FileConduit : FileConduit; + +//TODO: this is mostly broken now + +/** + * TODO + */ +class XMLWriter : AbstractPageWriter!(2, "xml") { + this(PageWriterFactory factory, OutputStream[] outputs) { + super(factory, outputs); + } + + void generateTOC(Module[] modules) { + // TODO + print.format(templates["toc"]); + } + + void generateModuleSection() { + // TODO + print.format(templates["modules"]); + } + + void generateListingSection() { + // TODO + print.format(templates["listings"]); + } + + void generateDepGraphSection() { + // TODO + print.format(templates["dependencies"]); + } + + void generateIndexSection() { } + + void generateLastPage() { } + + void generateFirstPage() { } + + void addList(char[][] contents, bool ordered) { + foreach(item; contents) { + switch(item) { + case "(": print(ordered ? "
      " : "
    " : ""); continue; + default: print("
  • ")(xml_escape(item))("
  • "); + } + } + } +} diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/sourcelisting/htmlwriter.d --- a/trunk/src/docgen/sourcelisting/htmlwriter.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/sourcelisting/htmlwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -14,9 +14,9 @@ * TODO */ class HTMLWriter : AbstractWriter!(ListingWriterFactory), ListingWriter { - DocumentWriter writer; + PageWriter writer; - this(ListingWriterFactory factory, DocumentWriter writer) { + this(ListingWriterFactory factory, PageWriter writer) { super(factory); this.writer = writer; } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/sourcelisting/latexwriter.d --- a/trunk/src/docgen/sourcelisting/latexwriter.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/sourcelisting/latexwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -12,9 +12,9 @@ * Adds a code listing section for the given file. */ class LaTeXWriter : AbstractWriter!(ListingWriterFactory), ListingWriter { - DocumentWriter writer; + PageWriter writer; - this(ListingWriterFactory factory, DocumentWriter writer) { + this(ListingWriterFactory factory, PageWriter writer) { super(factory); this.writer = writer; } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/sourcelisting/plaintextwriter.d --- a/trunk/src/docgen/sourcelisting/plaintextwriter.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/sourcelisting/plaintextwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -13,9 +13,9 @@ * TODO */ class PlainTextWriter : AbstractWriter!(ListingWriterFactory), ListingWriter { - DocumentWriter writer; + PageWriter writer; - this(ListingWriterFactory factory, DocumentWriter writer) { + this(ListingWriterFactory factory, PageWriter writer) { super(factory); this.writer = writer; } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/sourcelisting/writer.d --- a/trunk/src/docgen/sourcelisting/writer.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/sourcelisting/writer.d Tue Oct 30 15:41:30 2007 +0200 @@ -5,7 +5,7 @@ module docgen.sourcelisting.writer; public import docgen.misc.misc; -public import docgen.document.writer; +public import docgen.page.writer; //import dil.Parser; import tango.io.model.IConduit : OutputStream, InputStream; @@ -15,5 +15,5 @@ } interface ListingWriterFactory : WriterFactory { - ListingWriter createListingWriter(DocumentWriter writer, DocFormat outputFormat); + ListingWriter createListingWriter(PageWriter writer, DocFormat outputFormat); } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/sourcelisting/writers.d --- a/trunk/src/docgen/sourcelisting/writers.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/sourcelisting/writers.d Tue Oct 30 15:41:30 2007 +0200 @@ -15,7 +15,7 @@ super(generator); } - ListingWriter createListingWriter(DocumentWriter writer, DocFormat outputFormat) { + ListingWriter createListingWriter(PageWriter writer, DocFormat outputFormat) { switch (outputFormat) { case DocFormat.LaTeX: return new LaTeXWriter(this, writer); diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/sourcelisting/xmlwriter.d --- a/trunk/src/docgen/sourcelisting/xmlwriter.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/sourcelisting/xmlwriter.d Tue Oct 30 15:41:30 2007 +0200 @@ -11,9 +11,9 @@ * TODO */ class XMLWriter : AbstractWriter!(ListingWriterFactory), ListingWriter { - DocumentWriter writer; + PageWriter writer; - this(ListingWriterFactory factory, DocumentWriter writer) { + this(ListingWriterFactory factory, PageWriter writer) { super(factory); this.writer = writer; } diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/tests/doctemplate.d --- a/trunk/src/docgen/tests/doctemplate.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/tests/doctemplate.d Tue Oct 30 15:41:30 2007 +0200 @@ -5,7 +5,7 @@ module docgen.tests.doctemplate; import docgen.tests.common; -import docgen.document.writers; +import docgen.page.writers; import tango.io.FileConduit; // doc template @@ -14,9 +14,9 @@ auto gen = new TestDocGenerator; auto fname = "doctemplate.tex"; - auto gwf = new DefaultDocumentWriterFactory(gen); + auto gwf = new DefaultPageWriterFactory(gen); auto file = new FileConduit("docgen/teststuff/" ~ fname, FileConduit.WriteCreate); - auto writer = gwf.createDocumentWriter( [ file ], DocFormat.LaTeX ); + auto writer = gwf.createPageWriter( [ file ], DocFormat.LaTeX ); writer.generateFirstPage(); writer.generateTOC(null); diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/tests/graphs.d --- a/trunk/src/docgen/tests/graphs.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/tests/graphs.d Tue Oct 30 15:41:30 2007 +0200 @@ -7,7 +7,7 @@ import docgen.tests.common; import docgen.misc.parser; import docgen.graphutils.writers; -import docgen.document.writers; +import docgen.page.writers; import tango.io.FileConduit; import dil.Module; @@ -18,12 +18,12 @@ //gen.options.graph.graphFormat = GraphFormat.ModuleNames; //gen.options.graph.graphFormat = GraphFormat.ModulePaths; gen.options.graph.depth = 5; - auto ddf = new DefaultDocumentWriterFactory(gen); + auto ddf = new DefaultPageWriterFactory(gen); auto gwf = new DefaultGraphWriterFactory(gen); auto file = new FileConduit("docgen/teststuff/" ~ fname, FileConduit.WriteCreate); auto file2 = new FileConduit("docgen/teststuff/" ~ fname ~ "-2", FileConduit.WriteCreate); auto writer = gwf.createGraphWriter( - ddf.createDocumentWriter( [ file2 ], DocFormat.LaTeX), + ddf.createPageWriter( [ file2 ], DocFormat.LaTeX), GraphFormat.Dot ); @@ -114,7 +114,7 @@ auto fname = "dependencies.tex"; auto imgFname = "depgraph.dot"; - auto ddf = new DefaultDocumentWriterFactory(gen); + auto ddf = new DefaultPageWriterFactory(gen); auto gwf = new DefaultGraphWriterFactory(gen); auto file = new FileConduit("docgen/teststuff/" ~ fname, FileConduit.WriteCreate); auto imgFile = new FileConduit("docgen/teststuff/" ~ imgFname, FileConduit.WriteCreate); @@ -137,7 +137,7 @@ ); auto writer = gwf.createGraphWriter( - ddf.createDocumentWriter( [ file ], DocFormat.LaTeX ), + ddf.createPageWriter( [ file ], DocFormat.LaTeX ), GraphFormat.Dot ); diff -r de2675bc9afa -r 33a4cb255fcc trunk/src/docgen/tests/listing.d --- a/trunk/src/docgen/tests/listing.d Tue Oct 30 02:35:56 2007 +0200 +++ b/trunk/src/docgen/tests/listing.d Tue Oct 30 15:41:30 2007 +0200 @@ -7,7 +7,7 @@ import docgen.misc.parser; import docgen.tests.common; import docgen.sourcelisting.writers; -import docgen.document.writers; +import docgen.page.writers; import tango.io.FileConduit; import tango.text.Util; @@ -18,7 +18,7 @@ gen.options.outputFormats = [ DocFormat.LaTeX ]; auto fname = "files.tex"; - auto ddf = new DefaultDocumentWriterFactory(gen); + auto ddf = new DefaultPageWriterFactory(gen); auto dlwf = new DefaultListingWriterFactory(gen); auto file = new FileConduit("docgen/teststuff/" ~ fname, FileConduit.WriteCreate); @@ -38,7 +38,7 @@ auto srcFile = new FileConduit(mod.filePath); auto dstFile = new FileConduit("docgen/teststuff/_" ~ dstFname ~ ".d", FileConduit.WriteCreate); - auto writer = dlwf.createListingWriter( ddf.createDocumentWriter( [ file ], + auto writer = dlwf.createListingWriter( ddf.createPageWriter( [ file ], DocFormat.LaTeX ), DocFormat.LaTeX ); writer.generateListing(srcFile, dstFile, mod.moduleFQN);