/* Copyright (c) Eric Ledoux. All rights reserved. */ /* See http://www.dwell.net/terms for code sharing information. */ // DefaultTopicRenderer.cs // // Implements class DefaultTopicRenderer and related types. // using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Web.UI; using System.Xml; using DwellNet.CodeDoc; using CodeDocRenderer.Properties; namespace DwellNet.CodeDoc {
public class DefaultTopicRenderer : TopicRenderer { ////////////////////////////////////////////////////////////////////////// // Public Methods //
DefaultTopicRenderer Constructor
Initializes an instance of this class. |
public DefaultTopicRenderer()
{
}
DefaultTopicRenderer.GenerateDocHtml Method
Executes one of two documentation generation passes: In the first pass, each section (e.g. "<summary>") of a given Topic's Xml property is converted to HTML, stored in Topic.XmlCommentSections. In the second pass, HTML documentation for the topic is written to an HtmlTextWriterHelper.
Parameters
embedded If true "embedded" HTML is generated, i.e. a "<div>" designed to fit compactly within formatted source code. If false, a complete HTML document is generated. Ignored for the first pass. htmlWriter For the first pass, this is null. For the second path, this is HtmlTextWriterHelper to write to.
Remarks
The first pass of the documentation generation process must be peformed for all documentation topics before the second pass is performed on any topic. |
public override void GenerateDocHtml(bool embedded, HtmlTextWriterHelper htmlWriter) { // make sure we have unique topic HTML file names etc. Topic.DocumentationSet.BeginUsingSources(); // execute the appropriate pass if (htmlWriter == null) { // first pass... // generate XML comment section HTML foreach (XmlCommentSection section in Topic.XmlCommentSections) { using (XmlReader xmlReader = section.GetXmlReader()) { // generate HTML for this section, stored in <html> StringBuilder html = new StringBuilder(2000); using (StringWriter stringWriter = new StringWriter(html)) { using (HtmlTextWriterHelper sectionWriter = new HtmlTextWriterHelper(stringWriter)) { try { TopicWriter topicWriter = CreateTopicWriter( Topic, sectionWriter, this); topicWriter.WarningInSourceFile += delegate(SourceFile sourceFile, int lineNumber, string message) { FireWarningInSourceFile(lineNumber, "{0}", message); }; topicWriter.GenerateXmlSectionHtml(section, xmlReader); } catch (XmlException ex) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.UnexpectedXmlError, ex.Message); } } } // do special processing, if required, based on what kind // of section this is if (section.SectionKind == XmlCommentSectionKind.Param) { // this is a "<param>" section -- make sure there's a // matching parameter in the source code if (String.IsNullOrEmpty(section.NameAttribute)) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.MissingAttribute, "param", "name"); } else { Parameter parameter = Topic.GetParameter(section.NameAttribute); if (parameter == null) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.NoParameter, section.NameAttribute, Topic.QualifiedMemberNameWithoutNamespace); } } } else if (section.SectionKind == XmlCommentSectionKind.TypeParam) { // this is a "<typeparam>" section -- make sure // there's a matching type parameter in the source code if (String.IsNullOrEmpty(section.NameAttribute)) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.MissingAttribute, "typeparam", "name"); } else { if (!Topic.HasTypeParameter(section.NameAttribute)) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.NoTypeParameter, section.NameAttribute, Topic.QualifiedMemberNameWithoutNamespace); } } } else if (section.SectionKind == XmlCommentSectionKind.Exception) { // this is a "<exception>" section -- look up the // exception type if (String.IsNullOrEmpty(section.CrefAttribute)) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.MissingAttribute, "exception", "cref"); } else { section.ReferencedTopic = Topic.DocumentationSet.FindDocumentedTopic( section.CrefAttribute, Topic, ((IXmlLineInfo) xmlReader).LineNumber, FindTopicSettings.TypeOnly); } } else if (section.SectionKind == XmlCommentSectionKind.Permission) { // this is a "<permission>" section -- look up the // permission type if (String.IsNullOrEmpty(section.CrefAttribute)) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.MissingAttribute, "permission", "cref"); } else { section.ReferencedTopic = Topic.DocumentationSet.FindDocumentedTopic( section.CrefAttribute, Topic, ((IXmlLineInfo) xmlReader).LineNumber, FindTopicSettings.TypeOnly); } } else if (section.SectionKind == XmlCommentSectionKind.SeeAlso) { // this is a "<seealso>" section -- look up the // reference, if "cref" is provided bool hasCref = !String.IsNullOrEmpty( section.CrefAttribute); bool hasHref = !String.IsNullOrEmpty( section.HrefAttribute); if (hasCref && !hasHref) { section.ReferencedTopic = Topic.DocumentationSet.FindDocumentedTopic( section.CrefAttribute, Topic, ((IXmlLineInfo) xmlReader).LineNumber, 0); } else if (hasHref && !hasCref) { // this "<seealso>" has an "href", not a "cref" } else { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.CrefOrHrefAttribute, "seealso"); } } // store <html> in <section> Topic.AddXmlSectionHtml(section, html.ToString()); } } } else { // second pass: generate the HTML page TopicWriter topicWriter = CreateTopicWriter(Topic, htmlWriter, this); topicWriter.WarningInSourceFile += delegate(SourceFile sourceFile, int lineNumber, string message) { FireWarningInSourceFile(lineNumber, "{0}", message); }; if (embedded) topicWriter.WriteEmbeddedTopic(); else topicWriter.WriteTopicPage(); } }
DefaultTopicRenderer.GenerateCodeNamespaceHtml Method
Assuming Topic is a namespace topic, this method generates the HTML file, used in the formatted code directory, that represents the namespace and contains links to the formatted code HTML files. list.
Parameters
htmlWriter The HtmlTextWriterHelper to write to. |
public override void GenerateCodeNamespaceHtml( HtmlTextWriterHelper htmlWriter) { // quit if this isn't a namespace topic NamespaceTopic namespaceTopic = Topic as NamespaceTopic; if (namespaceTopic == null) return; // this isn't an overload list topic // generate the HTML page Debug.Assert(CodeHtml == true); TopicWriter topicWriter = CreateTopicWriter(Topic, htmlWriter, this); topicWriter.WarningInSourceFile += delegate(SourceFile sourceFile, int lineNumber, string message) { FireWarningInSourceFile(lineNumber, "{0}", message); }; topicWriter.WriteCodeNamespacePage(); }
DefaultTopicRenderer.GenerateCodeOverloadListHtml Method
Assuming Topic is an overload list topic, this method generates the HTML file, used in the formatted code directory, that contains links to the documentation block of each overload topic in the overload list.
Parameters
htmlWriter The HtmlTextWriterHelper to write to. |
public override void GenerateCodeOverloadListHtml( HtmlTextWriterHelper htmlWriter) { // quit if this isn't an overload list topic OverloadListTopic overloadListTopic = Topic as OverloadListTopic; if (overloadListTopic == null) return; // this isn't an overload list topic // generate the HTML page Debug.Assert(CodeHtml == true); TopicWriter topicWriter = CreateTopicWriter(Topic, htmlWriter, this); topicWriter.WarningInSourceFile += delegate(SourceFile sourceFile, int lineNumber, string message) { FireWarningInSourceFile(lineNumber, "{0}", message); }; topicWriter.WriteCodeOverloadListPage(); }
DefaultTopicRenderer.CreateTopicWriter Method
Creates an instance of TopicWriter or a derived class.
Parameters
topic The topic to render. textWriter The TextWriter that renders the markup content. topicRenderer The TopicRenderer that created this TextWriter.
Remarks
The default implementation of CreateTopicWriter creates an instance of TopicWriter. This method is intended to be overridden by a derived class, which can cause an instance of a subclass of TopicWriter to be returned. |
public virtual TopicWriter CreateTopicWriter(Topic topic, TextWriter textWriter, DefaultTopicRenderer topicRenderer) { return new TopicWriter(topic, textWriter, topicRenderer); } }
TopicWriter Class
Converts a topic to HTML. |
public class TopicWriter : HtmlTextWriterHelper { ////////////////////////////////////////////////////////////////////////// // Private Constants //
TopicWriter.LBrace Field
Left brace (to make brace matching work better in text editor). |
const char LBrace = '{';
TopicWriter.RBrace Field
Right brace (to make brace matching work better in text editor). |
const char RBrace = '}';
TopicWriter.LParen Field
Left parenthesis (to make parenthesis matching work better in a text editor). |
const char LParen = '(';
TopicWriter.RParen Field
Right parenthesis (to make parenthesis matching work better in a text editor). |
const char RParen = ')';
TopicWriter.LSquare Field
Left square bracket (to make square bracket matching work better in a text editor). |
const char LSquare = '[';
TopicWriter.RSquare Field
Right square bracket (to make square bracket matching work better in a text editor). |
const char RSquare = ']';
TopicWriter.LAngle Field
Left angle bracket (to make angle bracket matching work better in a text editor). |
const char LAngle = '<';
TopicWriter.RAngle Field
Right angle bracket (to make angle bracket matching work better in a text editor). |
const char RAngle = '>'; ////////////////////////////////////////////////////////////////////////// // Private Fields //
TopicWriter.s_insignificantWhiteSpaceRegex Field
Matches what would be considered insignificant white space in HTML. |
static readonly Regex s_insignificantWhiteSpaceRegex = new Regex(@"[ \r\n\t]+");
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
Topic m_topic;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
DefaultTopicRenderer m_topicRenderer;
//////////////////////////////////////////////////////////////////////////
// Public Properties
//
public Topic Topic { [DebuggerStepThrough] get { return m_topic; } [DebuggerStepThrough] internal set { m_topic = value; } }
public DefaultTopicRenderer TopicRenderer { [DebuggerStepThrough] get { return m_topicRenderer; } [DebuggerStepThrough] internal set { m_topicRenderer = value; } } ////////////////////////////////////////////////////////////////////////// // Public Events //
TopicWriter.WarningInSourceFile Event
Fired to indicate a warning associated with a given line number in a source file.
Remarks
The application may want to use this event to provide feedback to the user. |
public event WarningInSourceFileEventDelegate WarningInSourceFile; ////////////////////////////////////////////////////////////////////////// // Private Properties //
char ParamListStart { get { if (Topic.PropertyKind == PropertyKind.Indexer) return LSquare; else return LParen; } }
char ParamListEnd { get { if (Topic.PropertyKind == PropertyKind.Indexer) return RSquare; else return RParen; } } ////////////////////////////////////////////////////////////////////////// // Public Methods //
TopicWriter Constructor
Initializes an instance of this class.
Parameters
topic The topic to render. textWriter The TextWriter that renders the markup content. topicRenderer The TopicRenderer that created this TextWriter. |
public TopicWriter(Topic topic, TextWriter textWriter, DefaultTopicRenderer topicRenderer) : base(textWriter) { m_topic = topic; m_topicRenderer = topicRenderer; }
TopicWriter.GenerateXmlSectionHtml Method
Generates HTML for a single section (e.g. "<summary>") within the XML of a single topic, and sets XmlCommentSection.NameAttribute, XmlCommentSection.CrefAttribute, and XmlCommentSection.LineNumber. Used in the first pass of documentation generation.
Parameters
section The section being parsed. xmlReader After the first call to XmlReader.Read, this is positioned on the XML element that begins the section; for example, "<summary>". |
public void GenerateXmlSectionHtml(XmlCommentSection section, XmlReader xmlReader) { // initialize <xmlReader> int initialDepth = xmlReader.Depth; bool ok = xmlReader.Read(); Debug.Assert(ok); Debug.Assert(String.Compare(xmlReader.Name, section.SectionName.ToString(), true) == 0); // set <section.LineNumber> to the line number of this XML section // within the source file, for error reporting purposes section.LineNumber = ((IXmlLineInfo) xmlReader).LineNumber; // get the "name", "cref", and "href" attributes section.NameAttribute = xmlReader.GetAttribute("name"); section.CrefAttribute = xmlReader.GetAttribute("cref"); section.HrefAttribute = xmlReader.GetAttribute("href"); // if this element has no child elements there's nothing further to do if (xmlReader.IsEmptyElement) return; // keep track of the state of the "<list>" elements we're nested within Stack<ListState> listStateStack = new Stack<ListState>(); // if this XML section has internal="true" specified and this is an // external-only documentation build, skip the XML bool skipSection = false; if (Topic.DocumentationSet.ExternalOnly) { try { string value = xmlReader.GetAttribute("internal"); if (value != null) skipSection = XmlConvert.ToBoolean(value); } catch (FormatException ex) { FireWarningInSourceFile(section.LineNumber, Resources.InvalidXmlAttributeValue, "internal", xmlReader.Name, ex.Message); } } // process the XML in the section; convert to HTML bool nextNodeAlreadyRead = false; string listType; ListState listState; while ((nextNodeAlreadyRead || xmlReader.Read()) && (xmlReader.Depth > initialDepth)) { if (skipSection) continue; nextNodeAlreadyRead = false; string element, text, name, cref; switch (xmlReader.NodeType) { case XmlNodeType.Element: switch (element = xmlReader.Name) { case "n": // name (unlinked) // format as an unlinked name if ((text = ReadXmlElementText(xmlReader)) != null) { FormatBeginTag("span,class", "n"); WriteEncodedText(text); RenderEndTag(); } nextNodeAlreadyRead = true; break; case "r": // reference // "<r>" has an optional "cref" attribute if ((cref = xmlReader.GetAttribute("cref")) == null) { // no "cref" attribute if ((text = ReadXmlElementText(xmlReader)) != null) { GenerateInlineReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, text, null, false, 0); } } else { // "cref" attribute present if ((text = ReadXmlElementText(xmlReader)) != null) { GenerateInlineReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, cref, text, false, 0); } } nextNodeAlreadyRead = true; break; case "ar": // ancestor reference // "<ar>" has an optional "cref" attribute if ((cref = xmlReader.GetAttribute("cref")) == null) { // no "cref" attribute if ((text = ReadXmlElementText(xmlReader)) != null) { GenerateInlineReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, text, null, false, FindTopicSettings.SearchOnlyAncestors); } } else { // "cref" attribute present if ((text = ReadXmlElementText(xmlReader)) != null) { GenerateInlineReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, cref, text, false, FindTopicSettings.SearchOnlyAncestors); } } nextNodeAlreadyRead = true; break; case "s": // short reference if ((text = ReadXmlElementText(xmlReader)) != null) { GenerateInlineReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, text, null, true, 0); } nextNodeAlreadyRead = true; break; case "pr": // same as <paramref> if ((text = ReadXmlElementText(xmlReader)) != null) { GenerateInlineParameterReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, text); } nextNodeAlreadyRead = true; break; case "tpr": // same as <typeparamref> if ((text = ReadXmlElementText(xmlReader)) != null) { GenerateInlineTypeParameterReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, text); } nextNodeAlreadyRead = true; break; case "see": // "<see>" has a required "cref" attribute if ((cref = xmlReader.GetAttribute("cref")) == null) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.MissingAttribute, "see", "cref"); } else { GenerateInlineReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, cref, null, false, 0); } break; case "para": WriteLine(); RenderBeginTag("p"); break; case "c": RenderBeginTag("code"); break; case "code": string language = xmlReader.GetAttribute("language"); if (language == null) language = Resources.RenderCSharp; BeginGrid("Code", language); RenderBeginTag("tr"); FormatBeginTag("td,class\n", "Content_"); int initialDepth2 = xmlReader.Depth; Write("\r\n<pre>"); // avoid tabs bool nextNodeAlreadyRead2 = false; while ((nextNodeAlreadyRead2 || xmlReader.Read()) && (xmlReader.Depth > initialDepth2)) { nextNodeAlreadyRead2 = false; switch (xmlReader.NodeType) { case XmlNodeType.Element: string xml = xmlReader.ReadOuterXml(); nextNodeAlreadyRead2 = true; WriteEncodedText(xml); break; default: WriteEncodedText( xmlReader.Value.Replace("\n", "\r\n")); break; } } Write("</pre>"); WriteLine(); RenderEndTag(); // "td" FormatEndTag("\n"); // "tr" EndGrid(); break; case "paramref": // set <name> to the value of the "name" attribute if ((name = xmlReader.GetAttribute("name")) == null) { // missing "name" attribute int lineNumber = ((IXmlLineInfo) xmlReader).LineNumber; FireWarningInSourceFile(lineNumber, Resources.MissingAttribute, "paramref", "name"); } else { GenerateInlineParameterReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, name); } break; case "typeparamref": // set <name> to the value of the "name" attribute if ((name = xmlReader.GetAttribute("name")) == null) { // missing "name" attribute int lineNumber = ((IXmlLineInfo) xmlReader).LineNumber; FireWarningInSourceFile(lineNumber, Resources.MissingAttribute, "typeparamref", "name"); } else { GenerateInlineTypeParameterReferenceHtml(section, ((IXmlLineInfo) xmlReader).LineNumber, name); } break; case "list": // set <listType> to the value of the "type" attribute if ((listType = xmlReader.GetAttribute("type")) == null) { // missing "type" attribute int lineNumber = ((IXmlLineInfo) xmlReader).LineNumber; FireWarningInSourceFile(lineNumber, Resources.MissingAttribute, "list", "type"); break; } // set <tagName> to the name of the element to begin, or // String.Empty if none, or null if <listType> is invalid string tagName; if (listType == "bullet") tagName = "ul"; else if (listType == "number") tagName = "ol"; else if (listType == "table") tagName = String.Empty; else { // invalid "type" attribute int lineNumber = ((IXmlLineInfo) xmlReader).LineNumber; FireWarningInSourceFile(lineNumber, Resources.InvalidListType); tagName = null; } // begin the list HTML (if any) if (tagName != null) { // keep track of the "type" attribute of the "<list>" // elements we're nested within listStateStack.Push(new ListState(listType)); // render <tagName> if (tagName.Length > 0) RenderBeginTag(tagName); } WriteLine(); break; case "listheader": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if (listState.ListType == "table") listState.InListHeader = true; break; case "item": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if (listState.ListType == "table") { listState.BeginGridIfNeeded(this); RenderBeginTag("tr"); } break; case "term": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if (listState.ListType == "table") { if (listState.InListHeader) { if ((text = ReadXmlElementText(xmlReader)) != null) listState.TermHeading = text; nextNodeAlreadyRead = true; } else { listState.BeginGridIfNeeded(this); RenderBeginTag("td"); } } break; case "description": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if ((listState.ListType == "bullet") || (listState.ListType == "number")) RenderBeginTag("li"); else if (listState.ListType == "table") { if (listState.InListHeader) { if ((text = ReadXmlElementText(xmlReader)) != null) listState.DescriptionHeading = text; nextNodeAlreadyRead = true; } else { listState.BeginGridIfNeeded(this); RenderBeginTag("td"); } } break; default: // unknown XML element... // call the TransformCustomInsideXml custom hook, if any string nodeName = xmlReader.Name; try { if (TransformCustomInsideXml(section, xmlReader)) { nextNodeAlreadyRead = true; break; } } catch (XmlException ex) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.InvalidXmlElementSyntax, nodeName, ex.Message); break; } catch (WarningException ex) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, "{0}", ex.Message); break; } // write the XML element as-is (i.e. as HTML), but first // check to see if it's in the "<AllowXmlElements>" section // of the CodeDoc XML project file string elementName = xmlReader.Name; if (!Topic.DocumentationSet.IsAllowedXmlElement( elementName)) { int lineNumber = ((IXmlLineInfo) xmlReader).LineNumber; FireWarningInSourceFile(lineNumber, Resources.NotAllowedXmlElement, elementName); } // write element Write(LAngle); Write(elementName); if (xmlReader.MoveToFirstAttribute()) { while (true) { Write(' '); Write(xmlReader.Name); Write('='); Write('"'); WriteEncodedText(xmlReader.Value); Write('"'); if (!xmlReader.MoveToNextAttribute()) break; } } Write(RAngle); break; } break; case XmlNodeType.EndElement: switch (xmlReader.Name) { case "para": RenderEndTag(); WriteLine(); break; case "c": RenderEndTag(); break; case "list": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // end the list HTML if (listState.ListType == "table") { if (listState.BegunGrid) EndGrid(); } else RenderEndTag(); WriteLine(); break; case "listheader": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if (listState.ListType == "table") listState.InListHeader = false; break; case "item": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if (listState.ListType == "table") { RenderEndTag(); // "tr" WriteLine(); } break; case "term": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if (listState.ListType == "table") { if (!listState.InListHeader) { RenderEndTag(); // "td" WriteLine(); } } break; case "description": // do nothing if we're not within a list -- this should // only happen if the XML is incorrect if (listStateStack.Count == 0) break; // set <listState> to information about the "<list>" // element we're nested within listState = listStateStack.Peek(); // process this element if ((listState.ListType == "bullet") || (listState.ListType == "number")) RenderEndTag(); else if (listState.ListType == "table") { if (!listState.InListHeader) { RenderEndTag(); // "td" WriteLine(); } } break; default: // unknown XML element -- send it out as-is Write(LAngle); Write('/'); Write(xmlReader.Name); Write(RAngle); break; } break; case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: case XmlNodeType.Text: WriteEncodedText(s_insignificantWhiteSpaceRegex .Replace(xmlReader.Value, " ").Replace("\n", "\r\n")); break; } } }
TopicWriter.WriteTopicPage Method
Generates HTML corresponding to the topic specified in the constructor. The HTML is written to the TextWriter specified in the constructor. Generates a standalone page. Used in the second pass of documentation generation. |
public void WriteTopicPage() { // begin the HTML document, including beginning the "<html>" block BeginHtmlDocument(HtmlDocType.XhtmlTransitional, TopicRenderer.MarkOfTheWeb); // begin the "<head>" block FormatBeginTag("head\n"); // write the "<title>" block RenderBeginTag("title"); WriteEncodedText(Topic.ShortTitle); FormatEndTag("\n\n"); // write the "<link>" element FormatTag("link,rel,href\n", "stylesheet", "_CodeDoc.css"); // end the "<head>" block FormatEndTag("\n\n"); // begin the "<body>" block FormatBeginTag("body,id\n","DocBrowserTopic"); // write the topic HTML that goes on the page WriteTopicInnerHtml(false, true); // write the page footer, if any (e.g. copyright) WriteTopicFooterHtml(); // write script code which, when the page loads, notifies the parent // window (if any) that the topic page has loaded FormatBeginTag("script,type,defer", "text/javascript", "defer"); Write("if (parent.OnTopicLoaded != undefined)"); WriteLine(); Write(String.Format(" parent.OnTopicLoaded({0}, {1});", Topic.Id, ((Topic.OverloadListTopic != null) ? Topic.OverloadListTopic.Id.ToString() : "null"))); FormatEndTag("\n\n"); // end the "<body>" and "<html>" blocks FormatEndTag("\n"); FormatEndTag("\n"); }
TopicWriter.WriteEmbeddedTopic Method
Generates HTML corresponding to the topic specified in the constructor. The HTML is written to the TextWriter specified in the constructor. Generates "embedded" HTML, i.e. a "<div>" designed to fit compactly within formatted source code. |
public void WriteEmbeddedTopic() { // begin the "<div>" FormatBeginTag("div,class\n", "EmbeddedTopic_"); // write the topic HTML WriteTopicInnerHtml(true, false); // end the "<div>" FormatEndTag("\n"); }
TopicWriter.WriteCodeNamespacePage Method
Generates HTML corresponding to the topic specified in the constructor. The HTML is written to the TextWriter specified in the constructor. Assuming the current topic is a namespace topic, this method generates the HTML file, used in the formatted code directory, that represents the namespace and contains links to the formatted code HTML files. |
public void WriteCodeNamespacePage() { // begin the HTML document, including beginning the "<html>" block BeginHtmlDocument(HtmlDocType.XhtmlTransitional, TopicRenderer.MarkOfTheWeb); // begin the "<head>" block FormatBeginTag("head\n"); // write the "<title>" block RenderBeginTag("title"); string title = String.Format(Resources.CodeOverloadTitle, Topic.ShortTitle); WriteEncodedText(title); FormatEndTag("\n\n"); // write the "<link>" element FormatTag("link,rel,href\n", "stylesheet", "_CodeDoc.css"); // end the "<head>" block FormatEndTag("\n\n"); // begin the "<body>" block FormatBeginTag("body,id\n","DocBrowserTopic"); // write the namespace member list sections WriteTopicInnerHtml(false, false); // write the page footer, if any (e.g. copyright) WriteTopicFooterHtml(); // end the "<body>" and "<html>" blocks FormatEndTag("\n"); FormatEndTag("\n"); }
TopicWriter.WriteCodeOverloadListPage Method
Generates HTML corresponding to the topic specified in the constructor. The HTML is written to the TextWriter specified in the constructor. Assuming the current topic is an overload list, this method generates a code overload list page, i.e. a page, designed to be used within a directory of formatted source code, containing a list of links to embedded code blocks, one link per overload in the overload list. |
public void WriteCodeOverloadListPage() { // begin the HTML document, including beginning the "<html>" block BeginHtmlDocument(HtmlDocType.XhtmlTransitional, TopicRenderer.MarkOfTheWeb); // begin the "<head>" block FormatBeginTag("head\n"); // write the "<title>" block RenderBeginTag("title"); string title = String.Format(Resources.CodeOverloadTitle, Topic.ShortTitle); WriteEncodedText(title); FormatEndTag("\n\n"); // write the "<link>" element FormatTag("link,rel,href\n", "stylesheet", "_CodeDoc.css"); // end the "<head>" block FormatEndTag("\n\n"); // begin the "<body>" block FormatBeginTag("body,id\n","DocBrowserTopic"); // write the topic header FormatBeginTag("div,class", "TopicHeader"); WriteEncodedText(Topic.ShortTitle); FormatEndTag("\n\n"); // cast to the derived type OverloadListTopic overloadListTopic = (OverloadListTopic) Topic; // begin the "Overloads List" section BeginSection(title); // begin the table BeginGrid("Overloads", Resources.RenderName, Resources.RenderDescription); // sort overloads in <overloadListTopic> overloadListTopic.SortOverloadTopics(); // write each row foreach (Topic overloadTopic in overloadListTopic.OverloadTopics) { // begin the row RenderBeginTag("tr"); // write the first cell RenderBeginTag("td"); FormatBeginTag("a,href", overloadTopic.CodeHtmlUrl); WriteEncodedText(overloadTopic.ShortSignature); RenderEndTag(); // "a" FormatEndTag("\n"); // "td" // write the second cell RenderBeginTag("td"); overloadTopic.WriteSummaryHtml(this); RenderEndTag(); // "td" // end the row RenderEndTag(); // "tr" } // end the table EndGrid(); // end the "Overloads List" section EndSection(); // write the space at the bottom of the page FormatBeginTag("div,class", "TopicFooter"); FormatEndTag("\n\n"); // write the page footer, if any (e.g. copyright) WriteTopicFooterHtml(); // end the "<body>" and "<html>" blocks FormatEndTag("\n"); FormatEndTag("\n"); } ////////////////////////////////////////////////////////////////////////// // Protected Methods //
TopicWriter.GetTopicUrl Method
Returns the URL to a given topic, which varies depending on the value of TopicRenderer.CodeHtml.
Parameters
topic The topic to return the URL of. |
protected string GetTopicUrl(Topic topic) { if (TopicRenderer.CodeHtml) return topic.CodeHtmlUrl; else return topic.DocHtmlFileName; }
TopicWriter.GenerateInlineReferenceHtml Method
Generates HTML corresponding to a "<r>...</r>" (reference) "<s>...</s>" (short reference) XML construct.
Parameters
section The section being parsed. lineNumber The line number of the line of the source file containing this XML construct. name The contents of "<r>...</r>" or "<s>...</s>". text The text to include in the generated HTML. If text is null, text is derived from name and isShortReference. isShortReference true if name is a "<s>...</s>" construct; false if it's a "<r>...</r>" construct. settings Settings that control the search for name. |
protected void GenerateInlineReferenceHtml(XmlCommentSection section, int lineNumber, string name, string text, bool isShortReference, FindTopicSettings settings) { // treat "{" and "}" like "<" and ">" in <name> (so user doesn't have // to type e.g. "<" and ">" in XML) name = name.Replace('{', '<').Replace('}', '>'); // if <text> is not explicitly specified, set <text> to the text to // display -- short text for "<s>", full text for "<r>" if (text == null) { if (isShortReference) { // remove leading types; e.g. "A<>.B<>" --> "B<>" int ich = name.LastIndexOf('.'); if ((ich > 0) && (ich < (name.Length - 1))) text = name.Substring(ich + 1); else text = name; // remove trailing type parameters, e.g. "B<>" --> "B" if ((ich = text.IndexOf('<')) > 0) text = text.Substring(0, ich); } else text = name; } // set <targetTopic> to the referenced topic, or null if none; for // error reporting purposes, set <lineNumber> to the line number of // this XML element Topic targetTopic = Topic.DocumentationSet.FindDocumentedTopic( name, section.Topic, lineNumber, settings); // format <text> if (targetTopic != null) { // format as a hyperlink to the target topic FormatBeginTag("a,class,href,title", "r", GetTopicUrl(targetTopic), targetTopic.LongTitle); WriteEncodedText(text); RenderEndTag(); } else { // format as an unlinked name FormatBeginTag("span,class", "n"); WriteEncodedText(text); RenderEndTag(); } }
TopicWriter.GenerateInlineParameterReferenceHtml Method
Generates HTML corresponding to a "<pr>...</pr>" or "<paramref> name="..."/>" (parameter reference) XML construct.
Parameters
section The section being parsed. lineNumber The line number of the line of the source file containing this XML construct. name The name of the parameter being referenced. |
protected void GenerateInlineParameterReferenceHtml( XmlCommentSection section, int lineNumber, string name) { // check to make sure there is a parameter named <name>; generate a // warning if not if (!Topic.HasParameter(name)) { FireWarningInSourceFile(lineNumber, Resources.NoParameter, name, Topic.ShortTitle); } // format <name> as a parameter reference FormatBeginTag("span,class", "pr"); WriteEncodedText(name); RenderEndTag(); }
TopicWriter.GenerateInlineTypeParameterReferenceHtml Method
Generates HTML corresponding to a "<tpr>...</tpr>" or "<typeparamref> name="..."/>" (type parameter reference) XML construct.
Parameters
section The section being parsed. lineNumber The line number of the line of the source file containing this XML construct. name The name of the type parameter being referenced. |
protected void GenerateInlineTypeParameterReferenceHtml( XmlCommentSection section, int lineNumber, string name) { // check to make sure there is a type parameter named <name>; generate // a warning if not if (!Topic.HasTypeParameter(name)) { FireWarningInSourceFile(lineNumber, Resources.NoTypeParameter, name, Topic.ShortTitle); } // format the <name> as a type parameter reference FormatBeginTag("span,class", "tpr"); WriteEncodedText(name); RenderEndTag(); }
TopicWriter.GenerateCodeBlockHtml Method
Generates HTML corresponding to a block of code.
Parameters
xmlReader The XML element to read. |
protected void GenerateCodeBlockHtml(XmlReader xmlReader) { int initialDepth2 = xmlReader.Depth; Write("\r\n<pre>"); // avoid tabs bool nextNodeAlreadyRead2 = false; while ((nextNodeAlreadyRead2 || xmlReader.Read()) && (xmlReader.Depth > initialDepth2)) { nextNodeAlreadyRead2 = false; switch (xmlReader.NodeType) { case XmlNodeType.Element: string xml = xmlReader.ReadOuterXml(); nextNodeAlreadyRead2 = true; WriteEncodedText(xml); break; default: WriteEncodedText( xmlReader.Value.Replace("\n", "\r\n")); break; } } Write("</pre>"); }
TopicWriter.WriteTopicInnerHtml Method
Generates HTML corresponding to the topic specified in the constructor. The HTML is written to the TextWriter specified in the constructor. Generates a "<div>" appropriate for inclusion on an existing HTML page.
Parameters
embedded If true "embedded" HTML is generated, i.e. a "<div>" designed to fit compactly within formatted source code. If false, complete HTML is generated, designed for use in standalone documentation pages. writeViewTableOfContentsLink If true, a "View Table of Contents" link is written (or, rather, script is written which display that link if the table of contents is not visible, i.e. if the page is not running in the DocBrowser frameset). |
protected void WriteTopicInnerHtml(bool embedded, bool writeViewTableOfContentsLink) { // write some comments for debugging purposes Write(String.Format("<!-- Id: {0} -->", Topic.Id)); WriteLine(); Write(String.Format("<!-- Name: {0} -->", Topic.Name)); WriteLine(); Write(String.Format("<!-- CanonicalName: {0} -->", Topic.CanonicalName)); WriteLine(); WriteLine(); // write the topic header FormatBeginTag("div,class", "TopicHeader"); WriteEncodedText(Topic.ShortTitle); FormatEndTag("\n\n"); if (writeViewTableOfContentsLink) { // write script code which, when the page loads, detects if the // page is being displayed within the context of the parent // frameset and, if not, displays a link which, when clicked, opens // the frameset FormatBeginTag("script,type", "text/javascript"); Write("if (parent.OnTopicLoaded == undefined)"); WriteLine(); Write(String.Format( " document.write('<div class=\"ViewToc\"><a href=\"_SyncToc.htm#{0}\">{1}</a></div>');", Topic.DocHtmlFileName, Resources.ViewTableOfContents)); WriteLine(); FormatEndTag("\n\n"); } // write the "Summary" section, if any if (Topic.TopicKind != TopicKind.NamespaceTopic) WriteSummarySection(embedded); // if this is an overload list topic, write the "Overloads List" // section and then quit if (Topic is OverloadListTopic) { WriteOverloadListSection(); return; } // write the "Syntax" section, if any if (Topic.TopicKind != TopicKind.NamespaceTopic) WriteSyntaxSection(embedded); // write the "Members" section, if any if (Topic.TopicKind == TopicKind.EnumTopic) WriteEnumerationMemberListSection(); else if (!embedded) { if ((Topic.TopicKind == TopicKind.ClassTopic) || (Topic.TopicKind == TopicKind.StructTopic) || (Topic.TopicKind == TopicKind.NamespaceTopic) || (Topic.TopicKind == TopicKind.InterfaceTopic)) WriteMemberListSections(); } // write the "Exceptions" section, if any if (Topic.HasExceptionsHtml) WriteExceptionsSection(); // write the "Permissions" section, if any if (Topic.HasPermissionsHtml) WritePermissionsSection(); // write the "Remarks" section, if any if (Topic.HasRemarksHtml) { BeginSection(Resources.RenderRemarks); Topic.WriteRemarksHtml(this); EndSection(); } // write the "Example" section, if any if (Topic.HasExampleHtml) { BeginSection(Resources.RenderExample); Topic.WriteExampleHtml(this); EndSection(); } // write the "See Also" section, if any if (Topic.HasSeeAlsoHtml) WriteSeeAlsoSection(); // write the space at the bottom of the page, if any if (!embedded) { FormatBeginTag("div,class", "TopicFooter"); FormatEndTag("\n\n"); } }
TopicWriter.WriteSummarySection Method
Writes the "Summary" section of the topic.
Parameters
embedded If true "embedded" HTML is generated, designed to fit compactly within formatted source code. If false, complete HTML is generated, designed for use in standalone documentation pages. |
protected void WriteSummarySection(bool embedded) { // begin the Summary section FormatBeginTag("div,class", "Summary"); // write the topic summary text Topic.WriteSummaryHtml(this); if (!embedded) { // write the parent type name (if any) TokenList parentTypeName = Topic.ParentTypeName; if (parentTypeName != null) { WriteLabeledParagraph(Resources.RenderParentTypeLabel, LinkHtml(parentTypeName.ToString(), Topic.ParentTopic)); } // write the namespace name (if any) TokenList namespaceName = Topic.NamespaceName; if (namespaceName != null) { WriteLabeledParagraph(Resources.RenderNamespaceLabel, LinkHtml(namespaceName.ToString(), Topic.NamespaceTopic)); } // write the assembly name (if any) if ((Topic.SourceFile != null) && (Topic.SourceFile.AssemblyName != null)) { WriteLabeledParagraph(Resources.RenderAssemblyLabel, Html(Topic.SourceFile.AssemblyName)); } } // end the Summary section FormatEndTag("\n"); // "div" }
TopicWriter.WriteOverloadListSection Method
Writes the "Overload List" section of the topic.
Remarks
This method can only be called if this topic is of type OverloadListTopic. |
protected void WriteOverloadListSection() { // cast to the derived type OverloadListTopic overloadListTopic = (OverloadListTopic) Topic; // begin the "Overloads List" section BeginSection(Resources.RenderOverloadList); // begin the table BeginGrid("Overloads", Resources.RenderName, Resources.RenderDescription); // sort overloads in <overloadListTopic> overloadListTopic.SortOverloadTopics(); // write each row foreach (Topic overloadTopic in overloadListTopic.OverloadTopics) { // begin the row RenderBeginTag("tr"); // write the first cell RenderBeginTag("td"); FormatBeginTag("a,href", GetTopicUrl(overloadTopic)); WriteEncodedText(overloadTopic.ShortSignature); RenderEndTag(); // "a" FormatEndTag("\n"); // "td" // write the second cell RenderBeginTag("td"); overloadTopic.WriteSummaryHtml(this); RenderEndTag(); // "td" // end the row RenderEndTag(); // "tr" } // end the table EndGrid(); // end the "Overloads List" section EndSection(); }
TopicWriter.WriteSyntaxSection Method
Writes the "Syntax" section of the topic.
Parameters
embedded If true "embedded" HTML is generated, designed to fit compactly within formatted source code. If false, complete HTML is generated, designed for use in standalone documentation pages. |
protected void WriteSyntaxSection(bool embedded) { // begin the "Syntax" section BeginSection(embedded ? null : Resources.RenderSyntax); // retrieve this topic's type parameters and regular parameters TokenList[] typeParameters = Topic.TypeParameters; IList<Parameter> parameters = Topic.Parameters; if (!embedded) { // begin the table (one row, one column) BeginGrid("Code", Resources.RenderCSharp); RenderBeginTag("tr"); FormatBeginTag("td,class\n", "Content_"); // write attributes, if any; skip attributes that match any regular // expresion in <TopicRenderer.HideAttributesRegexList> if (Topic.Attributes != null) { foreach (TokenList attribute in Topic.Attributes) { string attributeString = attribute.ToString(); bool hideAttribute = false; foreach (Regex regex in TopicRenderer.HideAttributesRegexList) { if (regex.Match(attributeString).Success) { hideAttribute = true; break; } } if (!hideAttribute) { RenderBeginTag("p"); Write(LSquare); WriteEncodedText(attributeString); Write(RSquare); FormatEndTag("\n"); // "p" } } } // begin the next paragraph of the declaration -- first line is // left-justified, following lines are indented RenderBeginTag("p"); // write modifiers (e.g. "public static") WriteEncodedTokenList(Topic.Modifiers, " "); // write the appropriate C# type declaration keyword, if any switch (Topic.TopicKind) { case TopicKind.ClassTopic: Write("class "); break; case TopicKind.StructTopic: Write("struct "); break; case TopicKind.InterfaceTopic: Write("interface "); break; case TopicKind.EventTopic: Write("event "); break; case TopicKind.DelegateTopic: Write("delegate "); break; case TopicKind.EnumTopic: Write("enum "); break; } // write the member type, if any if (Topic.MemberType != null) { WriteTypeNameHtml(Topic.MemberType); Write(' '); } // write the member name if (Topic.ExplicitPrefix != null) WriteEncodedText(Topic.ExplicitPrefix.ToString()); if (Topic.PropertyKind == PropertyKind.Indexer) WriteEncodedText(Topic.MemberName.Replace("Item", "this")); else WriteEncodedText(Topic.MemberName); // if this topic has a type parameter list, write it; set // <typeParameters> to the list of type parameters if (typeParameters != null) { WriteEncodedText(String.Format("<{0}>", TokenList.Join(',', typeParameters).ToString())); } // add a blank Write(' '); // if this topic has a base type list, write it TokenList[] baseTypes = Topic.BaseTypes; if (baseTypes != null) { Write(": "); bool first = true; foreach (TokenList baseType in baseTypes) { if (first) first = false; else Write(", "); WriteTypeNameHtml(baseType); } } // if this topic has a parameter list, write it; set <parameters> // to the list of parameters and <lastParamIndex> to the 0-based // index of the last parameter int lastParamIndex; if (parameters != null) { // topic has a parameter list with zero or more parameters lastParamIndex = parameters.Count - 1; if (lastParamIndex >= 0) { // one or more parameters -- write them Write(ParamListStart); FormatTag("br\n"); for (int paramIndex = 0; paramIndex <= lastParamIndex; paramIndex++) { Parameter parameter = parameters[paramIndex]; string kind = parameter.CSharpKind; if (kind != null) WriteEncodedText(String.Format("{0} ", kind)); WriteTypeNameHtml(parameter.ParameterType); Write(' '); FormatBeginTag("span,class", "ParameterName"); WriteEncodedText(parameter.ParameterName); RenderEndTag(); if (paramIndex != lastParamIndex) Write(','); FormatTag("br\n"); } } else { // zero parameters -- write "()" on a single line Write(ParamListStart); Write(ParamListEnd); } } else lastParamIndex = -1; // end this paragraph of the declaration FormatEndTag("\n"); // "p" // begin the second paragraph of the declaration (if any) if (lastParamIndex >= 0) { RenderBeginTag("p"); Write(ParamListEnd); Write(' '); } // if this topic has get and/or set accessors, write them Accessor getAccessor = Topic.GetAccessor; Accessor setAccessor = Topic.SetAccessor; if ((getAccessor != null) || (setAccessor != null)) { Write(LBrace); Write(' '); if ((getAccessor != null) && (!Topic.DocumentationSet.ExternalOnly || getAccessor.IsExternallyAccessible)) { WriteEncodedText(getAccessor.ToString()); Write("; "); } if ((setAccessor != null) && (!Topic.DocumentationSet.ExternalOnly || setAccessor.IsExternallyAccessible)) { WriteEncodedText(setAccessor.ToString()); Write("; "); } Write(RBrace); } // end the second paragraph of the declaration (if any) if (lastParamIndex >= 0) FormatEndTag("\n"); // "p" // if this topic has constraints ("where" in C#), write them if (Topic.Constraints != null) { // put each "where" clause on a new line RenderBeginTag("p"); bool first = true; foreach (Token token in Topic.Constraints) { if (token.IsReservedWord("where") && !first) { FormatEndTag("\n"); // "p" RenderBeginTag("p"); } WriteEncodedText(token.ToString()); first = false; } FormatEndTag("\n"); // "p" } // end the table RenderEndTag(); // "td" FormatEndTag("\n"); // "tr" EndGrid(); } // write the "Type Parameters" subsection, if there are one or more // type parameters if (typeParameters != null) { BeginSubsection(Resources.RenderTypeParameters); foreach (TokenList typeParameter in typeParameters) { // set <name> to the type parameter name string name = typeParameter.ToString(); // write the type parameter name FormatBeginTag("p,class", "TypeParameterName"); WriteEncodedText(name); FormatEndTag("\n"); // "p" // set <descriptionHtml> to the type parameter description HTML string descriptionHtml = Topic.GetTypeParameterHtml(name); if (descriptionHtml == null) { FireWarningInSourceFile( Topic.FirstXmlComment.GetLineNumber(), Resources.NoDocForTypeParameter, name); descriptionHtml = ""; } // write the type parameter description FormatBeginTag("p,class", "TypeParameterDescription"); Write(descriptionHtml); RenderEndTag(); // "p" } EndSubsection(); } // write the "Parameters" subsection, if there are one or more // parameters if ((parameters != null) && (parameters.Count > 0)) { BeginSubsection(Resources.RenderParameters); foreach (Parameter parameter in parameters) { // write the parameter name FormatBeginTag("p,class", "ParameterName"); WriteEncodedText(parameter.ParameterName); FormatEndTag("\n"); // "p" // set <descriptionHtml> to the parameter description HTML string descriptionHtml = Topic.GetParameterHtml(parameter.ParameterName); if (descriptionHtml == null) { FireWarningInSourceFile( Topic.FirstXmlComment.GetLineNumber(), Resources.NoDocForParameter, parameter.ParameterName); descriptionHtml = ""; } // write the parameter description FormatBeginTag("p,class", "ParameterDescription"); Write(descriptionHtml); RenderEndTag(); // "p" } EndSubsection(); } // write the "Returns" section, if any if (Topic.HasReturnsHtml) { BeginSubsection(Resources.RenderReturns); Topic.WriteReturnsHtml(this); EndSubsection(); } // write the "Value" section, if any if (Topic.HasValueHtml) { BeginSubsection(Resources.RenderValue); Topic.WriteValueHtml(this); EndSubsection(); } // end the "Syntax" section EndSection(); }
TopicWriter.WriteEnumerationMemberListSection Method
Writes the "Members" section of the topic, assuming the topic is TopicKind.EnumTopic. |
protected void WriteEnumerationMemberListSection() { // begin the "Members" section BeginSection(Resources.RenderMembers); // begin the table BeginGrid("Members", Resources.RenderName, Resources.RenderDescription); // sort child topics Topic.SortChildTopics(); // write each row foreach (Topic memberTopic in Topic.ChildTopics) { // begin the row RenderBeginTag("tr"); // write the first cell RenderBeginTag("td"); FormatBeginTag("span,class", "n"); WriteEncodedText(memberTopic.MemberName); RenderEndTag(); FormatEndTag("\n"); // "td" // write the second cell RenderBeginTag("td"); memberTopic.WriteSummaryHtml(this); memberTopic.WriteRemarksHtml(this); RenderEndTag(); // "td" // end the row RenderEndTag(); // "tr" } // end the table EndGrid(); // end the "Members" section EndSection(); }
TopicWriter.WriteMemberListSections Method
Writes the members sections of the topic, assuming the topic is not a TopicKind.EnumTopic. |
protected void WriteMemberListSections() { // divide each member topic into elements of <sections> List<MemberInfo>[] sections = new List<MemberInfo>[(int) MemberSection.Length]; foreach (MemberInfo memberInfo in Topic.MemberTopics) { // categorize this topic if (memberInfo.Topic.ExplicitPrefix != null) { AddItem(memberInfo, ref sections[ (int) MemberSection.Implementations]); } else switch (memberInfo.Topic.TopicKind) { case TopicKind.MethodTopic: switch (memberInfo.Topic.MethodKind) { case MethodKind.Constructor: AddItem(memberInfo, ref sections[ (int) MemberSection.Constructors]); break; case MethodKind.Destructor: AddItem(memberInfo, ref sections[ (int) MemberSection.Destructors]); break; case MethodKind.Operator: AddItem(memberInfo, ref sections[ (int) MemberSection.Operators]); break; default: AddItem(memberInfo, ref sections[ (int) MemberSection.Methods]); break; } break; case TopicKind.FieldTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Fields]); break; case TopicKind.PropertyTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Properties]); break; case TopicKind.EventTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Events]); break; case TopicKind.ClassTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Classes]); break; case TopicKind.InterfaceTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Interfaces]); break; case TopicKind.StructTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Structures]); break; case TopicKind.DelegateTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Delegates]); break; case TopicKind.EnumTopic: AddItem(memberInfo, ref sections[ (int) MemberSection.Enumerations]); break; } } // loop once for each potential members section for (MemberSection memberSection = 0; memberSection < MemberSection.Length; memberSection++) { // set <sectionTopics> to the topics in this section List<MemberInfo> sectionTopics = sections[(int) memberSection]; // skip this section if there are no topics if (sectionTopics == null) continue; // sort this section sectionTopics.Sort(); // set <title> to the section title string title; switch (memberSection) { case MemberSection.Constructors: title = Resources.RenderConstructors; break; case MemberSection.Destructors: title = Resources.RenderDestructors; break; case MemberSection.Fields: title = Resources.RenderFields; break; case MemberSection.Properties: title = Resources.RenderProperties; break; case MemberSection.Methods: title = Resources.RenderMethods; break; case MemberSection.Operators: title = Resources.RenderOperators; break; case MemberSection.Events: title = Resources.RenderEvents; break; case MemberSection.Implementations: title = Resources.RenderImplementations; break; case MemberSection.Classes: title = Resources.RenderClasses; break; case MemberSection.Interfaces: title = Resources.RenderInterfaces; break; case MemberSection.Structures: title = Resources.RenderStructures; break; case MemberSection.Delegates: title = Resources.RenderDelegates; break; case MemberSection.Enumerations: title = Resources.RenderEnumerations; break; default: title = Resources.RenderMembers; break; } // begin the section BeginSection(title); // begin the table; write the access icon column unless we're in // external-only mode and this a namespace topic (in which case all // members are public bool writeAccessIconColumn; if (Topic.DocumentationSet.ExternalOnly && (Topic.TopicKind == TopicKind.NamespaceTopic)) { writeAccessIconColumn = false; BeginGrid("Members", Resources.RenderName, Resources.RenderDescription); } else { writeAccessIconColumn = true; BeginGrid("Members", "", Resources.RenderName, Resources.RenderDescription); } // write each row foreach (MemberInfo memberInfo in sectionTopics) { // begin the row RenderBeginTag("tr"); // write the access icon cell, if any if (writeAccessIconColumn) { RenderBeginTag("td"); string accessTitle = Resources.RenderPublic; string accessCssClass = "PublicIcon"; string accessChar = "Ð"; bool isConst = false, isStatic = false; if (memberInfo.Topic.Modifiers != null) { foreach (Token modifier in memberInfo.Topic.Modifiers) { switch (modifier.Text) { case "protected": accessTitle = Resources.RenderProtected; accessCssClass = "ProtectedIcon"; accessChar = "Ï"; break; case "internal": // special case: "protected internal" if (accessCssClass != "ProtectedIcon") { accessTitle = Resources.RenderInternal; accessCssClass = "InternalIcon"; accessChar = "d"; } break; case "private": accessTitle = Resources.RenderPrivate; accessCssClass = "PrivateIcon"; accessChar = "r"; break; case "const": isConst = true; break; case "static": isStatic = true; break; } } } FormatBeginTag("span,class,title", accessCssClass, accessTitle); Write(accessChar); RenderEndTag(); // "span" if (isConst) { FormatBeginTag("span,class,title", "ConstIcon", Resources.RenderConst); Write('C'); RenderEndTag(); // "span" } if (isStatic) { FormatBeginTag("span,class,title", "StaticIcon", Resources.RenderStatic); Write('S'); RenderEndTag(); // "span" } FormatEndTag("\n"); // "td" } // write the second cell RenderBeginTag("td"); FormatBeginTag("a,class,href,title", "r", GetTopicUrl(memberInfo.Topic), memberInfo.Topic.LongTitle); WriteEncodedText(memberInfo.Topic.VeryShortTitleNoKind); FormatEndTag("\n"); // "a" FormatEndTag("\n"); // "td" // write the third cell RenderBeginTag("td"); memberInfo.Topic.WriteSummaryHtml(this, delegate(HtmlTextWriter htmlWriter) { if (memberInfo.InheritedFromTopic != null) { // write "Inherited from..." htmlWriter.Write( String.Format(Resources.RenderInheritedFrom, LinkNameHtml(memberInfo.InheritedFromTopic))); } }); RenderEndTag(); // "td" // end the row RenderEndTag(); // "tr" } // end the table EndGrid(); // end the section EndSection(); } }
TopicWriter.WriteExceptionsSection Method
Writes the "Exceptions" section of the topic.
Remarks
This method can only be called if Topic.HasExceptionsHtml is true. |
protected void WriteExceptionsSection() { // begin the "Exceptions" section BeginSection(Resources.RenderExceptions); // begin the table BeginGrid("Exceptions", Resources.RenderExceptionType, Resources.RenderExceptionCondition); // write each row foreach (XmlCommentSection section in Topic.GetRenderedXmlCommentSections( XmlCommentSectionKind.Exception)) { // begin the row RenderBeginTag("tr"); // write the first cell RenderBeginTag("td"); if (section.ReferencedTopic != null) { // format as a hyperlink to the referenced topic FormatBeginTag("a,class,href,title", "r", GetTopicUrl(section.ReferencedTopic), section.ReferencedTopic.LongTitle); WriteEncodedText(section.CrefAttribute); RenderEndTag(); } else { // format as an unlinked name FormatBeginTag("span,class", "n"); WriteEncodedText(section.CrefAttribute); RenderEndTag(); } FormatEndTag("\n"); // "td" // write the second cell RenderBeginTag("td"); RenderBeginTag("p"); Write(section.Html.Trim()); RenderEndTag(); // "p" WriteLine(); RenderEndTag(); // "td" // end the row RenderEndTag(); // "tr" } // end the table EndGrid(); // end the "Exceptions" section EndSection(); }
TopicWriter.WritePermissionsSection Method
Writes the "Permissions" section of the topic.
Remarks
This method can only be called if Topic.HasPermissionsHtml is true. |
protected void WritePermissionsSection() { // begin the "Permissions" section BeginSection(Resources.RenderPermissions); // begin the table BeginGrid("Permissions", Resources.RenderName, Resources.RenderDescription); // write each row foreach (XmlCommentSection section in Topic.GetRenderedXmlCommentSections( XmlCommentSectionKind.Permission)) { // begin the row RenderBeginTag("tr"); // write the first cell RenderBeginTag("td"); if (section.ReferencedTopic != null) { // format as a hyperlink to the referenced topic FormatBeginTag("a,class,href,title", "r", GetTopicUrl(section.ReferencedTopic), section.ReferencedTopic.LongTitle); WriteEncodedText(section.CrefAttribute); RenderEndTag(); } else { // format as an unlinked name FormatBeginTag("span,class", "n"); WriteEncodedText(section.CrefAttribute); RenderEndTag(); } FormatEndTag("\n"); // "td" // write the second cell RenderBeginTag("td"); RenderBeginTag("p"); Write(section.Html.Trim()); RenderEndTag(); // "p" WriteLine(); RenderEndTag(); // "td" // end the row RenderEndTag(); // "tr" } // end the table EndGrid(); // end the "Permissions" section EndSection(); }
TopicWriter.WriteSeeAlsoSection Method
Writes the "See Also" section of the topic.
Remarks
This method can only be called if Topic.HasSeeAlsoHtml is true. |
protected void WriteSeeAlsoSection() { // begin the "See Also" section BeginSection(Resources.RenderSeeAlso); // write each reference foreach (XmlCommentSection section in Topic.GetRenderedXmlCommentSections( XmlCommentSectionKind.SeeAlso)) { FormatBeginTag("p,class", "SeeAlso"); string html = section.Html; if (html != null) html = html.Trim(); if ((html != null) && (html.Length == 0)) html = null; if (section.ReferencedTopic != null) { // format as a hyperlink to the referenced topic FormatBeginTag("a,class,href,title", "r", GetTopicUrl(section.ReferencedTopic), section.ReferencedTopic.LongTitle); if (html != null) Write(html); else WriteEncodedText(section.ReferencedTopic.ShortTitle); RenderEndTag(); } else if ((section.HrefAttribute != null) && (html != null)) { // format non-topic link if (section.HrefAttribute.StartsWith("http") || section.HrefAttribute.StartsWith("ftp")) { // external link FormatBeginTag("a,class,href,title", "r", section.HrefAttribute, Resources.ExternalLink); Write(html); FormatBeginTag("span,class", "ExternalLinkIcon"); Write(" Þ"); RenderEndTag(); RenderEndTag(); } else { // internal non-topic link FormatBeginTag("a,class,href", "r", section.HrefAttribute); Write(html); RenderEndTag(); } } FormatEndTag("\n"); // "p" } // end the "See Also" section EndSection(); }
TopicWriter.BeginSection Method
Begins a section (e.g. "Exceptions") within a topic.
Parameters
headerTitle The text of the section title. If null, no section header is written. |
protected void BeginSection(string headerTitle) { // write the section header, if any if (headerTitle != null) { FormatBeginTag("div,class", "SectionHeader"); WriteEncodedText(headerTitle); FormatEndTag("\n"); // "div" } // begin the section "<div>" FormatBeginTag("div,class", "Section"); }
protected void EndSection() { // end the section "<div>" FormatEndTag("\n"); }
TopicWriter.BeginSubsection Method
Begins a subsection (e.g. "Parameters") within a topic.
Parameters
headerTitle The text of the section title. |
protected void BeginSubsection(string headerTitle) { // write the subsection header FormatBeginTag("div,class", "SubsectionHeader"); WriteEncodedText(headerTitle); FormatEndTag("\n"); // "div" // begin the subsection "<div>" FormatBeginTag("div,class", "Subsection"); }
protected void EndSubsection() { // end the subsection "<div>" FormatEndTag("\n"); }
TopicWriter.BeginGrid Method
Begins an HTML table that uses CSS class "Grid".
Parameters
cssClassName An additional CSS class name to apply to the table. columnLabels The labels that appear at the top of the table columns. |
protected void BeginGrid(string cssClassName, params string[] columnLabels) { // begin the "<table>" WriteLine(); FormatBeginTag("table,class", String.Format("Grid {0}", cssClassName)); // write the table "<col>" elements for (int i = 0; i < columnLabels.Length; i++) FormatTag("col,class\n", String.Format("Column{0}_", i + 1)); // write the table header row FormatBeginTag("tr,class", "Header_"); for (int i = 0; i < columnLabels.Length; i++) { FormatBeginTag("td,class\n", String.Format("Header{0}_", i + 1)); WriteEncodedText(columnLabels[i]); FormatEndTag("\n"); // "td" } // end the table header row FormatEndTag("\n"); // "tr" }
protected void EndGrid() { // end the grid "<table>" FormatEndTag("\n"); }
TopicWriter.WriteMemberNameHtml Method
Finds a topic that has Topic.IsDocumented equal to true given a member name of the sort that might be found in XML comments, and writes a hyperlink to that topic if it's found, or non-link text if not.
Parameters
memberName The qualified or unqualified member name. Examples: "Bar", "Foo.Bar", "Foo<T>.Bar". settings Settings that control the method. |
protected void WriteMemberNameHtml(string memberName, FindTopicSettings settings) { Topic targetTopic = Topic.DocumentationSet.FindDocumentedTopic( memberName, Topic, 0, settings); if (targetTopic != null) { FormatBeginTag("a,href,title", GetTopicUrl(targetTopic), targetTopic.LongTitle); } WriteEncodedText(memberName); if (targetTopic != null) RenderEndTag(); }
TopicWriter.WriteTypeNameHtml Method
Finds a topic that has Topic.IsDocumented equal to true given a type name, and writes a hyperlink to that topic if it's found, or non-link text if not.
Parameters
typeName The qualified or unqualified type name. Examples: "Bar", "Foo.Bar", "Foo<T>.Bar", "Foo<Abc<Def[,]>>.Bar". |
protected void WriteTypeNameHtml(TokenList typeName) { Topic targetTopic; DissectTypeReference(typeName.HeadToken.Next, Topic, this, out targetTopic); }
TopicWriter.ResolveTypeReference Method
Finds a topic that has Topic.IsDocumented equal to true given a type reference. For example, given "Outer<MyList>.Inner<MyPoint<bool>?,int[,]>.Inner2", a reference to the topic with canonical name "Outer<>.Inner<,>.Inner2" is returned.
Parameters
typeName The qualified or unqualified type name. Examples: "Bar", "Foo.Bar", "Foo<T>.Bar".
Return Value
The Topic corresponding to typeName, or null if none.
Remarks
The topic specified by the Topic property is used as the "context topic", i.e. typeName is assumed to be a reference within that topic. |
protected Topic ResolveTypeReference(string typeName) { #if false // this code works, but is slower Topic targetTopic; DissectTypeReference(typeName.HeadToken, Topic, null, out targetTopic); return targetTopic; #else return Topic.DocumentationSet.FindDocumentedTopic( typeName, Topic, 0, FindTopicSettings.TypeOnly); #endif }
TopicWriter.DissectTypeReference Method
Helps implement WriteTypeNameHtml and ResolveTypeReference: a given type name is broken up into each of its inner type components. Optionally generates hyperlinks to all types contained within the type name (in type parameters).
Parameters
token The first token of the qualified or unqualified type name. contextTopic The topic that contains the type name reference. htmlWriter The HtmlTextWriterHelper to write to. If targetTopic Set to the
Return Value
The first token after the type name. |
protected static Token DissectTypeReference(Token token, Topic contextTopic, HtmlTextWriterHelper htmlWriter, out Topic targetTopic) { // Algorithm: // // Consider this <typeName> value: // // Outer<MyList>.Inner<MyPoint<bool>?,int[,]>.Inner2[] // // This is divided into the following three "prefix types": // // Outer<MyList> // Outer<MyList>.Inner<MyPoint<bool>?,int[,]> // Outer<MyList>.Inner<MyPoint<bool>?,int[,]>.Inner2[] // // (These are divided at outer type parameter list boundaries, not // periods. For example, "Inner" could be "Abc.Def.Ghi" and the // result would still be three total "prefix types".) // // The algorithm is to parse one "prefix type" at a time, canonicalize // it and create the link for that prefix. Assuming Outer is in // namespace MyNs, the text "Outer", "Inner", and "Inner2" needs to // be hyperlinked to the topics with the following Topic.CanonicalName // values: // // "Outer" --> MyNs.Outer<> // "Inner" --> MyNs.Outer<>.Inner<,> // "Inner2" --> MyNs.Outer<>.Inner<,>.Inner2 // // This algorithm has to be run recursively, to get these hyperlinks // (assuming MyList and MyPoint are in namespace MyNs2): // // "MyList" --> MyNs2.MyList // "MyPoint" --> MyNs2.MyPoint<> // // <memberName> will hold e.g. "Inner" StringBuilder memberName = new StringBuilder(100); // <canonicalPrefix> will hold e.g. "MyNs.Outer<>.Inner<<>,>" StringBuilder canonicalPrefix = new StringBuilder(200); // loop once for each "prefix type" (see comments above) while (true) { // reset <memberName> memberName.Length = 0; // advance to the first type parameter list or the end of the // entire type, whichever comes first; note that we may be called // recursively, so the entire type ends at either <RAngle> or // end of token list while (!token.IsTail && !token.IsCharacter(LAngle) && !token.IsCharacter(RAngle) && !token.IsCharacter(LSquare) && !token.IsCharacter(RSquare) && !token.IsCharacter('?') && !token.IsCharacter(',')) { canonicalPrefix.Append(token.Text); memberName.Append(token.Text); token = token.Next; } // advance to the end of the type parameter list; only include // '<' and ',' and '>' characters in <canonicalPrefix> Token typeParameters; #if false int trailingTypeParameterIndex = -1; #endif if (token.IsCharacter(LAngle)) { // track the beginning of the type parameters typeParameters = token; // canonicalize the type parameter list int angleNesting = 0; // in "<...>" int squareNesting = 0; // in "[...]"; ignore arrays, e.g. "[,]" while (!token.IsTail) { if (token.IsCharacter(LAngle)) { if (angleNesting == 0) { #if false trailingTypeParameterIndex = canonicalPrefix.Length; #endif canonicalPrefix.Append(LAngle); } angleNesting++; } else if (token.IsCharacter(RAngle)) { angleNesting--; if (angleNesting == 0) { canonicalPrefix.Append(RAngle); token = token.Next; break; } } else if (token.IsCharacter(LSquare)) squareNesting++; else if (token.IsCharacter(RSquare)) squareNesting--; else if (token.IsCharacter(',') && (squareNesting == 0) && (angleNesting == 1)) canonicalPrefix.Append(token.Text); token = token.Next; } Debug.Assert(angleNesting == 0); Debug.Assert(squareNesting == 0); } else typeParameters = null; #if false // remove trailing type parameters, if any; set <canonicalName> // to the result string canonicalName = canonicalPrefix.ToString(); if (trailingTypeParameterIndex >= 0) { canonicalName = canonicalName.Substring( 0, trailingTypeParameterIndex); } #else // set <canonicalName> to the precanonicalized name to look up string canonicalName = canonicalPrefix.ToString(); #endif // set <targetTopic> to the topic corresponding to <canonicalName> targetTopic = contextTopic.DocumentationSet.FindDocumentedTopic( canonicalName, contextTopic, 0, FindTopicSettings.TypeOnly | FindTopicSettings.Precanonicalized); // write the hyperlink (or non-hyperlinked text, if we can't find a // target topic) for this "prefix type" if (htmlWriter != null) { if (targetTopic != null) { htmlWriter.FormatBeginTag("a,href,title", targetTopic.DocHtmlFileName, targetTopic.LongTitle); } htmlWriter.WriteEncodedText(memberName.ToString()); if (targetTopic != null) htmlWriter.RenderEndTag(); } // if there were type parameters, write them recursively if (typeParameters != null) { // begin the type parameter list if (htmlWriter != null) htmlWriter.WriteEncodedText(LAngle.ToString()); // loop once for each type parameter Debug.Assert(typeParameters.IsCharacter(LAngle)); Token token2 = typeParameters.Next; while (true) { // write the type parameter Topic unused; token2 = DissectTypeReference(token2, contextTopic, htmlWriter, out unused); // if there are more type parameters, continue if (!token2.IsCharacter(',')) break; if (htmlWriter != null) htmlWriter.Write(','); token2 = token2.Next; while (token2.IsWhiteSpace) { if (htmlWriter != null) htmlWriter.Write(' '); token2 = token2.Next; } } Debug.Assert(token2.IsCharacter(RAngle)); Debug.Assert(token2.Next == token); // end the type parameter list if (htmlWriter != null) htmlWriter.WriteEncodedText(RAngle.ToString()); } // write and advance past anything following the type, e.g. "[]" // or "?", until we get to either the start of the next "prefix // type" or the end of the entire type int squareNesting2 = 0; // in "[...]"; ignore arrays, e.g. "[,]" while (true) { // we're done if we hit the end of the type if (token.IsTail || token.IsCharacter(RAngle) || (token.IsCharacter(',') && (squareNesting2 == 0))) return token; // end of the entire type // if this type has "[]" or "?" etc at the end of it, then we // can't return a target type because the actual type (e.g. // an array) is one we don't have a topic for targetTopic = null; // ignore commas inside square brackets if (token.IsCharacter(LSquare)) squareNesting2++; else if (token.IsCharacter(RSquare)) squareNesting2--; // stop if we hit the start of the next "prefix type" bool isDot = token.IsCharacter('.'); if (htmlWriter != null) htmlWriter.WriteEncodedText(token.Text); token = token.Next; if (isDot) { canonicalPrefix.Append('.'); break; // start of the next "prefix type" } } } }
TopicWriter.ReadXmlElementText Method
Assuming a given XmlReader is positioned at the beginning of an XML element, this method reads the text inside the element. If the element contains any child elements, null is returned.
Parameters
xmlReader The XML element to read. |
protected string ReadXmlElementText(XmlReader xmlReader) { string nodeName = xmlReader.Name; try { return xmlReader.ReadElementContentAsString(); } catch (XmlException ex) { FireWarningInSourceFile( ((IXmlLineInfo) xmlReader).LineNumber, Resources.InvalidXmlElementSyntax, nodeName, ex.Message); return null; } }
TopicWriter.WriteLabeledParagraph Method
Generates HTML for a paragraph containing a label followed by text.
Parameters
label The label text. html The HTML of the rest of the paragraph. |
protected void WriteLabeledParagraph(string label, string html) { FormatBeginTag("p,class", "LabeledParagraph"); FormatBeginTag("span,class", "Label_"); WriteEncodedText(label); RenderEndTag(); Write(html); FormatEndTag("\n"); }
protected void WriteEncodedTokenList(TokenList tokenList, string after) { if (tokenList != null) WriteEncodedText(tokenList.ToString() + (after ?? " ")); }
TopicWriter.WriteEncodedText Method
Writes a string, converted from plain text to HTML.
Parameters
text The string to write. If null, nothing is written. after If not null, then this string is written after text is written. |
protected void WriteEncodedText(string text, string after) { if (text != null) WriteEncodedText(text + (after ?? " ")); }
TopicWriter.FireWarningInSourceFile Method
Fires the WarningInSourceFile event.
Parameters
lineNumber The line number within the source file that the warning relates to. format A String.Format-style format string used to format the warning message text. args Arguments for the format string. |
protected void FireWarningInSourceFile(int lineNumber, string format, params object[] args) { if (WarningInSourceFile != null) { WarningInSourceFile(Topic.SourceFile, lineNumber, String.Format(format, args)); } }
TopicWriter.LinkHtml Method
Constructs a link to a topic. If the linked-to topic does not have Topic.IsDocumented set to true, non-linked text is returned instead.
Parameters
text The plain text of the link. topic The topic to link to.
Return Value
The HTML of the link or non-linked text. |
protected static string LinkHtml(string text, Topic topic) { if (topic.IsDocumented) { return String.Format("<a href=\"{0}\">{1}</a>", Html(topic.DocHtmlFileName), Html(text)); } else return Html(text); }
TopicWriter.LinkNameHtml Method
Constructs a link to a topic. If the linked-to topic does not have Topic.IsDocumented set to true, non-linked text is returned instead, formatted with
Parameters
topic The topic to link to.
Return Value
The HTML of the link or non-linked text. |
protected static string LinkNameHtml(Topic topic) { if (topic.IsDocumented) { // format as a hyperlink to the specified topic return String.Format("<a href=\"{0}\" title=\"{1}\">{2}</a>", Html(topic.DocHtmlFileName), Html(topic.LongTitle), Html(topic.MemberName)); } else { // format as an unlinked name return String.Format("<span class=\"n\">{0}</span>", Html(topic.MemberName)); } }
TopicWriter.WriteTopicFooterHtml Method
Writes the footer HTML, if any (for example, a copyright notice). |
protected void WriteTopicFooterHtml() { if (TopicRenderer.TopicFooterHtml != null) { FormatBeginTag("div,class", "PageFooter"); Write(TopicRenderer.TopicFooterHtml); FormatEndTag("\n"); } }
TopicWriter.Html Method
Converts plain text to HTML.
Parameters
text The plain text to convert.
Return Value
The converted HTML. |
protected static string Html(string text) { return HttpUtility.HtmlEncode(text); }
TopicWriter.AddItem Method
Adds an item to a list. Allocates the list if necessary.
Type Parameters
T The type of item in the list.
Parameters
item The item to add to the list. list The list. If list is null, a new list is allocated. |
protected static void AddItem<T>(T item, ref List<T> list) { if (list == null) list = new List<T>(); list.Add(item); } ////////////////////////////////////////////////////////////////////////// // Protected Helper Types //
TopicWriter.MemberSection Enumeration
Identifies a member list section of a topic; for example, "Constructors".
Members
|
protected enum MemberSection {
TopicWriter.MemberSection.Constructors Enumeration Value
"Constructors" section. |
Constructors = 0,
TopicWriter.MemberSection.Destructors Enumeration Value
"Destructors" section. |
Destructors = 1,
TopicWriter.MemberSection.Fields Enumeration Value
"Fields" section. |
Fields = 2,
TopicWriter.MemberSection.Properties Enumeration Value
"Properties" section. |
Properties = 3,
TopicWriter.MemberSection.Methods Enumeration Value
"Methods" section. |
Methods = 4,
TopicWriter.MemberSection.Operators Enumeration Value
"Operators" section. |
Operators = 5,
TopicWriter.MemberSection.Events Enumeration Value
"Events" section. |
Events = 6,
TopicWriter.MemberSection.Implementations Enumeration Value
"Implementations" section. |
Implementations = 7,
TopicWriter.MemberSection.Classes Enumeration Value
"Classes" section. |
Classes = 8,
TopicWriter.MemberSection.Interfaces Enumeration Value
"Classes" section. |
Interfaces = 9,
TopicWriter.MemberSection.Structures Enumeration Value
"Structures" section. |
Structures = 10,
TopicWriter.MemberSection.Delegates Enumeration Value
"Classes" section. |
Delegates = 11,
TopicWriter.MemberSection.Enumerations Enumeration Value
"Classes" section. |
Enumerations = 12,
TopicWriter.MemberSection.Length Enumeration Value
The count of possible member sections. |
Length = 13 // must be last element
}
TopicWriter.ListState Class
State of the current "<list>" XML documentation construct. |
protected class ListState {
TopicWriter.ListState.ListType Field
The value of the "type" attribute of the "<list>" XML documentation element. One of the following: "bullet", "number", "table". |
public string ListType;
TopicWriter.ListState.InListHeader Field
For ListType equal to "table", InListHeader is set to true while we're inside "<listheader>...</listheader>". |
public bool InListHeader;
public bool BegunGrid;
TopicWriter.ListState.TermHeading Field
For ListType equal to "table", TermHeading is set to the column heading (if one is specified) for the term column. |
public string TermHeading;
TopicWriter.ListState.DescriptionHeading Field
For ListType equal to "table", DescriptionHeading is set to the column heading (if one is specified) for the description column. |
public string DescriptionHeading;
ListState Constructor
Initializes an instance of this class.
Parameters
listType The value to initialize ListType to. |
public ListState(string listType) { Debug.Assert((listType == "bullet") || (listType == "number") || (listType == "table")); ListType = listType; }
TopicWriter.ListState.BeginGridIfNeeded Method
For ListType equal to "table", BeginGrid is called if it hasn't been called yet for this list, i.e. if BegunGrid is still false.
Parameters
writer The TopicWriter to write to. |
public void BeginGridIfNeeded(TopicWriter writer) { if (!BegunGrid) { writer.BeginGrid("List", TermHeading ?? Resources.DefaultTermHeading, DescriptionHeading ?? Resources.DefaultDescriptionHeading); BegunGrid = true; } } }
TopicWriter.TransformCustomInsideXml Method
When overridden by a derived class, this method can transform an XML element that's inside a section (e.g. within "<summary>...lt;/summary>") within an XML comment into corresponding HTML.
Parameters
section The section being parsed. xmlReader The input XML. On entry, xmlReader refers to the opening tag of the XML element to process. On exit, if true is returned, the method is responsible for positioning xmlReader to the first XML element after the element being processed. If false is returned, or an exception is thrown, the method must not reposition xmlReader.
Return Value
true if the element was processed, false if not. If false is returned, xmlReader must not be repositioned away from its initial value -- in other words, the method must be able to determine whether or not the XML element is one it can process purely by looking at its name and attributes.
Exceptions
Remarks
The default implementation of TransformCustomInsideXml does nothing except return false. This method is intended to be overridden by a derived class. |
protected virtual bool TransformCustomInsideXml(XmlCommentSection section, XmlReader xmlReader) { // the default implementation does nothing return false; } }
WarningException Class
Indicates an error in a custom hook that should be displayed as a warning to the user. |
public class WarningException : Exception {
WarningException 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 WarningException(string format, params object[] args) : base(String.Format(format, args)) { } } }