public static void PopulateTreeFromIndexFile(string indexFilePath, string idPrefix, Tree tree, IDocStorage storage, Dictionary <string, XElement> nsSummaries, Func <XElement, string> indexGenerator = null) { var root = tree.RootNode; int resID = 0; var asm = Path.GetDirectoryName(indexFilePath); storage = storage ?? new Storage.NullStorage(); // nsSummaries is allowed to be null if the user doesn't care about it nsSummaries = nsSummaries ?? new Dictionary <string, XElement> (); // default index generator uses a counter indexGenerator = indexGenerator ?? (_ => resID++.ToString()); using (var reader = XmlReader.Create(File.OpenRead(indexFilePath))) { reader.ReadToFollowing("Types"); var types = XElement.Load(reader.ReadSubtree()); foreach (var ns in types.Elements("Namespace")) { var nsName = (string)ns.Attribute("Name"); nsName = !string.IsNullOrEmpty(nsName) ? nsName : "global"; var nsNode = root.GetOrCreateNode(nsName, "N:" + nsName); XElement nsElements; if (!nsSummaries.TryGetValue(nsName, out nsElements)) { nsSummaries[nsName] = nsElements = new XElement("elements", new XElement("summary"), new XElement("remarks")); } foreach (var type in ns.Elements("Type")) { // Add the XML file corresponding to the type to our storage var id = indexGenerator(type); string typeFilePath; var typeDocument = EcmaDoc.LoadTypeDocument(asm, nsName, type.Attribute("Name").Value, out typeFilePath); if (typeDocument == null) { continue; } using (var file = File.OpenRead(typeFilePath)) storage.Store(id, file); nsElements.Add(ExtractClassSummary(typeFilePath)); var typeCaption = EcmaDoc.GetTypeCaptionFromIndex(type); var url = idPrefix + id + '#' + typeCaption + '/'; typeCaption = EcmaDoc.GetTypeCaptionFromIndex(type, true); var typeNode = nsNode.CreateNode(typeCaption, url); // Add meta "Members" node typeNode.CreateNode("Members", "*"); var membersNode = typeDocument.Root.Element("Members"); if (membersNode == null || !membersNode.Elements().Any()) { continue; } var members = membersNode .Elements("Member") .ToLookup(EcmaDoc.GetMemberType); foreach (var memberType in members) { // We pluralize the member type to get the caption and take the first letter as URL var node = typeNode.CreateNode(EcmaDoc.PluralizeMemberType(memberType.Key), memberType.Key[0].ToString()); var memberIndex = 0; var isCtors = memberType.Key[0] == 'C'; // We do not escape much member name here foreach (var memberGroup in memberType.GroupBy(m => MakeMemberCaption(m, isCtors))) { if (memberGroup.Count() > 1) { // Generate overload var overloadCaption = MakeMemberCaption(memberGroup.First(), false); var overloadNode = node.CreateNode(overloadCaption, overloadCaption); foreach (var member in memberGroup) { overloadNode.CreateNode(MakeMemberCaption(member, true), (memberIndex++).ToString()); } overloadNode.Sort(); } else { // We treat constructor differently by showing their argument list in all cases node.CreateNode(MakeMemberCaption(memberGroup.First(), isCtors), (memberIndex++).ToString()); } } node.Sort(); } } nsNode.Sort(); } root.Sort(); } }
public static void PopulateTreeFromIndexFile(string indexFilePath, string idPrefix, Tree tree, IDocStorage storage, Dictionary <string, XElement> nsSummaries, Func <XElement, string> indexGenerator = null, IEcmaProviderFileSource fileSource = null) { fileSource = fileSource ?? DefaultEcmaProviderFileSource.Default; var root = tree.RootNode; int resID = 0; var asm = Path.GetDirectoryName(indexFilePath); storage = storage ?? new Storage.NullStorage(); // nsSummaries is allowed to be null if the user doesn't care about it nsSummaries = nsSummaries ?? new Dictionary <string, XElement> (); // default index generator uses a counter indexGenerator = indexGenerator ?? (_ => resID++.ToString()); using (var reader = fileSource.GetIndexReader(indexFilePath)) { reader.ReadToFollowing("Types"); var types = XElement.Load(reader.ReadSubtree()); foreach (var ns in types.Elements("Namespace")) { var nsName = (string)ns.Attribute("Name"); nsName = !string.IsNullOrEmpty(nsName) ? nsName : "global"; var nsNode = root.GetOrCreateNode(nsName, "N:" + nsName); XElement nsElements; if (!nsSummaries.TryGetValue(nsName, out nsElements)) { nsSummaries[nsName] = nsElements = new XElement("elements", new XElement("summary"), new XElement("remarks")); } //Add namespace summary and remarks data from file, if available var nsFileName = fileSource.GetNamespaceXmlPath(asm, nsName); if (File.Exists(nsFileName)) { var nsEl = fileSource.GetNamespaceElement(nsFileName); nsElements.Element("summary").ReplaceWith(nsEl.Descendants("summary").First()); nsElements.Element("remarks").ReplaceWith(nsEl.Descendants("remarks").First()); } else { Console.WriteLine("Error reading namespace XML for {0} at {1}", nsName, nsFileName); } foreach (var type in ns.Elements("Type")) { // Add the XML file corresponding to the type to our storage var id = indexGenerator(type); string typeFilePath; var typeDocument = EcmaDoc.LoadTypeDocument(asm, nsName, type.Attribute("Name").Value, out typeFilePath, fileSource); if (typeDocument == null) { continue; } // write the document (which may have been modified by the fileSource) to the storage MemoryStream io = new MemoryStream(); using (var writer = XmlWriter.Create(io)) { typeDocument.WriteTo(writer); } io.Seek(0, SeekOrigin.Begin); storage.Store(id, io); nsElements.Add(ExtractClassSummary(typeDocument)); var typeCaption = EcmaDoc.GetTypeCaptionFromIndex(type); var url = idPrefix + id + '#' + typeCaption + '/'; typeCaption = EcmaDoc.GetTypeCaptionFromIndex(type, true); var typeNode = nsNode.CreateNode(typeCaption, url); // Add meta "Members" node typeNode.CreateNode("Members", "*"); var membersNode = typeDocument.Root.Element("Members"); if (membersNode == null || !membersNode.Elements().Any()) { continue; } var members = membersNode .Elements("Member") .ToLookup(EcmaDoc.GetMemberType); foreach (var memberType in members) { // We pluralize the member type to get the caption and take the first letter as URL var node = typeNode.CreateNode(EcmaDoc.PluralizeMemberType(memberType.Key), memberType.Key[0].ToString()); var memberIndex = 0; var isCtors = memberType.Key[0] == 'C'; // We do not escape much member name here foreach (var memberGroup in memberType.GroupBy(m => MakeMemberCaption(m, isCtors))) { if (memberGroup.Count() > 1) { // Generate overload var overloadCaption = MakeMemberCaption(memberGroup.First(), false); var overloadNode = node.CreateNode(overloadCaption, overloadCaption); foreach (var member in memberGroup) { overloadNode.CreateNode(MakeMemberCaption(member, true), (memberIndex++).ToString()); } overloadNode.Sort(); } else { // We treat constructor differently by showing their argument list in all cases node.CreateNode(MakeMemberCaption(memberGroup.First(), isCtors), (memberIndex++).ToString()); } } node.Sort(); } } nsNode.Sort(); } root.Sort(); } }
public override void PopulateSearchableIndex(IndexWriter writer) { StringBuilder text = new StringBuilder(); SearchableDocument searchDoc = new SearchableDocument(); foreach (Node ns_node in Tree.RootNode.ChildNodes) { foreach (Node type_node in ns_node.ChildNodes) { string typename = type_node.Caption.Substring(0, type_node.Caption.IndexOf(' ')); string full = ns_node.Caption + "." + typename; string url = type_node.PublicUrl; string doc_tag = GetKindFromCaption(type_node.Caption); string rest, hash; var id = GetInternalIdForInternalUrl(type_node.GetInternalUrl(), out hash); var xdoc = XDocument.Load(GetHelpStream(id)); if (xdoc == null) { continue; } if (string.IsNullOrEmpty(doc_tag)) { continue; } // For classes, structures or interfaces add a doc for the overview and // add a doc for every constructor, method, event, ... // doc_tag == "Class" || doc_tag == "Structure" || doc_tag == "Interface" if (doc_tag[0] == 'C' || doc_tag[0] == 'S' || doc_tag[0] == 'I') { // Adds a doc for every overview of every type SearchableDocument doc = searchDoc.Reset(); doc.Title = type_node.Caption; doc.HotText = typename; doc.Url = url; doc.FullTitle = full; var node_sel = xdoc.Root.Element("Docs"); text.Clear(); GetTextFromNode(node_sel, text); doc.Text = text.ToString(); text.Clear(); GetExamples(node_sel, text); doc.Examples = text.ToString(); writer.AddDocument(doc.LuceneDoc); var exportParsable = doc_tag[0] == 'C' && (ns_node.Caption.StartsWith("MonoTouch") || ns_node.Caption.StartsWith("MonoMac")); //Add docs for contructors, methods, etc. foreach (Node c in type_node.ChildNodes) // c = Constructors || Fields || Events || Properties || Methods || Operators { if (c.Element == "*") { continue; } const float innerTypeBoost = 0.2f; IEnumerable <Node> ncnodes = c.ChildNodes; // The rationale is that we need to properly handle method overloads // so for those method node which have children, flatten them if (c.Caption == "Methods") { ncnodes = ncnodes .Where(n => n.ChildNodes == null || n.ChildNodes.Count == 0) .Concat(ncnodes.Where(n => n.ChildNodes.Count > 0).SelectMany(n => n.ChildNodes)); } else if (c.Caption == "Operators") { ncnodes = ncnodes .Where(n => !n.Caption.EndsWith("Conversion")) .Concat(ncnodes.Where(n => n.Caption.EndsWith("Conversion")).SelectMany(n => n.ChildNodes)); } var prematchedMembers = xdoc.Root.Element("Members").Elements("Member").ToLookup(n => (string)n.Attribute("MemberName"), n => n); foreach (Node nc in ncnodes) { XElement docsNode = null; try { docsNode = GetDocsFromCaption(xdoc, c.Caption[0] == 'C' ? ".ctor" : nc.Caption, c.Caption[0] == 'O', prematchedMembers); } catch {} if (docsNode == null) { Console.Error.WriteLine("Problem: {0}", nc.PublicUrl); continue; } SearchableDocument doc_nod = searchDoc.Reset(); doc_nod.Title = LargeName(nc) + " " + EcmaDoc.EtcKindToCaption(c.Caption[0]); doc_nod.FullTitle = ns_node.Caption + '.' + typename + "::" + nc.Caption; doc_nod.HotText = string.Empty; /* Disable constructors hottext indexing as it's often "polluting" search queries * because it has the same hottext than standard types */ if (c.Caption != "Constructors") { //dont add the parameters to the hottext int ppos = nc.Caption.IndexOf('('); doc_nod.HotText = ppos != -1 ? nc.Caption.Substring(0, ppos) : nc.Caption; } var urlnc = nc.PublicUrl; doc_nod.Url = urlnc; text.Clear(); GetTextFromNode(docsNode, text); doc_nod.Text = text.ToString(); text.Clear(); GetExamples(docsNode, text); doc_nod.Examples = text.ToString(); Document lucene_doc = doc_nod.LuceneDoc; lucene_doc.Boost = innerTypeBoost; writer.AddDocument(lucene_doc); // Objective-C binding specific parsing of [Export] attributes if (exportParsable) { try { var exports = docsNode.Parent.Elements("Attributes").Elements("Attribute").Elements("AttributeName") .Select(a => (string)a).Where(txt => txt.Contains("Foundation.Export")); foreach (var exportNode in exports) { var parts = exportNode.Split('"'); if (parts.Length != 3) { Console.WriteLine("Export attribute not found or not usable in {0}", exportNode); continue; } var export = parts[1]; var export_node = searchDoc.Reset(); export_node.Title = export + " Export"; export_node.FullTitle = ns_node.Caption + '.' + typename + "::" + export; export_node.Url = urlnc; export_node.HotText = export; export_node.Text = string.Empty; export_node.Examples = string.Empty; lucene_doc = export_node.LuceneDoc; lucene_doc.Boost = innerTypeBoost; writer.AddDocument(lucene_doc); } } catch (Exception e) { Console.WriteLine("Problem processing {0} for MonoTouch/MonoMac exports\n\n{0}", e); } } } } // doc_tag == "Enumeration" } else if (doc_tag[0] == 'E') { var members = xdoc.Root.Element("Members").Elements("Member"); if (members == null) { continue; } text.Clear(); foreach (var member_node in members) { string enum_value = (string)member_node.Attribute("MemberName"); text.Append(enum_value); text.Append(" "); GetTextFromNode(member_node.Element("Docs"), text); text.AppendLine(); } SearchableDocument doc = searchDoc.Reset(); text.Clear(); GetExamples(xdoc.Root.Element("Docs"), text); doc.Examples = text.ToString(); doc.Title = type_node.Caption; doc.HotText = (string)xdoc.Root.Attribute("Name"); doc.FullTitle = full; doc.Url = url; doc.Text = text.ToString(); writer.AddDocument(doc.LuceneDoc); // doc_tag == "Delegate" } else if (doc_tag[0] == 'D') { SearchableDocument doc = searchDoc.Reset(); doc.Title = type_node.Caption; doc.HotText = (string)xdoc.Root.Attribute("Name"); doc.FullTitle = full; doc.Url = url; var node_sel = xdoc.Root.Element("Docs"); text.Clear(); GetTextFromNode(node_sel, text); doc.Text = text.ToString(); text.Clear(); GetExamples(node_sel, text); doc.Examples = text.ToString(); writer.AddDocument(doc.LuceneDoc); } } } }