From be5bbdcb328692ff583d15ec71adbb101068e4b3 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Thu, 12 May 2011 14:40:19 -0400 Subject: [PATCH] Another overhaul of doc generation. - Added generic facility for pre- and post-processor scripts to be run. - Added support utility script for inclusion by processors. - Totally overhauled css to make the pages more readable (I hope). - Fixed some doc errors in CPTableView. - Don't generate XML. - Added colorize() and colorPrint() functions to common.jake. - Added docs-no-frame task for generating docs without a sidebar frame. --- AppKit/CPTableView.j | 16 +- Jakefile | 73 +- Tools/Documentation/Cappuccino.doxygen | 4 +- Tools/Documentation/cleanup_headers | 3 - Tools/Documentation/cleanup_markdown.sh | 5 - Tools/Documentation/doxygen.css | 783 ++++++++++++++++++ Tools/Documentation/make_headers.sh | 25 - .../postprocess/001.cleanup_headers.sh | 20 + .../postprocess/002.transform_text.sh | 27 + .../preprocess/001.markdown_readme.sh | 21 + .../preprocess/002.make_headers.sh | 34 + .../003.make_headers.rb} | 6 + Tools/Documentation/process_markdown.sh | 7 - Tools/Documentation/processor_setup.sh | 22 + common.jake | 24 +- 15 files changed, 995 insertions(+), 75 deletions(-) delete mode 100755 Tools/Documentation/cleanup_headers delete mode 100755 Tools/Documentation/cleanup_markdown.sh create mode 100644 Tools/Documentation/doxygen.css delete mode 100755 Tools/Documentation/make_headers.sh create mode 100755 Tools/Documentation/postprocess/001.cleanup_headers.sh create mode 100755 Tools/Documentation/postprocess/002.transform_text.sh create mode 100755 Tools/Documentation/preprocess/001.markdown_readme.sh create mode 100755 Tools/Documentation/preprocess/002.make_headers.sh rename Tools/Documentation/{make_headers => preprocess/003.make_headers.rb} (95%) delete mode 100755 Tools/Documentation/process_markdown.sh create mode 100755 Tools/Documentation/processor_setup.sh diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 777124b60..018b8ab45 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -743,9 +743,10 @@ NOT YET IMPLEMENTED /*! Returns an enumerated value for the selection highlight style. -
+
 
     Valid values are:
+
         CPTableViewSelectionHighlightStyleNone
         CPTableViewSelectionHighlightStyleRegular
         CPTableViewSelectionHighlightStyleSourceList
@@ -757,11 +758,11 @@ NOT YET IMPLEMENTED
 }
 
 /*!
-
     Sets the selection highlight style to an enumerated value.
     This value can also affect the way the tableview draws feedback when the user is dragging.
 
     Valid values are:
+
         CPTableViewSelectionHighlightStyleNone
         CPTableViewSelectionHighlightStyleRegular
         CPTableViewSelectionHighlightStyleSourceList
@@ -803,10 +804,11 @@ NOT YET IMPLEMENTED
 }
 
 /*!
-
+
     Sets the highlight gradient for a row or column selection
     This is specific to the
     @param aDictionary a CPDictionary expects three keys to be set:
+
         CPSourceListGradient which is a CGGradient
         CPSourceListTopLineColor which is a CPColor
         CPSourceListBottomLineColor which is a CPColor
@@ -820,8 +822,8 @@ NOT YET IMPLEMENTED
 }
 
 /*!
-
     Returns a dictionary of containing the keys:
+
     CPSourceListGradient
     CPSourceListTopLineColor
     CPSourceListBottomLineColor
@@ -1994,10 +1996,10 @@ NOT YET IMPLEMENTED
 }
 
 /*!
-
     Sets the column autoresizing style of the receiver to a given style.
 
     @param aStyle the column autoresizing style for the receiver. Valid values are:
+
         CPTableViewNoColumnAutoresizing
         CPTableViewUniformColumnAutoresizingStyle
         CPTableViewLastColumnOnlyAutoresizingStyle
@@ -2920,11 +2922,11 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
 }
 
 /*!
-
     Sets the feedback style for when the table is the destination of a drag operation.
     This style is used to determine how the tableview looks when it is the receiver of a drag and drop operation.
 
     Can be:
+
         CPTableViewDraggingDestinationFeedbackStyleNone
         CPTableViewDraggingDestinationFeedbackStyleRegular
         CPTableViewDraggingDestinationFeedbackStyleSourceList
@@ -2937,10 +2939,10 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
 }
 
 /*!
-
     Returns the tableview dragging destination feedback style.
 
     Can be:
+
         CPTableViewDraggingDestinationFeedbackStyleNone
         CPTableViewDraggingDestinationFeedbackStyleRegular
         CPTableViewDraggingDestinationFeedbackStyleSourceList
diff --git a/Jakefile b/Jakefile
index 9716c9f58..be6eff3d5 100644
--- a/Jakefile
+++ b/Jakefile
@@ -46,8 +46,8 @@ task ("install", ["CommonJS"], function()
     // FIXME: require("narwhal/tusk/install").install({}, $COMMONJS);
     // Doesn't work due to some weird this.print business.
     if (OS.system(["tusk", "install", "--force", $BUILD_CJS_OBJECTIVE_J, $BUILD_CJS_CAPPUCCINO])) {
-        stream.print("\0red(Installation failed, possibly because you do not have permissions.\0)");
-        stream.print("\0red(Try re-running using '\0yellow(jake sudo-install\0)'.\0)");
+        colorPrint("Installation failed, possibly because you do not have permissions.", "red");
+        colorPrint("Try re-running using '" + colorize("jake sudo-install", "yellow") + "'.", "red");
         OS.exit(1); //rake abort if ($? != 0)
     }
 });
@@ -82,6 +82,18 @@ $DOCUMENTATION_BUILD = FILE.join($BUILD_DIR, "Documentation");
 task ("docs", ["documentation"]);
 
 task ("documentation", function()
+{
+    generateDocs(false);
+});
+
+task ("docs-no-frame", ["documentation-no-frame"]);
+
+task ("documentation-no-frame", function()
+{
+    generateDocs(true);
+});
+
+function generateDocs(/* boolean */ noFrame)
 {
     // try to find a doxygen executable in the PATH;
     var doxygen = executableExists("doxygen");
@@ -100,31 +112,47 @@ task ("documentation", function()
 
     if (!doxygen || !FILE.exists(doxygen))
     {
-        stream.print("\0yellow(Doxygen not installed, skipping documentation generation.\0)");
+        colorPrint("Doxygen not installed, skipping documentation generation.", "yellow");
         return;
     }
 
-    stream.print("\0green(Using " + doxygen + " for doxygen binary.\0)");
+    colorPrint("Using " + doxygen + " for doxygen binary.", "green");
+    colorPrint("Pre-processing source files...", "green");
 
-    // Also need Markdown to proccess README file (`brew install Markdown` on the Mac).
-    var markdown = executableExists("markdown")
-    if (!markdown || !FILE.exists(markdown))
+    var documentationDir = FILE.canonical(FILE.join("Tools", "Documentation")),
+        processors = FILE.glob(FILE.join(documentationDir, "preprocess/*"));
+
+    for (var i = 0; i < processors.length; ++i)
+        if (OS.system([processors[i], documentationDir]))
+            return;
+
+    if (noFrame)
     {
-        stream.print("\0yellow(Markdown not installed, skipping documentation generation.\0)");
-        return;
+        // Back up the default settings, turn off the treeview
+        if (OS.system(["sed", "-i", ".bak", "s/GENERATE_TREEVIEW.*=.*YES/GENERATE_TREEVIEW = NO/", FILE.join(documentationDir, "Cappuccino.doxygen")]))
+            return;
     }
+    else if (FILE.exists(FILE.join(documentationDir, "Cappuccino.doxygen.bak")))
+        mv(FILE.join(documentationDir, "Cappuccino.doxygen.bak"), FILE.join(documentationDir, "Cappuccino.doxygen"));
 
-    stream.print("\0green(Using " + markdown + " for Markdown binary.\0)");
+    var doxygenDidSucceed = !OS.system([doxygen, FILE.join(documentationDir, "Cappuccino.doxygen")]);
 
-    var documentationDir = FILE.join("Tools", "Documentation");
+    // Restore the original doxygen settings
+    if (FILE.exists(FILE.join(documentationDir, "Cappuccino.doxygen.bak")))
+        mv(FILE.join(documentationDir, "Cappuccino.doxygen.bak"), FILE.join(documentationDir, "Cappuccino.doxygen"));
 
-    if (OS.system([FILE.join(documentationDir, "process_markdown.sh"), markdown]))
-        OS.exit(1); //rake abort if ($? != 0)
+    colorPrint("Post-processing generated documentation...", "green");
 
-    if (OS.system([FILE.join(documentationDir, "make_headers.sh")]))
-        OS.exit(1); //rake abort if ($? != 0)
+    processors = FILE.glob(FILE.join(documentationDir, "postprocess/*"));
 
-    if (!OS.system([doxygen, FILE.join(documentationDir, "Cappuccino.doxygen")]))
+    for (var i = 0; i < processors.length; ++i)
+        if (OS.system([processors[i], documentationDir, FILE.join("Documentation", "html")]))
+        {
+            rm_rf("Documentation");
+            return;
+        }
+
+    if (doxygenDidSucceed)
     {
         if (!FILE.isDirectory($BUILD_DIR))
             FILE.mkdirs($BUILD_DIR);
@@ -133,10 +161,7 @@ task ("documentation", function()
         mv("debug.txt", FILE.join("Documentation", "debug.txt"));
         mv("Documentation", $DOCUMENTATION_BUILD);
     }
-
-    OS.system(["ruby", FILE.join(documentationDir, "cleanup_headers")]);
-    OS.system([FILE.join(documentationDir, "cleanup_markdown.sh")]);
-});
+}
 
 // Downloads
 
@@ -312,7 +337,7 @@ function pushPackage(path, remote, branch)
 
     var packagePath = pushPackagesPath.join(remote.replace(/[^\w]/g, "_"));
 
-    stream.print("Pushing \0blue(" + path + "\0) to "+branch+" of \0blue(" + remote + "\0)");
+    stream.print("Pushing " + colorize(path, "blue") + " to " + branch + " of " + colorize(remote, "blue"));
 
     if (packagePath.isDirectory())
         OS.system(buildCmd([["cd", packagePath], ["git", "fetch"]]));
@@ -336,9 +361,9 @@ function pushPackage(path, remote, branch)
 
     var pkg = JSON.parse(packagePath.join("package.json").read({ charset : "UTF-8" }));
 
-    stream.print("    Version:   \0purple(" + pkg["version"] + "\0)");
-    stream.print("    Revision:  \0purple(" + pkg["cappuccino-revision"] + "\0)");
-    stream.print("    Timestamp: \0purple(" + pkg["cappuccino-timestamp"] + "\0)");
+    stream.print("    Version:   " + colorize(pkg["version"], "purple"));
+    stream.print("    Revision:  " + colorize(pkg["cappuccino-revision"], "purple"));
+    stream.print("    Timestamp: " + colorize(pkg["cappuccino-timestamp"], "purple"));
 
     var cmd = [
         ["cd", packagePath],
diff --git a/Tools/Documentation/Cappuccino.doxygen b/Tools/Documentation/Cappuccino.doxygen
index fc9f5524a..50222fb25 100644
--- a/Tools/Documentation/Cappuccino.doxygen
+++ b/Tools/Documentation/Cappuccino.doxygen
@@ -679,7 +679,7 @@ EXCLUDE_SYMBOLS        = _*
 # directories that contain example code fragments that are included (see
 # the \include command).
 
-EXAMPLE_PATH           = ./README.html \
+EXAMPLE_PATH           = ./Tools/Documentation/README.html \
                          ./LICENSE
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
@@ -845,7 +845,7 @@ HTML_FOOTER            =
 # the style sheet file to the HTML output directory, so don't put your own
 # stylesheet in the HTML output directory as well, or it will be erased!
 
-HTML_STYLESHEET        =
+HTML_STYLESHEET        = ./Tools/Documentation/doxygen.css
 
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
 # Doxygen will adjust the colors in the stylesheet and background images
diff --git a/Tools/Documentation/cleanup_headers b/Tools/Documentation/cleanup_headers
deleted file mode 100755
index bed3a70fb..000000000
--- a/Tools/Documentation/cleanup_headers
+++ /dev/null
@@ -1,3 +0,0 @@
-#! /bin/sh
-rm -rf AppKit.doc
-rm -rf Foundation.doc
diff --git a/Tools/Documentation/cleanup_markdown.sh b/Tools/Documentation/cleanup_markdown.sh
deleted file mode 100755
index 35db2f0ad..000000000
--- a/Tools/Documentation/cleanup_markdown.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-#
-# NOTE: The working directory should be the main capp directory when this script is run
-
-rm README.html
diff --git a/Tools/Documentation/doxygen.css b/Tools/Documentation/doxygen.css
new file mode 100644
index 000000000..5951918c7
--- /dev/null
+++ b/Tools/Documentation/doxygen.css
@@ -0,0 +1,783 @@
+/* The standard CSS for doxygen */
+
+body, table, td, div, p, dl, dd, dt, em {
+    margin: 0;
+    padding: 0;
+}
+
+body, table, div, p {
+    font: 13px normal "Lucida Grande", Helvetica, Arial, Geneva, sans-serif;
+}
+
+table {
+    border-collapse: collapse;
+}
+
+pre, code {
+    font-family: Courier;
+}
+
+p {
+    margin: 1em 0;
+}
+
+dl {
+    margin-bottom: 1em;
+}
+
+dd {
+    margin: .25em 1em;
+}
+
+ul {
+    list-style-type: square;
+}
+
+li {
+    margin: 0;
+    padding: .2em 0;
+}
+
+em {
+    font-style: normal;
+    color: #7B509F;
+}
+
+/* @group Heading Levels */
+
+h1, h2, h3, h4 {
+    font-family: "Lucida Grande", Helvetica, Arial, Geneva, sans-serif;
+    margin: 2em 0 1em 0;
+}
+
+h1 {
+	font-size: 150%;
+}
+
+h2 {
+	font-size: 120%;
+}
+
+h3 {
+	font-size: 100%;
+}
+
+dt {
+	font-weight: bold;
+}
+
+div.multicol {
+	-moz-column-gap: 1em;
+	-webkit-column-gap: 1em;
+	-moz-column-count: 3;
+	-webkit-column-count: 3;
+}
+
+p.startli, p.startdd, p.starttd {
+	margin-top: 2px;
+}
+
+p.endli {
+	margin-bottom: 0px;
+}
+
+p.enddd {
+	margin-bottom: 4px;
+}
+
+p.endtd {
+	margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+	font-weight: bold;
+}
+
+span.legend {
+        font-size: 70%;
+        text-align: center;
+}
+
+h3.version {
+        font-size: 90%;
+        text-align: center;
+}
+
+div.qindex, div.navtab {
+	background-color: #ECEFF6;
+	border: 1px solid #A4B5D6;
+	text-align: center;
+	margin: 2px;
+	padding: 2px;
+}
+
+div.qindex, div.navpath {
+	width: 100%;
+	line-height: 140%;
+}
+
+div.qindex+table td {
+    padding: .2em 0;
+}
+
+div.navtab {
+	margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+	color: #2F4697;
+	font-weight: normal;
+	text-decoration: none;
+}
+
+.contents a:visited {
+}
+
+a:hover {
+	text-decoration: underline;
+	/* background-color: #D5E8FF; */
+}
+
+a.qindex {
+	font-weight: bold;
+}
+
+a.qindexHL {
+	font-weight: bold;
+	background-color: #9DAFD3;
+	color: #ffffff;
+	border: 1px double #879DC9;
+}
+
+.contents a.qindexHL:visited {
+        color: #ffffff;
+}
+
+a.el {
+	padding: 1px;
+}
+
+a.elRef {
+}
+
+a.code {
+	color: #4765A1;
+}
+
+a.codeRef {
+	color: #4765A1;
+}
+
+/* @end */
+
+dl.el {
+	margin-left: -1cm;
+}
+
+.fragment {
+	font-family: Courier, monospace, fixed;
+	font-size: 105%;
+}
+
+pre.fragment {
+    margin-top: 1em;
+	border: 1px solid #C5CFE5;
+	/* background-color: #FBFCFD; */
+	padding: 4px 6px;
+	overflow: auto;
+	word-wrap: break-word;
+	font-size: 9pt;
+	line-height: 125%;
+}
+
+div.ah {
+	background-color: black;
+	font-weight: bold;
+	color: #ffffff;
+	margin-bottom: 3px;
+	margin-top: 3px;
+	padding: 0.2em;
+	border: solid thin #333;
+	border-radius: 0.5em;
+	-webkit-border-radius: .5em;
+	-moz-border-radius: .5em;
+	-webkit-box-shadow: 2px 2px 3px #999;
+	-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+	background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+	background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.groupHeader {
+	margin-left: 16px;
+	margin-top: 12px;
+	margin-bottom: 6px;
+	font-weight: bold;
+}
+
+div.groupText {
+	margin-left: 16px;
+	font-style: italic;
+}
+
+body {
+	background: white;
+	color: black;
+        margin: 0;
+}
+
+div.contents {
+    margin: 1.5em;
+}
+
+/* If the first element of the contents is a table, give it some space */
+div.contents > table {
+    margin-top: 1.5em;
+}
+
+td.indexkey {
+    font-family: Consolas, "Lucida Console";
+	border-bottom: 1px solid #eee;
+	padding: .25em 0 .25em .5em;
+}
+
+table tr.indexkey:first-child td {
+    padding-top: 1.5em;
+}
+
+td.indexvalue {
+    font-family: Consolas, "Lucida Console";
+	border-bottom: 1px solid #eee;
+	padding: .25em 0 .25em .5em;
+}
+
+table tr.memlist:first-child td {
+    padding-top: 1.5em;
+}
+
+table tr.memlist > td {
+    padding-left: .5em;
+}
+
+tr.memlist td {
+    font-family: Consolas, "Lucida Console";
+	padding: .25em 0;
+	border-bottom: 1px solid #eee;
+}
+
+/* Don't show the [static] column in full member list */
+tr.memlist td code {
+    display: none;
+}
+
+p.formulaDsp {
+	text-align: center;
+}
+
+img.formulaDsp {
+	
+}
+
+img.formulaInl {
+	vertical-align: middle;
+}
+
+div.center {
+	text-align: center;
+        margin-top: 0px;
+        margin-bottom: 0px;
+        padding: 0px;
+}
+
+div.center img {
+	border: 0px;
+}
+
+address.footer {
+	text-align: right;
+	padding-right: 12px;
+}
+
+img.footer {
+	border: 0px;
+	vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+	color: #008000
+}
+
+span.keywordtype {
+	color: #604020
+}
+
+span.keywordflow {
+	color: #e08000
+}
+
+span.comment {
+	color: #A085E4
+}
+
+span.preprocessor {
+	color: #806020
+}
+
+span.stringliteral {
+	color: #002080
+}
+
+span.charliteral {
+	color: #008080
+}
+
+span.vhdldigit { 
+	color: #ff00ff 
+}
+
+span.vhdlchar { 
+	color: #000000 
+}
+
+span.vhdlkeyword { 
+	color: #700070 
+}
+
+span.vhdllogic { 
+	color: #ff0000 
+}
+
+/* @end */
+
+/*
+.search {
+	color: #003399;
+	font-weight: bold;
+}
+
+form.search {
+	margin-bottom: 0px;
+	margin-top: 0px;
+}
+
+input.search {
+	font-size: 75%;
+	color: #000080;
+	font-weight: normal;
+	background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+	font-size: 75%;
+}
+
+.dirtab {
+	padding: 4px;
+	border-collapse: collapse;
+	border: 1px solid #A4B5D6;
+}
+
+th.dirtab {
+	background: #ECEFF6;
+	font-weight: bold;
+}
+
+hr {
+	height: 0px;
+	border: none;
+	border-top: 2px solid #ddd;
+	margin: 1em 0;
+}
+
+hr.footer {
+	height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+    font-family: Consolas, "Lucida Console";
+	border-spacing: 0px;
+	padding: 0px;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+	border: none;
+	margin: 4px;
+	padding: .25em 0;
+}
+
+.mdescLeft, .mdescRight {
+	color: #555;
+	padding-bottom: 1em;
+}
+
+.memItemLeft, .memItemRight, .memTemplParams {
+}
+
+.memItemLeft, .memTemplItemLeft {
+        white-space: nowrap;
+}
+
+.memTemplParams {
+	color: #4765A1;
+    white-space: nowrap;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+	font-size: 80%;
+	color: #4765A1;
+	font-weight: normal;
+	margin-left: 3px;
+}
+
+.memnav {
+	background-color: #ECEFF6;
+	border: 1px solid #A4B5D6;
+	text-align: center;
+	margin: 2px;
+	margin-right: 15px;
+	padding: 2px;
+}
+
+.memitem {
+	padding: 0;
+	margin-top: .5em;
+}
+
+.memname {
+    white-space: nowrap;
+    font: bold 105% Consolas, "Lucida Console";
+    margin: .25em 0 0 .25em;
+}
+
+.memproto {
+    margin-top: 2em;
+    border-top: 1px solid #ccc;
+    padding: 6px 0px 6px 0px;
+    color: #253554;
+    background-color: #f6f6f6;
+    font-family: Consolas, "Lucida Console";
+    font-weight: bold;
+}
+
+.memdoc {
+    padding: .5em .5em 0;
+}
+
+.memdoc > p {
+    margin-top: 0;
+}
+
+.memdoc dl dd td {
+    padding-right: 1em;
+}
+
+.memdoc dl dd table tr td:first-child {
+    padding-right: 0;
+}
+
+.memdoc dl.return dd {
+    margin-left: 1.25em;
+}
+
+.memdoc dl dd td em {
+    font-family: Consolas, "Lucida Console";
+    font-weight: bold;
+	white-space: nowrap;    
+}
+
+.paramkey {
+	text-align: right;
+}
+
+.paramtype {
+	white-space: nowrap;
+	color: #DD6800;
+}
+
+.paramname {
+	color: #602020;
+	white-space: nowrap;
+}
+.paramname em {
+	font-style: normal;
+}
+
+/* @end */
+
+/* @group Directory (tree) */
+
+/* for the tree view */
+
+.ftvtree {
+	font-family: sans-serif;
+	margin: 0px;
+}
+
+/* these are for tree view when used as main index */
+
+.directory {
+	font-size: 9pt;
+	font-weight: bold;
+	margin: 5px;
+}
+
+.directory h3 {
+	margin: 0px;
+	margin-top: 1em;
+	font-size: 11pt;
+}
+
+/*
+    The following two styles can be used to replace the root node title
+    with an image of your choice.  Simply uncomment the next two styles,
+    specify the name of your image and be sure to set 'height' to the
+    proper pixel height of your image.
+*/
+
+/*
+.directory h3.swap {
+	height: 61px;
+	background-repeat: no-repeat;
+	background-image: url("yourimage.gif");
+}
+.directory h3.swap span {
+	display: none;
+}
+*/
+
+.directory > h3 {
+	margin-top: 0;
+}
+
+.directory p {
+	margin: 0px;
+	white-space: nowrap;
+}
+
+.directory div {
+	display: none;
+	margin: 0px;
+}
+
+.directory img {
+	vertical-align: -30%;
+}
+
+/* these are for tree view when not used as main index */
+
+.directory-alt {
+	font-size: 100%;
+	font-weight: bold;
+}
+
+.directory-alt h3 {
+	margin: 0px;
+	margin-top: 1em;
+	font-size: 11pt;
+}
+
+.directory-alt > h3 {
+	margin-top: 0;
+}
+
+.directory-alt p {
+	margin: 0px;
+	white-space: nowrap;
+}
+
+.directory-alt div {
+	display: none;
+	margin: 0px;
+}
+
+.directory-alt img {
+	vertical-align: -30%;
+}
+
+/* @end */
+
+div.dynheader {
+        margin-top: 8px;
+}
+
+address {
+	font-style: normal;
+	color: #2B3D61;
+}
+
+table.doxtable {
+	border-collapse:collapse;
+}
+
+table.doxtable td, table.doxtable th {
+	border: 1px solid #2E4167;
+	padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+	background-color: #384F7E;
+	color: #FFFFFF;
+	font-size: 110%;
+	padding-bottom: 4px;
+	padding-top: 5px;
+	text-align:left;
+}
+
+.tabsearch {
+	top: 0px;
+	left: 10px;
+	height: 36px;
+	background-image: url('tab_b.png');
+	z-index: 101;
+	overflow: hidden;
+	font-size: 13px;
+}
+
+.navpath ul
+{
+	font-size: 11px;
+	background-image:url('tab_b.png');
+	background-repeat:repeat-x;
+	height:30px;
+	line-height:30px;
+	color:#8BA0CB;
+	border:solid 1px #C2CEE4;
+	overflow:hidden;
+	margin:0px;
+	padding:0px;
+}
+
+.navpath li
+{
+	list-style-type:none;
+	float:left;
+	padding-left:10px;
+	padding-right: 15px;
+	background-image:url('bc_s.png');
+	background-repeat:no-repeat;
+	background-position:right;
+	color:#374E7C;
+}
+
+.navpath a
+{
+	height:32px;
+	display:block;
+	text-decoration: none;
+	outline: none;
+}
+
+.navpath a:hover
+{
+	color:#6985BC;
+}
+
+div.summary
+{
+	float: right;
+	font-size: 90%;
+	padding-right: 5px;
+	width: 50%;
+	text-align: right;
+}       
+
+div.summary a
+{
+	white-space: nowrap;
+}
+
+div.header
+{
+    background-image:url('nav_h.png');
+    background-repeat:repeat-x;
+	background-color: #F9FAFC;
+	margin: 0;
+	padding: 1.5em;
+	border-bottom: 1px solid #C5CFE5;
+}
+
+div.headertitle h1 {
+    margin: 0;
+}
+
+/* @group Tabs */
+
+.tabs, .tabs2, .tabs3 {
+    background-image: url('tab_b.png');
+    width: 100%;
+    z-index: 101;
+    font-size: 100%;
+}
+
+.tabs2 {
+    font-size: 90%;
+}
+
+.tabs3 {
+    font-size: 75%;
+}
+
+.tablist {
+    margin: 0;
+    padding: 0;
+    display: table;
+}
+
+.tablist li {
+    float: left;
+    display: table-cell;
+    background-image: url('tab_b.png');
+    line-height: 36px;
+    list-style: none;
+    padding: 0;
+}
+
+.tablist a {
+    display: block;
+    padding: 0 20px;
+    font-weight: bold;
+    background-image:url('tab_s.png');
+    background-repeat:no-repeat;
+    background-position:right;
+    color: #293A5C;
+    text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+    text-decoration: none;
+    outline: none;
+}
+
+.tabs3 .tablist a {
+    padding: 0 10px;
+}
+
+.tablist a:hover {
+    background-image: url('tab_h.png');
+    background-repeat:repeat-x;
+    color: #fff;
+    text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+    text-decoration: none;
+}
+
+.tablist li.current a {
+    background-image: url('tab_a.png');
+    background-repeat:repeat-x;
+    color: #fff;
+    text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+}
+
+/* @end */
diff --git a/Tools/Documentation/make_headers.sh b/Tools/Documentation/make_headers.sh
deleted file mode 100755
index 0d8cf3a4b..000000000
--- a/Tools/Documentation/make_headers.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh
-#
-# NOTE: The working directory should be the main capp directory when this script is run
-
-if [ -d AppKit.doc ]; then
-    rm -rf AppKit.doc
-fi
-
-if [ -d Foundation.doc ]; then
-    rm -rf Foundation.doc
-fi
-
-echo "Processing source files..."
-bsdtar cf AppKit.doc.tar --exclude='_*' -s /^AppKit/AppKit.doc/ AppKit/*.j AppKit/**/*.j
-bsdtar xf AppKit.doc.tar
-rm AppKit.doc.tar
-
-bsdtar cf Foundation.doc.tar --exclude='_*' -s /^Foundation/Foundation.doc/ Foundation/*.j Foundation/**/*.j
-bsdtar xf Foundation.doc.tar
-rm Foundation.doc.tar
-
-find AppKit.doc -name *.j -exec sed -e '/@import.*/ d' -i '' {} \;
-find Foundation.doc -name *.j -exec sed -e '/@import.*/ d' -i '' {} \;
-
-exec Tools/Documentation/make_headers
diff --git a/Tools/Documentation/postprocess/001.cleanup_headers.sh b/Tools/Documentation/postprocess/001.cleanup_headers.sh
new file mode 100755
index 000000000..bbb23414c
--- /dev/null
+++ b/Tools/Documentation/postprocess/001.cleanup_headers.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# NOTE: The working directory should be the main capp directory when this script is run
+#
+# $1 Cappuccino Tools/Documentation directory
+# $2 Generated documentation directory
+
+# Do this if you want to use the utility functions
+source "$1"/processor_setup.sh
+
+# Cleanup the files we generated to feed to doxygen
+processor_msg "Cleaning up generated header files..."
+
+if [ -d AppKit.doc ]; then
+    rm -rf AppKit.doc
+fi
+
+if [ -d Foundation.doc ]; then
+    rm -rf Foundation.doc
+fi
diff --git a/Tools/Documentation/postprocess/002.transform_text.sh b/Tools/Documentation/postprocess/002.transform_text.sh
new file mode 100755
index 000000000..850114903
--- /dev/null
+++ b/Tools/Documentation/postprocess/002.transform_text.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# NOTE: The working directory should be the main capp directory when this script is run
+#
+# $1 Cappuccino Tools/Documentation directory
+# $2 Generated documentation directory
+
+# Do this if you want to use the utility functions
+source "$1"/processor_setup.sh
+
+# The following transforms are performed:
+# - Strip useless "[implementation]" littering the docs
+# - Change "Static Public Member Functions" to "Class Methods"
+# - Change "Public Member Functions" to "Instance Methods"
+
+if [ ! -d "$2" ]; then
+    exit 0
+fi
+
+processor_msg 'Massaging text...'
+
+sed -i '' -E \
+-e 's/ \[implementation\]<\/code>/\ /g'     \
+-e 's/Static Public Member Functions/Class Methods/g'  \
+-e 's/Public Member Functions/Instance Methods/g'      \
+-e 's/(AppKit|Foundation)\.doc/\1/g'               \
+"$2"/*.html
diff --git a/Tools/Documentation/preprocess/001.markdown_readme.sh b/Tools/Documentation/preprocess/001.markdown_readme.sh
new file mode 100755
index 000000000..72a040eff
--- /dev/null
+++ b/Tools/Documentation/preprocess/001.markdown_readme.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# NOTE: The working directory should be the main capp directory when this script is run
+#
+# $1 Cappuccino documentation directory
+
+# Do this if you want to use the utility functions
+source "$1"/processor_setup.sh
+
+markdown=`which markdown`
+
+if [ -n "$markdown" ]; then
+    processor_msg "Markdown main page..."
+    "$markdown" README.markdown > "$1"/README.html
+else
+    processor_msg "markdown binary is not installed, documentation cannot be generated." "red"
+    echo "On Mac OS X, install brew with the following command line:"
+    echo '  ruby -e "$(curl -fsSL https://gist.github.com/raw/323731/install_homebrew.rb)"'
+    echo "Then use 'brew install markdown' from the command line to install markdown."
+    exit 1
+fi
diff --git a/Tools/Documentation/preprocess/002.make_headers.sh b/Tools/Documentation/preprocess/002.make_headers.sh
new file mode 100755
index 000000000..f4e43fef3
--- /dev/null
+++ b/Tools/Documentation/preprocess/002.make_headers.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# NOTE: The working directory should be the main capp directory when this script is run
+#
+# $1 Cappuccino documentation directory
+
+# Do this if you want to use the utility functions
+source "$1"/processor_setup.sh
+
+if [ -d AppKit.doc ]; then
+    rm -rf AppKit.doc
+fi
+
+if [ -d Foundation.doc ]; then
+    rm -rf Foundation.doc
+fi
+
+# Tar all of the AppKit/*.j files, excluding any files that begin with "_", and replace
+# "AppKit" with "AppKit.doc" in the files path within the archive. Then unarchive the result.
+# This turns out to  be the quickest way I could find to get the correct files and rename them.
+processor_msg "Collecting source files..."
+bsdtar cf AppKit.doc.tar --exclude='_*' -s /^AppKit/AppKit.doc/ AppKit/*.j AppKit/**/*.j
+bsdtar xf AppKit.doc.tar
+rm AppKit.doc.tar
+
+# Now do the same thing with Foundation files.
+bsdtar cf Foundation.doc.tar --exclude='_*' -s /^Foundation/Foundation.doc/ Foundation/*.j Foundation/**/*.j
+bsdtar xf Foundation.doc.tar
+rm Foundation.doc.tar
+
+# Remove @import from the source files, doxygen doesn't know what to do with them
+processor_msg "Removing @import from source files..."
+find AppKit.doc -name *.j -exec sed -e '/@import.*/ d' -i '' {} \;
+find Foundation.doc -name *.j -exec sed -e '/@import.*/ d' -i '' {} \;
diff --git a/Tools/Documentation/make_headers b/Tools/Documentation/preprocess/003.make_headers.rb
similarity index 95%
rename from Tools/Documentation/make_headers
rename to Tools/Documentation/preprocess/003.make_headers.rb
index 1dbe51d8f..327df1ea0 100755
--- a/Tools/Documentation/make_headers
+++ b/Tools/Documentation/preprocess/003.make_headers.rb
@@ -1,4 +1,9 @@
 #! /usr/bin/env ruby
+#
+# NOTE: The working directory should be the main capp directory when this script is run
+#
+# $1 Cappuccino documentation directory
+
 
 ACCESSOR_GET_TEMPLATE = <README.html
diff --git a/Tools/Documentation/processor_setup.sh b/Tools/Documentation/processor_setup.sh
new file mode 100755
index 000000000..1d4ed7a5f
--- /dev/null
+++ b/Tools/Documentation/processor_setup.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+function processor_msg ()
+{
+    color=${2:-cyan}
+    
+    case "$color" in
+        black           ) code="30";;
+        red             ) code="31";;
+        green           ) code="32";;
+        yellow          ) code="33";;
+        blue            ) code="34";;
+        purple|magenta  ) code="35";;
+        cyan            ) code="36";;
+        white           ) code="37";;
+        *               ) code="36";;
+    esac
+    
+    echo -e "\033[${code}m$1\033[0m"
+}
+
+export -f processor_msg
diff --git a/common.jake b/common.jake
index 2fec57d27..12fc19caa 100644
--- a/common.jake
+++ b/common.jake
@@ -456,12 +456,12 @@ global.copyManPage = function(/*String*/ name, /*int*/ section)
     }
 }
 
-global.xcodebuildCanListSDKs = function ()
+global.xcodebuildCanListSDKs = function()
 {
     return OS.system("xcodebuild -showsdks > /dev/null 2>&1") == 0;
 }
 
-global.xcodebuildHasTenPointFiveSDK = function ()
+global.xcodebuildHasTenPointFiveSDK = function()
 {
     if (xcodebuildCanListSDKs())
         return OS.system("xcodebuild -showsdks | grep 'macosx10.5' > /dev/null 2>&1") == 0;
@@ -469,6 +469,26 @@ global.xcodebuildHasTenPointFiveSDK = function ()
     return FILE.exists(FILE.join("/", "Developer", "SDKs", "MacOSX10.5.sdk"));
 }
 
+global.colorize = function(/* String */ message, /* String */ color)
+{
+    var matches = color.match(/(bold(?: |\+))?(.+)/);
+
+    if (!matches)
+        return;
+
+    message = "\0" + matches[2] + "(" + message + "\0)";
+
+    if (matches[1])
+        message = "\0bold(" + message + "\0)";
+
+    return message;
+}
+
+global.colorPrint = function(/* String */ message, /* String */ color)
+{
+    stream.print(colorize(message, color));
+}
+
 
 // built in tasks