/* Copyright (c) Eric Ledoux. All rights reserved. */ /* See http://www.dwell.net/terms for code sharing information. */ // App.cs // // Application entry point. // using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Web.UI; using System.Xml; using System.Xml.Schema; using DwellNet.CodeDoc; using CodeDoc.Properties; // TODO (deferred): change code to use typed XmlReader calls to read the // CodeDoc XML project file, now that there's an XML schema defined namespace DwellNet.CodeDoc.Application {
App Class
Created documentation from source code. |
class App { ////////////////////////////////////////////////////////////////////////// // Private Fields - Maintained Across Multiple CodeDoc XML Project Files //
App.m_warningCount Field
The number of warning messages displayed. |
int m_warningCount;
App.m_exePath Field
The full path of this .exe file. |
string m_exePath;
App.s_app Field
For debugging purposes. |
static App s_app;
App.s_docBrowserSupportFiles Field
The names of static (i.e. non-generated) files that are used in DocBrowser (i.e. what WriteDocumentation() writes) |
static readonly string[] s_docBrowserSupportFiles = new string[] { "_1px.gif", "_Closed.gif", "_CodeDoc.css", "_DocBrowser.js", "_Leaf.gif", "_Maximize.gif", "_Opened.gif", "_SyncToc.gif", "_SyncToc.htm", "_TabLeft.gif", "_TabRight.gif" };
App.s_formattedCodeSupportFiles Field
The names of static (i.e. non-generated) files that are used in the HTML files that WriteFormattedCode() generates. |
static readonly string[] s_formattedCodeSupportFiles = new string[] { "_CodeDoc.css" }; ////////////////////////////////////////////////////////////////////////// // Private Fields - Reset For Each CodeDoc XML Project File //
App.m_projectFilePath Field
The full path to the CodeDoc XML project file currently being processed, or null if none. |
string m_projectFilePath;
App.m_supportFilesPath Field
The full path to directory containing CodeDoc support files. |
string m_supportFilesPath;
App.m_docSet Field
The documentation set being generated. Consists of one or more source code files. |
DocumentationSet m_docSet;
App.m_documentedTopicCount Field
The count of documented topics. |
int m_documentedTopicCount;
App.m_overloadLists Field
When a DocumentationSet.DuplicateCanonicalName event is fired, an entry is added or updated in m_overloadLists with the key being the canonical name and the value being the number of overloads for that canonical name. |
Dictionary<string,int> m_overloadLists;
App.m_referencesNotFound Field
The list of potential references from one topic to another that were not found. These do not necessarily indicate errors. |
List<ReferenceNotFound> m_referencesNotFound;
App.m_externalReferences Field
The contents of the <ExternalReferences> section of the CodeDoc XML project file. Each line of that section is a key in this dictionary; the values are all true. These are external references, which means that they are not reported as "references not found". |
Dictionary<string, bool> m_externalReferences;
App.m_verbose Field
The verbosity level. 0 is minimal output, positive integers produce more output. |
int m_verbose;
App.m_docBrowserNodes Field
The collection of DocBrowserNode objects that have NodeID values; the key is the NodeId value. A value may be DocBrowser object (i.e. the root of a DocBrowser tree) or a regular DocBrowserNode object. |
Dictionary<string, DocBrowserNode> m_docBrowserNodes;
bool m_processedTopics; ////////////////////////////////////////////////////////////////////////// // Private Properties //
App.FalseTrue Property
An IEnumerable which yields false and then true. |
IEnumerable<bool> FalseTrue { get { yield return false; yield return true; } } ////////////////////////////////////////////////////////////////////////// // Methods //
App.Main Method
Main entry point for the application.
Parameters
args Command-line arguments. |
public static int Main(string[] args) { bool pauseOnExit = false; // true if "/Pause" specifed on command line bool success; try { s_app = new App(); success = s_app.Run(args, ref pauseOnExit); } catch (UsageException) { // display command-line usage information; in a debug build include // debug-only options Console.Error.WriteLine(Resources.Usage, #if DEBUG Resources.DebugUsage #else String.Empty #endif ); return 2; } #if DEBUG catch (UnitTests.TestFailedException ex) { Console.Error.WriteLine("\n" + Resources.TestsFailed, ex.Message); return 2; } #endif #if !DEBUG catch (Exception ex) { Console.Error.WriteLine("\n" + Resources.Error, ex.Message); return 2; } #endif // execute "/Pause" command-line argument, if present if (pauseOnExit) { Console.Error.WriteLine(Resources.PressAnyKey); Console.ReadKey(false); } // done; return exit code 1 if there were warnings return (success ? 0 : 1); }
App.Run Method
Executes the application.
Parameters
args Command-line arguments. pauseOnExit Set to true if the "/Pause" command-line argument is given. The caller should initialize this parameter to false.
Return Value
true if the run succeeded with no warning messages, false if one or more warnings were displayed. |
public bool Run(string[] args, ref bool pauseOnExit) { // initialize <m_exePath> to be the full path of this .exe file. m_exePath = System.Reflection.Assembly.GetExecutingAssembly().Location; // parse command-line arguments System.Collections.IEnumerator argEnum = args.GetEnumerator(); while (argEnum.MoveNext()) { string arg = (string) argEnum.Current; #if DEBUG Match match; #endif if (arg == "/Pause") { pauseOnExit = true; } #if DEBUG else if ((match = Regex.Match(arg, @"/RunTests(?::([A-Za-z0-9,]+))?")) .Success) { string[] tests = match.Groups[1].Value.Split( new char[] {','}, StringSplitOptions.RemoveEmptyEntries); bool unused; string testDataDirPath = MakePath(NextArg(argEnum), FileFlags.Directory, out unused); UnitTests.RunTests(testDataDirPath, tests); } else if (arg == "/UpdateTests") { bool unused; string testDataDirPath = MakePath(NextArg(argEnum), FileFlags.Directory, out unused); UnitTests.UpdateTests(testDataDirPath); } else if (arg == "/Verbose") { m_verbose = NextArgAsInt(argEnum); } #endif else if (arg == "/?") throw new UsageException(); else { // <arg> should be the name of a command file -- process it XmlSchema xmlSchema; using (XmlReader xmlReader = XmlReader.Create( App.GetPath("CodeDoc.xsd", m_exePath))) { xmlSchema = XmlSchema.Read(xmlReader, delegate(object sender, ValidationEventArgs e) { Debug.Fail("Error in CodeDoc.xsd", e.Message); }); } XmlReaderSettings xmlSettings = new XmlReaderSettings(); xmlSettings.Schemas.Add(xmlSchema); xmlSettings.ValidationType = ValidationType.Schema; using (XmlReader xmlReader = XmlReader.Create(arg, xmlSettings)) { try { // initialize the state of <this> for this CodeDoc XML // project file m_projectFilePath = Path.GetFullPath(arg); m_docSet = new DocumentationSet(); InitializeDocumentationSet(); m_documentedTopicCount = 0; m_overloadLists = new Dictionary<string,int>(50); m_referencesNotFound = new List<ReferenceNotFound>(100); m_externalReferences = DefaultCSharpExternalReferences(); new Dictionary<string,bool>(100); m_verbose = 1; m_docBrowserNodes = new Dictionary<string,DocBrowserNode>(); m_processedTopics = false; // process the CodeDoc XML project file ProcessProjectFile(xmlReader); // to reduce bugs, clear most of the state that only // makes sense in the context of a given project file m_projectFilePath = null; m_supportFilesPath = null; m_docSet = null; m_overloadLists = null; m_referencesNotFound = null; m_externalReferences = null; } catch (XmlSchemaValidationException ex) { throw new ProjectFileException("{0}({1}): {2}", arg, ((IXmlLineInfo)xmlReader).LineNumber, ex.Message); } #if false catch (XmlException ex) { throw new ProjectFileException("{0}: {1}", arg, ex.Message); } #endif catch (ProjectFileException ex) { throw new ProjectFileException("{0}({1}): {2}", arg, ((IXmlLineInfo)xmlReader).LineNumber, ex.Message); } catch (BegunUsingSourcesException ex) { throw new ProjectFileException("{0}({1}): {2}", arg, ((IXmlLineInfo)xmlReader).LineNumber, ex.Message); } } } } // provide feedback on warnings Console.WriteLine(Resources.Done, m_warningCount); if ((m_referencesNotFound != null) && (m_referencesNotFound.Count > 0) && (m_verbose < 1)) Console.Error.WriteLine(Resources.TipReferencesNotFound); // done return (m_warningCount == 0); }
App.InitializeDocumentationSet Method
Initializes m_docSet. |
public void InitializeDocumentationSet() { // hook up <m_docSet> events m_docSet.AddingSourceFile += new AddingSourceFileEventDelegate(m_docSet_AddingSourceFile); m_docSet.AddedSourceFile += new AddedSourceFileEventDelegate(m_docSet_AddedSourceFile); m_docSet.ParsingError += new ParsingErrorEventDelegate(m_docSet_ParsingError); m_docSet.DuplicateTopicTitle += new DuplicateTopicTitleEventDelegate(m_docSet_DuplicateTopicTitle); m_docSet.DuplicateCanonicalName += new DuplicateCanonicalNameEventDelegate( m_docSet_DuplicateCanonicalName); m_docSet.ReferenceNotFound += new ReferenceNotFoundEventDelegate(m_docSet_ReferenceNotFound); }
App.DefaultCSharpExternalReferences Method
Returns a collection of default external references for the C# languages; for example, predefined types like "int". May be used to initialize m_externalReferences. |
Dictionary<string,bool> DefaultCSharpExternalReferences() { string[] wordsArray = new string[] { "bool", "byte", "char", "decimal", "double", "fixed", "float", "int", "long", "object", "sbyte", "short", "string", "uint", "ulong", "ushort", "void" }; Dictionary<string, bool> words = new Dictionary<string, bool>(wordsArray.Length); foreach (string word in wordsArray) words.Add(word, true); return words; }
App.ProcessProjectFile Method
Performs the operations specified in a CodeDoc XML project file.
Parameters
xmlReader An XmlReader which, on entry, is positioned at the beginning of the CodeDoc XML project file. |
void ProcessProjectFile(XmlReader xmlReader) { // advance to the root "<CodeDoc>" XML element if (!xmlReader.ReadToFollowing("CodeDoc")) throw new ProjectFileException(Resources.ProjectFileMissingRoot); if (xmlReader.IsEmptyElement) return; // empty "<CodeDoc/>" --> nothing to do // parse attributes on the "<CodeDoc>" element string pathFromExe = GetAttribute(xmlReader, "SupportFilesPathFromExe", "SupportFiles"); bool unused; m_supportFilesPath = MakePath(GetPath(pathFromExe, m_exePath), FileFlags.Directory, out unused); // parse XML elements under "<CodeDoc>" while (xmlReader.Read()) { if (xmlReader.NodeType == XmlNodeType.Element) { switch (xmlReader.Name) { case "ExternalReferences": // populate <m_externalReferences> using lines of text from // <ExternalReferences>...</ExternalReferences> xmlReader.Read(); xmlReader.MoveToContent(); foreach (string line in xmlReader.Value.Split( new char[] { '\n' })) { string reference = line.Trim(); if (reference.Length > 0) m_externalReferences[reference] = true; } xmlReader.Read(); break; case "DefinedSymbols": // call DocumentationSet.DefineSymbol() using lines of // text from <DefinedSymbols>...</DefinedSymbols> m_docSet.ClearSymbols(); xmlReader.Read(); xmlReader.MoveToContent(); foreach (string line in xmlReader.Value.Split( new char[] { '\n' })) { string symbol = line.Trim(); if (symbol.Length > 0) m_docSet.DefineSymbol(symbol); } xmlReader.Read(); break; case "AllowXmlElements": // call DocumentationSet.AllowXmlElement() using lines of // text from <AllowXmlElements>...</AllowXmlElements> m_docSet.ClearAllowedXmlElements(); xmlReader.Read(); xmlReader.MoveToContent(); foreach (string line in xmlReader.Value.Split( new char[] { '\n' })) { string elementName = line.Trim(); if (elementName.Length > 0) m_docSet.AllowXmlElement(elementName); } xmlReader.Read(); break; case "DeleteFilesInDirectory": DeleteFilesInDirectory(xmlReader); break; case "CreateDocBrowser": // begin a DocBrowser CreateDocBrowser(xmlReader); break; case "DocBrowserStaticPages": // add static content to a DocBrowser DocBrowserStaticPages(xmlReader); break; case "ReadSource": // add source code from the file or directory specified by // the "Path" attribute to the documentation set ReadSource(xmlReader); break; case "ClearSources": // remove all source files from the documentation set m_docSet.ClearSourceFiles(); break; case "WriteDocumentation": // generate documentation from the source files in the // documentation set WriteDocumentation(xmlReader); break; case "WriteFormattedCode": // generate code HTML from the source files in the // documentation set WriteFormattedCode(xmlReader); break; default: throw new ProjectFileException( Resources.ProjectFileUnknownCommand, xmlReader.Name); } } else if (xmlReader.NodeType == XmlNodeType.Text) throw UnexpectedText(xmlReader); } // finish generating each DocBrowser that was begun with a // "<CreateDocBrowser>" element in the CodeDoc XML project file foreach (KeyValuePair<string,DocBrowserNode> kvp in m_docBrowserNodes) { DocBrowserNode docBrowserNode = kvp.Value; DocBrowser docBrowser = docBrowserNode as DocBrowser; if (docBrowser != null) FinishDocBrowser(docBrowser); } // list references not found, sorted by reference name m_referencesNotFound.Sort(); List<ReferenceNotFound>.Enumerator listEnum = m_referencesNotFound.GetEnumerator(); ReferenceNotFound previous = null; int count = 0; List<string> topicsNotFound = new List<string>(20); while (true) { bool atEnd = !listEnum.MoveNext(); if ((previous != null) && (atEnd || (listEnum.Current.Reference != previous.Reference) || (listEnum.Current.IsTypeOnly != previous.IsTypeOnly))) { string message = String.Format(Resources.ReferencesNotFound, previous, count); Console.Error.WriteLine(message); if (m_verbose >= 1) { // at high enough verbosity level, display the context // topics topicsNotFound.Sort(); foreach (string location in topicsNotFound) { Console.Error.WriteLine(Resources.ReferenceNotFound, location, previous); } } count = 1; topicsNotFound.Clear(); } else count++; if (atEnd) break; previous = listEnum.Current; if ((previous.LineNumber > 0) && (previous.ContextTopic.SourceFile != null)) { topicsNotFound.Add(String.Format("{0}({1})", previous.ContextTopic.SourceFile.SourceFileAbsolutePath, previous.LineNumber)); } else topicsNotFound.Add(previous.ContextTopic.Location); } // at a high enough verbosity level, summarize the duplicate overloads // (i.e. the results from DuplicateCanonicalName events) if (m_verbose >= 3) { List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>(m_overloadLists.Count); foreach (KeyValuePair<string, int> kvp in m_overloadLists) list.Add(kvp); list.Sort(delegate(KeyValuePair<string, int> kvp1, KeyValuePair<string, int> kvp2) { return String.Compare(kvp1.Key, kvp2.Key); }); foreach (KeyValuePair<string, int> kvp in list) { string message = String.Format(Resources.OverloadsDetected, kvp.Key, kvp.Value); Console.Error.WriteLine(message); } } // at a high enough verbosity level, output a list of all documented // topics, excluding namespaces and overloads if (m_verbose >= 4) { Console.WriteLine(); Console.WriteLine(Resources.DocumentedMembers); foreach (Topic topic in m_docSet.Topics) { if (topic.IsDocumented && (topic.TopicKind != TopicKind.NamespaceTopic) && (topic.OverloadListTopic == null)) { Console.WriteLine(topic.QualifiedMemberName); } } Console.WriteLine(); } }
App.DeleteFilesInDirectory Method
Executes a "<DeleteFilesInDirectory>" CodeDoc XML project file command: deletes all files in a given directory, if that directory exists. Does not delete subdirectories, or files in subdirectories.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<DeleteFilesInDirectory>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</DeleteFilesInDirectory>" element (or, equivalently, "<DeleteFilesInDirectory/>"). |
void DeleteFilesInDirectory(XmlReader xmlReader) { // set <directoryPath> to the full path to the directory to delete the // files of; do nothing if the directory doesn't exist bool directoryExists; string directoryPath = MakePath(GetPath(xmlReader, "Path", m_projectFilePath), FileFlags.Directory | FileFlags.Nonexistent, out directoryExists); if (!directoryExists) return; // delete all files in the directory foreach (string filePath in Directory.GetFiles(directoryPath)) { try { File.Delete(filePath); } catch (Exception) { // give the user extra information, i.e. the line number within // the CodeDoc XML project file of the // "<DeleteFilesInDirectory>" element, before re-throwing the // exception Console.WriteLine(Resources.DeleteFileError, m_projectFilePath, ((IXmlLineInfo)xmlReader).LineNumber); throw; } } }
App.CreateDocBrowser Method
Executes a "<CreateDocBrowser>" CodeDoc XML project file command: begins a DocBrowser.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<CreateDocBrowser>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</CreateDocBrowser>" element (or, equivalently, "<CreateDocBrowser/>"). |
void CreateDocBrowser(XmlReader xmlReader) { // set <rootPath> to the full path to DocBrowser root directory // (i.e. the directory into which the frameset files will be written) bool unused; string rootPath = MakePath( GetPath(xmlReader, "Path", m_projectFilePath), FileFlags.Directory | FileFlags.Nonexistent, out unused); CreateDirectoryIfNeeded(rootPath); // parse other attributes on the "<CreateDocBrowser>" element string pagesRelativePath = GetAttribute(xmlReader, "PagesRelativePath", null); string framesetFileName = GetAttribute(xmlReader, "FramesetFileName", null); string basicFramesetFileName = GetAttribute(xmlReader, "BasicFramesetFileName", null); string nodeId = GetAttribute(xmlReader, "NodeId"); string baseName = GetAttribute(xmlReader, "BaseName", "Default"); string title = GetAttribute(xmlReader, "Title", baseName); int leftFrameWidth = GetAttribute<int>(xmlReader, "LeftFrameWidth", 300); bool markOfTheWeb = GetAttribute<bool>(xmlReader, "MarkOfTheWeb", true); // set <docBrowser> to a new DocBrowser object corresponding to this // XML node DocBrowser docBrowser = new DocBrowser(nodeId, rootPath, pagesRelativePath, framesetFileName, basicFramesetFileName, title, baseName, leftFrameWidth, markOfTheWeb); // create the pages directory if it doesn't exist already CreateDirectoryIfNeeded(docBrowser.PagesAbsolutePath); // parse the contents of the "<CreateDocBrowser>" element, if any if (!xmlReader.IsEmptyElement) { int initialDepth = xmlReader.Depth; while (xmlReader.Read() && (xmlReader.Depth != initialDepth)) { if (xmlReader.NodeType == XmlNodeType.Element) { if (xmlReader.Name == "CopyFile") { string sourcePath = GetPath(xmlReader, "Path", m_projectFilePath); string destinationFileName = GetAttribute(xmlReader, "NewName", Path.GetFileName(sourcePath)); CopyStaticFile(sourcePath, destinationFileName, docBrowser.PagesAbsolutePath, xmlReader); } else { throw new ProjectFileException( Resources.ProjectFileUnexpectedElement, xmlReader.Name); } } else if (xmlReader.NodeType == XmlNodeType.Text) throw UnexpectedText(xmlReader); } } // create the DocBrowser pages directory CreateDirectoryIfNeeded(docBrowser.PagesAbsolutePath); // add <docBrowser> to <m_docBrowserNodes> m_docBrowserNodes[nodeId] = docBrowser; }
App.FinishDocBrowser Method
Finishes generating each DocBrowser that was begun with a "<CreateDocBrowser>" element in the CodeDoc XML project file.
Parameters
docBrowser The DocBrowser to finish. |
void FinishDocBrowser(DocBrowser docBrowser) { // provide user feedback Console.WriteLine(Resources.WritingDocBrowser, docBrowser.NodeId); // copy support files into the DocBrowser pages directory foreach (string fileName in s_docBrowserSupportFiles) { string originalFilePath = Path.Combine(m_supportFilesPath, fileName); string newFilePath = Path.Combine(docBrowser.PagesAbsolutePath, fileName); try { CopyFileContents(originalFilePath, newFilePath, false); } catch (Exception) { // give the user extra information, i.e. the line number within // the CodeDoc XML project file of the "<DocBrowserNode>" // element, before re-throwing the exception Console.WriteLine( Resources.ErrorCopyingDocBrowserSupportFile, docBrowser.NodeId, fileName); throw; } } // write the DocBrowser root frameset HTML file; we actually write two // files: the regular DHTML version and a basic (downlevel) version string outputFileName, outputPath; foreach (bool basic in FalseTrue) { outputFileName = (basic ? docBrowser.BasicFramesetFileName : docBrowser.FramesetFileName); if (outputFileName == null) continue; // no frameset file requested in project file outputPath = Path.Combine(docBrowser.RootPath, outputFileName); using (StreamWriter streamWriter = new StreamWriter(outputPath)) { using (HtmlTextWriterHelper htmlWriter = new HtmlTextWriterHelper(streamWriter)) { WriteDocBrowserFrameset(docBrowser, basic, htmlWriter); } } } // write <root-name>_Tabs.htm (implements the tabs) -- not used in the // basic version outputFileName = docBrowser.TabsHtmlFileName; outputPath = Path.Combine(docBrowser.PagesAbsolutePath, outputFileName); using (StreamWriter streamWriter = new StreamWriter(outputPath)) { // copy DocBrowserTabs.htm to <outputFileName>; prepend the /// "Mark of the Web", if specified if (docBrowser.MarkOfTheWeb) { streamWriter.WriteLine( HtmlTextWriterHelper.MarkOfTheWebHtml); } string path = Path.Combine(m_supportFilesPath, "DocBrowserTabs.htm"); streamWriter.Write(File.ReadAllText(path)); } // write <root-name>_Contents.htm (the "Contents" tab) int topicCount = 0; foreach (bool basic in FalseTrue) { outputFileName = (basic ? Resources.BasicDocBrowserPrefix : String.Empty) + docBrowser.ContentsHtmlFileName; outputPath = Path.Combine(docBrowser.PagesAbsolutePath, outputFileName); using (StreamWriter streamWriter = new StreamWriter(outputPath)) { using (HtmlTextWriterHelper htmlWriter = new HtmlTextWriterHelper(streamWriter)) { topicCount = WriteDocBrowserContentsHtml(docBrowser, basic, htmlWriter); } } } // sort index entries and remove duplicate index entries docBrowser.SortIndexEntries(); docBrowser.RemoveDuplicateIndexEntries(); // write <root-name>_Index.htm (the "Index" tab) foreach (bool basic in FalseTrue) { outputFileName = (basic ? Resources.BasicDocBrowserPrefix : String.Empty) + docBrowser.IndexHtmlFileName; outputPath = Path.Combine(docBrowser.PagesAbsolutePath, outputFileName); using (StreamWriter streamWriter = new StreamWriter(outputPath)) { using (HtmlTextWriterHelper htmlWriter = new HtmlTextWriterHelper(streamWriter)) { WriteDocBrowserIndexHtml(docBrowser, basic, topicCount, htmlWriter); } } } // write <root-name>_Index.xml (an XML version of the index) outputPath = Path.Combine(docBrowser.PagesAbsolutePath, docBrowser.IndexXmlFileName); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = "\t"; using (XmlWriter xmlWriter = XmlWriter.Create(outputPath)) WriteDocBrowserIndexXml(docBrowser, xmlWriter); }
App.DocBrowserStaticPages Method
Executes a "<DocBrowserStaticPages>" CodeDoc XML project file command: adds static (non-generated) content to a DocBrowser.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<DocBrowserStaticPages>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</DocBrowserStaticPages>" element (or, equivalently, "<DocBrowserStaticPages/>"). |
void DocBrowserStaticPages(XmlReader xmlReader) { // parse attributes on the "<DocBrowserStaticPages>" element string nodeId = GetAttribute(xmlReader, "NodeId"); // set <parentDocBrowserNode> to the DocBrowserNode that child // "<DocBrowserNode>" elements will append their content to DocBrowserNode parentDocBrowserNode; try { parentDocBrowserNode = m_docBrowserNodes[nodeId]; } catch (KeyNotFoundException) { throw new ProjectFileException(Resources.UndefinedNodeId, nodeId); } // set <docBrowser> to the DocBrowser that contains (or is) // <parentDocBrowserNode> DocBrowserNode docBrowserNode = parentDocBrowserNode; while (docBrowserNode.ParentNode != null) docBrowserNode = docBrowserNode.ParentNode; DocBrowser docBrowser = (DocBrowser) docBrowserNode; // parse the contents of the "<DocBrowserStaticPages>" element, if any if (!xmlReader.IsEmptyElement) { int initialDepth = xmlReader.Depth; while (xmlReader.Read() && (xmlReader.Depth != initialDepth)) { if (xmlReader.NodeType == XmlNodeType.Element) { if (xmlReader.Name == "DocBrowserNode") { ProcessDocBrowserNode(xmlReader, docBrowser, parentDocBrowserNode); } else { throw new ProjectFileException( Resources.ProjectFileUnexpectedElement, xmlReader.Name); } } else if (xmlReader.NodeType == XmlNodeType.Text) throw UnexpectedText(xmlReader); } } }
App.ProcessDocBrowserNode Method
Adds a node to a DocBrowser tree.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<DocBrowserNode>" or "<SourceFilesNode>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</DocBrowserNode>" or "</SourceFilesNode>" element. (or, equivalently, "<DocBrowserNode/> or "<SourceFilesNode/>"). docBrowser The current DocBrowser. parentDocBrowserNode The DocBrowserNode that the content specified by this "<DocBrowserNode>" element will be placed under.
Return Value
The newly-created |
DocBrowserNode ProcessDocBrowserNode(XmlReader xmlReader,
DocBrowser docBrowser, DocBrowserNode parentDocBrowserNode)
{
// parse attributes on the "<DocBrowserNode>" or "<SourceFilesNode>"
// element
string nodeId = GetAttribute(xmlReader, "NodeId", null);
bool unused;
string originalFilePath = MakePath(GetAttribute(xmlReader, "Path"),
FileFlags.File, out unused);
string fileName = GetAttribute(xmlReader, "NewFileName",
Path.GetFileName(originalFilePath));
string title = GetAttribute(xmlReader, "Title",
Path.GetFileNameWithoutExtension(fileName));
bool initiallyExpanded = GetAttribute<bool>(xmlReader,
"InitiallyExpanded", false);
// don't allow initially expanding a node if its parent isn't initially
// expanded
if (!parentDocBrowserNode.InitiallyExpanded)
initiallyExpanded = false;
// copy the original file into the DocBrowser pages directory
string newFilePath = Path.Combine(docBrowser.PagesAbsolutePath,
fileName);
try
{
CopyFileContents(originalFilePath, newFilePath, false);
}
catch (Exception)
{
// give the user extra information, i.e. the line number within
// the CodeDoc XML project file of the "<DocBrowserNode>" or
// "<SourceFilesNode>" element, before re-throwing the exception
Console.WriteLine(Resources.CopyFileError, m_projectFilePath,
((IXmlLineInfo)xmlReader).LineNumber);
throw;
}
// set <docBrowserNode> to a new DocBrowserNode object correpsonding
// to this XML node
DocBrowserNode docBrowserNode = new DocBrowserNode(nodeId,
m_docSet.GenerateTopicId(), originalFilePath, fileName, fileName,
title, initiallyExpanded);
// add <docBrowserNode> as a child of <parentDocBrowserNode>
parentDocBrowserNode.AddChild(docBrowserNode);
// add <docBrowserNode> to <m_docBrowserNodes> if the "NodeId"
// attribute was specified
if (nodeId != null)
m_docBrowserNodes[nodeId] = docBrowserNode;
// parse the contents of the "<DocBrowserNode>" or "<SourceFilesNode>"
// element, if any
if (!xmlReader.IsEmptyElement)
{
int initialDepth = xmlReader.Depth;
while (xmlReader.Read() && (xmlReader.Depth != initialDepth))
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
if (xmlReader.Name == "IndexEntry")
{
// add an index entry
ProcessDocBrowserIndexEntry(xmlReader, docBrowserNode,
docBrowser);
}
else
if (xmlReader.Name == "DocBrowserNode")
{
// recursively add DocBrowser nodes
ProcessDocBrowserNode(xmlReader, docBrowser,
docBrowserNode);
}
else
{
throw new ProjectFileException(
Resources.ProjectFileUnexpectedElement,
xmlReader.Name);
}
}
else
if (xmlReader.NodeType == XmlNodeType.Text)
throw UnexpectedText(xmlReader);
}
}
return docBrowserNode;
}
App.ProcessDocBrowserIndexEntry Method
Adds an index entry to a DocBrowser tree, corresponding to a given node in the tree.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<IndexEntry>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</IndexEntry>" element (or, equivalently, "<IndexEntry/>"). docBrowserNode The DocBrowser node that contains the index entry. docBrowser The DocBrowser that contains the index. |
void ProcessDocBrowserIndexEntry(XmlReader xmlReader, DocBrowserNode docBrowserNode, DocBrowser docBrowser) { // parse attributes on the "<IndexEntry>" element string bookmark = GetAttribute(xmlReader, "Bookmark", null); // parse the contents of the "<IndexEntry>" element, if any if (!xmlReader.IsEmptyElement) { int initialDepth = xmlReader.Depth; while (xmlReader.Read() && (xmlReader.Depth != initialDepth)) { if (xmlReader.NodeType == XmlNodeType.Element) { throw new ProjectFileException( Resources.ProjectFileUnexpectedElement, xmlReader.Name); } else if (xmlReader.NodeType == XmlNodeType.Text) { docBrowser.AddIndexEntry(xmlReader.Value, docBrowserNode, bookmark); } } } }
App.ReadSource Method
Executes an "<AddSource>" CodeDoc XML project file command: adds a given source file, or all source files in a given directory tree, to the documentation set.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<ReadSource>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</ReadSource>" element (or, equivalently, "<ReadSource/>"). |
void ReadSource(XmlReader xmlReader) { // set <sourcePath> to the full path to the source file or directory string sourcePath = GetPath(xmlReader, "Path", m_projectFilePath); // set <prefix> to the value of the "Prefix" attribute; this is used // in the table of contents as the prefix for the relative file // path(s); use null if none string prefix = GetAttribute(xmlReader, "Prefix", null); // parse the contents of the "<ReadSource>" element, if any; set // <excludeFilePaths> to the collection of regular expressions // specified in "<ExcludeFilePaths>" elements; set <assemblyName> // to the "Name" attribute specified in an "<Assembly>" element, or // null if none List<Regex> excludeFilePaths = new List<Regex>(10); string assemblyName = null; if (!xmlReader.IsEmptyElement) { int initialDepth = xmlReader.Depth; while (xmlReader.Read() && (xmlReader.Depth != initialDepth)) { if (xmlReader.NodeType == XmlNodeType.Element) { if (xmlReader.Name == "ExcludeFilePaths") { excludeFilePaths.Add( GetRegexAttribute(xmlReader, "Regex")); } else if (xmlReader.Name == "Assembly") { assemblyName = GetAttribute(xmlReader, "Name"); } else { throw new ProjectFileException( Resources.ProjectFileUnexpectedElement, xmlReader.Name); } } else if (xmlReader.NodeType == XmlNodeType.Text) throw UnexpectedText(xmlReader); } } // add <sourcePath> to the documentation set bool isDir; string sourceFileOrDirPath = MakePath(sourcePath, FileFlags.File | FileFlags.Directory, out isDir); if (isDir) { m_docSet.AddSourceFilesInDirectoryTree(sourceFileOrDirPath, (prefix ?? ""), excludeFilePaths, assemblyName); } else { if (!MatchRegexList(excludeFilePaths, sourceFileOrDirPath, false)) { try { string relativePath = Path.GetFileName(sourceFileOrDirPath); if (prefix != null) relativePath = Path.Combine(prefix, relativePath); m_docSet.AddSourceFile(sourceFileOrDirPath, relativePath, assemblyName); } catch (ArgumentException ex) { // unsupported source file name extension throw new ProjectFileException("{0}", ex.Message); } } } }
App.WriteDocumentation Method
Executes a "<WriteDocumentation>" CodeDoc XML project file command: generates documentation from the source files in the documentation set.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<WriteDocumentation>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</WriteDocumentation>" element (or, equivalently, "<WriteDocumentation/>"). |
void WriteDocumentation(XmlReader xmlReader) { // reset the state of <n>m_docSet</n> to be the same as it was before // the last call to WriteDocumentation() or WriteFormattedCode(). ResetDocSet(); // set <docHtmlDirPath> to the full path to the documentation HTML // directory; create it if it doesn't exist bool unused; string docHtmlDirPath = MakePath(GetPath(xmlReader, "Path", m_projectFilePath), FileFlags.Directory | FileFlags.Nonexistent, out unused); CreateDirectoryIfNeeded(docHtmlDirPath); // parse other attributes on the "<WriteDocumentation>" element m_docSet.ExternalOnly = GetAttribute<bool>(xmlReader, "ExternalOnly", false); bool markOfTheWeb = GetAttribute<bool>(xmlReader, "MarkOfTheWeb", true); string topicFooterHtml = GetAttribute(xmlReader, "TopicFooterHtml", null); // parse the contents of the "<WriteDocumentation>" element, if any; // set <namespaceRegexList> to the collection of regular expressions // specified in "<Namespace>" elements -- these regular expressions // identify which namespaces to include in the documentation set; // if none are specified, all namespaces are included; similarly, // <memberRegexList> lists member names to include (unless the list // is empty, in which case all members are included); set // <hideAttributesRegexList> to the list of regular expressions which // match "[attribute]" declarations we don't want to display in the // generated documentation List<Regex> namespaceRegexList = new List<Regex>(10); List<Regex> memberRegexList = new List<Regex>(10); List<Regex> hideAttributesRegexList = new List<Regex>(10); TopicRenderer topicRenderer = null; DocBrowserNode addToDocBrowserNode = null; InitiallyExpand initiallyExpand = InitiallyExpand.None; string indexLabelSuffix = null; List<KeyValuePair<Regex, string>> namespaceTitleReplacements = null; if (!xmlReader.IsEmptyElement) { int initialDepth = xmlReader.Depth; while (xmlReader.Read() && (xmlReader.Depth != initialDepth)) { if (xmlReader.NodeType == XmlNodeType.Element) { if (xmlReader.Name == "HideAttributes") { hideAttributesRegexList.Add( GetRegexAttribute(xmlReader, "Regex")); } else if (xmlReader.Name == "IncludeNamespaces") { namespaceRegexList.Add( GetRegexAttribute(xmlReader, "Regex")); } else if (xmlReader.Name == "IncludeMembers") { memberRegexList.Add( GetRegexAttribute(xmlReader, "Regex")); } else if (xmlReader.Name == "CopyFile") { string sourcePath = GetPath(xmlReader, "Path", m_projectFilePath); string destinationFileName = GetAttribute(xmlReader, "NewName", Path.GetFileName(sourcePath)); CopyStaticFile(sourcePath, destinationFileName, docHtmlDirPath, xmlReader); } else if (xmlReader.Name == "AddToDocBrowser") { string nodeId = GetAttribute(xmlReader, "NodeId"); initiallyExpand = GetInitiallyExpandAttribute(xmlReader, "InitiallyExpand"); indexLabelSuffix = GetAttribute(xmlReader, "IndexLabelSuffix", null); try { addToDocBrowserNode = m_docBrowserNodes[nodeId]; } catch (KeyNotFoundException) { throw new ProjectFileException( Resources.UndefinedNodeId, nodeId); } namespaceTitleReplacements = ReadChangeTitleElements(xmlReader); } else if (xmlReader.Name == "TopicRenderer") { try { topicRenderer = TopicRenderer.CreateRenderer( GetAttribute(xmlReader, "Assembly"), GetAttribute(xmlReader, "Type"), markOfTheWeb, topicFooterHtml, hideAttributesRegexList); } catch (CreateExternalObjectException ex) { throw new ProjectFileException("{0}", ex.Message); } } else { throw new ProjectFileException( Resources.ProjectFileUnexpectedElement, xmlReader.Name); } } else if (xmlReader.NodeType == XmlNodeType.Text) throw UnexpectedText(xmlReader); } } // if no "<TopicRenderer>" element was specified, create an instance of // the default topic renderer if (topicRenderer == null) { topicRenderer = TopicRenderer.CreateRenderer("CodeDocRenderer", "DwellNet.CodeDoc.DefaultTopicRenderer", markOfTheWeb, topicFooterHtml, hideAttributesRegexList); } // receive events from <topicRenderer> topicRenderer.WarningInSourceFile += new WarningInSourceFileEventDelegate( topicRenderer_WarningInSourceFile); // perform initial processing on topics topicRenderer.CodeHtml = false; ProcessTopics(namespaceRegexList, memberRegexList, topicRenderer); // loop once for each topic in the documentation set Console.WriteLine(Resources.WritingTopics, m_documentedTopicCount); foreach (Topic topic in m_docSet.Topics) { // skip undocumented topics if (!topic.IsDocumented) continue; // generate a documentation HTML file for each documented topic try { TopicRenderer.GenerateDocHtmlInDirectory(topic, docHtmlDirPath, topicRenderer); } catch (ParsingException ex) { Console.Error.WriteLine(ex.WarningMessage); m_warningCount++; } } // if specified, add documented topics to a specified DocBrowser if (addToDocBrowserNode != null) { AddTopicsToDocBrowserContents(initiallyExpand, namespaceTitleReplacements, indexLabelSuffix, addToDocBrowserNode, false); } }
App.WriteFormattedCode Method
Executes a "<WriteFormattedCode>" CodeDoc XML project file command: generates code HTML from the source files in the documentation set.
Parameters
xmlReader An XmlReader which, on entry, is positioned on a "<WriteFormattedCode>" element within the CodeDoc XML project file. On exit, xmlReader must be positioned on the "</WriteFormattedCode>" element (or, equivalently, "<WriteFormattedCode/>"). |
void WriteFormattedCode(XmlReader xmlReader) { // reset the state of <n>m_docSet</n> to be the same as it was before // the last call to WriteDocumentation() or WriteFormattedCode(). ResetDocSet(); // set <codeHtmlDirPath> to the full path to the code HTML directory; // create it if it doesn't exist bool unused; string codeHtmlDirPath = MakePath(GetPath(xmlReader, "Path", m_projectFilePath), FileFlags.Directory | FileFlags.Nonexistent, out unused); CreateDirectoryIfNeeded(codeHtmlDirPath); // parse other attributes on the "<WriteFormattedCode>" element InitiallyExpand initiallyExpand = InitiallyExpand.None; bool markOfTheWeb = GetAttribute<bool>(xmlReader, "MarkOfTheWeb", true); string topicFooterHtml = GetAttribute(xmlReader, "TopicFooterHtml", null); // parse the contents of the "<WriteFormattedCode>" element, if any SourceFileRenderer sourceFileRenderer = null; TopicRenderer topicRenderer = null; DocBrowserNode addToDocBrowserNode = null; DocBrowserNode sourceFilesDocBrowserNode = null; string indexLabelSuffix = null; List<KeyValuePair<Regex, string>> namespaceTitleReplacements = null; if (!xmlReader.IsEmptyElement) { int initialDepth = xmlReader.Depth; while (xmlReader.Read() && (xmlReader.Depth != initialDepth)) { if (xmlReader.NodeType == XmlNodeType.Element) { if (xmlReader.Name == "CopyFile") { string sourcePath = GetPath(xmlReader, "Path", m_projectFilePath); string destinationFileName = GetAttribute(xmlReader, "NewName", Path.GetFileName(sourcePath)); CopyStaticFile(sourcePath, destinationFileName, codeHtmlDirPath, xmlReader); } else if (xmlReader.Name == "AddToDocBrowser") { string nodeId = GetAttribute(xmlReader, "NodeId"); initiallyExpand = GetInitiallyExpandAttribute(xmlReader, "InitiallyExpand"); indexLabelSuffix = GetAttribute(xmlReader, "IndexLabelSuffix", null); try { addToDocBrowserNode = m_docBrowserNodes[nodeId]; } catch (KeyNotFoundException) { throw new ProjectFileException( Resources.UndefinedNodeId, nodeId); } namespaceTitleReplacements = ReadChangeTitleElements(xmlReader); } else if (xmlReader.Name == "SourceFilesNode") { if (addToDocBrowserNode == null) { throw new ProjectFileException( Resources.SourceFilesNodeUsesAddToDocBrowser); } sourceFilesDocBrowserNode = ProcessDocBrowserNode( xmlReader, addToDocBrowserNode.DocBrowser, addToDocBrowserNode); } else if (xmlReader.Name == "SourceFileRenderer") { try { sourceFileRenderer = SourceFileRenderer.CreateRenderer( GetAttribute(xmlReader, "Assembly"), GetAttribute(xmlReader, "Type"), markOfTheWeb); } catch (CreateExternalObjectException ex) { throw new ProjectFileException("{0}", ex.Message); } } else if (xmlReader.Name == "TopicRenderer") { try { topicRenderer = TopicRenderer.CreateRenderer( GetAttribute(xmlReader, "Assembly"), GetAttribute(xmlReader, "Type"), markOfTheWeb, topicFooterHtml, null); } catch (CreateExternalObjectException ex) { throw new ProjectFileException("{0}", ex.Message); } } else { throw new ProjectFileException( Resources.ProjectFileUnexpectedElement, xmlReader.Name); } } else if (xmlReader.NodeType == XmlNodeType.Text) throw UnexpectedText(xmlReader); } } // if no "<SourceFileRenderer>" element was specified, create an // instance of the default source file renderer if (sourceFileRenderer == null) { sourceFileRenderer = SourceFileRenderer.CreateRenderer( "CodeDocRenderer", "DwellNet.CodeDoc.DefaultSourceFileRenderer", markOfTheWeb); } // if no "<TopicRenderer>" element was specified, create an instance // of the default topic renderer if (topicRenderer == null) { topicRenderer = TopicRenderer.CreateRenderer("CodeDocRenderer", "DwellNet.CodeDoc.DefaultTopicRenderer", markOfTheWeb, topicFooterHtml, null); } // perform initial processing on topics topicRenderer.CodeHtml = true; ProcessTopics(null, null, topicRenderer); // write formatted source code HTML for each source file in the // documentation set Console.WriteLine(Resources.WritingFormattedSourceFiles, m_docSet.SourceFiles.Count); foreach (SourceFile sourceFile in m_docSet.SourceFiles) { string htmlPath = Path.Combine(codeHtmlDirPath, sourceFile.CodeHtmlFileName); sourceFileRenderer.SourceFile = sourceFile; sourceFileRenderer.GenerateCodeHtml(topicRenderer, htmlPath); } // generate code namespace files foreach (Topic topic in m_docSet.NamespaceTopics) { try { string htmlPath = Path.Combine(codeHtmlDirPath, topic.CodeNamespaceHtmlFileName); using (StreamWriter streamWriter = new StreamWriter(htmlPath)) { using (HtmlTextWriterHelper htmlWriter = new HtmlTextWriterHelper(streamWriter)) { topicRenderer.Topic = topic; topicRenderer.GenerateCodeNamespaceHtml(htmlWriter); } } } catch (ParsingException ex) { Console.Error.WriteLine(ex.WarningMessage); m_warningCount++; } } // generate code overload topic files foreach (Topic topic in m_docSet.OverloadListTopics) { try { string htmlPath = Path.Combine(codeHtmlDirPath, topic.CodeOverloadListHtmlFileName); using (StreamWriter streamWriter = new StreamWriter(htmlPath)) { using (HtmlTextWriterHelper htmlWriter = new HtmlTextWriterHelper(streamWriter)) { topicRenderer.Topic = topic; topicRenderer.GenerateCodeOverloadListHtml( htmlWriter); } } } catch (ParsingException ex) { Console.Error.WriteLine(ex.WarningMessage); m_warningCount++; } } // if specified (by an "<AddToDocBrowser>" element in the CodeDoc XML // project file), add documented topics to the specified DocBrowser if (addToDocBrowserNode != null) { // write DocBrowser Contents nodes corresponding to namespaces, // types and members AddTopicsToDocBrowserContents(initiallyExpand, namespaceTitleReplacements, indexLabelSuffix, addToDocBrowserNode, true); // if specified (by a "<SourceFilesNode>" element in the CodeDoc // XML project file), write DocBrowser Contents nodes corresponding // to source files if (sourceFilesDocBrowserNode != null) { DocBrowser docBrowser = sourceFilesDocBrowserNode.DocBrowser; foreach (SourceFile sourceFile in m_docSet.SourceFiles) { // add a node to the table of contents string url = sourceFile.CodeHtmlFileName; DocBrowserNode node = new DocBrowserNode(null, sourceFile.SourceFileTopicId, null, url, url, sourceFile.SourceFileRelativePath, false); sourceFilesDocBrowserNode.AddChild(node); // add an index entry (e.g. "Foo.cs (Source Code)"); if the // source file relative path includes a directory component // (e.g. "Abc\Def\Foo.cs") include an entry for both the // full path (e.g. "Abc\Def\Foo.cs") and base file name // (e.g. // "Foo.cs") string fileName1 = sourceFile.SourceFileRelativePath; string fileName2 = Path.GetFileName(fileName1); docBrowser.AddIndexEntry(fileName1 + indexLabelSuffix, node, null); if (fileName1 != fileName2) { docBrowser.AddIndexEntry(fileName2 + indexLabelSuffix, node, null); } } } } }
App.ReadChangeTitleElements Method
Parses "<ChangeTitle>" elements.
Parameters
xmlReader An XmlReader pointing to the current location within the CodeDoc XML project file.
Return Value
A list of change-title Regex/replacement-string pairs, or null if no "<ChangeTitle>" elements were present. |
List<KeyValuePair<Regex, string>> ReadChangeTitleElements( XmlReader xmlReader) { List<KeyValuePair<Regex, string>> titleReplacements = null; int initialDepth = xmlReader.Depth; while (xmlReader.Read() && (xmlReader.Depth != initialDepth)) { if (xmlReader.NodeType == XmlNodeType.Element) { if (xmlReader.Name == "ChangeTitle") { if (titleReplacements == null) { titleReplacements = new List<KeyValuePair<Regex, string>>(); } Regex regex = GetRegexAttribute(xmlReader, "Regex"); string replacement = GetAttribute(xmlReader, "Replacement"); titleReplacements.Add(new KeyValuePair<Regex, string> (regex, replacement)); } else { throw new ProjectFileException( Resources.ProjectFileUnexpectedElement, xmlReader.Name); } } else if (xmlReader.NodeType == XmlNodeType.Text) throw UnexpectedText(xmlReader); } return titleReplacements; }
App.ResetDocSet Method
Resets the state of m_docSet to be the same as it was before the last call to WriteDocumentation() or WriteFormattedCode(). |
void ResetDocSet() { // if ProcessTopics() was previously called, we need to reset the state // of <m_docSet> if (m_processedTopics) { // create a new DocumentationSet DocumentationSet newDocSet = new DocumentationSet(); // copy "core" state from the old DocumentationSet to the new one m_docSet.CopyCoreState(newDocSet); // switch <m_docSet> over to the new DocumentationSet m_docSet = newDocSet; // initialize <m_docSet> InitializeDocumentationSet(); } else m_processedTopics = true; // other initialization m_documentedTopicCount = 0; }
App.ProcessTopics Method
Performs initial processing on topics that's common to WriteDocumentation and WriteFormattedCode.
Parameters
namespaceRegexList The collection of regular expressions specified in "<Namespace>" elements -- these regular expressions identify which namespaces to include in the documentation set; if none are specified, or namespaceRegexList is null, all namespaces are included. memberRegexList The collection of regular expressions specified in "<Member>" elements -- these regular expressions identify the member names names to include in the documentation set; if none are specified, or memberRegexList is null, all members are included. topicRenderer The TopicRenderer to use to generate HTML corresponding to XML comments. |
void ProcessTopics(List<Regex> namespaceRegexList, List<Regex> memberRegexList, TopicRenderer topicRenderer) { // perform general processing on the list of topics, such as generating // unique file names; do this before any topic lists get sorted so that // the file name suffix numbering is relatively consistent among runs m_docSet.BeginUsingSources(); // for debugging purposes, list all topics if (m_verbose >= 99) { foreach (Topic topic in m_docSet.Topics) Console.WriteLine(topic.QualifiedMemberName); } // pass 1: sets Topic.IsDocumented to true for each topic we want to // generate documentation for; also, update <m_documentedTopicCount> to // be the count of documented topics Console.WriteLine(Resources.EnumeratingTopicsToDocument); foreach (NamespaceTopic namespaceTopic in m_docSet.NamespaceTopics) { // see if <namespaceRegexList> matches this namespace; if the // list is empty, all namespaces are included if (!MatchRegexList(namespaceRegexList, namespaceTopic.MemberName, true)) continue; // keep track of the number of topics that will be documented in // this namespace, not including the namespace itself int documentedTopicsInNamespace = 0; // sort topics namespaceTopic.SortTypeTopics(); namespaceTopic.SortChildTopics(); // loop once per type in this namespace foreach (Topic typeTopic in namespaceTopic.TypeTopics) { // mark <typeTopic> as documentable if <memberRegexList> // matches it or is empty if (MatchRegexList(memberRegexList, typeTopic.QualifiedMemberName.ToString(), true)) { if (!m_docSet.ExternalOnly || typeTopic.IsExternallyAccessible) { typeTopic.IsDocumented = true; documentedTopicsInNamespace++; m_documentedTopicCount++; } } // loop once per member of type <typeTopic>, but skip nested // type topics since we're already enumerating through all type // topics foreach (Topic childTopic in Topic.EnumerateDescendentNonTypes(typeTopic)) { // mark <childTopic> as documentable if <memberRegexList> // matches it or is empty; exclude enumeration value topics // since we only document the enumeration topics (not // one topic for each individual value) if (MatchRegexList(memberRegexList, childTopic.QualifiedMemberName.ToString(), true) && (childTopic.TopicKind != TopicKind.EnumValueTopic) && (!m_docSet.ExternalOnly || childTopic.IsExternallyAccessible)) { childTopic.IsDocumented = true; documentedTopicsInNamespace++; m_documentedTopicCount++; } } } // mark this namespace topic as documentable, unless it has no // child topics if (documentedTopicsInNamespace > 0) { namespaceTopic.IsDocumented = true; m_documentedTopicCount++; } } // perform general processing on the list of topics, such as // determining the base class of each documented topic, that must occur // after the application has set Topic.IsDocumented to true for all // topics the applicatin wants documented m_docSet.AfterSettingIsDocumented(); // pass 2: generates Topic.XmlCommentSections Console.WriteLine(Resources.ConvertingXmlToHtml); foreach (Topic topic in m_docSet.Topics) { if (topic.CanLinkTo) { try { TopicRenderer.GenerateDocHtmlInDirectory(topic, null, topicRenderer); } catch (ParsingException ex) { Console.Error.WriteLine(ex.WarningMessage); m_warningCount++; } } } }
App.CopyStaticFile Method
Copies a static file (i.e. a file that's not generated) to the documentation HTML directory or code HTML directory.
Parameters
sourcePath The path of the file to copy. destinationFileName The file name (without a path) to use for the file copy. If null, the file name portion of sourcePath is used. destinationDirPath The full path to the destination HTML directory. xmlReader An XmlReader pointing to the current location within the CodeDoc XML project file. |
void CopyStaticFile(string sourcePath, string destinationFileName, string destinationDirPath, XmlReader xmlReader) { if (destinationFileName == null) destinationFileName = Path.GetFileName(sourcePath); string destinationPath = Path.Combine(destinationDirPath, destinationFileName); bool textToHtml = GetAttribute<bool>(xmlReader, "TextToHtml", false); try { if (textToHtml) ConvertTextFileToHtml(sourcePath, destinationPath, true); else CopyFileContents(sourcePath, destinationPath, true); } catch (Exception) { Console.WriteLine(Resources.CopyFileError, m_projectFilePath, ((IXmlLineInfo)xmlReader).LineNumber); throw; } } #if false /// <summary> /// Writes the BasicContents.htm file. /// </summary> /// /// <param name="htmlWriter">Open onto the BasicContents.htm file.</param> /// /// <param name="markOfTheWeb"><n>true</n> to include the Mark of the Web /// on the page. See <r>HtmlTextWriterHelper.BeginHtmlDocument</r> /// for more information.</param> /// void WriteBasicContentsHtm(HtmlTextWriterHelper htmlWriter, bool markOfTheWeb) { // begin the HTML document htmlWriter.BeginHtmlDocument(HtmlDocType.XhtmlTransitional, markOfTheWeb); // begin the "<head>" block htmlWriter.FormatBeginTag("head\n"); // write the "<title>" block htmlWriter.RenderBeginTag("title"); htmlWriter.WriteEncodedText(Resources.DefaultContentsTitle); htmlWriter.FormatEndTag("\n\n"); // write the "<link>" element htmlWriter.FormatTag("link,rel,href\n", "stylesheet", "_CodeDoc.css"); // end the "<head>" block htmlWriter.FormatEndTag("\n\n"); // begin the "<body>" block htmlWriter.FormatBeginTag("body\n"); // write the body text -- loop once for each namespace List<Topic> childTopics = new List<Topic>(100); foreach (NamespaceTopic namespaceTopic in m_docSet.GetSortedNamespaceTopics()) { // skip this namespace if it's not documented if (!namespaceTopic.IsDocumented) continue; // write the namespace header tag htmlWriter.FormatBeginTag("p,class", "ContentsNamespace"); htmlWriter.FormatBeginTag("a,target,href,title", "CodeDocTopic", namespaceTopic.DocHtmlFileName, namespaceTopic.LongTitle); htmlWriter.WriteEncodedText(namespaceTopic.LongTitle); htmlWriter.RenderEndTag(); htmlWriter.FormatEndTag("\n"); // loop once for each type within the namespace foreach (Topic typeTopic in namespaceTopic.TypeTopics) { // skip this type if it's not documented if (!typeTopic.IsDocumented) continue; // skip this topic if it an overload list topic if (typeTopic is OverloadListTopic) continue; // write the type header tag htmlWriter.FormatBeginTag("p,class", "ContentsType"); htmlWriter.FormatBeginTag("a,target,href,title", "CodeDocTopic", typeTopic.DocHtmlFileName, typeTopic.LongTitle); htmlWriter.WriteEncodedText(typeTopic.ShortTitle); htmlWriter.RenderEndTag(); htmlWriter.FormatEndTag("\n"); // loop once for each member of this type topic, but skip type // topics since we're already enumerating through all type // topics childTopics.Clear(); foreach (Topic childTopic in Topic.EnumerateDescendentNonTypes(typeTopic)) childTopics.Add(childTopic); childTopics.Sort(); foreach (Topic childTopic in childTopics) { // skip this topic if it's not documented if (!childTopic.IsDocumented) continue; // skip this topic if it's included in an overload list // topic if (childTopic.OverloadListTopic != null) continue; // write the link to the child topic htmlWriter.FormatBeginTag("p,class", "ContentsMember"); htmlWriter.FormatBeginTag("a,target,href,title", "CodeDocTopic", childTopic.DocHtmlFileName, childTopic.LongTitle); htmlWriter.WriteEncodedText(childTopic.VeryShortTitle); htmlWriter.RenderEndTag(); htmlWriter.FormatEndTag("\n"); } } } // write the footer htmlWriter.FormatBeginTag("div,class", "ContentsFooter"); htmlWriter.FormatEndTag("\n\n"); // end the "<body>" block htmlWriter.FormatEndTag("\n"); // end the HTML document htmlWriter.EndHtmlDocument(); } #endif
App.WriteDocBrowserFrameset Method
Writes the root frameset HTML file of the DocBrowser web UI.
Parameters
docBrowser The DocBrowser to generate the root frameset HTML file for. basic If true, write HTML for the basic (downlevel) version of the DocBrowser. Otherwise write HTML for the regular (DHTML) version. htmlWriter Open onto the DocBrowser root frameset HTML file. |
void WriteDocBrowserFrameset(DocBrowser docBrowser, bool basic, HtmlTextWriterHelper htmlWriter) { // set <firstNode> to the topmost node to display (null if none) ICollection<DocBrowserNode> childNodes = docBrowser.ChildNodes; DocBrowserNode firstNode; if (childNodes != null) { IEnumerator<DocBrowserNode> nodeEnumerator = docBrowser.ChildNodes.GetEnumerator(); if (nodeEnumerator.MoveNext()) firstNode = nodeEnumerator.Current; else firstNode = null; } else firstNode = null; // set <scriptPath>, <tabsPath>, <contentsPath>, <indexPath>, and // <firstTopicPath> to the path to the script file and tabs, contents, // index and initial topic frame pages, relative to the location of the // root frameset pages string scriptPath, tabsPath, contentsPath, indexPath, firstTopicPath; if (!basic) { scriptPath = "_DocBrowser.js"; tabsPath = docBrowser.TabsHtmlFileName; contentsPath = docBrowser.ContentsHtmlFileName; indexPath = docBrowser.IndexHtmlFileName; firstTopicPath = (firstNode != null) ? firstNode.Url : null; } else { scriptPath = null; // unused in basic DocBrowser tabsPath = null; // unused in basic DocBrowser contentsPath = Resources.BasicDocBrowserPrefix + docBrowser.ContentsHtmlFileName; indexPath = Resources.BasicDocBrowserPrefix + docBrowser.IndexHtmlFileName; if (firstNode != null) firstTopicPath = firstNode.Url; else firstTopicPath = null; } if (docBrowser.PagesRelativePath != null) { if (scriptPath != null) { scriptPath = Path.Combine(docBrowser.PagesRelativePath, scriptPath); } if (tabsPath != null) { tabsPath = Path.Combine(docBrowser.PagesRelativePath, tabsPath); } contentsPath = Path.Combine(docBrowser.PagesRelativePath, contentsPath); indexPath = Path.Combine(docBrowser.PagesRelativePath, indexPath); if (firstTopicPath != null) { firstTopicPath = Path.Combine(docBrowser.PagesRelativePath, firstTopicPath); } } // switch paths to URL form if (scriptPath != null) scriptPath = scriptPath.Replace('\\', '/'); if (tabsPath != null) tabsPath = tabsPath.Replace('\\', '/'); contentsPath = contentsPath.Replace('\\', '/'); indexPath = indexPath.Replace('\\', '/'); if (firstTopicPath != null) firstTopicPath = firstTopicPath.Replace('\\', '/'); // begin the HTML document htmlWriter.BeginHtmlDocument(HtmlDocType.XhtmlFrameset, docBrowser.MarkOfTheWeb); // begin the "<head>" block htmlWriter.FormatBeginTag("head\n"); // write the "<title>" block if specified if (docBrowser.Title != null) { htmlWriter.RenderBeginTag("title"); htmlWriter.WriteEncodedText(docBrowser.Title); htmlWriter.FormatEndTag("\n\n"); } // write the "<script>" block if applicable if (!basic) { htmlWriter.FormatBeginTag("script,src,type", scriptPath, "text/javascript"); htmlWriter.FormatEndTag("\n"); } // end the "<head>" block htmlWriter.FormatEndTag("\n\n"); // begin the outer frameset htmlWriter.FormatBeginTag("frameset,cols\n", String.Format("{0},*", docBrowser.LeftFrameWidth)); // write the contents of the outer frameset if (!basic) { // regular (DHTML) version htmlWriter.FormatBeginTag("frameset,id,rows,frameBorder,frameSpacing,tabIndex", "LeftFrameset", "23,*,0", "0", "0", "-1"); htmlWriter.FormatTag("frame,id,src,scrolling,tabIndex\n", "TabsFrame", tabsPath, "no", "0"); htmlWriter.FormatTag("frame,id,src,tabIndex\n", "ContentsFrame", contentsPath, "0"); htmlWriter.FormatTag("frame,id,src,tabIndex\n", "IndexFrame", indexPath, "0"); htmlWriter.FormatEndTag("\n"); // "frameset" htmlWriter.FormatTag("frame,id,src,tabIndex,onLoad\n", "DocTopic", ""/*firstTopicPath ?? String.Empty*/, "1", "DB_DocTopic_OnLoad()"); } else { // basic (downlevel) version htmlWriter.FormatBeginTag("frameset,rows", "*,*"); htmlWriter.FormatTag("frame,src\n", contentsPath); htmlWriter.FormatTag("frame,src\n", indexPath); htmlWriter.FormatEndTag("\n"); // "frameset" htmlWriter.FormatTag("frame,name,src\n", "DocTopic", firstTopicPath ?? String.Empty); } // begin the outer frameset htmlWriter.FormatEndTag("\n"); // "frameset" // end the HTML document htmlWriter.EndHtmlDocument(); }
App.WriteDocBrowserContentsHtml Method
Writes the DocBrowser *_Contents.htm file.
Parameters
docBrowser The DocBrowser to generate Contents for. basic If true, write HTML for the basic (downlevel) version of the DocBrowser. Otherwise write HTML for the regular (DHTML) version. htmlWriter Open onto the DocBrowser *_Contents.htm file.
Return Value
The number of nodes in the DocBrowser Contents tree. |
int WriteDocBrowserContentsHtml(DocBrowser docBrowser, bool basic, HtmlTextWriterHelper htmlWriter) { // begin the HTML document htmlWriter.BeginHtmlDocument(HtmlDocType.XhtmlTransitional, docBrowser.MarkOfTheWeb); // begin the "<head>" block htmlWriter.FormatBeginTag("head\n"); // write the stylesheet "<link>" block htmlWriter.FormatTag("link,rel,href\n\n", "stylesheet", "_CodeDoc.css"); // write the "<script>" blocks if applicable if (!basic) { // write the "<script>" block that loads _DocBrowser.js htmlWriter.FormatBeginTag("script,src,type", "_DocBrowser.js", "text/javascript"); htmlWriter.FormatEndTag("\n\n"); // write the "<script>" block that redirects to "_SyncToc.htm" if this page is loaded // outside the context of a DocBrowser frameset htmlWriter.FormatBeginTag("script,type", "text/javascript"); htmlWriter.WriteLine("if (parent.DocTopic == undefined)"); htmlWriter.WriteLine(" window.navigate(\"_SyncToc.htm\");"); htmlWriter.FormatEndTag("\n\n"); // write the topic map script block -- this defines a script array // that maps a topic name (e.g. "Intro.htm") to a numeric topic ID // (e.g. 1000001) for those topics that don't call OnTopicLoaded() // (in _DocBrowser.js) when they load htmlWriter.FormatBeginTag("script,type", "text/javascript"); htmlWriter.WriteLine("dbc_TopicMap = new Array;"); foreach (DocBrowserNode node in docBrowser.AllNodes) { if (node.OriginalFilePath != null) { htmlWriter.WriteLine("dbc_TopicMap[\"{0}\"] = {1};", node.FileName, node.TopicId); } } htmlWriter.FormatEndTag("\n"); } // end the "<head>" block htmlWriter.FormatEndTag("\n\n"); // begin the "<body>" block if (!basic) { htmlWriter.FormatBeginTag( "body,id,onLoad,onSelectStart,onMouseDown,onMouseOver,onKeyDown,onKeyPress", "DocBrowserContents", "return DBC_OnLoad()", "return false", "return DBC_OnMouseDown()", "return DBC_OnMouseOver()", "return DBC_OnKeyDown()", "return DBC_OnKeyPress()"); } else htmlWriter.FormatBeginTag("body,id", "BasicDocBrowserContents"); // the basic version includes a header if (basic) { string pathToEnhancedFrameset = docBrowser.FramesetFileName; string pathFromPagesToRoot = docBrowser.PathFromPagesToRoot; if (pathFromPagesToRoot != null) { pathToEnhancedFrameset = Path.Combine(pathFromPagesToRoot, pathToEnhancedFrameset); } htmlWriter.FormatBeginTag("table,class,cellpadding,cellspacing", "Header_", "0", "0"); htmlWriter.RenderBeginTag("tr"); htmlWriter.FormatBeginTag("td,class", "Left_"); htmlWriter.WriteEncodedText( Resources.BasicDocBrowserContentsHeader); htmlWriter.FormatEndTag("\n"); // "td" htmlWriter.FormatBeginTag("td,class", "Right_"); #if false // omit "Use Enhanced View" link htmlWriter.FormatBeginTag("a,target,href,title", "_parent", pathToEnhancedFrameset, Resources.BasicDocBrowserUseEnhancedToolTip); htmlWriter.WriteEncodedText(Resources.BasicDocBrowserUseEnhanced); htmlWriter.RenderEndTag(); // "a" #endif htmlWriter.FormatEndTag("\n"); // "td" htmlWriter.RenderEndTag(); // "tr" htmlWriter.FormatEndTag("\n"); // "table" } // generate HTML for the tree nodes; set <topicCount> to the number of // tree nodes generated int topicCount; ICollection<DocBrowserNode> childNodes = docBrowser.ChildNodes; if (childNodes != null) { topicCount = WriteDocBrowserNodes(childNodes, basic, 1, htmlWriter); } else topicCount = 0; // end the "<body>" block htmlWriter.FormatEndTag("\n\n"); // end the HTML document htmlWriter.EndHtmlDocument(); // done return topicCount; }
App.WriteDocBrowserNodes Method
Writes HTML for a collection of sibling DocBrowser nodes.
Parameters
nodes The nodes to generate HTML for. basic If true, write HTML for the basic (downlevel) version of the DocBrowser. Otherwise write HTML for the regular (DHTML) version. level The level within the tree; 1 is the topmost level. htmlWriter Where to write the HTML. |
int WriteDocBrowserNodes(ICollection<DocBrowserNode> nodes, bool basic, int level, HtmlTextWriterHelper htmlWriter) { // loop once for each child <node> of <parentNode> int topicCount = 0; foreach (DocBrowserNode node in nodes) { // begin the "<div>" of this tree node if (!basic) { htmlWriter.FormatBeginTag("div,class,id,Topic", String.Format("L{0}_", level), String.Format("Topic{0}", node.TopicId), node.Url); } else { htmlWriter.FormatBeginTag("div,class", String.Format("L{0}_", level)); } // set <childNodes> to the collection of children of <node> ICollection<DocBrowserNode> childNodes = node.ChildNodes; if (!basic) { // write the icon for this tree node if (childNodes != null) { if (node.InitiallyExpanded) htmlWriter.FormatTag("img,src", "_Opened.gif"); else htmlWriter.FormatTag("img,src", "_Closed.gif"); } else htmlWriter.FormatTag("img,src", "_Leaf.gif"); // write the text contents of the tree node htmlWriter.RenderBeginTag("span"); htmlWriter.WriteEncodedText(node.Title); htmlWriter.RenderEndTag(); // "span" } else { // write the hyperlink for this tree node htmlWriter.FormatBeginTag("a,target,href", "DocTopic", node.Url); if (childNodes != null) htmlWriter.RenderBeginTag("b"); htmlWriter.WriteEncodedText(node.Title); if (childNodes != null) htmlWriter.RenderEndTag(); htmlWriter.RenderEndTag(); // "a" } // end the "<div>" of this tree node htmlWriter.FormatEndTag("\n"); // "div" // write the subtree node, if this node has children if (childNodes != null) { if (!basic) { // begin the subtree node if (node.InitiallyExpanded) { htmlWriter.FormatBeginTag("div,class,id,style", "Subtree", String.Format("Subtree{0}", node.TopicId), "display: block"); } else { htmlWriter.FormatBeginTag("div,class,id", "Subtree", String.Format("Subtree{0}", node.TopicId)); } // recurse topicCount += WriteDocBrowserNodes(childNodes, basic, level + 1, htmlWriter); // end the subtree node htmlWriter.FormatEndTag("\n"); // "div" } else { // recurse topicCount += WriteDocBrowserNodes(childNodes, basic, level + 1, htmlWriter); } } } return topicCount; }
App.WriteDocBrowserIndexHtml Method
Writes the DocBrowser *_Index.htm file.
Parameters
docBrowser The DocBrowser to generate the Index for. basic If true, write HTML for the basic (downlevel) version of the DocBrowser. Otherwise write HTML for the regular (DHTML) version. topicCount The approximate number of topics in the table of contents. htmlWriter Open onto the DocBrowser *_Index.htm file. |
void WriteDocBrowserIndexHtml(DocBrowser docBrowser, bool basic, int topicCount, HtmlTextWriterHelper htmlWriter) { // begin the HTML document htmlWriter.BeginHtmlDocument(HtmlDocType.XhtmlTransitional, docBrowser.MarkOfTheWeb); // begin the "<head>" block htmlWriter.FormatBeginTag("head\n"); // write the stylesheet "<link>" block htmlWriter.FormatTag("link,rel,href\n\n", "stylesheet", "_CodeDoc.css"); // write the "<script>" block if applicable if (!basic) { // write the "<script>" block that loads _DocBrowser.js htmlWriter.FormatBeginTag("script,src,type", "_DocBrowser.js", "text/javascript"); htmlWriter.FormatEndTag("\n"); // write the "<script>" block that redirects to "_SyncToc.htm" if this page is loaded // outside the context of a DocBrowser frameset htmlWriter.FormatBeginTag("script,type", "text/javascript"); htmlWriter.WriteLine("if (parent.DocTopic == undefined)"); htmlWriter.WriteLine(" window.navigate(\"_SyncToc.htm\");"); htmlWriter.FormatEndTag("\n\n"); } // end the "<head>" block htmlWriter.FormatEndTag("\n\n"); // begin the "<body>" block if (!basic) { htmlWriter.FormatBeginTag( "body,id,onLoad,onSelectStart,onMouseDown,onMouseOver,onKeyDown,onFocus", "DocBrowserIndex", "return DBI_OnLoad()", "return false", "return DBI_OnMouseDown()", "return DBI_OnMouseOver()", "return DBI_OnKeyDown()", "return DBI_OnFocus()"); } else htmlWriter.FormatBeginTag("body,id", "BasicDocBrowserIndex"); // the basic version includes a header if (basic) { htmlWriter.FormatBeginTag("table,class,cellpadding,cellspacing", "Header_", "0", "0"); htmlWriter.RenderBeginTag("tr"); htmlWriter.FormatBeginTag("td,class", "Left_"); htmlWriter.WriteEncodedText( Resources.BasicDocBrowserIndexHeader); htmlWriter.FormatEndTag("\n"); // "td" htmlWriter.RenderEndTag(); // "tr" htmlWriter.FormatEndTag("\n"); // "table" } // write the body text foreach (IndexEntry indexEntry in docBrowser.IndexEntries) { string url = indexEntry.DocBrowserNode.Url; if (indexEntry.Bookmark != null) url += "#" + indexEntry.Bookmark; if (!basic) { htmlWriter.FormatBeginTag("div,id,Topic", String.Format("Topic{0}", indexEntry.DocBrowserNode.TopicId), url); htmlWriter.RenderBeginTag("span"); htmlWriter.WriteEncodedText(indexEntry.Label); htmlWriter.RenderEndTag(); // "span" htmlWriter.FormatEndTag("\n"); // "div" } else { htmlWriter.RenderBeginTag("div"); htmlWriter.FormatBeginTag("a,target,href", "DocTopic", url); htmlWriter.WriteEncodedText(indexEntry.Label); htmlWriter.RenderEndTag(); // "a" htmlWriter.FormatEndTag("\n"); // "div" } } // end the "<body>" block htmlWriter.FormatEndTag("\n\n"); // end the HTML document htmlWriter.EndHtmlDocument(); }
App.WriteDocBrowserIndexXml Method
Writes the DocBrowser *_Index.xml file.
Parameters
docBrowser The DocBrowser to generate the Index for. xmlWriter Open onto the DocBrowser *_Index.xml file. |
void WriteDocBrowserIndexXml(DocBrowser docBrowser, XmlWriter xmlWriter) { // begin the index XML file xmlWriter.WriteStartDocument(); xmlWriter.WriteStartElement("Index", "urn:schemas-dwell-net:codedoc:project-file"); xmlWriter.WriteString("\n"); // loop once for index entry foreach (IndexEntry indexEntry in docBrowser.IndexEntries) { xmlWriter.WriteStartElement("IndexEntry"); xmlWriter.WriteAttributeString("TopicId", XmlConvert.ToString(indexEntry.DocBrowserNode.TopicId)); xmlWriter.WriteAttributeString("Url", indexEntry.DocBrowserNode.Url); xmlWriter.WriteValue(indexEntry.Label); xmlWriter.WriteEndElement(); xmlWriter.WriteString("\n"); } // end the index XML file xmlWriter.WriteEndElement(); }
App.AddTopicsToDocBrowserContents Method
Adds Topic objects from m_docSet to the Contents view of a given DocBrowser. Also updates the Index view.
Parameters
initiallyExpand Specifies which nodes to initially expand, if any. titleReplacements If not null, this is a list of namespace title Regex/replacement-title pairs that will be applied to the title of each namespace node. If null, the namespace topic title is used. indexLabelSuffix If not null, this string is appended to the label of each index entry added by this method. parentDocBrowserNode The DocBrowserNode that the topics of m_docSet will be added to as child nodes. codeHtml If true, links to topics are made to formatted source code pages (i.e. "<WriteFormattedCode>" in the CodeDoc XML project file) rather than to documentation pages (i.e. "<WriteDocumentation>" in the CodeDoc XML project file). |
void AddTopicsToDocBrowserContents(InitiallyExpand initiallyExpand, List<KeyValuePair<Regex, string>> titleReplacements, string indexLabelSuffix, DocBrowserNode parentDocBrowserNode, bool codeHtml) { // set <docBrowser> to the DocBrowser containing <parentDocBrowserNode> DocBrowser docBrowser = parentDocBrowserNode.DocBrowser; // loop once for each namespace List<Topic> memberTopics = new List<Topic>(100); foreach (NamespaceTopic namespaceTopic in m_docSet.GetSortedNamespaceTopics()) { // skip this namespace if it's not documented if (!namespaceTopic.IsDocumented) continue; // set <namespaceTitle> to the title of the namespace string namespaceTitle = namespaceTopic.LongTitle; if (titleReplacements != null) { foreach (KeyValuePair<Regex, string> replacement in titleReplacements) { namespaceTitle = replacement.Key.Replace(namespaceTitle, replacement.Value); } } // set <namespaceNode> to a new DocBrowserNode object // correpsonding to <namespaceTopic> string url = (codeHtml ? namespaceTopic.CodeHtmlUrl : namespaceTopic.DocHtmlFileName); //Debug.Assert(url != null); DocBrowserNode namespaceNode = new DocBrowserNode(null, namespaceTopic.Id, null, url, url, namespaceTitle, (initiallyExpand >= InitiallyExpand.Namespaces)); // add <namespaceNode> as a child of <parentDocBrowserNode> parentDocBrowserNode.AddChild(namespaceNode); // add index entries for <namespaceNode> AddNodeIndexEntries(docBrowser, namespaceNode, namespaceTopic, indexLabelSuffix); // loop once for each type within the namespace foreach (Topic typeTopic in namespaceTopic.TypeTopics) { // skip this type if it's not documented if (!typeTopic.IsDocumented) continue; // skip this topic if it an overload list topic if (typeTopic is OverloadListTopic) continue; // set <typeNode> to a new DocBrowserNode object // correpsonding to <typeTopic> url = (codeHtml ? typeTopic.CodeHtmlUrl : typeTopic.DocHtmlFileName); Debug.Assert(url != null); DocBrowserNode typeNode = new DocBrowserNode(null, typeTopic.Id, null, url, url, typeTopic.ShortTitle, (initiallyExpand >= InitiallyExpand.NamespacesAndTypes)); // add <docBrowserNode> as a child of <namespaceNode> namespaceNode.AddChild(typeNode); // add index entries for <namespaceNode> AddNodeIndexEntries(docBrowser, typeNode, typeTopic, indexLabelSuffix); // loop once for each member of this type topic, but skip type // topics since we're already enumerating through all type // topics memberTopics.Clear(); foreach (Topic memberTopic in Topic.EnumerateDescendentNonTypes(typeTopic)) memberTopics.Add(memberTopic); memberTopics.Sort(); foreach (Topic memberTopic in memberTopics) { // skip this topic if it's not documented if (!memberTopic.IsDocumented) continue; // skip this topic if it's included in an overload list // topic if (memberTopic.OverloadListTopic != null) continue; // set <memberNode> to a new DocBrowserNode object // correpsonding to <memberTopic> url = (codeHtml ? memberTopic.CodeHtmlUrl : memberTopic.DocHtmlFileName); Debug.Assert(url != null); DocBrowserNode memberNode = new DocBrowserNode(null, memberTopic.Id, null, url, url, memberTopic.VeryShortTitle, (initiallyExpand >= InitiallyExpand.All)); // add <docBrowserNode> as a child of <namespaceNode> typeNode.AddChild(memberNode); // add index entries for <namespaceNode> AddNodeIndexEntries(docBrowser, memberNode, memberTopic, indexLabelSuffix); } } } }
App.AddNodeIndexEntries Method
Adds index entries related to a Topic to a DocBrowser.
Parameters
docBrowser The DocBrowser to add index entries to. docBrowserNode The DocBrowserNode that topic is related to. topic The topic to add index entries for. indexLabelSuffix If not null, this string is appended to the label of each index entry added by this method. |
void AddNodeIndexEntries(DocBrowser docBrowser, DocBrowserNode docBrowserNode, Topic topic, string indexLabelSuffix) { // add an index topic using Topic.ShortTitle as the label string label = topic.ShortTitle; if (indexLabelSuffix != null) label += indexLabelSuffix; docBrowser.AddIndexEntry(label, docBrowserNode, null); // add an index topic using Topic.VeryShortTitle as the label label = topic.VeryShortTitle; if (topic.ParentTopic != null) { // avoid e.g. "Foo - Foo" (e.g. constructor) if (topic.ParentTopic.MemberName != topic.MemberName) label += " - " + topic.ParentTopic.MemberName; } if (indexLabelSuffix != null) label += indexLabelSuffix; docBrowser.AddIndexEntry(label, docBrowserNode, null); }
App.ToString Method
Returns the result from calling ToString on a value, or String.Empty if that value is null.
Parameters
value |
static string ToString(object value) { if (value == null) return String.Empty; else return value.ToString(); }
App.m_docSet_AddingSourceFile Method
Called when a source file is about to be added to the documentation set m_docSet.
Parameters
sourceFileAbsolutePath The value of the SourceFileAbsolutePath property of the new SourceFile object. sourceFileRelativePath The value of the SourceFileRelativePath property of the new SourceFile object. |
void m_docSet_AddingSourceFile(string sourceFileAbsolutePath, string sourceFileRelativePath) { // provide user feedback that a source file is being loaded if (m_verbose >= 1) Console.WriteLine(Resources.Loading, sourceFileRelativePath); }
App.m_docSet_AddedSourceFile Method
Called when a source file has been successfully added to the documentation set m_docSet.
Parameters
sourceFile The newly-added SourceFile object. |
void m_docSet_AddedSourceFile(SourceFile sourceFile) { // display warnings to the user (if any) foreach (ParsingException ex in sourceFile.Warnings) { Console.Error.WriteLine(ex.WarningMessage); m_warningCount++; } }
App.m_docSet_ParsingError Method
Called when an error occurs while trying to parse a source file.
Parameters
exception Information about the error. |
void m_docSet_ParsingError(ParsingException exception)
{
Console.Error.WriteLine(exception.WarningMessage);
m_warningCount++;
}
App.m_docSet_DuplicateTopicTitle Method
Called when two topics are found to have the same Topic.LongTitle. This may indicate that the same source file was added twice to the documentation set.
Parameters
topic1 The first topic. topic2 The second topic. |
void m_docSet_DuplicateTopicTitle(Topic topic1, Topic topic2)
{
Console.Error.WriteLine(Resources.DuplicateTopicTitle,
topic1.LongTitle, GetTopicSourceFileLabel(topic1),
GetTopicSourceFileLabel(topic2));
m_warningCount++;
}
App.m_docSet_DuplicateCanonicalName Method
Called when two topics are found to have the same Topic.CanonicalName. This is purely informational -- it indicates that an overload topic needed to be created since a reference to the canonical name does not resolve to a unique topic.
Parameters
topic1 The first topic. topic2 The second topic. |
void m_docSet_DuplicateCanonicalName(Topic topic1, Topic topic2) { string canonicalName = topic1.CanonicalName.ToString(); int count; if (m_overloadLists.TryGetValue(canonicalName, out count)) m_overloadLists[canonicalName] = count + 1; else { // the first event indicates a duplicate canonical name, so you // might think the value below should be 2 instead of 1 -- however, // this event is also fired for the overload list topic itself m_overloadLists[canonicalName] = 1; } }
App.m_docSet_ReferenceNotFound Method
Called when a topic is found to made a potential reference to another topic, and that reference wasn't found. This is informational, and doesn't necessarily indicate an error.
Parameters
reference The presumed (but failed) qualified or unqualified member name of the topic being referenced. contextTopic The topic containing the reference. lineNumber The line number of the reference, within the source file containing contextTopic. settings Settings used to resolve the reference. |
void m_docSet_ReferenceNotFound(string reference, Topic contextTopic, int lineNumber, FindTopicSettings settings) { if (!IsExternalReference(reference)) { m_referencesNotFound.Add(new ReferenceNotFound(reference, contextTopic, lineNumber, settings)); m_warningCount++; } }
App.topicRenderer_WarningInSourceFile Method
Called when a TopicRenderer reports a warning associated with a given line number in a source file.
Parameters
sourceFile The souce file that the warning relates to. lineNumber The line number within the source file that the warning relates to. message The warning message text. |
void topicRenderer_WarningInSourceFile(SourceFile sourceFile, int lineNumber, string message) { Console.Error.WriteLine(Resources.Warning3, sourceFile.SourceFileAbsolutePath, lineNumber, message); m_warningCount++; }
App.GetTopicSourceFileLabel Method
Returns a label referring to the source file of a given topic. Returns a label such as "(none)" if there is no source file for the given topic, or if the given topic is null.
Parameters
topic |
static string GetTopicSourceFileLabel(Topic topic) { if ((topic != null) && (topic.SourceFile != null) && (topic.SourceFile.SourceFileAbsolutePath != null)) return topic.SourceFile.SourceFileAbsolutePath; else return Resources.None; }
App.MatchRegexList Method
Returns true if a given name is matched by any regular expression in a given list.
Parameters
regexList The list of regular expressions to search. name The name to match. trueIfNullOrEmpty If true, then true is returned if regexList is null or empty. |
static bool MatchRegexList(List<Regex> regexList, string name, bool trueIfNullOrEmpty) { // return true if the list is empty, if specified if (trueIfNullOrEmpty && ((regexList == null) || (regexList.Count == 0))) return true; // search the list for a regular expression that <name> matches return regexList.Find(delegate(Regex regex) { return regex.Match(name).Success; }) != null; }
App.GetPath Method (string, string)
If a given path is absolute, it's returned; if the path is relative, it's interpreted as being relative to a given file name, converted to an absolute path, and returned.
Parameters
path The given absolute or relative path. relativeTo The full path of a file that path is relative to (if it's a relative path). |
public static string GetPath(string path, string relativeTo) { if (Path.IsPathRooted(path)) return path; else return Path.GetFullPath(Path.Combine( Path.GetDirectoryName(relativeTo), path)); }
App.GetPath Method (XmlReader, string, string)
Reads a specified attribute of the current element of an XmlReader and interprets as a path: if the path is absolute, it's returned; if the path is relative, it's interpreted as being relative to a given file name, converted to an absolute path, and returned.
Parameters
xmlReader The XmlReader to read from. attributeName The name of the XML attribute to read; for example, "Path". relativeTo The full path of a file that the attribute value is relative to (if the attribute value is a relative path).
Exceptions
|
public static string GetPath(XmlReader xmlReader, string attributeName, string relativeTo) { return GetPath(GetAttribute(xmlReader, attributeName), relativeTo); }
App.GetAttribute Method (XmlReader, string)
Reads the string value of an attribute of the current element of an XmlReader that's reading the CodeDoc XML project file. Throws a ProjectFileException if the specified attribute doesn't exist.
Parameters
xmlReader An XmlReader which, on entry, is positioned on an element within the CodeDoc XML project file. This method does not move the position of this reader. attributeName The name of the attribute to get the value of.
Exceptions
|
static string GetAttribute(XmlReader xmlReader, string attributeName) { string value = xmlReader.GetAttribute(attributeName); if (value == null) { throw new ProjectFileException(Resources.ProjectFileMissingAttr, attributeName, xmlReader.Name); } else return value; }
App.GetAttribute Method (XmlReader, string, string)
Reads the string value of an attribute of the current element of an XmlReader that's reading the CodeDoc XML project file. Returns a specified default value if the specified attribute doesn't exist.
Parameters
xmlReader An XmlReader which, on entry, is positioned on an element within the CodeDoc XML project file. This method does not move the position of this reader. attributeName The name of the attribute to get the value of. defaultValue The value to returne if the specified attribute doesn't exist. |
static string GetAttribute(XmlReader xmlReader, string attributeName, string defaultValue) { string value = xmlReader.GetAttribute(attributeName); if (value == null) return defaultValue; else return value; }
App.GetAttribute<T> Method (XmlReader, string)
Reads the value of an attribute of the current element of an XmlReader that's reading the CodeDoc XML project file. The value is converted to a specified type. An exception is thrown if the specified attribute doesn't exist.
Type Parameters
T The type to convert to.
Parameters
xmlReader An XmlReader which, on entry, is positioned on an element within the CodeDoc XML project file. This method does not move the position of this reader. attributeName The name of the attribute to get the value of.
Exceptions
|
static T GetAttribute<T>(XmlReader xmlReader, string attributeName) where T : struct { string value = GetAttribute(xmlReader, attributeName); try { return XmlConvertString<T>(value); } catch (FormatException) { throw new ProjectFileException(Resources.ProjectFileBadAttrType, attributeName, xmlReader.Name, typeof(T).Name); } }
App.GetAttribute<T> Method (XmlReader, string, T)
Reads the value of an attribute of the current element of an XmlReader that's reading the CodeDoc XML project file. The value is converted to a specified type. A default value is used if the specified attribute doesn't exist.
Type Parameters
T The type to convert to.
Parameters
xmlReader An XmlReader which, on entry, is positioned on an element within the CodeDoc XML project file. This method does not move the position of this reader. attributeName The name of the attribute to get the value of. defaultValue The value to returne if the specified attribute doesn't exist.
Exceptions
|
static T GetAttribute<T>(XmlReader xmlReader, string attributeName, T defaultValue) where T : struct { string value = GetAttribute(xmlReader, attributeName, null); if (value == null) return defaultValue; try { return XmlConvertString<T>(value); } catch (FormatException) { throw new ProjectFileException(Resources.ProjectFileBadAttrType, attributeName, xmlReader.Name, typeof(T).Name); } }
App.GetInitiallyExpandAttribute Method
Reads the InitiallyExpand-typed value of an attribute of the current element of an XmlReader that's reading the CodeDoc XML project file. Returns InitiallyExpand.None if the specified attribute doesn't exist.
Parameters
xmlReader An XmlReader which, on entry, is positioned on an element within the CodeDoc XML project file. This method does not move the position of this reader. attributeName The name of the attribute to get the value of. |
InitiallyExpand GetInitiallyExpandAttribute(XmlReader xmlReader,
string attributeName)
{
string value = GetAttribute(xmlReader, attributeName, "None");
switch (value)
{
default:
case "None":
return InitiallyExpand.None;
case "Namespaces":
return InitiallyExpand.Namespaces;
case "NamespacesAndTypes":
return InitiallyExpand.NamespacesAndTypes;
case "All":
return InitiallyExpand.All;
}
}
App.XmlConvertString Method
Converts a string from a format that's correct for use within an XML file to a CLR type. Only certain CLR types are supported.
Type Parameters
T The CLR type to convert to.
Parameters
value The value to convert.
Exceptions
|
static T XmlConvertString<T>(string value) where T : struct { if (typeof(T) == typeof(int)) return (T) (object) XmlConvert.ToInt32(value); else if (typeof(T) == typeof(double)) return (T) (object) XmlConvert.ToDouble(value); else if (typeof(T) == typeof(bool)) return (T) (object) XmlConvert.ToBoolean(value); else throw new FormatException(); }
App.GetRegexAttribute Method
Reads the Regex value of an attribute of the current element of an XmlReader that's reading the CodeDoc XML project file.
Parameters
xmlReader An XmlReader which, on entry, is positioned on an element within the CodeDoc XML project file. This method does not move the position of this reader. attributeName The name of the attribute to get the value of.
Exceptions
|
static Regex GetRegexAttribute(XmlReader xmlReader, string attributeName) { string stringValue = GetAttribute(xmlReader, attributeName); try { return new Regex(stringValue); } catch (ArgumentException) { throw new ProjectFileException(Resources.ProjectFileBadRegexAttr, attributeName, xmlReader.Name, stringValue); } }
App.IsExternalReference Method
Returns true if a given reference is an external reference, i.e. one listed in the <ExternalReferences> secton of the CodeDoc XML project file. External references are not reported as "references not found".
Parameters
reference The reference to check. |
bool IsExternalReference(string reference) { bool unused; return m_externalReferences.TryGetValue(reference, out unused); }
App.UnexpectedText Method
Returns a ProjectFileException indicating that the current node of an XmlReader that's reading the CodeDoc XML project file contains text which is unexpected.
Parameters
xmlReader An XmlReader positioned on an element within the CodeDoc XML project file. |
ProjectFileException UnexpectedText(XmlReader xmlReader)
{
string text = xmlReader.ReadContentAsString();
const int maxLen = 50;
if (text.Length > maxLen)
text = text.Substring(0, maxLen) + "...";
return new ProjectFileException(Resources.ProjectFileUnexpectedText,
text);
}
App.NextArg Method
Returns the next command-line argument.
Parameters
argEnum An enumerator of command-line arguments. |
string NextArg(System.Collections.IEnumerator argEnum) { if (!argEnum.MoveNext()) throw new UsageException(); return (string)argEnum.Current; }
App.NextArgAsInt Method
Returns the next command-line argument as an int.
Parameters
argEnum An enumerator of command-line arguments. |
int NextArgAsInt(System.Collections.IEnumerator argEnum) { try { return int.Parse(NextArg(argEnum)); } catch (FormatException) { throw new UsageException(); } }
App.MakePath Method
Returns a full path to a file or directory given a full path or a path relative to the directory containing the CodeDoc XML project file or, if m_projectFilePath hasn't been set yet, relative to the current directory.
Parameters
fileOrDirName The name of the file or directory -- an absolute path or a path relative to the directory containing the CodeDoc XML project file or, if m_projectFilePath hasn't been set yet, relative to the current directory. flags Contains FileFlags.File if fileOrDirName is allowed to be a file, FileFlags.Directory if fileOrDirName is allowed to be a directory, FileFlags.Nonexistent if the file or directory is allowed to not exist, or any combination of the three as long as at least one of FileFlags.File or FileFlags.Directory is present. isDir On exit, contains true if fileOrDirName refers to an existing directory.
Exceptions
|
string MakePath(string fileOrDirName, FileFlags flags, out bool isDir) { // set <fullPath> to the absolute path of the file or directory named // <fileOrDirName>; throw an exception if the file or directory doesn't // obey <flags>; set <isDir> to true if <fullPath> is an existing // directory isDir = false; string fullPath; try { if (m_projectFilePath != null) fullPath = GetPath(fileOrDirName, m_projectFilePath); else fullPath = Path.GetFullPath(fileOrDirName); if (File.Exists(fullPath)) { // <fullPath> is an existing file -- check if that's allowed if ((flags & FileFlags.File) == 0) { // directory expected but file found throw new ProjectFileException(Resources.DirectoryExpected, fullPath); } } else if (Directory.Exists(fullPath)) { // <fullPath> is an existing directory -- check if that's // allowed if ((flags & FileFlags.Directory) == 0) { // file expected but directory found throw new ProjectFileException(Resources.FileExpected, fullPath); } isDir = true; } else { // <fullPath> doesn't exist -- check if that's allowed if ((flags & FileFlags.Nonexistent) == 0) { if ((flags & (FileFlags.File | FileFlags.Directory)) == FileFlags.File) { // file expected but not found throw new ProjectFileException(Resources.FileNotFound, fullPath); } else if ((flags & (FileFlags.File | FileFlags.Directory)) == FileFlags.Directory) { // directory expected but not found throw new ProjectFileException(Resources.DirectoryNotFound, fullPath); } else { // either file or directory expected but neither found throw new ProjectFileException( Resources.FileOrDirectoryNotFound, fullPath); } } } } catch (ArgumentException) { fullPath = null; } catch (NotSupportedException) { fullPath = null; } catch (PathTooLongException) { fullPath = null; } catch (FileNotFoundException) { fullPath = null; } catch (DirectoryNotFoundException) { fullPath = null; } if (fullPath == null) { throw new ProjectFileException(Resources.InvalidPath, fileOrDirName); } return fullPath; }
App.CreateDirectoryIfNeeded Method
Creates a directory if it doesn't exist already.
Parameters
dirPath The full path to the directory to create (if it doesn't exist). |
void CreateDirectoryIfNeeded(string dirPath) { // create the directory if needed; if an error occurs, set <error> to // the exception text string error; try { if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath); return; } catch (IOException ex) { error = ex.Message; } catch (UnauthorizedAccessException ex) { error = ex.Message; } catch (NotSupportedException ex) { error = ex.Message; } // throw a more general exception than those above throw new ProjectFileException(Resources.CannotCreateDirectory, dirPath); }
App.CopyFileContents Method
Copies the contents of a file. Unlike File.Copy, this method does not copy file attributes such as read-only.
Parameters
sourceFileName The name of the file to copy. destFileName The name of the destination file. overwrite true to allow overwriting of the destination file if it exsts, false if not. |
void CopyFileContents(string sourceFileName, string destFileName, bool overwrite) { // if the destination file already exists and the caller didn't // specify allowing overwriting, throw an exception if (!overwrite && File.Exists(destFileName)) { throw new Exception(String.Format(Resources.DestinationFileExists, destFileName)); } // copy the file using (FileStream sourceStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read)) { using (FileStream destStream = new FileStream(destFileName, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[ Math.Min(0x10000, sourceStream.Length)]; while (true) { int bytesRead = sourceStream.Read(buffer, 0, buffer.Length); if (bytesRead == 0) break; destStream.Write(buffer, 0, bytesRead); } } } }
App.ConvertTextFileToHtml Method
Converts a text file to HTML.
Parameters
sourceFileName The name of the text file to convert. destFileName The name of the destination HTML file. overwrite true to allow overwriting of the destination file if it exsts, false if not. |
void ConvertTextFileToHtml(string sourceFileName, string destFileName, bool overwrite) { // if the destination file already exists and the caller didn't // specify allowing overwriting, throw an exception if (!overwrite && File.Exists(destFileName)) { throw new Exception(String.Format(Resources.DestinationFileExists, destFileName)); } // convert the text file to HTML using (TextReader textReader = new StreamReader(sourceFileName)) { using (TextWriter textWriter = new StreamWriter(destFileName)) { using (HtmlTextWriterHelper htmlWriter = new HtmlTextWriterHelper(textWriter, null)) { ConvertTextStreamToHtml(textReader, htmlWriter); } } } }
App.ConvertTextStreamToHtml Method
Converts a text stream to HTML.
Parameters
textReader The stream of text to read. htmlWriter Where to write the HTML. |
void ConvertTextStreamToHtml(TextReader textReader, HtmlTextWriterHelper htmlWriter) { // begin the HTML document htmlWriter.BeginHtmlDocument(HtmlDocType.XhtmlTransitional, true); // begin the "<head>" block htmlWriter.FormatBeginTag("head\n"); // write the "<title>" block htmlWriter.RenderBeginTag("title"); htmlWriter.WriteEncodedText(Resources.DefaultContentsTitle); htmlWriter.FormatEndTag("\n\n"); // write the "<link>" element htmlWriter.FormatTag("link,rel,href\n", "stylesheet", "_CodeDoc.css"); // end the "<head>" block htmlWriter.FormatEndTag("\n\n"); // begin the "<body>" block htmlWriter.AddAttribute("id", "TextFile"); htmlWriter.FormatBeginTag("body\n"); // begin the "<pre>" block htmlWriter.FormatBeginTag("pre"); // write the body text -- loop once for each line in the input file StringBuilder buffer = new StringBuilder(1000); while (true) { // read a line of text string line = textReader.ReadLine(); if (line == null) break; // convert the line to HTML htmlWriter.WriteEncodedText(ExpandTabs(line, 4, buffer)); htmlWriter.WriteLine(); } // end the "<pre>" block htmlWriter.FormatEndTag("\n"); // write the footer htmlWriter.FormatBeginTag("div,class", "ContentsFooter"); htmlWriter.FormatEndTag("\n\n"); // end the "<body>" block htmlWriter.FormatEndTag("\n"); // end the HTML document htmlWriter.EndHtmlDocument(); }
App.ExpandTabs Method
Expands tab characters to spaces.
Parameters
input tabWidth The number of columns (spaces) represented by a tab character. buffer A StringBuilder to use as a buffer. |
string ExpandTabs(string input, int tabWidth, StringBuilder buffer) { buffer.Length = 0; for (int index = 0; index < input.Length; index++) { char ch = input[index]; if (ch == '\t') { buffer.Append(' '); while ((buffer.Length % tabWidth) != 0) buffer.Append(' '); } else buffer.Append(ch); } return buffer.ToString(); } #if false /// <summary> /// Returns <n>true</n> if two file paths appear to refer to the same file, /// or at least to two files that have the same length and last-modified /// time. /// </summary> /// /// <param name="path1">The first path.</param> /// /// <param name="path2">The second path.</param> /// bool AreFilesEqual(string path1, string path2) { FileInfo file1 = new FileInfo(path1); FileInfo file2 = new FileInfo(path2); return ((file1.Length == file2.Length) && (file1.LastWriteTime == file2.LastWriteTime)); } #endif
App.RemoveDuplicates Method
Returns an output list containing the same values as a given input list, but with duplicate values removed.
Type Parameters
T The type of element in the list.
Parameters
input The sorted input list. |
public static List<T> RemoveDuplicates<T>(List<T> input) { List<T> output = new List<T>(input.Count); T previous = default(T); bool first = true; foreach (T value in input) { if (first || !value.Equals(previous)) output.Add(value); previous = value; first = false; } return output; } ////////////////////////////////////////////////////////////////////////// // Helper Classes & Enums //
App.ReferenceNotFound Class
Holds information about an unresolved hyperlink reference from one topic to another. This is informational, and doesn't necessarily indicate an error. |
public class ReferenceNotFound : IComparable<ReferenceNotFound> { ////////////////////////////////////////////////////////////////////// // Private Fields //
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_reference;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
Topic m_contextTopic;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
int m_lineNumber;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
FindTopicSettings m_settings;
//////////////////////////////////////////////////////////////////////
// Public Properties
//
App.ReferenceNotFound.Reference Property
The presumed (but failed) qualified or unqualified member name of the topic being referenced. |
public string Reference { [DebuggerStepThrough] get { return m_reference; } }
App.ReferenceNotFound.ContextTopic Property
The context containing the failed reference. |
public Topic ContextTopic { [DebuggerStepThrough] get { return m_contextTopic; } }
App.ReferenceNotFound.LineNumber Property
The line number of the reference, within the source file containing ContextTopic. |
public int LineNumber { [DebuggerStepThrough] get { return m_lineNumber; } }
App.ReferenceNotFound.Settings Property
Settings used to resolved the failed refernce. |
public FindTopicSettings Settings { [DebuggerStepThrough] get { return m_settings; } }
App.ReferenceNotFound.IsTypeOnly Property
Return true if this is a reference to a type, false if it may be a reference to anything (type, method, etc.) |
public bool IsTypeOnly { get { return (m_settings & FindTopicSettings.TypeOnly) != 0; } } ////////////////////////////////////////////////////////////////////// // Public Methods Fields //
ReferenceNotFound Constructor
Initializes an instance of this class.
Parameters
reference The presumed (but failed) qualified or unqualified member name of the topic being referenced. contextTopic The topic containing the reference. lineNumber The line number of the reference, within the source file containing contextTopic. settings Settings used to resolve the reference. |
public ReferenceNotFound(string reference, Topic contextTopic, int lineNumber, FindTopicSettings settings) { m_reference = reference; m_contextTopic = contextTopic; m_lineNumber = lineNumber; m_settings = settings; } ////////////////////////////////////////////////////////////////////// // Overrides // public override string ToString() { if (IsTypeOnly) return String.Format(Resources.TypeOnly, Reference); else return Reference; } ////////////////////////////////////////////////////////////////////// // IComparable Implementation // public int CompareTo(ReferenceNotFound other) { int compare; if ((compare = Reference.CompareTo(other.Reference)) != 0) return compare; if ((compare = ((IsTypeOnly ? 1 : 0) - (other.IsTypeOnly ? 1 : 0))) != 0) return compare; return LineNumber - other.LineNumber; } }
App.UsageException Class
Indicates a command-line usage error. |
class UsageException : Exception
{
}
App.ProjectFileException Class
Indicates an error in the CodeDoc XML project file.
Remarks
The application is responsible for adding the file name and current line number of the CodeDoc XML project file to the exception message. |
class ProjectFileException : Exception
{
ProjectFileException Constructor
Initializes an instance of this class.
Parameters
format A formatting string for an error message to include with the exception. args Formatting arguments for the error message. |
public ProjectFileException(string format, params object[] args) : base(String.Format(format, args)) { } }
App.FileFlags Enumeration
Information about a file or directory.
Members
|
[Flags]
enum FileFlags
{
App.FileFlags.File Enumeration Value
Item is a file. |
File = 0x1,
App.FileFlags.Directory Enumeration Value
Item is a directory. |
Directory = 0x2,
App.FileFlags.Nonexistent Enumeration Value
Item doesn't exist. |
Nonexistent = 0x4
}
}
DocBrowser Class
Represents a DocBrowser, i.e. an HTML content browser that includes a "Contents" and "Index" view. A DocBrowser object is also the root of the DocBrowserNode hierarchy that comprises the "Contents" view. |
[DebuggerDisplay("DocBrowserNode: {Title}")] class DocBrowser : DocBrowserNode { ////////////////////////////////////////////////////////////////////////// // Private Fields //
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_rootPath;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_pagesRelativePath;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_pagesAbsolutePath;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_framesetFileName;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_basicFramesetFileName;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_baseName;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
int m_leftFrameWidth;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
bool m_markOfTheWeb;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
List<IndexEntry> m_indexEntries = new List<IndexEntry>();
//////////////////////////////////////////////////////////////////////////
// Public Properties
//
DocBrowser.RootPath Property
Gets the full path to the DocBrowser root directory, i.e. the directory into which the frameset root file(s) will be written. Derived from the "Path" attribute of the "<CreateDocBrowser>" element of the CodeDoc XML project file. |
public string RootPath { [DebuggerStepThrough] get { return m_rootPath; } }
DocBrowser.PagesRelativePath Property
Gets the path to the DocBrowser pages directory, i.e. the directory into which generated files are written, relative to RootPath. null if the DocBrowser pages directory is the same as the DocBrowser root directory. From the "PagesRelativePath" attribute of the "<CreateDocBrowser>" element of the CodeDoc XML project file. |
public string PagesRelativePath { [DebuggerStepThrough] get { return m_pagesRelativePath; } }
DocBrowser.PagesAbsolutePath Property
Gets the full path to the DocBrowser pages directory, i.e. the directory into which generated files are written. Based on PagesRelativePath and RootPath. |
public string PagesAbsolutePath { [DebuggerStepThrough] get { return m_pagesAbsolutePath; } }
DocBrowser.PathFromPagesToRoot Property
Gets the path to the DocBrowser root directory, i.e. the directory into which the root frameset files are written, relative to the DocBrowser pages directory; for example, "../..". null if the DocBrowser pages directory is the same as the DocBrowser root directory. |
public string PathFromPagesToRoot { get { if (m_pagesRelativePath == null) return null; int slashes = Regex.Matches(m_pagesRelativePath, @"[\/]").Count; StringBuilder result = new StringBuilder(50); while (slashes-- >= 0) { if (result.Length > 0) result.Append('/'); result.Append(".."); } return result.ToString(); } }
DocBrowser.FramesetFileName Property
Gets the name of the enhanced frameset HTML file. null if no enhanced frameset HTML file will be generated. |
public string FramesetFileName { [DebuggerStepThrough] get { return m_framesetFileName; } }
DocBrowser.BasicFramesetFileName Property
Gets the name of the basic (downlevel) frameset HTML file. null if no basic frameset HTML file will be generated. |
public string BasicFramesetFileName { [DebuggerStepThrough] get { return m_basicFramesetFileName; } }
DocBrowser.BaseName Property
Gets the name of the DocBrowser frameset HTML file base; for example, if "BaseName" is "MyApi", the DocBrowser frameset HTML file is named "MyApi.htm". |
public string BaseName { [DebuggerStepThrough] get { return m_baseName; } }
DocBrowser.LeftFrameWidth Property
Gets the width of the left browser frame (i.e. the Contents/Index frame) of the DocBrowser, in pixels. From the "LeftFrameWidth" attribute of the "<CreateDocBrowser>" element of the CodeDoc XML project file. |
public int LeftFrameWidth { [DebuggerStepThrough] get { return m_leftFrameWidth; } }
DocBrowser.MarkOfTheWeb Property
Gets a value that indicates whether to include the Mark of the Web on generated HTML pages. See HtmlTextWriterHelper.BeginHtmlDocument for more information. |
public bool MarkOfTheWeb { [DebuggerStepThrough] get { return m_markOfTheWeb; } }
DocBrowser.IndexEntries Property
Gets the collection of IndexEntry objects that comprise the index extries associated with this DocBrowser. |
public ICollection<IndexEntry> IndexEntries { [DebuggerStepThrough] get { return new ReadOnlyCollection<IndexEntry>(m_indexEntries); } }
DocBrowser.TabsHtmlFileName Property
Gets the name of the DocBrowser *_Tabs.htm file, i.e. the frame that implements the tabs. |
public string TabsHtmlFileName { get { return String.Format("{0}_Tabs.htm", BaseName); } }
DocBrowser.ContentsHtmlFileName Property
Gets the name of the DocBrowser *_Contents.htm file, i.e. what's in the "Contents" tab frame. |
public string ContentsHtmlFileName { get { return String.Format("{0}_Contents.htm", BaseName); } }
DocBrowser.IndexHtmlFileName Property
Gets the name of the DocBrowser *_Index.htm file, i.e. what's in the "Index" tab frame. |
public string IndexHtmlFileName { get { return String.Format("{0}_Index.htm", BaseName); } }
DocBrowser.IndexXmlFileName Property
Gets the name of the DocBrowser *_Index.xml file (used by other applications). |
public string IndexXmlFileName { get { return String.Format("{0}_Index.xml", BaseName); } }
DocBrowser.AllNodes Property
Returns an enumeration of all DocBrowserNode objects in this DocBrowser, excluding the root node. |
public IEnumerable<DocBrowserNode> AllNodes { get { return GetDescendentNodes(); } } ////////////////////////////////////////////////////////////////////////// // Public Methods //
DocBrowser Constructor
Initializes an instance of this class.
Parameters
nodeId The value to use to initialize the DocBrowserNode.NodeId property. rootPath The value to use to initialize the RootPath property. pagesRelativePath The value to use to initialize the PagesRelativePath property. framesetFileName The value to use to initialize the FramesetFileName property. basicFramesetFileName The value to use to initialize the BasicFramesetFileName property. title The value to use to initialize the DocBrowserNode.Title property. baseName The value to use to initialize the BaseName property. leftFrameWidth The value to use to initialize the LeftFrameWidth property. markOfTheWeb The value to use to initialize the MarkOfTheWeb property. |
public DocBrowser(string nodeId, string rootPath, string pagesRelativePath, string framesetFileName, string basicFramesetFileName, string title, string baseName, int leftFrameWidth, bool markOfTheWeb) : base(nodeId, 0, null, null, null, title, true) { m_rootPath = rootPath; m_pagesRelativePath = pagesRelativePath; if (pagesRelativePath != null) m_pagesAbsolutePath = Path.Combine(rootPath, pagesRelativePath); else m_pagesAbsolutePath = rootPath; m_framesetFileName = framesetFileName; m_basicFramesetFileName = basicFramesetFileName; m_baseName = baseName; m_leftFrameWidth = leftFrameWidth; m_markOfTheWeb = markOfTheWeb; }
DocBrowser.AddIndexEntry Method (IndexEntry)
Adds an index entry to this node given an IndexEntry object.
Parameters
indexEntry The index entry to add. |
internal void AddIndexEntry(IndexEntry indexEntry) { m_indexEntries.Add(indexEntry); }
DocBrowser.AddIndexEntry Method (string, DocBrowserNode, string)
Adds an index entry to this node given a label and a DocBrowserNode.
Parameters
label The label of the index entry, i.e. what's displayed in the index. docBrowserNode The DocBrowserNode associated with this index entry. bookmark The bookmark of the index entry, or null if none. The bookmark is the part of a Web page's URL after "#". |
internal void AddIndexEntry(string label, DocBrowserNode docBrowserNode, string bookmark) { m_indexEntries.Add(new IndexEntry(label, docBrowserNode, bookmark)); }
DocBrowser.SortIndexEntries Method
Sorts the index entries. |
internal void SortIndexEntries() { m_indexEntries.Sort(); }
DocBrowser.RemoveDuplicateIndexEntries Method
Sorts the index entries. |
internal void RemoveDuplicateIndexEntries() { m_indexEntries = App.RemoveDuplicates(m_indexEntries); } }
DocBrowserNode Class
A node in a DocBrowser tree. |
[DebuggerDisplay("DocBrowserNode: {Title}")] class DocBrowserNode { ////////////////////////////////////////////////////////////////////////// // Private Fields //
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_nodeId;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
int m_topicId;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_originalFilePath;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_fileName;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_url;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_title;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
DocBrowserNode m_parentNode;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
bool m_initiallyExpanded;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
List<DocBrowserNode> m_childNodes;
//////////////////////////////////////////////////////////////////////////
// Public Properties
//
DocBrowserNode.NodeId Property
Gets the optional NodeId of this node, an arbitrary string used to refer to the node from elsewhere in the CodeDoc XML project file. From the "NodeId" attribute of a "<CreateDocBrowser>" or "<DocBrowserNode>" element. null if no ID is specified. |
public string NodeId { [DebuggerStepThrough] get { return m_nodeId; } }
DocBrowserNode.TopicId Property
Gets the optional TopicId of this node, an integer used to uniquely identify the node within the DocBrowser tree. A TopicId value may be automatically generated, or may be manually specified by the "TopicId" attribute of a "<CreateDocBrowser>" or "<DocBrowserNode>" element. Unlike NodeId, which is used primarily as a way of referring to another node within the CodeDoc XML project file, TopicId is used at run time of the DocBrowser HTML/JScript code. |
public int TopicId { [DebuggerStepThrough] get { return m_topicId; } }
DocBrowserNode.OriginalFilePath Property
Gets the full path of the original file referred to by this DocBrowser node, i.e. the file that will be copied into the DocBrowser directory. Derived from the "Path" attribute of a "<DocBrowserStaticPages>" or "<DocBrowserNode>" element. null for the root node, i.e. the DocBrowserNode object that's also a DocBrowser object; also null for DocBrowser nodes that don't have static original files (e.g. nodes corresponding to XML documentation). |
public string OriginalFilePath { [DebuggerStepThrough] get { return m_originalFilePath; } }
DocBrowserNode.FileName Property
Gets the name of the content file containing the page/document referred to by this DocBrowser node. This is the name of the file that's stored in the DocBrowser directory, if applicable. In the case of static (non-generated) files, this is derived from the "NewFileName" attribute of a "<DocBrowserStaticPages>" or "<DocBrowserNode>" element, or the "Path" attribute if "NewFileName" isn't specified. FileName may be automatically generated in the case of DocBrowser nodes that don't have static original files (e.g. nodes corresponding to XML documentation). |
public string FileName { [DebuggerStepThrough] get { return m_fileName; } }
DocBrowserNode.Url Property
Gets the URL of the page/document that the DocBrowser node refers to. The URL is relative to the DocBrowser directory. |
public string Url { [DebuggerStepThrough] get { return m_url; } }
DocBrowserNode.Title Property
Gets the title of this DocBrowser node. For the root DocBrowser node (i.e. the DocBrowserNode object that's also a DocBrowser object), Title is the title of the DocBrowser itself, i.e. the title that's displayed in the title bar of the browser. |
public string Title { [DebuggerStepThrough] get { return m_title; } }
DocBrowserNode.ParentNode Property
Gets the parent node of this DocBrowser node, or null if none. |
public DocBrowserNode ParentNode { [DebuggerStepThrough] get { return m_parentNode; } }
DocBrowserNode.InitiallyExpanded Property
Sets or gets a value indicating whether this DocBrowser node is initially expanded or collapsed. |
public bool InitiallyExpanded { [DebuggerStepThrough] get { return m_initiallyExpanded; } set { m_initiallyExpanded = value; } }
DocBrowserNode.ChildNodes Property
Gets the collection of DocBrowserNode objects that are children of this node; null if none. |
public ICollection<DocBrowserNode> ChildNodes { [DebuggerStepThrough] get { if (m_childNodes == null) return null; else return new ReadOnlyCollection<DocBrowserNode>(m_childNodes); } }
public DocBrowser DocBrowser { get { DocBrowserNode nodeSearch = this; while (!(nodeSearch is DocBrowser)) nodeSearch = nodeSearch.ParentNode; return (DocBrowser) nodeSearch; } } ////////////////////////////////////////////////////////////////////////// // Public Methods //
DocBrowserNode Constructor
Initializes an instance of this class.
Parameters
nodeId The value to use to initialize the NodeId property. topicId The value to use to initialize the TopicId property. originalFilePath The value to use to initialize the OriginalFilePath property. fileName The value to use to initialize the FileName property. url The value to use to initialize the Url property. title The value to use to initialize the Title property. initiallyExpanded |
public DocBrowserNode(string nodeId, int topicId, string originalFilePath, string fileName, string url, string title, bool initiallyExpanded) { m_nodeId = nodeId; m_topicId = topicId; m_originalFilePath = originalFilePath; m_fileName = fileName; m_url = url; m_title = title; m_initiallyExpanded = initiallyExpanded; }
DocBrowserNode.GetDescendentNodes Method
Returns an enumeration of all descendent nodes of this node, i.e. all nodes for which this node is a parent, grandparent, etc. |
public IEnumerable<DocBrowserNode> GetDescendentNodes() { if (m_childNodes == null) yield break; foreach (DocBrowserNode node in m_childNodes) { yield return node; foreach (DocBrowserNode descendentNode in node.GetDescendentNodes()) yield return descendentNode; } } ////////////////////////////////////////////////////////////////////////// // Internal Methods //
DocBrowserNode.AddChild Method
Adds a child DocBrowserNode to this node.
Parameters
childNode The node to add. |
internal void AddChild(DocBrowserNode childNode) { if (m_childNodes == null) m_childNodes = new List<DocBrowserNode>(); m_childNodes.Add(childNode); childNode.m_parentNode = this; } }
IndexEntry Class
An entry in a DocBrowser index. Each DocBrowserNode has zero or more associated index entries. |
class IndexEntry : IComparable<IndexEntry> { ////////////////////////////////////////////////////////////////////// // Private Fields //
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_label;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
DocBrowserNode m_docBrowserNode;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
string m_bookmark;
IndexEntry.m_sortKey Field
The string to sort by. |
string m_sortKey; ////////////////////////////////////////////////////////////////////// // Public Properties //
IndexEntry.Label Property
Gets the label of the index entry, i.e. what's displayed in the index. |
public string Label { [DebuggerStepThrough] get { return m_label; } }
IndexEntry.DocBrowserNode Property
Gets the DocBrowserNode associated with this index entry. Each DocBrowserNode refers to zero or more index entries. |
public DocBrowserNode DocBrowserNode { [DebuggerStepThrough] get { return m_docBrowserNode; } }
IndexEntry.Bookmark Property
Gets the bookmark of the index entry, or null if none. |
public string Bookmark { [DebuggerStepThrough] get { return m_bookmark; } } ////////////////////////////////////////////////////////////////////// // Override Methods // public override string ToString() { return Label; } public override bool Equals(object obj) { IndexEntry other = obj as IndexEntry; if (obj == null) return false; return StringComparer.OrdinalIgnoreCase.Equals(Label, other.Label) && (DocBrowserNode.TopicId == other.DocBrowserNode.TopicId) && StringComparer.OrdinalIgnoreCase.Equals(Bookmark, other.Bookmark); } public override int GetHashCode() { return StringComparer.OrdinalIgnoreCase.GetHashCode(Label) ^ DocBrowserNode.GetHashCode() ^ StringComparer.OrdinalIgnoreCase.GetHashCode(Bookmark); } ////////////////////////////////////////////////////////////////////// // IComparable<IndexEntry> Implementation // int IComparable<IndexEntry>.CompareTo(IndexEntry other) { return StringComparer.Ordinal.Compare(m_sortKey, other.m_sortKey); } ////////////////////////////////////////////////////////////////////// // Internal Methods //
IndexEntry Constructor
Initializes an instance of this class.
Parameters
label The value of the Label property. docBrowserNode The value of the DocBrowserNode property. bookmark The value of the Bookmark property. |
internal IndexEntry(string label, DocBrowserNode docBrowserNode, string bookmark) { // initialize state m_label = label; m_docBrowserNode = docBrowserNode; m_bookmark = bookmark; // create a sort key; note that sorting is done by converting // the label to lowercase and then doing an ordinal sort -- other // methods (e.g. doing a StringComparer.OrdinalIgnoreCase sort) // can cause problems (e.g. the characters "[\]^_`" sorting // incorrectly in JScript vs. C#) m_sortKey = label.ToLower(CultureInfo.InvariantCulture); } }
InitiallyExpand Enumeration
Specifies which nodes of a DocBrowser subtree generated from XML comment documentation are initially expanded.
Members
|
public enum InitiallyExpand {
InitiallyExpand.None Enumeration Value
No nodes are initially expanded. |
None,
InitiallyExpand.Namespaces Enumeration Value
Only namespace nodes are initially expanded. |
Namespaces,
InitiallyExpand.NamespacesAndTypes Enumeration Value
Only namespace and type nodes are initially expanded. |
NamespacesAndTypes,
InitiallyExpand.All Enumeration Value
All nodes are initially expanded. |
All, } }