summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs')
-rw-r--r--tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs333
1 files changed, 333 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs
new file mode 100644
index 0000000..4d67803
--- /dev/null
+++ b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs
@@ -0,0 +1,333 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace Microsoft.Ddue.Tools {
+
+ public class IntellisenseComponent : BuildComponent {
+
+ public IntellisenseComponent (BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) {
+
+ XPathNavigator output_node = configuration.SelectSingleNode("output");
+ if (output_node != null) {
+
+ string directory_value = output_node.GetAttribute("directory", String.Empty);
+ if (!String.IsNullOrEmpty(directory_value)) {
+ directory = Environment.ExpandEnvironmentVariables(directory_value);
+ if (!Directory.Exists(directory)) WriteMessage(MessageLevel.Error, String.Format("The output directory '{0}' does not exist.", directory));
+ }
+ }
+
+ // a way to get additional information into the intellisense file
+ XPathNodeIterator input_nodes = configuration.Select("input");
+ foreach (XPathNavigator input_node in input_nodes) {
+ string file_value = input_node.GetAttribute("file", String.Empty);
+ if (!String.IsNullOrEmpty(file_value)) {
+ string file = Environment.ExpandEnvironmentVariables(file_value);
+ ReadInputFile(file);
+ }
+ }
+
+ context.AddNamespace("ddue", "http://ddue.schemas.microsoft.com/authoring/2003/5");
+
+ summaryExpression.SetContext(context);
+ memberSummaryExpression.SetContext(context);
+ returnsExpression.SetContext(context);
+ parametersExpression.SetContext(context);
+ parameterNameExpression.SetContext(context);
+ templatesExpression.SetContext(context);
+ templateNameExpression.SetContext(context);
+ exceptionExpression.SetContext(context);
+ exceptionCrefExpression.SetContext(context);
+ }
+
+ // input content store
+
+ private void ReadInputFile (string file) {
+ try {
+ XPathDocument document = new XPathDocument(file);
+
+ XPathNodeIterator member_nodes = document.CreateNavigator().Select("/metadata/topic[@id]");
+ foreach (XPathNavigator member_node in member_nodes) {
+ string id = member_node.GetAttribute("id", String.Empty);
+ content[id] = member_node.Clone();
+ }
+
+ WriteMessage(MessageLevel.Info, String.Format("Read {0} input content nodes.", member_nodes.Count));
+
+ } catch (XmlException e) {
+ WriteMessage(MessageLevel.Error, String.Format("The input file '{0}' is not a well-formed XML file. The error message is: {1}", file, e.Message));
+ } catch (IOException e) {
+ WriteMessage(MessageLevel.Error, String.Format("An error occured while attempting to access the fileThe input file '{0}'. The error message is: {1}", file, e.Message));
+ }
+
+
+ }
+ private Dictionary<string, XPathNavigator> content = new Dictionary<string, XPathNavigator>();
+
+ // the action of the component
+
+ public override void Apply (XmlDocument document, string id) {
+
+ // only generate intellisense if id corresponds to an allowed intellisense ID
+ if (id.Length < 2) return;
+ if (id[1] != ':') return;
+ if (!((id[0] == 'T') || (id[0] == 'M') || (id[0] == 'P') || (id[0] == 'F') || (id[0] == 'E') || (id[0] == 'N'))) return;
+
+ XPathNavigator root = document.CreateNavigator().SelectSingleNode("/document/comments");
+
+ string assembly;
+
+ if ((string)root.Evaluate(groupExpression) == "namespace") {
+ // get the assembly for the namespace
+ //assembly = (string) root.Evaluate(namespaceAssemblyExpression);
+ // Assign general name for namespace assemblies since they do not belong to any specific assembly
+ assembly = "namespaces";
+ } else {
+ // get the assembly for the API
+ assembly = (string) root.Evaluate(assemblyExpression);
+ }
+
+ if (String.IsNullOrEmpty(assembly)) return;
+
+ // try/catch block for capturing errors
+ try {
+
+ // get the writer for the assembly
+ XmlWriter writer;
+ if (!writers.TryGetValue(assembly, out writer)) {
+
+ // create a writer for the assembly
+ string name = Path.Combine(directory, assembly + ".xml");
+ // Console.WriteLine("creating {0}", name);
+
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Indent = true;
+
+ try {
+ writer = XmlWriter.Create(name, settings);
+ } catch (IOException e) {
+ WriteMessage(MessageLevel.Error, String.Format("An access error occured while attempting to create the intellisense output file '{0}'. The error message is: {1}", name, e.Message));
+ }
+
+
+ writers.Add(assembly, writer);
+
+ // write out the initial data
+ writer.WriteStartDocument();
+ writer.WriteStartElement("doc");
+ //do not generate assembly nodes for namespace topics
+ if ((string)root.Evaluate(groupExpression) != "namespace")
+ {
+ writer.WriteStartElement("assembly");
+ writer.WriteElementString("name", assembly);
+ writer.WriteEndElement();
+ }
+ writer.WriteStartElement("members");
+ }
+
+ writer.WriteStartElement("member");
+ writer.WriteAttributeString("name", id);
+
+ // summary
+ WriteSummary(root, summaryExpression, writer);
+
+ // return value
+ XPathNavigator returns = root.SelectSingleNode(returnsExpression);
+ if (returns != null) {
+ writer.WriteStartElement("returns");
+
+ XmlReader reader = returns.ReadSubtree();
+ CopyContent(reader, writer);
+ reader.Close();
+
+ writer.WriteEndElement();
+ }
+
+ // parameters
+ XPathNodeIterator parameters = root.Select(parametersExpression);
+ foreach (XPathNavigator parameter in parameters) {
+
+ string name = (string)parameter.Evaluate(parameterNameExpression);
+
+ XmlReader reader = parameter.ReadSubtree();
+
+ writer.WriteStartElement("param");
+ writer.WriteAttributeString("name", name);
+ CopyContent(reader, writer);
+ writer.WriteEndElement();
+
+ reader.Close();
+ }
+
+ // templates
+ XPathNodeIterator templates = root.Select(templatesExpression);
+ foreach (XPathNavigator template in templates) {
+
+ string name = (string)template.Evaluate(templateNameExpression);
+
+ XmlReader reader = template.ReadSubtree();
+
+ writer.WriteStartElement("typeparam");
+ writer.WriteAttributeString("name", name);
+ CopyContent(reader, writer);
+ writer.WriteEndElement();
+
+ reader.Close();
+ }
+
+ // exceptions
+ XPathNodeIterator exceptions = root.Select(exceptionExpression);
+ foreach (XPathNavigator exception in exceptions) {
+
+ string exceptionCref = (string)exception.Evaluate(exceptionCrefExpression);
+
+ XmlReader reader = exception.ReadSubtree();
+
+ writer.WriteStartElement("exception");
+ writer.WriteAttributeString("cref", exceptionCref);
+ CopyContent(reader, writer);
+ writer.WriteEndElement();
+
+ reader.Close();
+ }
+
+ // stored contents
+ XPathNavigator input;
+ if (content.TryGetValue(id, out input)) {
+ XPathNodeIterator input_nodes = input.SelectChildren(XPathNodeType.Element);
+ foreach (XPathNavigator input_node in input_nodes) {
+ input_node.WriteSubtree(writer);
+ }
+ }
+
+ writer.WriteFullEndElement();
+
+ // enumeration members
+ string subgroup = (string)root.Evaluate(subgroupExpression);
+ if (subgroup == "enumeration") {
+
+ XPathNodeIterator elements = (XPathNodeIterator)root.Evaluate(elementsExpression);
+ foreach (XPathNavigator element in elements) {
+
+ string api = (string)element.GetAttribute("api", string.Empty);
+ writer.WriteStartElement("member");
+ writer.WriteAttributeString("name", api);
+
+ //summary
+ WriteSummary(element, memberSummaryExpression, writer);
+
+ writer.WriteFullEndElement();
+ }
+ }
+
+
+ } catch (IOException e) {
+ WriteMessage(MessageLevel.Error, String.Format("An access error occured while attempting to write intellisense data. The error message is: {0}", e.Message));
+ } catch (XmlException e) {
+ WriteMessage(MessageLevel.Error, String.Format("Intellisense data was not valid XML. The error message is: {0}", e.Message));
+ }
+
+ }
+
+ public override void Dispose () {
+ //Console.WriteLine("disposing intellisense writer...");
+ foreach (XmlWriter writer in writers.Values) {
+ writer.WriteEndDocument();
+ writer.Close();
+ }
+ }
+
+ private void WriteSummary(XPathNavigator node, XPathExpression expression, XmlWriter writer) {
+ XPathNavigator summary = node.SelectSingleNode(expression);
+ if (summary != null) {
+ writer.WriteStartElement("summary");
+
+ XmlReader reader = summary.ReadSubtree();
+ CopyContent(reader, writer);
+ reader.Close();
+
+ writer.WriteEndElement();
+ }
+ else {
+ // Console.WriteLine("no summary");
+ }
+ }
+
+ private void CopyContent (XmlReader reader, XmlWriter writer) {
+ reader.MoveToContent();
+ while (true) {
+
+ //Console.WriteLine("{0} {1}", reader.ReadState, reader.NodeType);
+
+ if (reader.NodeType == XmlNodeType.Text) {
+ writer.WriteString(reader.ReadString());
+ } else if (reader.NodeType == XmlNodeType.Element) {
+ //Console.WriteLine(reader.LocalName);
+ if (reader.LocalName == "codeEntityReference") {
+ writer.WriteStartElement("see");
+ writer.WriteAttributeString("cref", reader.ReadElementString());
+ writer.WriteEndElement();
+ } else if (reader.LocalName == "parameterReference") {
+ writer.WriteStartElement("paramref");
+ writer.WriteAttributeString("name", reader.ReadElementString());
+ writer.WriteEndElement();
+ } else if (reader.LocalName == "link") {
+ string displayText = reader.ReadElementString();
+ if (displayText.StartsWith("GTMT#")) {
+ writer.WriteString(displayText.Substring(displayText.IndexOf("#") + 1));
+ } else {
+ writer.WriteString(displayText);
+ }
+ } else {
+ reader.Read();
+ }
+ } else {
+ if (!reader.Read()) break;
+ }
+
+ }
+
+ }
+
+ private string directory = String.Empty;
+
+ private Dictionary<string,XmlWriter> writers = new Dictionary<string,XmlWriter>();
+
+ private XPathExpression assemblyExpression = XPathExpression.Compile("string(/document/reference/containers/library/@assembly)");
+
+ private XPathExpression namespaceAssemblyExpression = XPathExpression.Compile("string(/document/reference/elements/element/containers/library/@assembly)");
+
+ private XPathExpression summaryExpression = XPathExpression.Compile("ddue:dduexml/ddue:summary");
+
+ private XPathExpression returnsExpression = XPathExpression.Compile("ddue:dduexml/ddue:returnValue");
+
+ private XPathExpression parametersExpression = XPathExpression.Compile("ddue:dduexml/ddue:parameters/ddue:parameter/ddue:content");
+
+ private XPathExpression parameterNameExpression = XPathExpression.Compile("string(../ddue:parameterReference)");
+
+ private XPathExpression templatesExpression = XPathExpression.Compile("ddue:dduexml/ddue:genericParameters/ddue:genericParameter/ddue:content");
+
+ private XPathExpression templateNameExpression = XPathExpression.Compile("string(../ddue:parameterReference)");
+
+ private XPathExpression exceptionExpression = XPathExpression.Compile("ddue:dduexml/ddue:exceptions/ddue:exception/ddue:content");
+
+ private XPathExpression exceptionCrefExpression = XPathExpression.Compile("string(../ddue:codeEntityReference)");
+
+ private XPathExpression subgroupExpression = XPathExpression.Compile("string(/document/reference/apidata/@subgroup)");
+
+ private XPathExpression groupExpression = XPathExpression.Compile("string(/document/reference/apidata/@group)");
+
+ private XPathExpression elementsExpression = XPathExpression.Compile("/document/reference/elements/element");
+
+ private XPathExpression memberSummaryExpression = XPathExpression.Compile("ddue:summary");
+
+ private XmlNamespaceManager context = new CustomContext();
+
+ }
+
+} \ No newline at end of file