// trolls the help extension help directories and compiles a doc with links


var path, doc, result, headingIndices, headingFont, excluded, addFunc;

var underlineStarts, underlineRanges, titleString, thirdParty, thirdPartyIndex;

var extensions, extensionsIndex, extensionFunc, extensionsRoots, extensionsFolders;

var undoc, undocIndex;


path = PathName.new("Help/");


headingIndices = List.new;


titleString = "A Generated List of all Documented Extension Classes";

undoc = "*Show All Undocumented Classes";


result = titleString ++ Char.nl ++ Char.nl ++ "Below is an automatically generated list of all documented extension classes (i.e. those whose class and help files are in /Library/Application Support/SuperCollider/Extensions or ~/Library/Application Support/SuperCollider/Extensions), sorted by directory.\n\nFor a list of undocumented classes click here:" + Char.tab;


undocIndex = result.size;


result = result ++ undoc ++ Char.nl ++ Char.nl;


// put included third party libraries at the end

excluded = [PathName("Help/crucial"), PathName("Help/JITLib")];


// this func trolls the directory and harvests the descriptions

addFunc = {|folderPathName|

var classFiles, heading, currentFile, currentFileString, temp;

classFiles = "";

folderPathName.files.do({|item|

var nameString, nameIndex, end;

nameString = item.fileName.split($.).at(0);

if(nameString.asSymbol.asClass.notNil, { 

currentFile = File(item.fullPath, "r");

currentFileString = currentFile.readAllString;

// fix accent acute (remove it)

currentFileString.findAll("\'8").reverseDo({ |i|

currentFileString = currentFileString.copyFromStart(i-2) ++

currentFileString.copyToEnd(i+2);

});

currentFile.close;

// strip RTF gunk

currentFileString = currentFileString.stripRTF;

nameIndex = currentFileString.find(nameString);

if(nameIndex.notNil, {

currentFileString = currentFileString.drop(nameIndex);

end = currentFileString.find("\n");

if( end.notNil, {

end = end - 1;

currentFileString = currentFileString.copyFromStart(end);

});

// remove tab stops

currentFileString = currentFileString.reject({|item|item == $\t});

// remove commas, hyphens, and spaces

while({(currentFileString[nameString.size] == $,) || 

(currentFileString[nameString.size] == $ ) || 

(currentFileString[nameString.size] == $-)},

{currentFileString = currentFileString.copyFromStart(nameString.size -1) ++

currentFileString.copyToEnd(nameString.size + 1);

}

);

if(currentFileString.size > nameString.size, {

currentFileString = currentFileString.insert(nameString.size, "\t");

});}, 

{  

currentFileString = nameString; 

}

);

// add square brackets

currentFileString = currentFileString.insert(nameString.size, "]");

currentFileString = currentFileString.insert(0, "[");

classFiles = classFiles ++ Char.tab ++ currentFileString ++ Char.nl;

});

});

if(classFiles.size > 0, {

//heading = folderPathName.fileName;

heading = folderPathName.fullPath;

headingIndices.add([result.size, heading.size]);

result = result ++ heading ++ Char.nl ++ Char.nl ++ classFiles ++ Char.nl;

});

folderPathName.foldersWithoutCVS.do({|folder| 

if(excluded.detect({|item| item.fileName == folder.fileName; }).isNil, 

{addFunc.value(folder);}

); 

});

};


//addFunc.value(path);


// Check for Extensions Folders and add if they exist


extensionsRoots = [PathName("/Library/Application Support/SuperCollider/Extensions"), 

PathName("~/Library/Application Support/SuperCollider/Extensions")];


extensionsRoots.any({|item| item.pathMatch.size > 0 }).if({

extensionsFolders = List.new;

extensionFunc = { |path|

path.folders.do({|item| 

item.fullPath.containsi("help").if({ extensionsFolders.add(item)},{ 

extensionFunc.value(item);});

});

};

extensionsRoots.do({|item| extensionFunc.value(item); });

result = result ++ "\n\n";

// result = result ++ "\n------------------------\n\n";

// extensions = "Extensions:";

// extensionsIndex = result.size;

// result = result ++ extensions + Char.nl + Char.nl;

extensionsFolders.do({|item| addFunc.value(item);});

});


// Third Party Libraries

//result = result ++ "\n------------------------\n\n";

//

//thirdParty = "Included Third Party Libraries:";

//thirdPartyIndex = result.size;

//

//result = result ++ thirdParty + Char.nl + Char.nl;

//

//excluded.do({|item| addFunc.value(item); result = result ++ "\n------------\n\n";});


//doc = Document.new("Documented Classes");


// this sets basic tab stops and line spacing

doc = Document.open(File.getcwd ++ "/" ++ "Help/help-scripts/tab-template.rtf");


doc.title = "Documented Extension Classes";


// set the fonts

doc.setFont(Font("Helvetica", 12));

doc.string = result;


doc.setFont(Font("Helvetica-Bold", 18), 0, titleString.size);


//doc.setFont(Font("Helvetica-Bold", 16), thirdPartyIndex, thirdParty.size);


extensionsIndex.notNil.if({

doc.setFont(Font("Helvetica-Bold", 16), extensionsIndex, extensions.size);

});


headingFont = Font("Helvetica-Bold", 14);

headingIndices.do({|item| doc.setFont(headingFont, *item)});


// find the underlines for help links. Apparently faster than storing them above.

underlineStarts = doc.string.findAll("[").reverse + 1;

underlineRanges = doc.string.findAll("]").reverse - underlineStarts;


underlineStarts.do({|item, i| doc.selectRange(item, underlineRanges[i]); doc.underlineSelection;});


doc.selectRange(undocIndex, undoc.size); 

doc.underlineSelection;


doc.selectRange(0,0);

doc.editable_(false);


// keeps window title as it should be!

doc.mouseDownAction = { {doc.title = "Documented Classes";}.defer(0.00001) };


{doc.removeUndo;}.defer(0.001);