2 // The provider for a tree of ECMA documents
5 // Miguel de Icaza (miguel@ximian.com)
6 // Joshua Tauberer (tauberer@for.net)
8 // (C) 2002, 2003 Ximian, Inc.
9 // (C) 2003 Joshua Tauberer.
10 // Copyright 2003-2011 Novell
11 // Copyright 2011 Xamarin Inc
14 // Should cluster together constructors
17 // Should render attributes on the signature.
18 // Include examples as well.
22 using System.Diagnostics;
23 using System.Reflection;
26 using System.Xml.XPath;
30 using System.Collections;
31 using System.Collections.Generic;
32 using Mono.Lucene.Net.Index;
33 using Mono.Lucene.Net.Documents;
35 using Mono.Documentation;
37 using BF = System.Reflection.BindingFlags;
40 // Helper routines to extract information from an Ecma XML document
42 public static class EcmaDoc {
43 public static string GetFullClassName (XmlDocument doc)
45 return doc.SelectSingleNode ("/Type").Attributes ["FullName"].InnerText;
48 public static string GetClassName (XmlDocument doc)
50 return GetDisplayName (doc.SelectSingleNode ("/Type")).Replace ("+", ".");
53 public static string GetDisplayName (XmlNode type)
55 if (type.Attributes ["DisplayName"] != null) {
56 return type.Attributes ["DisplayName"].Value;
58 return type.Attributes ["Name"].Value;
61 public static string GetClassAssembly (XmlDocument doc)
63 return doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName").InnerText;
66 public static string GetClassNamespace (XmlDocument doc)
68 string s = doc.SelectSingleNode ("/Type").Attributes ["FullName"].InnerText;
70 return s.Substring (0, s.LastIndexOf ("."));
73 public static string GetTypeKind (XmlDocument doc)
75 XmlNode node = doc.SelectSingleNode ("/Type/Base/BaseTypeName");
78 if (GetFullClassName (doc) == "System.Object")
83 switch (node.InnerText){
85 case "System.Delegate":
86 case "System.MulticastDelegate":
88 case "System.ValueType":
98 // Utility function: converts a fully .NET qualified type name into a C#-looking one
100 public static string ConvertCTSName (string type)
102 if (!type.StartsWith ("System."))
105 if (type.EndsWith ("*"))
106 return ConvertCTSName(type.Substring(0, type.Length - 1)) + "*";
107 if (type.EndsWith ("&"))
108 return ConvertCTSName(type.Substring(0, type.Length - 1)) + "&";
109 if (type.EndsWith ("[]"))
110 return ConvertCTSName(type.Substring(0, type.Length - 2)) + "[]";
113 case "System.Byte": return "byte";
114 case "System.SByte": return "sbyte";
115 case "System.Int16": return "short";
116 case "System.Int32": return "int";
117 case "System.Int64": return "long";
119 case "System.UInt16": return "ushort";
120 case "System.UInt32": return "uint";
121 case "System.UInt64": return "ulong";
123 case "System.Single": return "float";
124 case "System.Double": return "double";
125 case "System.Decimal": return "decimal";
126 case "System.Boolean": return "bool";
127 case "System.Char": return "char";
128 case "System.String": return "string";
130 case "System.Object": return "object";
131 case "System.Void": return "void";
134 if (type.LastIndexOf(".") == 6)
135 return type.Substring(7);
141 static bool IsItReallyAGenericType (string type)
148 case "TypeReference":
150 case "TimeZoneInfo+AdjustmentRule":
151 case "TimeZoneInfo+TransitionTime":
154 if (type.StartsWith ("Tuple"))
159 public static string ConvertFromCTSName (string ctsType)
161 if (string.IsNullOrEmpty (ctsType))
164 // Most normal type should have a namespace part and thus a point in their name
165 if (ctsType.IndexOf ('.') != -1)
168 if (ctsType.EndsWith ("*"))
169 return ConvertFromCTSName(ctsType.Substring(0, ctsType.Length - 1)) + "*";
170 if (ctsType.EndsWith ("&"))
171 return ConvertFromCTSName(ctsType.Substring(0, ctsType.Length - 1)) + "&";
172 if (ctsType.EndsWith ("]")) { // Array may be multidimensional
173 var idx = ctsType.LastIndexOf ('[');
174 return ConvertFromCTSName (ctsType.Substring (0, idx)) + ctsType.Substring (idx);
177 // Big hack here, we tentatively try to say if a type is a generic when it starts with a upper case T
178 if ((char.IsUpper (ctsType, 0) && ctsType.Length == 1) || (ctsType[0] == 'T' && IsItReallyAGenericType (ctsType)))
182 case "byte": return "System.Byte";
183 case "sbyte": return "System.SByte";
184 case "short": return "System.Int16";
185 case "int": return "System.Int32";
186 case "long": return "System.Int64";
188 case "ushort": return "System.UInt16";
189 case "uint": return "System.UInt32";
190 case "ulong": return "System.UInt64";
192 case "float": return "System.Single";
193 case "double": return "System.Double";
194 case "decimal": return "System.Decimal";
195 case "bool": return "System.Boolean";
196 case "char": return "System.Char";
197 case "string": return "System.String";
199 case "object": return "System.Object";
200 case "void": return "System.Void";
203 // If we arrive here, the type was probably stripped of its 'System.'
204 return "System." + ctsType;
207 internal static string GetNamespaceFile (string dir, string ns)
209 string nsxml = Path.Combine (dir, "ns-" + ns + ".xml");
210 if (!File.Exists (nsxml))
211 nsxml = Path.Combine (dir, ns + ".xml");
215 internal static string GetImageFile (string dir, string img)
217 string path = Path.Combine (dir, Path.Combine ("_images", img));
218 return File.Exists (path) ? path : null;
221 public static string GetCref (XmlElement member)
223 string typeName = XmlDocUtils.ToEscapedTypeName (member.SelectSingleNode("/Type/@FullName").InnerText);
224 if (member.Name == "Type")
225 return "T:" + typeName;
226 string memberType = member.SelectSingleNode("MemberType").InnerText;
227 switch (memberType) {
229 return "C:" + typeName + MakeArgs(member);
231 return "E:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName"));
233 return "F:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName"));
235 string name = "M:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName")) + MakeArgs(member);
236 if (member.GetAttribute("MemberName") == "op_Implicit" || member.GetAttribute("MemberName") == "op_Explicit")
237 name += "~" + XmlDocUtils.ToTypeName (member.SelectSingleNode("ReturnValue/ReturnType").InnerText, member);
241 return "P:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName")) + MakeArgs(member);
243 throw new NotSupportedException ("MemberType '" + memberType + "' is not supported.");
247 private static string MakeArgs (XmlElement member)
249 XmlNodeList parameters = member.SelectNodes ("Parameters/Parameter");
250 if (parameters.Count == 0)
251 return member.SelectSingleNode ("MemberType").InnerText != "Property" ? "()" : "";
252 StringBuilder args = new StringBuilder ();
254 args.Append (XmlDocUtils.ToTypeName (parameters [0].Attributes ["Type"].Value, member));
255 for (int i = 1; i < parameters.Count; ++i) {
257 args.Append (XmlDocUtils.ToTypeName (parameters [i].Attributes ["Type"].Value, member));
260 return args.ToString ();
265 // The Ecma documentation provider:
267 // It populates a tree with contents during the help assembly
269 public class EcmaProvider : Provider {
270 ArrayList/*<string>*/ asm_dirs = new ArrayList ();
272 public EcmaProvider ()
276 public EcmaProvider (string base_directory)
278 AddDirectory (base_directory);
281 public void AddDirectory (string directory)
283 if (!Directory.Exists (directory))
284 throw new FileNotFoundException (String.Format ("The directory `{0}' does not exist", directory));
285 asm_dirs.Add (directory);
288 public override void PopulateTree (Tree tree)
290 ArrayList ns_dirs = new ArrayList ();
291 foreach (string asm in asm_dirs) {
292 ns_dirs.AddRange (Directory.GetDirectories (asm));
295 foreach (string ns in ns_dirs){
296 string basedir = Directory.GetParent (ns).FullName;
297 string [] files = Directory.GetFiles (ns);
301 Hashtable nsnodes = new Hashtable();
303 foreach (string file in files){
304 if (!file.EndsWith (".xml"))
307 if (ns_node == null) {
308 tn = Path.GetFileName (ns);
309 tree.HelpSource.Message (TraceLevel.Info, "Processing namespace {0}", tn);
310 ns_node = tree.LookupNode (tn, "N:" + tn);
311 string ns_summary_file = EcmaDoc.GetNamespaceFile (basedir, tn);
313 nsnodes[ns_node] = nsnodes;
315 if (File.Exists (ns_summary_file)) {
316 XmlDocument nsSummaryFile = new XmlDocument ();
317 nsSummaryFile.Load (ns_summary_file);
318 namespace_realpath [tn] = ns_summary_file;
320 XmlNode ns_summary = nsSummaryFile.SelectSingleNode ("Namespace/Docs/summary");
321 if (ns_summary != null && ns_summary.InnerText.Trim () != "To be added." && ns_summary.InnerText != "") {
322 namespace_summaries [tn] = detached.ImportNode (ns_summary, true);
323 namespace_remarks [tn] = detached.ImportNode (nsSummaryFile.SelectSingleNode ("Namespace/Docs/remarks"), true);
326 } else if (!namespace_summaries.ContainsKey (tn)) {
327 namespace_summaries [tn] = null;
328 namespace_remarks [tn] = null;
331 tree.HelpSource.Message (TraceLevel.Verbose, " Processing input file {0}", Path.GetFileName (file));
333 PopulateClass (tree, tn, ns_node, file);
336 // Sort the list of types in each namespace
337 foreach (Node ns_node2 in nsnodes.Keys)
343 class TypeInfo : IComparable {
344 public string type_assembly;
345 public string type_name;
346 public string type_full;
347 public string type_kind;
348 public XmlNode type_doc;
350 public TypeInfo (string k, string a, string f, string s, XmlNode n)
359 public int CompareTo (object b)
362 TypeInfo nb = (TypeInfo) b;
364 return String.Compare (na.type_full, nb.type_full);
369 // Packs a file with the summary data
371 public override void CloseTree (HelpSource hs, Tree tree)
373 foreach (DictionaryEntry de in class_summaries){
374 XmlDocument doc = new XmlDocument ();
375 string ns = (string) de.Key;
377 ArrayList list = (ArrayList) de.Value;
380 XmlElement elements = doc.CreateElement ("elements");
381 doc.AppendChild (elements);
383 if (namespace_summaries [ns] != null)
384 elements.AppendChild (doc.ImportNode ((XmlNode)namespace_summaries [ns],true));
386 elements.AppendChild (doc.CreateElement("summary"));
388 if (namespace_remarks [ns] != null)
389 elements.AppendChild (doc.ImportNode ((XmlNode)namespace_remarks [ns],true));
391 elements.AppendChild (doc.CreateElement("remarks"));
393 hs.Message (TraceLevel.Info, "Have {0} elements in the {1}", list.Count, ns);
394 foreach (TypeInfo p in list){
397 switch (p.type_kind){
399 e = doc.CreateElement ("class");
403 e = doc.CreateElement ("enum");
407 e = doc.CreateElement ("struct");
411 e = doc.CreateElement ("delegate");
415 e = doc.CreateElement ("interface");
419 e.SetAttribute ("name", p.type_name);
420 e.SetAttribute ("fullname", p.type_full);
421 e.SetAttribute ("assembly", p.type_assembly);
422 XmlNode copy = doc.ImportNode (p.type_doc, true);
423 e.AppendChild (copy);
424 elements.AppendChild (e);
426 hs.PackXml ("xml.summary." + ns, doc,(string) namespace_realpath[ns]);
430 XmlDocument nsSummary = new XmlDocument ();
431 XmlElement root = nsSummary.CreateElement ("elements");
432 nsSummary.AppendChild (root);
434 foreach (DictionaryEntry de in namespace_summaries) {
435 XmlNode n = (XmlNode)de.Value;
436 XmlElement summary = nsSummary.CreateElement ("namespace");
437 summary.SetAttribute ("ns", (string)de.Key);
438 root.AppendChild (summary);
440 summary.AppendChild (nsSummary.ImportNode (n,true));
442 summary.AppendChild (nsSummary.CreateElement("summary"));
444 tree.HelpSource.PackXml ("mastersummary.xml", nsSummary, null);
445 AddExtensionMethods (tree);
446 AddImageFiles (hs, tree);
449 void AddExtensionMethods (Tree tree)
451 XmlDocument extensions = null;
454 foreach (string asm in asm_dirs) {
455 string overview_file = Path.Combine (asm, "index.xml");
456 if (File.Exists (overview_file)) {
457 XmlDocument overview = new XmlDocument ();
458 overview.Load (overview_file);
459 XmlNodeList e = overview.SelectNodes ("/Overview/ExtensionMethods/*");
461 if (extensions == null) {
462 extensions = new XmlDocument ();
463 root = extensions.CreateElement ("ExtensionMethods");
464 extensions.AppendChild (root);
466 foreach (XmlNode n in e) {
468 root.AppendChild (extensions.ImportNode (n, true));
473 if (extensions != null) {
474 tree.HelpSource.Message (TraceLevel.Info, "Have {0} extension methods", numMethods);
475 tree.HelpSource.PackXml ("ExtensionMethods.xml", extensions, "ExtensionMethods.xml");
479 void AddImageFiles (HelpSource hs, Tree tree)
481 foreach (string asm in asm_dirs) {
482 string path = Path.Combine (asm, "_images");
483 if (!Directory.Exists (path))
487 foreach (var img in Directory.GetFiles (path))
489 foreach (var img in Directory.EnumerateFiles (path))
491 hs.PackFile (img, Path.GetFileName (img));
495 Hashtable/*<string, List<TypeInfo>>*/ class_summaries = new Hashtable ();
496 Hashtable/*<string, XmlNode>*/ namespace_summaries = new Hashtable ();
497 Hashtable/*<string, XmlNode>*/ namespace_remarks = new Hashtable ();
498 Hashtable/*<string, string -- path>*/ namespace_realpath = new Hashtable ();
500 XmlDocument detached = new XmlDocument ();
502 void PopulateClass (Tree tree, string ns, Node ns_node, string file)
504 XmlDocument doc = new XmlDocument ();
507 string name = EcmaDoc.GetClassName (doc);
508 string assembly = EcmaDoc.GetClassAssembly (doc);
509 string kind = EcmaDoc.GetTypeKind (doc);
510 string full = EcmaDoc.GetFullClassName (doc);
513 string file_code = ns_node.tree.HelpSource.PackFile (file);
515 XmlNode class_summary = detached.ImportNode (doc.SelectSingleNode ("/Type/Docs/summary"), true);
516 ArrayList l = (ArrayList) class_summaries [ns];
518 l = new ArrayList ();
519 class_summaries [ns] = (object) l;
521 l.Add (new TypeInfo (kind, assembly, full, name, class_summary));
523 class_node = ns_node.LookupNode (String.Format ("{0} {1}", name, kind), "ecma:" + file_code + "#" + name + "/");
525 if (kind == "Delegate") {
526 if (doc.SelectSingleNode("/Type/ReturnValue") == null)
527 tree.HelpSource.Message (TraceLevel.Error, "Delegate " + name + " does not have a ReturnValue node. See the ECMA-style updates.");
530 if (kind == "Enumeration")
533 if (kind == "Delegate")
537 // Always add the Members node
539 class_node.CreateNode ("Members", "*");
541 PopulateMember (doc, name, class_node, "Constructor", "Constructors");
542 PopulateMember (doc, name, class_node, "Method", "Methods");
543 PopulateMember (doc, name, class_node, "Property", "Properties");
544 PopulateMember (doc, name, class_node, "Field", "Fields");
545 PopulateMember (doc, name, class_node, "Event", "Events");
546 PopulateMember (doc, name, class_node, "Operator", "Operators");
553 public NodeIndex (XmlNode node, int index)
560 struct NodeCompare : IComparer {
561 public int Compare (object a, object b)
563 NodeIndex na = (NodeIndex) a;
564 NodeIndex nb = (NodeIndex) b;
566 return String.Compare (na.node.Attributes ["MemberName"].InnerText,
567 nb.node.Attributes ["MemberName"].InnerText);
571 string GetMemberName (XmlNode node)
573 return node.Attributes ["MemberName"].InnerText;
577 // Performs an XPath query on the document to extract the nodes for the various members
578 // we also use some extra text to pluralize the caption
580 void PopulateMember (XmlDocument doc, string typename, Node node, string type, string caption)
582 string select = type;
583 if (select == "Operator") select = "Method";
585 XmlNodeList list1 = doc.SelectNodes (String.Format ("/Type/Members/Member[MemberType=\"{0}\"]", select));
586 ArrayList list = new ArrayList();
588 foreach (XmlElement n in list1) {
589 n.SetAttribute("assembler_index", (i++).ToString());
590 if (type == "Method" && GetMemberName(n).StartsWith("op_")) continue;
591 if (type == "Operator" && !GetMemberName(n).StartsWith("op_")) continue;
595 int count = list.Count;
601 string key = type.Substring (0, 1);
602 nodes_node = node.CreateNode (caption, key);
607 foreach (XmlElement n in list)
608 nodes_node.CreateNode (GetMemberName (n), n.GetAttribute("assembler_index"));
612 foreach (XmlElement n in list)
613 nodes_node.CreateNode (EcmaHelpSource.MakeSignature(n, typename), n.GetAttribute("assembler_index"));
616 case "Property": // properties with indexers can be overloaded too
619 foreach (XmlElement n in list) {
620 bool multiple = false;
621 foreach (XmlNode nn in list) {
622 if (n != nn && GetMemberName(n) == nn.Attributes ["MemberName"].InnerText) {
628 string group, name, sig;
629 if (type != "Operator") {
630 name = GetMemberName(n);
631 sig = EcmaHelpSource.MakeSignature(n, null);
634 EcmaHelpSource.MakeOperatorSignature(n, out name, out sig);
639 nodes_node.LookupNode (group, group)
640 .CreateNode (sig, n.GetAttribute("assembler_index"));
642 nodes_node.CreateNode (name, n.GetAttribute("assembler_index"));
646 foreach (Node n in nodes_node.Nodes) {
654 throw new InvalidOperationException();
663 // The Ecma HelpSource provider
665 public class EcmaHelpSource : HelpSource {
667 public EcmaHelpSource (string base_file, bool create) : base (base_file, create)
669 ExtObject = new ExtensionObject (this);
672 public EcmaHelpSource ()
674 ExtObject = new ExtensionObject (this);
677 static string css_ecma;
678 public static string css_ecma_code {
680 if (css_ecma != null)
683 System.Reflection.Assembly assembly = typeof(EcmaHelpSource).Assembly;
684 Stream str_css = assembly.GetManifestResourceStream ("mono-ecma.css");
685 css_ecma = (new StreamReader (str_css)).ReadToEnd();
687 css_ecma = String.Empty;
693 public override string InlineCss {
694 get {return base.InlineCss + css_ecma_code;}
698 public static string js_code {
703 System.Reflection.Assembly assembly = typeof(EcmaHelpSource).Assembly;
704 Stream str_js = assembly.GetManifestResourceStream ("helper.js");
705 js = (new StreamReader (str_js)).ReadToEnd();
713 public override string InlineJavaScript {
714 get {return js_code + base.InlineJavaScript;}
717 public override string GetPublicUrl (string url)
719 if (url == null || url.Length == 0)
723 XmlDocument d = GetXmlFromUrl (url, out rest);
725 return EcmaDoc.GetCref (d.DocumentElement);
726 XmlElement e = GetDocElement (d, rest);
728 return EcmaDoc.GetCref (d.DocumentElement) + "/" + rest;
729 return EcmaDoc.GetCref (e);
731 catch (Exception e) {
736 private static XmlElement GetDocElement (XmlDocument d, string rest)
738 string memberType = null;
739 string memberIndex = null;
741 string [] nodes = rest.Split (new char [] {'/'});
743 switch (nodes.Length) {
744 // e.g. C; not supported.
747 // e.g. C/0 or M/MethodName; the latter isn't supported.
750 // XPath wants 1-based indexes, while the url uses 0-based values.
751 memberIndex = (int.Parse (nodes [1]) + 1).ToString ();
752 memberType = GetMemberType (nodes [0]);
757 // e.g. M/MethodName/0
759 memberIndex = (int.Parse (nodes [2]) + 1).ToString ();
760 memberType = GetMemberType (nodes [0]);
766 string xpath = "/Type/Members/Member[MemberType=\"" + memberType + "\"]" +
767 "[position()=" + memberIndex + "]";
768 return (XmlElement) d.SelectSingleNode (xpath);
771 private static string GetMemberType (string type)
774 case "C": return "Constructor";
775 case "E": return "Event";
776 case "F": return "Field";
777 case "M": return "Method";
778 case "P": return "Property";
780 throw new NotSupportedException ("Member Type: '" + type + "'.");
784 public override string GetText (string url, out Node match_node)
788 string cached = GetCachedText (url);
794 XmlReader summary = GetHelpXml ("mastersummary.xml");
798 XsltArgumentList args = new XsltArgumentList();
799 args.AddExtensionObject("monodoc:///extensions", ExtObject);
800 args.AddParam("show", "", "masteroverview");
801 string s = Htmlize(summary, args);
802 return BuildHtml (css_ecma_code, js_code, s);
805 if (url.StartsWith ("ecma:")) {
806 string s = GetTextFromUrl (url);
807 return BuildHtml (css_ecma_code, js_code, s);
814 string RenderMemberLookup (string typename, string member, ref Node type_node)
816 if (type_node.Nodes == null)
819 string membername = member;
820 string[] argtypes = null;
821 if (member.IndexOf("(") > 0) {
822 membername = membername.Substring(0, member.IndexOf("("));
823 member = member.Replace("@", "&");
825 // reform the member signature with CTS names
827 string x = member.Substring(member.IndexOf("(")+1);
828 argtypes = x.Substring(0, x.Length-1).Split(',', ':'); // operator signatures have colons
830 if (membername == ".ctor")
831 membername = typename;
833 member = membername + "(";
834 for (int i = 0; i < argtypes.Length; i++) {
835 argtypes[i] = EcmaDoc.ConvertCTSName(argtypes[i]);
836 if (i > 0) member += ",";
837 member += argtypes[i];
842 // Check if a node caption matches exactly
844 bool isoperator = false;
846 if ((membername == "op_Implicit" || membername == "op_Explicit") && argtypes.Length == 2) {
848 membername = "Conversion";
849 member = argtypes[0] + " to " + argtypes[1];
850 } else if (membername.StartsWith("op_")) {
852 membername = membername.Substring(3);
855 foreach (Node x in type_node.Nodes){
858 if (isoperator && x.Caption != "Operators")
861 foreach (Node m in x.Nodes) {
862 string caption = m.Caption;
863 string ecaption = ToEscapedMemberName (caption);
865 // No overloading (usually), is just the member name. The whole thing for constructors.
866 if (caption == membername || caption == member ||
867 ecaption == membername || ecaption == member) {
869 return GetTextFromUrl (m.URL);
871 } else if (caption == member || ecaption == member) {
872 // Though there are overloads, no arguments are in the url, so use this base node
874 return GetTextFromUrl (m.URL);
876 // Check subnodes which are the overloads -- must match signature
877 foreach (Node mm in m.Nodes) {
878 ecaption = ToEscapedTypeName (mm.Caption);
879 if (mm.Caption == member || ecaption == member) {
881 return GetTextFromUrl (mm.URL);
891 public static string MakeSignature (XmlNode n, string cstyleclass)
895 if (cstyleclass == null)
896 sig = n.Attributes["MemberName"].InnerText;
902 /*if (n.SelectSingleNode("MemberType").InnerText == "Method" || n.SelectSingleNode("MemberType").InnerText == "Constructor") {*/ // properties with indexers too
903 XmlNodeList paramnodes = n.SelectNodes("Parameters/Parameter");
906 foreach (XmlNode p in paramnodes) {
907 if (!first) sig += ",";
908 string type = p.Attributes["Type"].InnerText;
909 type = EcmaDoc.ConvertCTSName(type);
919 public static void MakeOperatorSignature (XmlNode n, out string nicename, out string sig)
923 name = n.Attributes["MemberName"].InnerText;
924 nicename = name.Substring(3);
927 // unary operators: no overloading possible [ECMA-335 §10.3.1]
928 case "op_UnaryPlus": // static R operator+ (T)
929 case "op_UnaryNegation": // static R operator- (T)
930 case "op_LogicalNot": // static R operator! (T)
931 case "op_OnesComplement": // static R operator~ (T)
932 case "op_Increment": // static R operator++ (T)
933 case "op_Decrement": // static R operator-- (T)
934 case "op_True": // static bool operator true (T)
935 case "op_False": // static bool operator false (T)
936 case "op_AddressOf": // static R operator& (T)
937 case "op_PointerDereference": // static R operator* (T)
941 // binary operators: overloading is possible [ECMA-335 §10.3.2]
942 case "op_Addition": // static R operator+ (T1, T2)
943 case "op_Subtraction": // static R operator- (T1, T2)
944 case "op_Multiply": // static R operator* (T1, T2)
945 case "op_Division": // static R operator/ (T1, T2)
946 case "op_Modulus": // static R operator% (T1, T2)
947 case "op_ExclusiveOr": // static R operator^ (T1, T2)
948 case "op_BitwiseAnd": // static R operator& (T1, T2)
949 case "op_BitwiseOr": // static R operator| (T1, T2)
950 case "op_LogicalAnd": // static R operator&& (T1, T2)
951 case "op_LogicalOr": // static R operator|| (T1, T2)
952 case "op_Assign": // static R operator= (T1, T2)
953 case "op_LeftShift": // static R operator<< (T1, T2)
954 case "op_RightShift": // static R operator>> (T1, T2)
955 case "op_SignedRightShift": // static R operator>> (T1, T2)
956 case "op_UnsignedRightShift": // static R operator>>> (T1, T2)
957 case "op_Equality": // static bool operator== (T1, T2)
958 case "op_GreaterThan": // static bool operator> (T1, T2)
959 case "op_LessThan": // static bool operator< (T1, T2)
960 case "op_Inequality": // static bool operator!= (T1, T2)
961 case "op_GreaterThanOrEqual": // static bool operator>= (T1, T2)
962 case "op_LessThanOrEqual": // static bool operator<= (T1, T2)
963 case "op_UnsignedRightShiftAssignment": // static R operator>>>= (T1, T2)
964 case "op_MemberSelection": // static R operator-> (T1, T2)
965 case "op_RightShiftAssignment": // static R operator>>= (T1, T2)
966 case "op_MultiplicationAssignment": // static R operator*= (T1, T2)
967 case "op_PointerToMemberSelection": // static R operator->* (T1, T2)
968 case "op_SubtractionAssignment": // static R operator-= (T1, T2)
969 case "op_ExclusiveOrAssignment": // static R operator^= (T1, T2)
970 case "op_LeftShiftAssignment": // static R operator<<= (T1, T2)
971 case "op_ModulusAssignment": // static R operator%= (T1, T2)
972 case "op_AdditionAssignment": // static R operator+= (T1, T2)
973 case "op_BitwiseAndAssignment": // static R operator&= (T1, T2)
974 case "op_BitwiseOrAssignment": // static R operator|= (T1, T2)
975 case "op_Comma": // static R operator, (T1, T2)
976 case "op_DivisionAssignment": // static R operator/= (T1, T2)
977 default: // If all else fails, assume it can be overridden...whatever it is.
978 XmlNodeList paramnodes = n.SelectNodes("Parameters/Parameter");
979 sig = nicename + "(";
981 foreach (XmlNode p in paramnodes) {
982 if (!first) sig += ",";
983 string type = p.Attributes["Type"].InnerText;
984 type = EcmaDoc.ConvertCTSName(type);
991 // conversion operators: overloading based on parameter and return type [ECMA-335 §10.3.3]
992 case "op_Implicit": // static implicit operator R (T)
993 case "op_Explicit": // static explicit operator R (T)
994 nicename = "Conversion";
995 string arg = n.SelectSingleNode("Parameters/Parameter/@Type").InnerText;
996 string ret = n.SelectSingleNode("ReturnValue/ReturnType").InnerText;
997 sig = EcmaDoc.ConvertCTSName(arg) + " to " + EcmaDoc.ConvertCTSName(ret);
1003 // This routine has to perform a lookup on a type.
1005 // Example: T:System.Text.StringBuilder
1007 // The prefix is the kind of opereation being requested (T:, E:, M: etc)
1008 // ns is the namespace being looked up
1009 // type is the type being requested
1011 // This has to walk our toplevel (which is always a namespace)
1012 // And then the type space, and then walk further down depending on the request
1014 public override string RenderTypeLookup (string prefix, string ns, string type, string member, out Node match_node)
1016 string url = GetUrlForType (prefix, ns, type, member, out match_node);
1017 if (url == null) return null;
1018 return GetTextFromUrl (url);
1021 public virtual string GetIdFromUrl (string prefix, string ns, string type)
1023 Node tmp_node = new Node (Tree, "", "");
1024 string url = GetUrlForType (prefix, ns, type, null, out tmp_node);
1025 if (url == null) return null;
1026 return GetFile (url.Substring (5), out url);
1029 public string GetUrlForType (string prefix, string ns, string type, string member, out Node match_node)
1031 if (!prefix.EndsWith(":"))
1032 throw new ArgumentException("prefix");
1035 member = member.Replace ("#", ".").Replace ("{", "<").Replace ("}", ">");
1037 // If a nested type, compare only inner type name to node list.
1038 // This should be removed when the node list doesn't lose the containing type name.
1039 type = ToEscapedTypeName (type.Replace("+", "."));
1040 MatchAttempt[] attempts = GetAttempts (ns, type);
1042 foreach (Node ns_node in Tree.Nodes){
1043 string ns_node_namespace = ns_node.Element.Substring (2);
1045 if (!MatchesNamespace (attempts, ns_node_namespace, out type))
1048 foreach (Node type_node in ns_node.Nodes){
1049 string element = type_node.Element;
1052 if (element.StartsWith("T:")) {
1053 cname = element.Substring(2);
1055 RootTree.GetNamespaceAndType (cname, out _ns, out cname);
1056 cname = ToEscapedTypeName (cname);
1057 int pidx = cname.LastIndexOf (".");
1058 cname = cname.Substring(pidx+1);
1059 pidx = cname.LastIndexOf ("/");
1061 cname = cname.Substring(0, pidx);
1062 cname = cname.Replace("+", ".");
1064 int pidx = element.IndexOf ("#");
1065 int sidx = element.IndexOf ("/");
1066 cname = element.Substring (pidx + 1, sidx-pidx-1);
1067 cname = ToEscapedTypeName (cname);
1070 //Console.WriteLine ("t:{0} cn:{1} p:{2}", type, cname, prefix);
1072 if (type == cname && prefix == "T:") {
1073 match_node = type_node;
1074 return type_node.URL;
1075 } else if (type.StartsWith (cname)){
1076 int p = cname.Length;
1078 match_node = type_node;
1080 string ret = RenderMemberLookup (type, member, ref match_node);
1082 return type_node.URL;
1083 return match_node.URL;
1085 } else if (type [p] == '/'){
1087 // This handles summaries
1090 foreach (Node nd in type_node.Nodes) {
1091 if (nd.Element [nd.Element.Length - 1] == type [p + 1]) {
1097 string ret = type_node.URL;
1098 if (!ret.EndsWith("/")) ret += "/";
1099 return ret + type.Substring (p + 1);
1109 struct MatchAttempt {
1110 public string Namespace;
1113 public MatchAttempt (string ns, string t)
1120 private static MatchAttempt[] GetAttempts (string ns, string type)
1122 MatchAttempt[] attempts = new MatchAttempt [Count (ns, '.') + 1];
1124 for (int i = 0; i < ns.Length; ++i) {
1126 attempts [wns++] = new MatchAttempt (ns.Substring (0, i),
1127 ns.Substring (i+1) + "." + type);
1129 attempts [wns++] = new MatchAttempt (ns, type);
1133 private static int Count (string s, char c)
1136 for (int i = 0; i < s.Length; ++i)
1142 private static bool MatchesNamespace (MatchAttempt[] attempts, string ns, out string type)
1144 for (int i = 0; i < attempts.Length; ++i)
1145 if (ns == attempts [i].Namespace) {
1146 type = attempts [i].Type;
1153 public static string ToEscapedTypeName (string typename)
1155 return ToEscapedName (typename, "`");
1158 static string ToEscapedName (string name, string escape)
1160 StringBuilder filename = new StringBuilder (name.Length);
1165 for (int i = 0; i < name.Length; ++i) {
1177 filename.Append (escape).Append ((numArgs+1).ToString());
1188 filename.Append (c);
1192 return filename.ToString ();
1195 static string ToEscapedMemberName (string membername)
1197 return ToEscapedName (membername, "`");
1200 public override string GetNodeXPath (XPathNavigator n)
1202 if (n.Matches ("/Type/Docs/param")) {
1203 string type_name = (string) n.Evaluate ("string (ancestor::Type/@FullName)");
1204 string param_name = (string) n.Evaluate ("string (@name)");
1206 return String.Format ("/Type [@FullName = '{0}']/Docs/param[@name='{1}']", type_name, param_name);
1209 if (n.Matches ("/Type/Docs/*")) {
1210 string type_name = (string) n.Evaluate ("string (ancestor::Type/@FullName)");
1212 return String.Format ("/Type [@FullName = '{0}']/Docs/{1}", type_name, n.Name);
1215 if (n.Matches ("/Type/Members/Member/Docs/*")) {
1216 string type_name = (string) n.Evaluate ("string (ancestor::Type/@FullName)");
1217 string member_name = (string) n.Evaluate ("string (ancestor::Member/@MemberName)");
1218 string member_sig = (string) n.Evaluate ("string (ancestor::Member/MemberSignature [@Language='C#']/@Value)");
1219 string param_name = (string) n.Evaluate ("string (@name)");
1221 if (param_name == null || param_name == "") {
1222 return String.Format (
1223 "/Type [@FullName = '{0}']/Members/Member [@MemberName = '{1}'][MemberSignature [@Language='C#']/@Value = '{2}']/Docs/{3}",
1224 type_name, member_name, member_sig, n.Name);
1226 return String.Format (
1227 "/Type [@FullName = '{0}']/Members/Member [@MemberName = '{1}'][MemberSignature [@Language='C#']/@Value = '{2}']/Docs/param [@name = '{3}']",
1228 type_name, member_name, member_sig, param_name);
1232 Message (TraceLevel.Warning, "WARNING: Was not able to get clean XPath expression for node {0}", EditingUtils.GetXPath (n));
1233 return base.GetNodeXPath (n);
1236 protected virtual XmlDocument GetNamespaceDocument (string ns)
1238 return GetHelpXmlWithChanges ("xml.summary." + ns);
1241 public override string RenderNamespaceLookup (string nsurl, out Node match_node)
1243 foreach (Node ns_node in Tree.Nodes){
1244 if (ns_node.Element != nsurl)
1247 match_node = ns_node;
1248 string ns_name = nsurl.Substring (2);
1250 XmlDocument doc = GetNamespaceDocument (ns_name);
1254 XsltArgumentList args = new XsltArgumentList();
1255 args.AddExtensionObject("monodoc:///extensions", ExtObject);
1256 args.AddParam("show", "", "namespace");
1257 args.AddParam("namespace", "", ns_name);
1258 args.AddParam ("source-id", "", SourceID.ToString ());
1259 string s = Htmlize(new XmlNodeReader (doc), args);
1260 return BuildHtml (css_ecma_code, js_code, s);
1267 private string SelectString(XmlNode node, string xpath) {
1268 XmlNode ret = node.SelectSingleNode(xpath);
1269 if (ret == null) return "";
1270 return ret.InnerText;
1272 private int SelectCount(XmlNode node, string xpath) {
1273 return node.SelectNodes(xpath).Count;
1277 // Returns the XmlDocument from the given url, and fills in `rest'
1279 protected virtual XmlDocument GetXmlFromUrl(string url, out string rest) {
1281 url = url.Substring (5);
1282 string file = GetFile (url, out rest);
1284 // Console.WriteLine ("Got [{0}] and [{1}]", file, rest);
1285 return GetHelpXmlWithChanges (file);
1288 string GetTextFromUrl (string url)
1291 string path = XmlDocUtils.GetCachedFileName (base_dir, url);
1292 if (File.Exists (path))
1293 return File.OpenText (path).ReadToEnd ();
1300 XmlDocument doc = GetXmlFromUrl (url, out rest);
1302 // Load base-type information so the stylesheet can draw the inheritance
1303 // tree and (optionally) include inherited members in the members list.
1304 XmlElement basenode = (XmlElement)doc.SelectSingleNode("Type/Base");
1305 XmlElement membersnode = (XmlElement)doc.SelectSingleNode("Type/Members");
1306 XmlNode basetype = doc.SelectSingleNode("Type/Base/BaseTypeName");
1308 while (basetype != null) {
1309 // Add the ParentType node to Type/Base
1310 XmlElement inheritancenode = doc.CreateElement("ParentType");
1311 inheritancenode.SetAttribute("Type", basetype.InnerText);
1312 inheritancenode.SetAttribute("Order", (baseindex++).ToString());
1313 basenode.AppendChild(inheritancenode);
1315 // Load the base type XML data
1316 int dot = basetype.InnerText.LastIndexOf('.');
1317 string ns = basetype.InnerText.Substring(0, dot == -1 ? 0 : dot);
1318 string n = basetype.InnerText.Substring(dot == -1 ? 0 : dot+1);
1319 string basetypeurl = GetUrlForType("T:", ns, n, null, out node);
1320 XmlDocument basetypedoc = null;
1321 if (basetypeurl != null)
1322 basetypedoc = GetXmlFromUrl (basetypeurl, out rest2);
1323 if (basetypedoc == null) {
1324 inheritancenode.SetAttribute("Incomplete", "1");
1328 if (SettingsHandler.Settings.ShowInheritedMembers) {
1329 // Add inherited members
1330 foreach (XmlElement member in basetypedoc.SelectNodes("Type/Members/Member[not(MemberType='Constructor')]")) {
1331 string sig = SelectString(member, "MemberSignature[@Language='C#']/@Value");
1332 if (sig.IndexOf(" static ") >= 0) continue;
1334 // If the signature of member matches the signature of a member already in the XML,
1336 string xpath = "@MemberName='" + SelectString(member, "@MemberName") + "'";
1337 xpath += " and ReturnValue/ReturnType='" + SelectString(member, "ReturnValue/ReturnType") + "'";
1338 xpath += " and count(Parameters/Parameter)=" + SelectCount(member, "Parameters/Parameter") + "";
1340 foreach (XmlElement p in member.SelectNodes("Parameters/Parameter")) {
1341 xpath += " and Parameters/Parameter[position()=" + pi + "]/@Type = '" + p.GetAttribute("Type") + "'";
1345 // If a signature match is found, don't add.
1346 XmlNode match = membersnode.SelectSingleNode("Member[" + xpath + "]");
1350 member.SetAttribute("DeclaredIn", basetype.InnerText);
1351 membersnode.AppendChild(membersnode.OwnerDocument.ImportNode(member, true));
1355 basetype = basetypedoc.SelectSingleNode("Type/Base/BaseTypeName");
1357 ArrayList extensions = new ArrayList ();
1358 AddExtensionMethodsFromHelpSource (extensions, this);
1359 foreach (HelpSource hs in RootTree.HelpSources) {
1360 EcmaHelpSource es = hs as EcmaHelpSource;
1365 AddExtensionMethodsFromHelpSource (extensions, es);
1367 XmlDocUtils.AddExtensionMethods (doc, extensions, delegate (string s) {
1368 s = s.StartsWith ("T:") ? s : "T:" + s;
1369 return RootTree.GetHelpXml (s);
1372 XsltArgumentList args = new XsltArgumentList();
1374 args.AddExtensionObject("monodoc:///extensions", ExtObject);
1376 args.AddParam ("source-id", "", SourceID.ToString ());
1379 args.AddParam("show", "", "typeoverview");
1380 string s = Htmlize(new XmlNodeReader (doc), args);
1381 return BuildHtml (css_ecma_code, js_code, s);
1384 string [] nodes = rest.Split (new char [] {'/'});
1386 switch (nodes.Length) {
1388 args.AddParam("show", "", "members");
1389 args.AddParam("index", "", "all");
1392 // Could either be a single member, or an overload thingy
1394 int.Parse (nodes [1]); // is it an int
1396 args.AddParam("show", "", "member");
1397 args.AddParam("index", "", nodes [1]);
1399 args.AddParam("show", "", "overloads");
1400 args.AddParam("index", "", nodes [1]);
1404 args.AddParam("show", "", "member");
1405 args.AddParam("index", "", nodes [2]);
1408 return "What the hell is this URL " + url;
1413 args.AddParam("membertype", "", "Constructor");
1416 args.AddParam("membertype", "", "Method");
1419 args.AddParam("membertype", "", "Property");
1422 args.AddParam("membertype", "", "Field");
1425 args.AddParam("membertype", "", "Event");
1428 args.AddParam("membertype", "", "Operator");
1431 args.AddParam("membertype", "", "ExtensionMethod");
1434 args.AddParam("membertype", "", "All");
1437 return "Unknown url: " + url;
1440 string html = Htmlize(new XmlNodeReader (doc), args);
1441 return BuildHtml (css_ecma_code, js_code, html);
1444 void AddExtensionMethodsFromHelpSource (ArrayList extensions, EcmaHelpSource es)
1446 Stream s = es.GetHelpStream ("ExtensionMethods.xml");
1448 XmlDocument d = new XmlDocument ();
1450 foreach (XmlNode n in d.SelectNodes ("/ExtensionMethods/*")) {
1457 public override void RenderPreviewDocs (XmlNode newNode, XmlWriter writer)
1459 XsltArgumentList args = new XsltArgumentList ();
1460 args.AddExtensionObject ("monodoc:///extensions", ExtObject);
1461 args.AddParam ("source-id", "", SourceID.ToString ());
1463 Htmlize (new XmlNodeReader (newNode), args, writer);
1466 static XslCompiledTransform ecma_transform;
1468 public string Htmlize (XmlReader ecma_xml)
1470 return Htmlize(ecma_xml, null);
1473 public string Htmlize (XmlReader ecma_xml, XsltArgumentList args)
1477 var output = new StringBuilder ();
1478 ecma_transform.Transform (ecma_xml,
1480 XmlWriter.Create (output, ecma_transform.OutputSettings),
1481 CreateDocumentResolver ());
1482 return output.ToString ();
1485 protected virtual XmlResolver CreateDocumentResolver ()
1487 // results in using XmlUrlResolver
1491 static void Htmlize (XmlReader ecma_xml, XsltArgumentList args, XmlWriter w)
1495 if (ecma_xml == null)
1498 ecma_transform.Transform (ecma_xml, args, w, null);
1501 static XslCompiledTransform ecma_transform_css, ecma_transform_no_css;
1502 static void EnsureTransform ()
1504 if (ecma_transform == null) {
1505 ecma_transform_css = new XslCompiledTransform ();
1506 ecma_transform_no_css = new XslCompiledTransform ();
1507 Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
1509 Stream stream = assembly.GetManifestResourceStream ("mono-ecma-css.xsl");
1510 XmlReader xml_reader = new XmlTextReader (stream);
1511 XmlResolver r = new ManifestResourceResolver (".");
1512 ecma_transform_css.Load (xml_reader, XsltSettings.TrustedXslt, r);
1514 stream = assembly.GetManifestResourceStream ("mono-ecma.xsl");
1515 xml_reader = new XmlTextReader (stream);
1516 ecma_transform_no_css.Load (xml_reader, XsltSettings.TrustedXslt, r);
1519 ecma_transform = ecma_transform_css;
1521 ecma_transform = ecma_transform_no_css;
1524 // This ExtensionObject stuff is used to check at run time whether
1525 // types and members have been implemented and whether there are any
1526 // MonoTODO attributes left on them.
1528 public readonly ExtensionObject ExtObject;
1529 public class ExtensionObject {
1530 readonly EcmaHelpSource hs;
1533 // We are setting this to quiet now, as we need to transition
1534 // monodoc to run with the 2.x runtime and provide accurate
1535 // information in those cases.
1539 public ExtensionObject (EcmaHelpSource hs)
1544 public string Colorize(string code, string lang) {
1545 return(Mono.Utilities.Colorizer.Colorize(code,lang));
1547 // Used by stylesheet to nicely reformat the <see cref=> tags.
1548 public string MakeNiceSignature(string sig, string contexttype)
1556 sig = sig.Substring(2);
1559 case 'N': return sig;
1560 case 'T': return ShortTypeName(sig, contexttype);
1562 case 'C': case 'M': case 'P': case 'F': case 'E':
1563 string type, mem, arg;
1567 if (s == 'C' || s == 'M')
1568 paren = sig.IndexOf("(");
1570 paren = sig.IndexOf("[");
1574 if (paren > 0 && paren < sig.Length-1) {
1575 string[] args = sig.Substring(paren+1, sig.Length-paren-2).Split(',');
1576 for (int i = 0; i < args.Length; i++)
1577 args[i] = ShortTypeName(args[i], contexttype);
1578 arg = "(" + String.Join(", ", args) + ")";
1579 sig = sig.Substring(0, paren);
1584 // Get type and member names
1585 int dot = sig.LastIndexOf(".");
1586 if (s == 'C' || dot <= 0 || dot == sig.Length-1) {
1590 type = sig.Substring(0, dot);
1591 mem = sig.Substring(dot);
1594 type = ShortTypeName(type, contexttype);
1596 return type + mem + arg;
1603 public string EditUrl (XPathNodeIterator itr)
1605 if (itr.MoveNext ())
1606 return hs.GetEditUri (itr.Current);
1611 public string EditUrlNamespace (XPathNodeIterator itr, string ns, string section)
1613 if (hs is EcmaUncompiledHelpSource)
1614 return "edit:file:" + Path.Combine(((EcmaUncompiledHelpSource)hs).BasePath, ns + ".xml") + "@/Namespace/Docs/" + section;
1615 else if (itr.MoveNext ())
1616 return EditingUtils.FormatEditUri(itr.Current.BaseURI, "/elements/" + section);
1620 private static string ShortTypeName(string name, string contexttype)
1622 int dot = contexttype.LastIndexOf(".");
1623 if (dot < 0) return name;
1624 string contextns = contexttype.Substring(0, dot+1);
1626 if (name == contexttype)
1627 return name.Substring(dot+1);
1629 if (name.StartsWith(contextns))
1630 return name.Substring(contextns.Length);
1632 return name.Replace("+", ".");
1635 string MonoImpInfo(string assemblyname, string typename, string membername, string arglist, bool strlong)
1640 ArrayList a = new ArrayList();
1641 if (arglist != "") a.Add(arglist);
1642 return MonoImpInfo(assemblyname, typename, membername, a, strlong);
1645 string MonoImpInfo(string assemblyname, string typename, string membername, XPathNodeIterator itr, bool strlong)
1650 ArrayList rgs = new ArrayList ();
1651 while (itr.MoveNext ())
1652 rgs.Add (itr.Current.Value);
1654 return MonoImpInfo (assemblyname, typename, membername, rgs, strlong);
1657 string MonoImpInfo(string assemblyname, string typename, string membername, ArrayList arglist, bool strlong)
1660 Assembly assembly = null;
1663 assembly = Assembly.LoadWithPartialName(assemblyname);
1664 } catch (Exception) {
1668 if (assembly == null) {
1669 /*if (strlong) return "The assembly " + assemblyname + " is not available to MonoDoc.";
1671 return ""; // silently ignore
1674 Type t = assembly.GetType(typename, false);
1677 return typename + " has not been implemented.";
1679 return "Not implemented.";
1682 // The following code is flakey and fails to find existing members
1685 MemberInfo[] mis = t.GetMember(membername, BF.Static | BF.Instance | BF.Public | BF.NonPublic);
1687 if (mis.Length == 0)
1688 return "This member has not been implemented.";
1689 if (mis.Length == 1)
1690 return MonoImpInfo(mis[0], "member", strlong);
1692 // Scan for the appropriate member
1693 foreach (MemberInfo mi in mis) {
1694 System.Reflection.ParameterInfo[] pis;
1696 if (mi is MethodInfo || mi is ConstructorInfo)
1697 pis = ((MethodBase)mi).GetParameters();
1698 else if (mi is PropertyInfo)
1699 pis = ((PropertyInfo)mi).GetIndexParameters();
1705 if (pis.Length != arglist.Count) continue;
1706 for (int i = 0; i < pis.Length; i++) {
1707 if (pis[i].ParameterType.FullName != (string)arglist[i]) { good = false; break; }
1709 if (!good) continue;
1712 return MonoImpInfo(mi, "member", strlong);
1715 } catch (Exception) {
1720 string MonoImpInfo(System.Reflection.MemberInfo mi, string itemtype, bool strlong)
1727 object[] atts = mi.GetCustomAttributes(true);
1729 foreach (object att in atts) if (att.GetType().Name == "MonoTODOAttribute") todoctr++;
1733 s = "This " + itemtype + " is marked as being unfinished.<BR/>\n";
1741 public string MonoImpInfo(string assemblyname, string typename, bool strlong)
1747 if (assemblyname == "")
1750 Assembly assembly = Assembly.LoadWithPartialName(assemblyname);
1751 if (assembly == null)
1754 Type t = assembly.GetType(typename, false);
1757 return typename + " has not been implemented.";
1759 return "Not implemented.";
1762 string s = MonoImpInfo(t, "type", strlong);
1765 MemberInfo[] mis = t.GetMembers(BF.Static | BF.Instance | BF.Public | BF.NonPublic);
1767 // Scan members for MonoTODO attributes
1769 foreach (MemberInfo mi in mis) {
1770 string mii = MonoImpInfo(mi, null, false);
1771 if (mii != "") mctr++;
1774 s += "This type has " + mctr + " members that are marked as unfinished.<BR/>";
1780 } catch (Exception) {
1785 public bool MonoEditing ()
1787 return SettingsHandler.Settings.EnableEditing;
1790 public bool IsToBeAdded(string text) {
1791 return text.StartsWith("To be added");
1796 // This takes one of the ecma urls, which look like this:
1797 // ecma:NUMERIC_ID#OPAQUE/REST
1799 // NUMERIC_ID is the numeric ID assigned by the compressor
1800 // OPAQUE is opaque for node rendering (it typically contains T:System.Byte for example)
1801 // REST is the rest of the argument used to decode information
1803 static string GetFile (string url, out string rest)
1805 int pound = url.IndexOf ("#");
1806 int slash = url.IndexOf ("/");
1808 string fname = url.Substring (0, pound);
1809 rest = url.Substring (slash+1);
1815 // This should have a little cache or something.
1816 static XmlDocument GetDocument (HelpSource hs, string fname)
1818 Stream s = hs.GetHelpStream (fname);
1820 Error ("Could not fetch document {0}", fname);
1824 XmlDocument doc = new XmlDocument ();
1832 string GetKindFromCaption (string s)
1834 int p = s.LastIndexOf (' ');
1836 return s.Substring (p + 1);
1841 // Obtain an URL of the type T:System.Object from the node
1843 public static string GetNiceUrl (Node node) {
1844 if (node.Element.StartsWith("N:"))
1845 return node.Element;
1847 int bk_pos = node.Caption.IndexOf (' ');
1848 // node from an overview
1850 name = node.Caption.Substring (0, bk_pos);
1851 full = node.Parent.Caption + "." + name.Replace ('.', '+');
1854 // node that lists constructors, methods, fields, ...
1855 if ((node.Caption == "Constructors") || (node.Caption == "Fields") || (node.Caption == "Events")
1856 || (node.Caption == "Members") || (node.Caption == "Properties") || (node.Caption == "Methods")
1857 || (node.Caption == "Operators")) {
1858 bk_pos = node.Parent.Caption.IndexOf (' ');
1859 name = node.Parent.Caption.Substring (0, bk_pos);
1860 full = node.Parent.Parent.Caption + "." + name.Replace ('.', '+');
1861 return "T:" + full + "/" + node.Element;
1863 int pr_pos = node.Caption.IndexOf ('(');
1864 // node from a constructor
1865 if (node.Parent.Element == "C") {
1866 name = node.Parent.Parent.Parent.Caption;
1867 int idx = node.URL.IndexOf ('/');
1868 return node.URL[idx+1] + ":" + name + "." + node.Caption.Replace ('.', '+');
1869 // node from a method with one signature, field, property, operator
1870 } else if (pr_pos == -1) {
1871 bk_pos = node.Parent.Parent.Caption.IndexOf (' ');
1872 name = node.Parent.Parent.Caption.Substring (0, bk_pos);
1873 full = node.Parent.Parent.Parent.Caption + "." + name.Replace ('.', '+');
1874 int idx = node.URL.IndexOf ('/');
1875 return node.URL[idx+1] + ":" + full + "." + node.Caption;
1876 // node from a method with several signatures
1878 bk_pos = node.Parent.Parent.Parent.Caption.IndexOf (' ');
1879 name = node.Parent.Parent.Parent.Caption.Substring (0, bk_pos);
1880 full = node.Parent.Parent.Parent.Parent.Caption + "." + name.Replace ('.', '+');
1881 int idx = node.URL.IndexOf ('/');
1882 return node.URL[idx+1] + ":" + full + "." + node.Caption;
1886 public override Stream GetImage (string url)
1888 if (url.Contains ("/"))
1889 url = url.Substring (url.LastIndexOf ('/') + 1);
1890 return GetHelpStream (url);
1894 // Populates the searchable index.
1896 // The idea of this index is to capture the most common search terms, the UI for this
1897 // usually updates automatically as the user types.
1899 public override void PopulateIndex (IndexMaker index_maker)
1901 foreach (Node ns_node in Tree.Nodes){
1902 foreach (Node type_node in ns_node.Nodes){
1903 string typename = type_node.Caption.Substring (0, type_node.Caption.IndexOf (' '));
1904 string full = ns_node.Caption + "." + typename;
1906 string doc_tag = GetKindFromCaption (type_node.Caption);
1907 string url = "T:" + full;
1911 // Add MonoMac/MonoTouch [Export] attributes, those live only in classes
1913 if (doc_tag == "Class" && (ns_node.Caption.StartsWith ("MonoTouch") || ns_node.Caption.StartsWith ("MonoMac"))){
1916 var xdoc = GetXmlFromUrl (type_node.URL, out rest);
1918 var nodesWithExports = xdoc.SelectNodes ("/Type/Members/Member[contains (Attributes/Attribute/AttributeName, 'Foundation.Export') and (MemberType='Property' or MemberType='Method' or MemberType='Constructor')]");
1920 foreach (XmlNode n in nodesWithExports){
1921 string cref = EcmaDoc.GetCref ((XmlElement) n);
1923 var exports = n.SelectNodes ("Attributes/Attribute/AttributeName");
1924 foreach (XmlNode exportNode in exports){
1925 var inner = exportNode.InnerText;
1926 int p = inner.IndexOf ("Foundation.Export(\"");
1928 Console.WriteLine ("Not found the Export attribute in {0}", inner);
1931 var pa = inner.IndexOf ("\"", p);
1933 Console.WriteLine ("Export has no target in {0}", inner);
1936 var end = inner.IndexOf ("\"", pa+1);
1938 var export = end == -1 ? inner.Substring (pa+1) : inner.Substring (pa+1, end-(pa+1));
1940 index_maker.Add (export + " selector", export, cref);
1944 } catch (Exception e){
1945 Console.WriteLine ("Problem processing {0} for MonoTouch/MonoMac exports\n\n{0}", e);
1949 if (doc_tag == "Class" || doc_tag == "Structure" || doc_tag == "Interface"){
1951 index_maker.Add (type_node.Caption, typename, url);
1952 index_maker.Add (full + " " + doc_tag, full, url);
1954 foreach (Node c in type_node.Nodes){
1956 case "Constructors":
1957 index_maker.Add (" constructors", typename+"0", url + "/C");
1960 index_maker.Add (" fields", typename+"1", url + "/F");
1963 index_maker.Add (" events", typename+"2", url + "/E");
1966 index_maker.Add (" properties", typename+"3", url + "/P");
1969 index_maker.Add (" methods", typename+"4", url + "/M");
1972 index_maker.Add (" operators", typename+"5", url + "/O");
1978 // Now repeat, but use a different sort key, to make sure we come after
1979 // the summary data above, start the counter at 6
1981 string keybase = typename + "6.";
1983 foreach (Node c in type_node.Nodes){
1985 case "Constructors":
1988 foreach (Node nc in c.Nodes){
1989 string res = nc.Caption;
1991 string nurl = String.Format ("F:{0}.{1}", full, res);
1992 index_maker.Add (String.Format ("{0}.{1} field", typename, res),
1993 keybase + res, nurl);
1994 index_maker.Add (String.Format ("{0} field", res), res, nurl);
1999 foreach (Node nc in c.Nodes){
2000 string res = nc.Caption;
2001 string nurl = String.Format ("E:{0}.{1}", full, res);
2003 index_maker.Add (String.Format ("{0}.{1} event", typename, res),
2004 keybase + res, nurl);
2005 index_maker.Add (String.Format ("{0} event", res), res, nurl);
2009 foreach (Node nc in c.Nodes){
2010 string res = nc.Caption;
2011 string nurl = String.Format ("P:{0}.{1}", full, res);
2012 index_maker.Add (String.Format ("{0}.{1} property", typename, res),
2013 keybase + res, nurl);
2014 index_maker.Add (String.Format ("{0} property", res), res, nurl);
2018 foreach (Node nc in c.Nodes){
2019 string res = nc.Caption;
2020 int p = res.IndexOf ("(");
2022 res = res.Substring (0, p);
2023 string nurl = String.Format ("M:{0}.{1}", full, res);
2024 index_maker.Add (String.Format ("{0}.{1} method", typename, res),
2025 keybase + res, nurl);
2026 index_maker.Add (String.Format ("{0} method", res), res, nurl);
2031 foreach (Node nc in c.Nodes){
2032 string res = nc.Caption;
2033 string nurl = String.Format ("O:{0}.{1}", full, res);
2034 index_maker.Add (String.Format ("{0}.{1} operator", typename, res),
2035 keybase + res, nurl);
2040 } else if (doc_tag == "Enumeration"){
2042 // Enumerations: add the enumeration values
2044 index_maker.Add (type_node.Caption, typename, url);
2045 index_maker.Add (full + " " + doc_tag, full, url);
2047 // Now, pull the values.
2049 XmlDocument x = GetXmlFromUrl (type_node.URL, out rest);
2053 XmlNodeList members = x.SelectNodes ("/Type/Members/Member");
2055 if (members == null)
2058 foreach (XmlNode member_node in members){
2059 string enum_value = member_node.Attributes ["MemberName"].InnerText;
2060 string caption = enum_value + " value";
2061 index_maker.Add (caption, caption, url);
2063 } else if (doc_tag == "Delegate"){
2064 index_maker.Add (type_node.Caption, typename, url);
2065 index_maker.Add (full + " " + doc_tag, full, url);
2071 IEnumerable<string> ExtractArguments (string rawArgList)
2073 var sb = new System.Text.StringBuilder ();
2074 int genericDepth = 0;
2077 for (int i = 0; i < rawArgList.Length; i++) {
2078 char c = rawArgList[i];
2082 if (genericDepth == 0 && arrayDepth == 0) {
2083 yield return sb.ToString ();
2104 yield return sb.ToString ();
2107 // Caption is what you see on a tree node, either SomeName or SomeName(ArgList)
2108 void TryCreateXPathPredicateFragment (string caption, out string name, out string argListPredicate)
2110 name = argListPredicate = null;
2111 int parenIdx = caption.IndexOf ('(');
2112 // In case of simple name, there is no need for processing
2113 if (parenIdx == -1) {
2117 name = caption.Substring (0, parenIdx);
2118 // Now we create a xpath predicate which will check for all the args in the argsList
2119 var rawArgList = caption.Substring (parenIdx + 1, caption.Length - parenIdx - 2); // Only take what's inside the parens
2120 if (string.IsNullOrEmpty (rawArgList))
2123 var argList = ExtractArguments (rawArgList).Select (arg => arg.Trim ()).Select (type => EcmaDoc.ConvertFromCTSName (type));
2124 argListPredicate = "and " + argList.Select (type => string.Format ("Parameters/Parameter[@Type='{0}']", type)).Aggregate ((e1, e2) => e1 + " and " + e2);
2128 // Create list of documents for searching
2130 public override void PopulateSearchableIndex (IndexWriter writer)
2133 foreach (Node ns_node in Tree.Nodes) {
2134 Message (TraceLevel.Info, "\tNamespace: {0} ({1})", ns_node.Caption, ns_node.Nodes.Count);
2135 foreach (Node type_node in ns_node.Nodes) {
2136 string typename = type_node.Caption.Substring (0, type_node.Caption.IndexOf (' '));
2137 string full = ns_node.Caption + "." + typename;
2138 string doc_tag = GetKindFromCaption (type_node.Caption);
2139 string url = "T:" + full;
2141 XmlDocument xdoc = GetXmlFromUrl (type_node.URL, out rest);
2146 // For classes, structures or interfaces add a doc for the overview and
2147 // add a doc for every constructor, method, event, ...
2149 if (doc_tag == "Class" || doc_tag == "Structure" || doc_tag == "Interface"){
2151 // Adds a doc for every overview of every type
2152 SearchableDocument doc = new SearchableDocument ();
2153 doc.title = type_node.Caption;
2154 doc.hottext = typename;
2156 doc.fulltitle = full;
2158 XmlNode node_sel = xdoc.SelectSingleNode ("/Type/Docs");
2159 text = new StringBuilder ();
2160 GetTextFromNode (node_sel, text);
2161 doc.text = text.ToString ();
2163 text = new StringBuilder ();
2164 GetExamples (node_sel, text);
2165 doc.examples = text.ToString ();
2167 writer.AddDocument (doc.LuceneDoc);
2168 var exportParsable = doc_tag == "Class" && (ns_node.Caption.StartsWith ("MonoTouch") || ns_node.Caption.StartsWith ("MonoMac"));
2170 //Add docs for contructors, methods, etc.
2171 foreach (Node c in type_node.Nodes) { // c = Constructors || Fields || Events || Properties || Methods || Operators
2173 if (c.Element == "*")
2175 const float innerTypeBoost = 0.2f;
2177 var ncnodes = c.Nodes.Cast<Node> ();
2178 // The rationale is that we need to properly handle method overloads
2179 // so for those method node which have children, flatten them
2180 if (c.Caption == "Methods") {
2182 .Where (n => n.Nodes == null || n.Nodes.Count == 0)
2183 .Concat (ncnodes.Where (n => n.Nodes.Count > 0).SelectMany (n => n.Nodes.Cast<Node> ()));
2184 } else if (c.Caption == "Operators") {
2186 .Where (n => n.Caption != "Conversion")
2187 .Concat (ncnodes.Where (n => n.Caption == "Conversion").SelectMany (n => n.Nodes.Cast<Node> ()));
2189 foreach (Node nc in ncnodes) {
2190 //xpath to the docs xml node
2192 string name, argListPredicate;
2194 switch (c.Caption) {
2195 case "Constructors":
2196 TryCreateXPathPredicateFragment (nc.Caption, out name, out argListPredicate);
2197 xpath = String.Format ("/Type/Members/Member[@MemberName='.ctor'{0}]/Docs", argListPredicate ?? string.Empty);
2200 // The first case are explicit and implicit conversion operators which are grouped specifically
2201 if (nc.Caption.IndexOf (" to ") != -1) {
2202 var convArgs = nc.Caption.Split (new[] { " to " }, StringSplitOptions.None);
2203 xpath = String.Format ("/Type/Members/Member[(@MemberName='op_Explicit' or @MemberName='op_Implicit')" +
2204 " and ReturnValue/ReturnType='{0}'" +
2205 " and Parameters/Parameter[@Type='{1}']]/Docs",
2206 EcmaDoc.ConvertFromCTSName (convArgs[1]), EcmaDoc.ConvertFromCTSName (convArgs[0]));
2208 xpath = String.Format ("/Type/Members/Member[@MemberName='op_{0}']/Docs", nc.Caption);
2212 TryCreateXPathPredicateFragment (nc.Caption, out name, out argListPredicate);
2213 xpath = String.Format ("/Type/Members/Member[@MemberName='{0}'{1}]/Docs", name, argListPredicate ?? string.Empty);
2216 xpath = String.Format ("/Type/Members/Member[@MemberName='{0}']/Docs", nc.Caption);
2219 //construct url of the form M:Array.Sort
2221 if (c.Caption == "Constructors")
2222 urlnc = String.Format ("{0}:{1}.{2}", c.Caption[0], ns_node.Caption, nc.Caption);
2224 urlnc = String.Format ("{0}:{1}.{2}.{3}", c.Caption[0], ns_node.Caption, typename, nc.Caption);
2227 SearchableDocument doc_nod = new SearchableDocument ();
2228 doc_nod.title = LargeName (nc);
2229 switch (c.Caption[0]) {
2231 doc_nod.title += " Method";
2234 doc_nod.title += " Property";
2237 doc_nod.title += " Event";
2240 doc_nod.title += " Operator";
2243 doc_nod.title += " Constructor";
2248 doc_nod.fulltitle = string.Format ("{0}.{1}::{2}", ns_node.Caption, typename, nc.Caption);
2249 // Disable constructors hottext indexing as it's often "polluting" search queries
2250 // because it has the same hottext than standard types
2251 if (c.Caption != "Constructors") {
2252 //dont add the parameters to the hottext
2253 int ppos = nc.Caption.IndexOf ('(');
2255 doc_nod.hottext = nc.Caption.Substring (0, ppos);
2257 doc_nod.hottext = nc.Caption;
2259 doc_nod.hottext = string.Empty;
2262 doc_nod.url = urlnc;
2264 XmlNode xmln = xdoc.SelectSingleNode (xpath);
2266 Error ("Problem: {0}, with xpath: {1}", urlnc, xpath);
2270 text = new StringBuilder ();
2271 GetTextFromNode (xmln, text);
2272 doc_nod.text = text.ToString ();
2275 GetExamples (xmln, text);
2276 doc_nod.examples = text.ToString ();
2278 Document lucene_doc = doc_nod.LuceneDoc;
2279 lucene_doc.SetBoost (innerTypeBoost);
2280 writer.AddDocument (lucene_doc);
2282 // MonoTouch/Monomac specific parsing of [Export] attributes
2283 if (exportParsable) {
2286 xdoc.SelectNodes (string.Format ("/Type/Members/Member[@MemberName='{0}']/Attributes/Attribute/AttributeName[contains(text(), 'Foundation.Export')]", nc.Caption));
2287 foreach (XmlNode exportNode in exports) {
2288 var inner = exportNode.InnerText;
2289 var parts = inner.Split ('"');
2290 if (parts.Length != 3) {
2291 Console.WriteLine ("Export attribute not found or not usable in {0}", inner);
2295 var export = parts[1];
2296 var export_node = new SearchableDocument ();
2297 export_node.title = export + " Export";
2298 export_node.fulltitle = string.Format ("{0}.{1}::{2}", ns_node.Caption, typename, export);
2299 export_node.url = urlnc;
2300 export_node.hottext = export + ":";
2301 export_node.text = string.Empty;
2302 export_node.examples = string.Empty;
2303 lucene_doc = export_node.LuceneDoc;
2304 lucene_doc.SetBoost (innerTypeBoost);
2305 writer.AddDocument (lucene_doc);
2307 } catch (Exception e){
2308 Console.WriteLine ("Problem processing {0} for MonoTouch/MonoMac exports\n\n{0}", e);
2314 // Enumerations: add the enumeration values
2316 } else if (doc_tag == "Enumeration"){
2318 XmlNodeList members = xdoc.SelectNodes ("/Type/Members/Member");
2319 if (members == null)
2322 text = new StringBuilder ();
2323 foreach (XmlNode member_node in members) {
2324 string enum_value = member_node.Attributes ["MemberName"].InnerText;
2325 text.Append (enum_value);
2327 GetTextFromNode (member_node["Docs"], text);
2330 SearchableDocument doc = new SearchableDocument ();
2332 text = new StringBuilder ();
2333 GetExamples (xdoc.SelectSingleNode ("/Type/Docs"), text);
2334 doc.examples = text.ToString ();
2336 doc.title = type_node.Caption;
2337 doc.hottext = xdoc.DocumentElement.Attributes["Name"].Value;
2338 doc.fulltitle = full;
2340 doc.text = text.ToString();
2341 writer.AddDocument (doc.LuceneDoc);
2345 } else if (doc_tag == "Delegate"){
2346 SearchableDocument doc = new SearchableDocument ();
2347 doc.title = type_node.Caption;
2348 doc.hottext = xdoc.DocumentElement.Attributes["Name"].Value;
2349 doc.fulltitle = full;
2352 XmlNode node_sel = xdoc.SelectSingleNode ("/Type/Docs");
2354 text = new StringBuilder ();
2355 GetTextFromNode (node_sel, text);
2356 doc.text = text.ToString();
2358 text = new StringBuilder ();
2359 GetExamples (node_sel, text);
2360 doc.examples = text.ToString();
2362 writer.AddDocument (doc.LuceneDoc);
2369 // Extract the interesting text from the docs node
2371 void GetTextFromNode (XmlNode n, StringBuilder sb)
2373 //don't include example code
2374 if (n.Name == "code")
2377 //include the url to which points the see tag
2378 if (n.Name == "see" && n.Attributes.Count > 0)
2379 sb.Append (n.Attributes [0].Value);
2381 //include the name of the parameter
2382 if (n.Name == "paramref" && n.Attributes.Count > 0)
2383 sb.Append (n.Attributes [0].Value);
2385 //include the contents for the node that contains text
2386 if (n.NodeType == XmlNodeType.Text)
2387 sb.Append (n.Value);
2389 //add the rest of xml tags recursively
2390 if (n.HasChildNodes)
2391 foreach (XmlNode n_child in n.ChildNodes)
2392 GetTextFromNode (n_child, sb);
2395 // Extract the code nodes from the docs
2397 void GetExamples (XmlNode n, StringBuilder sb)
2399 if (n.Name == "code") {
2400 sb.Append (n.InnerText);
2402 if (n.HasChildNodes)
2403 foreach (XmlNode n_child in n.ChildNodes)
2404 GetExamples (n_child, sb);
2408 // Extract a large name for the Node
2409 // (copied from mono-tools/docbrowser/browser.Render()
2410 static string LargeName (Node matched_node)
2412 string[] parts = matched_node.URL.Split('/', '#');
2413 if(parts.Length == 3 && parts[2] != String.Empty) { //List of Members, properties, events, ...
2414 return parts[1] + ": " + matched_node.Caption;
2415 } else if(parts.Length >= 4) { //Showing a concrete Member, property, ...
2416 return parts[1] + "." + matched_node.Caption;
2418 return matched_node.Caption;
2424 public class EcmaUncompiledHelpSource : EcmaHelpSource {
2425 readonly DirectoryInfo basedir;
2426 readonly XmlDocument basedoc;
2428 public new readonly string Name;
2429 public readonly string BasePath;
2431 public EcmaUncompiledHelpSource (string base_file) : base ()
2433 Message (TraceLevel.Info, "Loading uncompiled help from " + base_file);
2435 basedir = new DirectoryInfo(base_file);
2436 BasePath = basedir.FullName;
2438 basedoc = new XmlDocument();
2439 basedoc.Load(Path.Combine(basedir.FullName, "index.xml"));
2441 Name = basedoc.SelectSingleNode("Overview/Title").InnerText;
2443 bool has_content = false;
2445 foreach (XmlElement ns in basedoc.SelectNodes("Overview/Types/Namespace")) {
2447 Node nsnode = Tree.CreateNode(ns.GetAttribute("Name"), "N:" + ns.GetAttribute("Name"));
2449 bool has_types = false;
2450 foreach (XmlElement t in ns.SelectNodes("Type")) {
2452 string typename = EcmaDoc.GetDisplayName (t).Replace("+", ".");
2454 // Must load in each document to get the list of members...
2455 XmlDocument typedoc = new XmlDocument();
2456 typedoc.Load(Path.Combine(Path.Combine(basedir.FullName, ns.GetAttribute("Name")), t.GetAttribute("Name") + ".xml"));
2457 string kind = EcmaDoc.GetTypeKind (typedoc);
2459 string url = ns.GetAttribute("Name") + "." + t.GetAttribute("Name");
2460 Node typenode = nsnode.CreateNode(typename + " " + kind, "T:" + url);
2461 //Node typemembers = typenode.CreateNode("Members", "T:" + url + "/*");
2463 Hashtable groups = new Hashtable();
2464 Hashtable groups_count = new Hashtable();
2465 foreach (XmlElement member in typedoc.SelectNodes("Type/Members/Member")) {
2466 string membername = member.GetAttribute("MemberName");
2467 string membertype = member.SelectSingleNode("MemberType").InnerText;
2469 if (membertype == "Constructor")
2470 membername = t.GetAttribute("Name");
2471 if (membername.StartsWith("op_"))
2472 membertype = "Operator";
2475 if (groups.ContainsKey(membertype)) {
2476 group = (Node)groups[membertype];
2478 string membertypeplural = membertype + "s";
2479 if (membertypeplural == "Propertys") membertypeplural = "Properties";
2481 group = typenode.CreateNode(membertypeplural, "T:" + url + "/" + membertype[0]);
2482 groups[membertype] = group;
2483 groups_count[membertype] = 0;
2486 if (membertype == "Constructor" || membertype == "Method" ||
2487 (membertype == "Property" && member.SelectNodes("Parameters/Parameter").Count > 0)) {
2488 membername = EcmaHelpSource.MakeSignature(member, membertype == "Constructor" ? membername : null);
2489 } else if (membertype == "Operator") {
2491 EcmaHelpSource.MakeOperatorSignature(member, out dummy, out membername);
2494 int index = (int)groups_count[membertype];
2495 groups_count[membertype] = index + 1;
2497 group.CreateNode(membername, index.ToString());
2500 foreach (Node group in groups.Values)
2512 public override string GetIdFromUrl (string prefix, string ns, string type)
2515 throw new NotImplementedException();
2516 return Path.Combine(Path.Combine(basedir.FullName, ns), type + ".xml");
2519 protected override XmlDocument GetXmlFromUrl(string url, out string rest) {
2521 url = url.Substring(2);
2523 int sidx = url.IndexOf("/");
2527 rest = url.Substring(sidx+1);
2528 url = url.Substring(0, sidx);
2532 if (!RootTree.GetNamespaceAndType (url, out ns, out type)) {
2533 Message (TraceLevel.Error, "Could not determine namespace/type for {0}", url);
2537 string file = Path.Combine(Path.Combine(basedir.FullName, ns),
2538 ToEscapedTypeName (type).Replace ('.', '+') + ".xml");
2539 if (!new FileInfo(file).Exists) return null;
2541 XmlDocument typedoc = new XmlDocument();
2546 public override string GetText (string url, out Node match_node) {
2547 if (url == "root:") {
2551 XmlDocument index = new XmlDocument ();
2552 index.Load (Path.Combine (basedir.FullName, "index.xml"));
2553 XmlNodeList nodes = index.SelectNodes ("/Overview/Types/Namespace");
2555 //recreate masteroverview.xml
2556 XmlDocument summary = new XmlDocument ();
2557 XmlElement elements = summary.CreateElement ("elements");
2558 foreach (XmlNode node in nodes) {
2559 XmlElement ns = summary.CreateElement ("namespace");
2560 XmlAttribute attr = summary.CreateAttribute ("ns");
2561 attr.Value = EcmaDoc.GetDisplayName (node);
2562 ns.Attributes.Append (attr);
2563 elements.AppendChild (ns);
2565 summary.AppendChild (elements);
2567 XmlReader reader = new XmlTextReader (new StringReader (summary.OuterXml));
2569 //transform the recently created masteroverview.xml
2570 XsltArgumentList args = new XsltArgumentList();
2571 args.AddExtensionObject("monodoc:///extensions", ExtObject);
2572 args.AddParam("show", "", "masteroverview");
2573 string s = Htmlize(reader, args);
2574 return BuildHtml (css_ecma_code, js_code, s);
2576 return base.GetText(url, out match_node);
2579 protected override XmlDocument GetNamespaceDocument (string ns)
2581 XmlDocument nsdoc = new XmlDocument();
2582 nsdoc.Load (EcmaDoc.GetNamespaceFile (basedir.FullName, ns));
2584 XmlDocument elements = new XmlDocument();
2585 XmlElement docnode = elements.CreateElement("elements");
2586 elements.AppendChild (docnode);
2588 foreach (XmlElement doc in nsdoc.SelectNodes("Namespace/Docs/*")) {
2589 docnode.AppendChild(elements.ImportNode(doc, true));
2592 foreach (XmlElement t in basedoc.SelectNodes("Overview/Types/Namespace[@Name='" + ns + "']/Type")) {
2593 XmlDocument typedoc = new XmlDocument();
2594 typedoc.Load(Path.Combine(Path.Combine(basedir.FullName, ns), t.GetAttribute("Name") + ".xml"));
2597 switch (EcmaDoc.GetTypeKind(typedoc)) {
2598 case "Class": typekind = "class"; break;
2599 case "Enumeration": typekind = "enum"; break;
2600 case "Structure": typekind = "struct"; break;
2601 case "Delegate": typekind = "delegate"; break;
2602 case "Interface": typekind = "interface"; break;
2603 default: throw new InvalidOperationException();
2606 XmlElement typenode = elements.CreateElement(typekind);
2607 typenode.SetAttribute("name", EcmaDoc.GetDisplayName (t).Replace ('+', '.'));
2608 typenode.SetAttribute("fullname", ns + "." + t.GetAttribute("Name"));
2609 typenode.AppendChild(elements.ImportNode(typedoc.SelectSingleNode("Type/Docs/summary"), true));
2611 docnode.AppendChild(typenode);
2617 public override Stream GetHelpStream (string id)
2619 if (id == "ExtensionMethods.xml") {
2620 // TODO: generate ExtensionMethods.xml based on index.xml contents.
2625 public override XmlDocument GetHelpXmlWithChanges (string id)
2627 XmlDocument doc = new XmlDocument ();
2632 public virtual Stream GetImage (string url)
2634 string path = EcmaDoc.GetImageFile (basedir.FullName, url);
2637 return File.OpenRead (path);
2640 class UncompiledResolver : XmlResolver {
2641 public override Uri ResolveUri (Uri baseUri, string relativeUri)
2646 public override object GetEntity (Uri absoluteUri, string role, Type ofObjectToReturn)
2651 public override System.Net.ICredentials Credentials {
2656 protected override XmlResolver CreateDocumentResolver ()
2658 return new UncompiledResolver ();