changeset 466:db7e27b5c180

Fixed parts of HTML output, some reorganizing.
author Jari-Matti M?kel? <jmjm@iki.fi>
date Wed, 31 Oct 2007 15:17:20 +0200
parents e0d24e05a9ee
children 32f4c3cb6a41
files trunk/src/docgen/config/default.cfg trunk/src/docgen/docgen.d trunk/src/docgen/document/generator.d trunk/src/docgen/document/htmlgenerator.d trunk/src/docgen/document/latexgenerator.d trunk/src/docgen/document/plaintextgenerator.d trunk/src/docgen/document/xmlgenerator.d trunk/src/docgen/graphutils/dotwriter.d trunk/src/docgen/graphutils/modulenamewriter.d trunk/src/docgen/graphutils/modulepathwriter.d trunk/src/docgen/graphutils/writer.d trunk/src/docgen/graphutils/writers.d trunk/src/docgen/misc/misc.d trunk/src/docgen/misc/parser.d trunk/src/docgen/page/htmlwriter.d trunk/src/docgen/page/latexwriter.d trunk/src/docgen/page/plaintextwriter.d trunk/src/docgen/page/writer.d trunk/src/docgen/page/xmlwriter.d trunk/src/docgen/sourcelisting/htmlwriter.d trunk/src/docgen/templates/README trunk/src/docgen/templates/default/html/classes.tpl trunk/src/docgen/templates/default/html/firstpage.tpl trunk/src/docgen/templates/default/html/listings.tpl trunk/src/docgen/templates/default/html/makefile.tpl trunk/src/docgen/templates/default/html/modules.tpl trunk/src/docgen/templates/default/html/pagetemplate.tpl trunk/src/docgen/templates/default/html/stylesheet.tpl trunk/src/docgen/templates/default/latex/classes.tpl trunk/src/docgen/templates/default/latex/makefile.tpl
diffstat 30 files changed, 525 insertions(+), 264 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/docgen/config/default.cfg	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/config/default.cfg	Wed Oct 31 15:17:20 2007 +0200
@@ -1,6 +1,6 @@
 (options
   (graph
-    (imageFormat PDF)
+    (imageFormat PNG)
     (depth -1)
     (nodeColor white)
     (cyclicNodeColor tomato)
@@ -34,6 +34,6 @@
     (commentFormat Doxygen)
     (depth -1)
   )
-  (outputFormats LaTeX)
+  (outputFormats LaTeX HTML)
   (outputDir tmp/)
 )
--- a/trunk/src/docgen/docgen.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/docgen.d	Wed Oct 31 15:17:20 2007 +0200
@@ -103,7 +103,7 @@
         Stdout("Generating LaTeX docs..");
         break;
       case DocFormat.HTML:
-        generator = new HTMLDocGenerator(*options, &parser);
+        generator = new HTMLDocGenerator(*options, &parser, graphcache);
         Stdout("Generating HTML docs..");
         break;
       case DocFormat.XML:
--- a/trunk/src/docgen/document/generator.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/document/generator.d	Wed Oct 31 15:17:20 2007 +0200
@@ -16,83 +16,108 @@
 
 alias void delegate(ref Module[], ref Edge[], ref Vertex[char[]]) ParserDg;
 
-template DefaultDocGenerator(char[] genDir) {
-  abstract class DefaultDocGenerator : DocGenerator {
-    DocGeneratorOptions m_options;
-    ParserDg m_parser;
-    PageWriter docWriter;
+abstract class DefaultDocGenerator : DocGenerator {
+  protected:
+
+  DocFormat docFormat;
+  auto makeFile = "make.sh";
+  char[] genDir;
+
+  DocGeneratorOptions m_options;
+  ParserDg m_parser;
+  PageWriter docWriter;
 
-    GraphWriterFactory graphFactory;
-    PageWriterFactory pageFactory;
-    DefaultListingWriterFactory listingFactory;
-    
-    Module[] modules;
-    Edge[] edges;
-    Vertex[char[]] vertices;
+  GraphWriterFactory graphFactory;
+  PageWriterFactory pageFactory;
+  DefaultListingWriterFactory listingFactory;
+  
+  Module[] modules;
+  Edge[] edges;
+  Vertex[char[]] vertices;
+
+  public:
+
+  this(DocGeneratorOptions options, ParserDg parser) {
+    m_options = options;
+    m_parser = parser;
 
-    this(DocGeneratorOptions options, ParserDg parser) {
-      m_options = options;
-      m_parser = parser;
+    createGraphWriterFactory();
+    createPageWriterFactory();
+    createListingWriterFactory();
 
-      createGraphWriterFactory();
-      createPageWriterFactory();
-      createListingWriterFactory();
+    // create output dir
+    (new FilePath(options.outputDir ~ "/" ~ genDir)).create();
+  }
+
+  DocGeneratorOptions *options() {
+    return &m_options;
+  }
 
-      // create output dir
-      (new FilePath(options.outputDir ~ "/" ~ genDir)).create();
-    }
+  protected:
+
+  void createGraphWriterFactory() {
+    graphFactory = new DefaultGraphWriterFactory(this);
+  }
 
-    protected void createGraphWriterFactory() {
-      graphFactory = new DefaultGraphWriterFactory(this);
-    }
+  void createPageWriterFactory() {
+    pageFactory = new DefaultPageWriterFactory(this);
+  }
+
+  void createListingWriterFactory() {
+    listingFactory = new DefaultListingWriterFactory(this);
+  }
 
-    protected void createPageWriterFactory() {
-      pageFactory = new DefaultPageWriterFactory(this);
-    }
+  char[] outPath(char[] file) {
+    return options.outputDir ~ "/" ~ genDir ~ "/" ~ file;
+  }
+
+  FileOutput outputFile(char[] fname) {
+    return new FileOutput(outPath(fname));
+  }
 
-    protected void createListingWriterFactory() {
-      listingFactory = new DefaultListingWriterFactory(this);
-    }
+  void parseSources() {
+    m_parser(modules, edges, vertices);
+  }
+
+  //---
 
-    protected char[] outPath(char[] file) {
-      return options.outputDir ~ "/" ~ genDir ~ "/" ~ file;
-    }
+  void writeSimpleFile(char[] fname, void delegate() dg) {
+    auto docFile = outputFile(fname);
+
+    docWriter.setOutput([docFile]);
+    dg();
+
+    docFile.close();
+  }
 
-    protected void parseSources() {
-      m_parser(modules, edges, vertices);
-    }
+  /**
+   * Generates "makefile" for processing e.g. .dot files.
+   */
+  void generateMakeFile(char[][] args ...) {
+    writeSimpleFile(makeFile, { docWriter.generateCustomPage("makefile", args); } );
+  }
+  
+}
 
-    void createDepGraph(char[] depGraphFile) {
-      auto imgFile = new FileOutput(outPath(depGraphFile));
-
-      auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot );
+abstract class DefaultCachingDocGenerator : DefaultDocGenerator, CachingDocGenerator {
+  private:
+    
+  GraphCache m_graphCache;
 
-      writer.generateDepGraph(vertices.values, edges, imgFile);
+  public:
 
-      imgFile.close();
-    }
+  this(DocGeneratorOptions options, ParserDg parser, GraphCache graphCache) {
+    super(options, parser);
+    m_graphCache = graphCache;
+  }
+  
+  GraphCache graphCache() {
+    return m_graphCache;
+  }
 
-    public DocGeneratorOptions *options() {
-      return &m_options;
-    }
+  protected:
+
+  void createGraphWriterFactory() {
+    graphFactory = new DefaultCachingGraphWriterFactory(this);
   }
 }
-
-template DefaultCachingDocGenerator(char[] genDir) {
-  abstract class DefaultCachingDocGenerator : DefaultDocGenerator!(genDir), CachingDocGenerator {
-    GraphCache m_graphCache;
-
-    this(DocGeneratorOptions options, ParserDg parser, GraphCache graphCache) {
-      super(options, parser);
-      m_graphCache = graphCache;
-    }
-    
-    GraphCache graphCache() {
-      return m_graphCache;
-    }
-
-    protected void createGraphWriterFactory() {
-      graphFactory = new DefaultCachingGraphWriterFactory(this);
-    }
-  }
-}
--- a/trunk/src/docgen/document/htmlgenerator.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/document/htmlgenerator.d	Wed Oct 31 15:17:20 2007 +0200
@@ -9,9 +9,112 @@
 import tango.io.stream.FileStream;
 import tango.text.Util : replace;
 
-class HTMLDocGenerator : DefaultDocGenerator!("html") {
-  this(DocGeneratorOptions options, ParserDg parser) {
-    super(options, parser);
+class HTMLDocGenerator : DefaultCachingDocGenerator {
+  private:
+
+  auto docFileNames = [
+    "index.html"[], "toc.html"[], "classes.html"[],
+    "modules.html"[], "files.html"[]
+  ];
+
+  auto depGraphFile = "depgraph.dot";
+  auto depGraphDocFile = "depgraph.html";
+  auto styleSheetFile = "default.css";
+
+  public:
+
+  this(DocGeneratorOptions options, ParserDg parser, GraphCache graphcache) {
+    genDir = "html";
+    docFormat = DocFormat.HTML;
+    super(options, parser, graphcache);
+  }
+
+  /**
+   * Generates the documentation.
+   */
+  void generate() {
+    parseSources();
+
+    docWriter = pageFactory.createPageWriter( null, docFormat );
+
+    // stylesheet needs to be created first to propagate the css file name
+    generateStyleSheet();
+
+    generateDoc();
+
+    if (options.listing.enableListings)
+      generateListings();
+
+    generateClasses();
+    generateModules();
+    generateDependencies();
+    generateMakeFile("", imageFormatExts[options.graph.imageFormat]);
+  }
+
+  protected:
+
+  /**
+   * Generates document skeleton.
+   */
+  void generateDoc() {
+    writeSimpleFile(docFileNames[0], { docWriter.generateFirstPage(); });
+    writeSimpleFile(docFileNames[1], { docWriter.generateTOC(modules); });
+    writeSimpleFile(docFileNames[2], { docWriter.generateClassSection(); });
+    writeSimpleFile(docFileNames[3], { docWriter.generateModuleSection(); });
+    writeSimpleFile(docFileNames[4], { docWriter.generateListingSection(); });
   }
-  public void generate() { /* TODO */ }
+
+  /**
+   * Generates a global style sheet.
+   */
+  void generateStyleSheet() {
+    writeSimpleFile(styleSheetFile, { docWriter.generateCustomPage("stylesheet"); } );
+  }
+
+  /**
+   * Generates documentation for classes.
+   */
+  void generateClasses() {
+    //auto docFile = outputFile(classesFile);
+    //docFile.close();
+  }
+
+  /**
+   * Generates documentation for modules.
+   */
+  void generateModules() {
+    //auto docFile = outputFile(modulesFile);
+    //docFile.close();
+  }
+
+  /**
+   * Generates source file listings.
+   */
+  void generateListings() {
+    auto writer = listingFactory.createListingWriter(docWriter, docFormat);
+
+    foreach(mod; modules) {
+      auto dstFname = replace(mod.moduleFQN.dup, '.', '_') ~ ".html";
+
+      writeSimpleFile(dstFname, {
+        auto srcFile = new FileInput(mod.filePath);
+        writer.generateListing(srcFile, null, mod.moduleFQN);
+        srcFile.close();
+      });
+    }
+  }
+
+  /**
+   * Generates dependency graphs.
+   */
+  void generateDependencies() {
+    writeSimpleFile(depGraphDocFile, {
+      auto imgFile = outputFile(depGraphFile);
+
+      auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot );
+      writer.generateDepGraph(vertices.values, edges, imgFile);
+
+      imgFile.close();
+    });
+  }
 }
--- a/trunk/src/docgen/document/latexgenerator.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/document/latexgenerator.d	Wed Oct 31 15:17:20 2007 +0200
@@ -12,28 +12,55 @@
 /**
  * Main routine for LaTeX doc generation.
  */
-class LaTeXDocGenerator : DefaultCachingDocGenerator!("latex") {
+class LaTeXDocGenerator : DefaultCachingDocGenerator {
+  private:
+
   auto docFileName = "document.tex";
-  auto depGraphTexFile = "dependencies.tex";
+  auto depGraphDocFile = "dependencies.tex";
   auto depGraphFile = "depgraph.dot";
   auto listingFile = "files.tex";
   auto modulesFile = "modules.tex";
   auto langDefFile = "lstlang0.sty";
-  auto makeFile = "make.sh";
+
+  public:
 
   this(DocGeneratorOptions options, ParserDg parser, GraphCache graphcache) {
+    genDir = "latex";
+    docFormat = DocFormat.LaTeX;
+
     super(options, parser, graphcache);
   }
 
   /**
+   * Generates the documentation.
+   */
+  void generate() {
+    parseSources();
+
+    generateDoc();
+
+    if (options.listing.enableListings)
+      generateListings();
+
+    generateClasses();
+    generateModules();
+    generateDependencies();
+    generateLangDef();
+    generateMakeFile(docFileName, "pdf");
+  }
+
+  protected:
+
+  /**
    * Generates document skeleton.
    */
-  void generateDoc(char[] docFileName) {
-    auto docFile = new FileOutput(outPath(docFileName));
-    docWriter = pageFactory.createPageWriter( [ docFile ], DocFormat.LaTeX );
+  void generateDoc() {
+    auto docFile = outputFile(docFileName);
+    docWriter = pageFactory.createPageWriter( [ docFile ], docFormat );
 
     docWriter.generateFirstPage();
     docWriter.generateTOC(modules);
+    docWriter.generateClassSection();
     docWriter.generateModuleSection();
     docWriter.generateListingSection();
     docWriter.generateDepGraphSection();
@@ -47,23 +74,14 @@
    * Generates D language definition file.
    */
   void generateLangDef() {
-    auto docFile = new FileOutput(outPath(langDefFile));
-
-    docWriter.setOutput([docFile]);
-    docWriter.generateLangDef();
-
-    docFile.close();
+    writeSimpleFile(langDefFile, { docWriter.generateCustomPage("langdef"); });
   }
 
   /**
-   * Generates "makefile" for processing the .dot and .tex files.
+   * Generates documentation for classes.
    */
-  void generateMakeFile() {
-    auto docFile = new FileOutput(outPath(makeFile));
-
-    docWriter.setOutput([docFile]);
-    docWriter.generateMakeFile();
-
+  void generateClasses() {
+    auto docFile = outputFile(modulesFile);
     docFile.close();
   }
 
@@ -71,7 +89,7 @@
    * Generates documentation for modules.
    */
   void generateModules() {
-    auto docFile = new FileOutput(outPath(modulesFile));
+    auto docFile = outputFile(modulesFile);
     docFile.close();
   }
 
@@ -79,52 +97,34 @@
    * Generates source file listings.
    */
   void generateListings() {
-    auto docFile = new FileOutput(outPath(listingFile));
-
-    docWriter.setOutput([docFile]);
-    auto writer = listingFactory.createListingWriter(docWriter, DocFormat.LaTeX);
+    writeSimpleFile(listingFile, {
+      auto writer = listingFactory.createListingWriter(docWriter, docFormat);
 
-    foreach(mod; modules) {
-      auto dstFname = replace(mod.moduleFQN.dup, '.', '_') ~ ".d";
-      
-      auto srcFile = new FileInput(mod.filePath);
-      auto dstFile = new FileOutput(outPath(dstFname));
-      
-      writer.generateListing(srcFile, dstFile, mod.moduleFQN);
+      foreach(mod; modules) {
+        auto dstFname = replace(mod.moduleFQN.dup, '.', '_') ~ ".d";
+        
+        auto srcFile = new FileInput(mod.filePath);
+        auto dstFile = outputFile(dstFname);
+        
+        writer.generateListing(srcFile, dstFile, mod.moduleFQN);
 
-      srcFile.close();
-      dstFile.close();
-    }
-    
-    docFile.close();
+        srcFile.close();
+        dstFile.close();
+      }
+    });
   }
 
   /**
    * Generates dependency graphs.
    */
   void generateDependencies() {
-    auto docFile = new FileOutput(outPath(depGraphTexFile));
-
-    docWriter.setOutput([docFile]);
-    createDepGraph(depGraphFile);
-
-    docFile.close();
-  }
+    writeSimpleFile(depGraphDocFile, {
+      auto imgFile = outputFile(depGraphFile);
 
-  /**
-   * Generates the documentation.
-   */
-  public void generate() {
-    parseSources();
-
-    generateDoc(docFileName);
+      auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot );
+      writer.generateDepGraph(vertices.values, edges, imgFile);
 
-    if (options.listing.enableListings)
-      generateListings();
-
-    generateModules();
-    generateDependencies();
-    generateLangDef();
-    generateMakeFile();
+      imgFile.close();
+    });
   }
 }
--- a/trunk/src/docgen/document/plaintextgenerator.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/document/plaintextgenerator.d	Wed Oct 31 15:17:20 2007 +0200
@@ -9,9 +9,15 @@
 import tango.io.stream.FileStream;
 import tango.text.Util : replace;
 
-class PlainTextDocGenerator : DefaultDocGenerator!("txt") {
+class PlainTextDocGenerator : DefaultDocGenerator {
+  public:
+
   this(DocGeneratorOptions options, ParserDg parser) {
+    genDir = "txt";
+    docFormat = DocFormat.PlainText;
+    
     super(options, parser);
   }
-  public void generate() { /* TODO */ }
+
+  void generate() { /* TODO */ }
 }
--- a/trunk/src/docgen/document/xmlgenerator.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/document/xmlgenerator.d	Wed Oct 31 15:17:20 2007 +0200
@@ -9,9 +9,15 @@
 import tango.io.stream.FileStream;
 import tango.text.Util : replace;
 
-class XMLDocGenerator : DefaultDocGenerator!("xml") {
+class XMLDocGenerator : DefaultDocGenerator {
+  public:
+
   this(DocGeneratorOptions options, ParserDg parser) {
+    genDir = "xml";
+    docFormat = DocFormat.XML;
+
     super(options, parser);
   }
-  public void generate() { /* TODO */ }
+
+  void generate() { /* TODO */ }
 }
--- a/trunk/src/docgen/graphutils/dotwriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/graphutils/dotwriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -16,10 +16,22 @@
  * Creates a graph rule file for the dot utility.
  */
 class DotWriter : AbstractGraphWriter {
+  public:
+
   this(GraphWriterFactory factory, PageWriter writer) {
     super(factory, writer);
   }
 
+  void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
+    generateImageTag(imageFile);
+    
+    auto image = generateDepImageFile(vertices, edges);
+    auto printer = new Print!(char)(new Layout!(char), imageFile);
+    printer(image);
+  }
+
+  protected:
+
   char[] generateDepImageFile(Vertex[] vertices, Edge[] edges) {
     char[] image;
     auto sprint = new Sprint!(char);
@@ -121,26 +133,22 @@
     fn = fn[0..$-3] ~ imageFormatExts[factory.options.graph.imageFormat];
     
     writer.addGraphics(fn);
-  }
-
-  protected void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
-    generateImageTag(imageFile);
-    
-    auto image = generateDepImageFile(vertices, edges);
-    auto printer = new Print!(char)(new Layout!(char), imageFile);
-    printer(image);
-  }
+  } 
 }
 
 class CachingDotWriter : DotWriter {
+  private:
+
   CachingGraphWriterFactory factory;
 
+  public:
+
   this(CachingGraphWriterFactory factory, PageWriter writer) {
     super(factory, writer);
     this.factory = factory;
   }
 
-  protected void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
+  override void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
     generateImageTag(imageFile);
 
     auto cached = factory.graphCache.getCachedGraph(vertices, edges, GraphFormat.Dot);
--- a/trunk/src/docgen/graphutils/modulenamewriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/graphutils/modulenamewriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -9,6 +9,8 @@
 import tango.text.convert.Layout : Layout;
 
 class ModuleNameWriter : AbstractGraphWriter {
+  public:
+
   this(GraphWriterFactory factory, PageWriter writer) {
     super(factory, writer);
   }
--- a/trunk/src/docgen/graphutils/modulepathwriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/graphutils/modulepathwriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -9,6 +9,8 @@
 import tango.text.convert.Layout : Layout;
 
 class ModulePathWriter : AbstractGraphWriter {
+  public:
+
   this(GraphWriterFactory factory, PageWriter writer) {
     super(factory, writer);
   }
--- a/trunk/src/docgen/graphutils/writer.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/graphutils/writer.d	Wed Oct 31 15:17:20 2007 +0200
@@ -69,8 +69,12 @@
 }
 
 abstract class AbstractGraphWriter : AbstractWriter!(GraphWriterFactory), GraphWriter {
+  protected:
+
   PageWriter writer;
   
+  public:
+
   this(GraphWriterFactory factory, PageWriter writer) {
     super(factory);
     this.writer = writer;
@@ -78,7 +82,11 @@
 }
 
 class DefaultGraphCache : GraphCache {
-  private char[][Object[]][Object[]][GraphFormat] m_graphCache;
+  private:
+    
+  char[][Object[]][Object[]][GraphFormat] m_graphCache;
+
+  public:
 
   char[] getCachedGraph(Object[] vertices, Object[] edges, GraphFormat format) {
     debug Stdout("Starting graph lookup\n");
@@ -101,6 +109,6 @@
   void setCachedGraph(Object[] vertices, Object[] edges, GraphFormat format, char[]
       contents) {
     m_graphCache[format][edges][vertices] = contents;
-      debug Stdout("Graph cache updated!\n");
-    }
+    debug Stdout("Graph cache updated!\n");
+  }
 }
--- a/trunk/src/docgen/graphutils/writers.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/graphutils/writers.d	Wed Oct 31 15:17:20 2007 +0200
@@ -10,6 +10,8 @@
 import docgen.graphutils.modulenamewriter;
 
 class DefaultGraphWriterFactory : AbstractWriterFactory, GraphWriterFactory {
+  public:
+
   this(DocGenerator generator) {
     super(generator);
   }
@@ -29,6 +31,8 @@
 }
 
 class DefaultCachingGraphWriterFactory : AbstractWriterFactory, CachingGraphWriterFactory {
+  public:
+
   CachingDocGenerator generator;
 
   this(CachingDocGenerator generator) {
@@ -40,7 +44,7 @@
     return generator.graphCache;
   }
 
-  GraphWriter createGraphWriter(PageWriter writer, GraphFormat outputFormat) {
+  override GraphWriter createGraphWriter(PageWriter writer, GraphFormat outputFormat) {
     switch (outputFormat) {
       case GraphFormat.Dot:
         return new CachingDotWriter(this, writer);
--- a/trunk/src/docgen/misc/misc.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/misc/misc.d	Wed Oct 31 15:17:20 2007 +0200
@@ -146,7 +146,9 @@
 abstract class AbstractWriterFactory : WriterFactory {
   protected DocGenerator generator;
 
-  public DocGeneratorOptions *options() {
+  public:
+  
+  DocGeneratorOptions *options() {
     return generator.options;
   }
 
@@ -159,19 +161,18 @@
 template AbstractWriter(T, int n = 0) {
   abstract class AbstractWriter {
     protected T factory;
+    protected OutputStream[] outputs;
   
     static if (n > 0) {
-      protected OutputStream[] outputs;
-      
       this(T factory, OutputStream[] outputs) {
         this.factory = factory;
         this.outputs = outputs;
         assert(outputs.length == n, "Incorrect number of outputs");
       }
-    } else {
-      this(T factory) {
-        this.factory = factory;
-      }
+    }
+
+    this(T factory) {
+      this.factory = factory;
     }
   }
 }
--- a/trunk/src/docgen/misc/parser.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/misc/parser.d	Wed Oct 31 15:17:20 2007 +0200
@@ -16,7 +16,9 @@
 alias void delegate (Module imported, Module importer, bool isPublic) importDg;
 
 class Parser {
-  private static char[] findModulePath(char[] moduleFQN, char[][] importPaths) {
+  private:
+    
+  static char[] findModulePath(char[] moduleFQN, char[][] importPaths) {
     char[] modulePath;
 
     foreach (path; importPaths) {
@@ -34,6 +36,8 @@
     return null;
   }
 
+  public:
+
   /**
    * Imports the transitive closure of imports starting from "filePath",
    * limited by recursionDepth.
@@ -51,7 +55,7 @@
    *     idg = Delegate that gets called for every import found
    *     modules = List of parsed modules
    */
-  public static void loadModules(char[] filePath, char[][] importPaths, char[][] strRegexps,
+  static void loadModules(char[] filePath, char[][] importPaths, char[][] strRegexps,
                                  bool IncludeUnlocatableModules, int recursionDepth,
                                  modDg mdg, importDg idg, out Module[] modules) {
 
@@ -76,7 +80,7 @@
    *     idg = Delegate that gets called for every import found
    *     modules = List of parsed modules
    */
-  public static void loadModules(char[][] filePaths, char[][] importPaths, char[][] strRegexps,
+  static void loadModules(char[][] filePaths, char[][] importPaths, char[][] strRegexps,
                                  bool IncludeUnlocatableModules, int recursionDepth,
                                  modDg mdg, importDg idg, out Module[] modules) {
     // Initialize regular expressions.
--- a/trunk/src/docgen/page/htmlwriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/page/htmlwriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -7,35 +7,39 @@
 import docgen.page.writer;
 import docgen.misc.textutils;
 import tango.io.FileConduit : FileConduit;
+import tango.text.convert.Sprint;
+import tango.io.FilePath;
 
 // TODO: this is mostly broken now
 
 /**
  * Writes a HTML document skeleton.
  */
-class HTMLWriter : AbstractPageWriter!(2, "html") {
+class HTMLWriter : AbstractPageWriter!("html") {
+  char[] styleSheetFile;
+  
   this(PageWriterFactory factory, OutputStream[] outputs) {
-    super(factory, outputs);
+    super(factory);
   }
 
   void generateTOC(Module[] modules) {
     // TODO
-    print.format(templates["toc"]);
+    print.format(getTemplate("toc"));
   }
 
   void generateModuleSection() {
     // TODO
-    print.format(templates["modules"]);
+    print.format(getTemplate("modules"));
   }
 
   void generateListingSection() {
     // TODO
-    print.format(templates["listings"]);
+    print.format(getTemplate("listings"));
   }
 
   void generateDepGraphSection() {
     // TODO
-    print.format(templates["dependencies"]);
+    print.format(getTemplate("dependencies"));
   }
 
   void generateIndexSection() { }
@@ -44,13 +48,49 @@
 
   void generateFirstPage() {
     print.format(
-      templates["firstpage"],
+      getTemplate("firstpage"),
       factory.options.templates.title,
-      factory.options.templates.copyright,
       factory.options.templates.versionString,
-      docgen_version
+      docgen_version,
+      factory.options.templates.copyright
     );
   }
+  
+  /**
+   * A hack for figuring out the stylesheet file name.
+   */
+  void generateCustomPage(char[] name, char[][] args ...) {
+    super.generateCustomPage(name, args);
+
+    if (name == "stylesheet") {
+      styleSheetFile = (new FilePath(
+        (cast(Object)outputs[0].conduit).toUtf8())).file();
+    }
+  }
+
+  /**
+   * Overrides the default template fetcher in order to
+   * provide a consistent layout for all pages.
+   */
+  override char[] getTemplate(char[] name) {
+    auto content = super.getTemplate(name);
+
+    foreach(pageName; [
+      "firstpage"[], "toc"[], "classes"[], "modules"[], "files"[],
+      "dependencies"[], "index"[], "lastpage"[] ]) {
+      if (name == pageName) {
+        auto sprint = new Sprint!(char)(5120);
+        return sprint.format(
+          super.getTemplate("pagetemplate"),
+          styleSheetFile,
+          name, // FIXME
+          content,
+          docgen_version);
+      }
+    }
+
+    return content;
+  }
 
   void addList(char[][] contents, bool ordered) {
     foreach(item; contents) {
--- a/trunk/src/docgen/page/latexwriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/page/latexwriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -10,14 +10,14 @@
 /**
  * Writes a LaTeX document skeleton.
  */
-class LaTeXWriter : AbstractPageWriter!(1, "latex") {
+class LaTeXWriter : AbstractPageWriter!("latex", 1) {
   this(PageWriterFactory factory, OutputStream[] outputs) {
     super(factory, outputs);
   }
 
   void generateFirstPage() {
     print.format(
-      templates["firstpage"],
+      getTemplate("firstpage"),
       factory.options.templates.paperSize,
       factory.options.templates.title,
       factory.options.templates.versionString,
--- a/trunk/src/docgen/page/plaintextwriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/page/plaintextwriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -13,29 +13,29 @@
 /**
  * Writes a plain text document skeleton.
  */
-class PlainTextWriter : AbstractPageWriter!(1, "plaintext") {
+class PlainTextWriter : AbstractPageWriter!("plaintext") {
   this(PageWriterFactory factory, OutputStream[] outputs) {
     super(factory, outputs);
   }
 
   void generateTOC(Module[] modules) {
     // TODO
-    print.format(templates["toc"]);
+    print.format(getTemplate("toc"));
   }
 
   void generateModuleSection() {
     // TODO
-    print.format(templates["modules"]);
+    print.format(getTemplate("modules"));
   }
 
   void generateListingSection() {
     // TODO
-    print.format(templates["listings"]);
+    print.format(getTemplate("listings"));
   }
 
   void generateDepGraphSection() {
     // TODO
-    print.format(templates["dependencies"]);
+    print.format(getTemplate("dependencies"));
   }
 
   void generateIndexSection() { }
--- a/trunk/src/docgen/page/writer.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/page/writer.d	Wed Oct 31 15:17:20 2007 +0200
@@ -13,18 +13,12 @@
 import tango.io.Stdout;
 import tango.io.Print: Print;
 import tango.text.convert.Layout : Layout;
+import tango.io.FilePath;
+import tango.io.FileScan;
 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
@@ -46,6 +40,11 @@
   void generateTOC(Module[] modules);
 
   /**
+   * Generates class documentation section.
+   */
+  void generateClassSection();
+
+  /**
    * Generates module documentation section.
    */
   void generateModuleSection();
@@ -71,15 +70,11 @@
   void generateLastPage();
 
   /**
-   * Generates a language definition file [LaTeX].
-   * Could be used for DTD too, I suppose.
+   * Generates a page using a custom template file.
+   *
+   * Some examples: style sheet, DTD files, makefiles.
    */
-  void generateLangDef();
-
-  /**
-   * Generates a makefile used for document post-processing.
-   */
-  void generateMakeFile();
+  void generateCustomPage(char[] name, char[][] args ...);
   
   // --- page components
   //
@@ -103,95 +98,116 @@
   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);
-}
+template AbstractPageWriter(char[] format, int n = 0) {
+  abstract class AbstractPageWriter : AbstractWriter!(PageWriterFactory, n), PageWriter {
+    protected:
 
-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;
-  }
+    char[][char[]] m_templates;
+    Print!(char) print;
 
-  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;
+    public:
          
     this(PageWriterFactory factory, OutputStream[] outputs) {
-      super(factory, outputs);
+      this(factory);
       setOutput(outputs);
-    
-      foreach(tpl; templateNames) {
-        templates[tpl] = loadTemplate(factory.options.templates.templateStyle, format, tpl);
-      }
     }
 
     void setOutput(OutputStream[] outputs) {
       this.outputs = outputs;
+      static if (n > 0)
+        assert(outputs.length == n, "Incorrect number of outputs");
 
       print = new Print!(char)(new Layout!(char), outputs[0]);
     }
 
     void generateTOC(Module[] modules) {
-      print.format(templates["toc"]);
+      print.format(getTemplate("toc"));
+    }
+
+    void generateClassSection() {
+      print.format(getTemplate("classes"));
     }
 
     void generateModuleSection() {
-      print.format(templates["modules"]);
+      print.format(getTemplate("modules"));
     }
 
     void generateListingSection() {
-      print.format(templates["listings"]);
+      print.format(getTemplate("listings"));
     }
 
     void generateDepGraphSection() {
-      print.format(templates["dependencies"]);
+      print.format(getTemplate("dependencies"));
     }
 
     void generateIndexSection() {
-      print.format(templates["index"]);
+      print.format(getTemplate("index"));
     }
 
     void generateLastPage() {
-      print.format(templates["lastpage"]);
-    }
-
-    void generateLangDef() {
-      print(templates["langdef"]);
+      print.format(getTemplate("lastpage"));
     }
 
-    void generateMakeFile() {
-      print(templates["makefile"]);
+    void generateCustomPage(char[] name, char[][] args ...) {
+      print.format(getTemplate(name), args);
     }
 
+    //---
 
     void addGraphics(char[] imageFile) {
-      print.format(templates["graphics"], imageFile);
+      print.format(getTemplate("graphics"), imageFile);
     }
     
     void addListing(char[] moduleName, char[] contents, bool inline) {
-      print.format(templates["listing"], moduleName, contents);
+      print.format(getTemplate("listing"), moduleName, contents);
+    }
+
+    protected:
+
+    this(PageWriterFactory factory) {
+      super(factory);
+    
+      auto scan = new FileScan();
+      scan(templateDir~factory.options.templates.templateStyle~"/"~format~"/", ".tpl");
+
+      debug Stdout(scan.files.length)(" template files loaded.\n");
+
+      foreach(tpl; scan.files) {
+        m_templates[tpl.name] = loadTemplate(tpl.toUtf8());
+      }
+    }
+
+    char[] getTemplate(char[] name) {
+      auto tpl = name in m_templates;
+      assert(tpl, "Error: template ["~format~"/"~name~"] not found!");
+      return *tpl;
+    }
+
+    char[] loadTemplate(char[] fn) {
+      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;
+    }
+    
+    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);
     }
   }
 }
--- a/trunk/src/docgen/page/xmlwriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/page/xmlwriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -13,29 +13,29 @@
 /**
  * TODO
  */
-class XMLWriter : AbstractPageWriter!(2, "xml") {
+class XMLWriter : AbstractPageWriter!("xml", 1) {
   this(PageWriterFactory factory, OutputStream[] outputs) {
     super(factory, outputs);
   }
 
   void generateTOC(Module[] modules) {
     // TODO
-    print.format(templates["toc"]);
+    print.format(getTemplate("toc"));
   }
 
   void generateModuleSection() {
     // TODO
-    print.format(templates["modules"]);
+    print.format(getTemplate("modules"));
   }
 
   void generateListingSection() {
     // TODO
-    print.format(templates["listings"]);
+    print.format(getTemplate("listings"));
   }
 
   void generateDepGraphSection() {
     // TODO
-    print.format(templates["dependencies"]);
+    print.format(getTemplate("dependencies"));
   }
 
   void generateIndexSection() { }
--- a/trunk/src/docgen/sourcelisting/htmlwriter.d	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/sourcelisting/htmlwriter.d	Wed Oct 31 15:17:20 2007 +0200
@@ -29,6 +29,7 @@
     auto bytesRead = inputStream.read (content);
     
     assert(bytesRead == inputStream.length, "Error reading source file");
+    assert(output == null);
     
     writer.addListing(
       moduleName,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/README	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,14 @@
+The docgen uses the following template file names by default
+
+firstpage
+toc
+classes
+modules
+listings
+dependencies
+index
+lastpage
+langdef
+makefile
+graphics
+listing
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/default/html/classes.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,2 @@
+<h2>Module {}</h2>
+<pre style="dcode">{}</pre>
--- a/trunk/src/docgen/templates/default/html/firstpage.tpl	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/templates/default/html/firstpage.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -1,16 +1,4 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>{0} Reference Manual</title>
-  <meta name="author" content="{1}" />
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-  <link rel="stylesheet" href="style.css" media="all" title="default" />
-  <link rel="stylesheet" href="print.css" media="print" />
-</head>
-<body>
 <h1>{0} Reference Manual</h1>
-<h2>{2}</h2>
-<h2>Generated by {3}</h2>
-<h3>{4}</h3>
-</body>
-</html>
+<h2>{1}</h2>
+<h2>Generated by {2}</h2>
+<h3>{3}</h3>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/default/html/listings.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,2 @@
+<h2>Module {}</h2>
+<pre style="dcode">{}</pre>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/default/html/makefile.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+for i in *.dot; do
+  F=`echo $i|sed 's/dot/png/'`
+  dot $i -Tpng -o$F
+done
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/default/html/modules.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,2 @@
+<h2>Module {}</h2>
+<pre style="dcode">{}</pre>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/default/html/pagetemplate.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,15 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>{1}</title>
+  <meta name="author" content="TODO" />
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <link rel="stylesheet" href="{0}" media="all" title="default" />
+</head>
+<body>
+<h1>{1}</h1>
+{2}
+<hr />
+<p>Generated by {3}</p>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/default/html/stylesheet.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,3 @@
+body {{
+background: #ccc;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/docgen/templates/default/latex/classes.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -0,0 +1,2 @@
+\chapter{{Class documentation}
+\input{{classes}
--- a/trunk/src/docgen/templates/default/latex/makefile.tpl	Tue Oct 30 20:27:24 2007 +0100
+++ b/trunk/src/docgen/templates/default/latex/makefile.tpl	Wed Oct 31 15:17:20 2007 +0200
@@ -1,10 +1,10 @@
 #!/bin/sh
 
 for i in *.dot; do
-  F=`echo $i|sed 's/dot/pdf/'`
-  dot $i -Tpdf -o$F
+  F=`echo $i|sed 's/dot/{2}/'`
+  dot $i -T{2} -o$F
 done
 
-pdflatex document.tex
+pdflatex {1}
 makeindex document
-pdflatex document.tex
+pdflatex {1}