diff options
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs')
-rw-r--r-- | tools/Sandcastle/Source/BuildAssembler/BuildComponents/IntellisenseComponent.cs | 333 |
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 |