//
// (C) 2002, 2003 Ximian, Inc.
// (C) 2003 Joshua Tauberer.
+// Copyright 2003-2011 Novell
+// Copyright 2011 Xamarin Inc
//
// TODO:
// Should cluster together constructors
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Text;
+using System.Linq;
using System.Collections;
-using Monodoc.Lucene.Net.Index;
-using Monodoc.Lucene.Net.Documents;
+using System.Collections.Generic;
+using Mono.Lucene.Net.Index;
+using Mono.Lucene.Net.Documents;
using Mono.Documentation;
return type;
}
+ // Lala
+ static bool IsItReallyAGenericType (string type)
+ {
+ switch (type) {
+ case "Type":
+ case "TimeZone":
+ case "TimeZoneInfo":
+ case "TimeSpan":
+ case "TypeReference":
+ case "TypeCode":
+ case "TimeZoneInfo+AdjustmentRule":
+ case "TimeZoneInfo+TransitionTime":
+ return false;
+ }
+ if (type.StartsWith ("Tuple"))
+ return false;
+ return true;
+ }
+
+ public static string ConvertFromCTSName (string ctsType)
+ {
+ if (string.IsNullOrEmpty (ctsType))
+ return string.Empty;
+
+ // Most normal type should have a namespace part and thus a point in their name
+ if (ctsType.IndexOf ('.') != -1)
+ return ctsType;
+
+ if (ctsType.EndsWith ("*"))
+ return ConvertFromCTSName(ctsType.Substring(0, ctsType.Length - 1)) + "*";
+ if (ctsType.EndsWith ("&"))
+ return ConvertFromCTSName(ctsType.Substring(0, ctsType.Length - 1)) + "&";
+ if (ctsType.EndsWith ("]")) { // Array may be multidimensional
+ var idx = ctsType.LastIndexOf ('[');
+ return ConvertFromCTSName (ctsType.Substring (0, idx)) + ctsType.Substring (idx);
+ }
+
+ // Big hack here, we tentatively try to say if a type is a generic when it starts with a upper case T
+ if ((char.IsUpper (ctsType, 0) && ctsType.Length == 1) || (ctsType[0] == 'T' && IsItReallyAGenericType (ctsType)))
+ return ctsType;
+
+ switch (ctsType) {
+ case "byte": return "System.Byte";
+ case "sbyte": return "System.SByte";
+ case "short": return "System.Int16";
+ case "int": return "System.Int32";
+ case "long": return "System.Int64";
+
+ case "ushort": return "System.UInt16";
+ case "uint": return "System.UInt32";
+ case "ulong": return "System.UInt64";
+
+ case "float": return "System.Single";
+ case "double": return "System.Double";
+ case "decimal": return "System.Decimal";
+ case "bool": return "System.Boolean";
+ case "char": return "System.Char";
+ case "string": return "System.String";
+
+ case "object": return "System.Object";
+ case "void": return "System.Void";
+ }
+
+ // If we arrive here, the type was probably stripped of its 'System.'
+ return "System." + ctsType;
+ }
+
internal static string GetNamespaceFile (string dir, string ns)
{
string nsxml = Path.Combine (dir, "ns-" + ns + ".xml");
nsxml = Path.Combine (dir, ns + ".xml");
return nsxml;
}
+
+ internal static string GetImageFile (string dir, string img)
+ {
+ string path = Path.Combine (dir, Path.Combine ("_images", img));
+ return File.Exists (path) ? path : null;
+ }
+
+ public static string GetCref (XmlElement member)
+ {
+ string typeName = XmlDocUtils.ToEscapedTypeName (member.SelectSingleNode("/Type/@FullName").InnerText);
+ if (member.Name == "Type")
+ return "T:" + typeName;
+ string memberType = member.SelectSingleNode("MemberType").InnerText;
+ switch (memberType) {
+ case "Constructor":
+ return "C:" + typeName + MakeArgs(member);
+ case "Event":
+ return "E:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName"));
+ case "Field":
+ return "F:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName"));
+ case "Method": {
+ string name = "M:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName")) + MakeArgs(member);
+ if (member.GetAttribute("MemberName") == "op_Implicit" || member.GetAttribute("MemberName") == "op_Explicit")
+ name += "~" + XmlDocUtils.ToTypeName (member.SelectSingleNode("ReturnValue/ReturnType").InnerText, member);
+ return name;
+ }
+ case "Property":
+ return "P:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName")) + MakeArgs(member);
+ default:
+ throw new NotSupportedException ("MemberType '" + memberType + "' is not supported.");
+ }
+ }
+
+ private static string MakeArgs (XmlElement member)
+ {
+ XmlNodeList parameters = member.SelectNodes ("Parameters/Parameter");
+ if (parameters.Count == 0)
+ return member.SelectSingleNode ("MemberType").InnerText != "Property" ? "()" : "";
+ StringBuilder args = new StringBuilder ();
+ args.Append ("(");
+ args.Append (XmlDocUtils.ToTypeName (parameters [0].Attributes ["Type"].Value, member));
+ for (int i = 1; i < parameters.Count; ++i) {
+ args.Append (",");
+ args.Append (XmlDocUtils.ToTypeName (parameters [i].Attributes ["Type"].Value, member));
+ }
+ args.Append (")");
+ return args.ToString ();
+ }
}
//
XmlNode ns_summary = nsSummaryFile.SelectSingleNode ("Namespace/Docs/summary");
if (ns_summary != null && ns_summary.InnerText.Trim () != "To be added." && ns_summary.InnerText != "") {
- namespace_summaries [tn] = ns_summary;
- namespace_remarks [tn] = nsSummaryFile.SelectSingleNode ("Namespace/Docs/remarks");
+ namespace_summaries [tn] = detached.ImportNode (ns_summary, true);
+ namespace_remarks [tn] = detached.ImportNode (nsSummaryFile.SelectSingleNode ("Namespace/Docs/remarks"), true);
}
} else if (!namespace_summaries.ContainsKey (tn)) {
}
- struct TypeInfo : IComparable {
+ class TypeInfo : IComparable {
public string type_assembly;
public string type_name;
public string type_full;
}
tree.HelpSource.PackXml ("mastersummary.xml", nsSummary, null);
AddExtensionMethods (tree);
+ AddImageFiles (hs, tree);
}
void AddExtensionMethods (Tree tree)
tree.HelpSource.PackXml ("ExtensionMethods.xml", extensions, "ExtensionMethods.xml");
}
}
-
- Hashtable class_summaries = new Hashtable ();
- Hashtable namespace_summaries = new Hashtable ();
- Hashtable namespace_remarks = new Hashtable ();
- Hashtable namespace_realpath = new Hashtable ();
- XmlDocument doc;
+
+ void AddImageFiles (HelpSource hs, Tree tree)
+ {
+ foreach (string asm in asm_dirs) {
+ string path = Path.Combine (asm, "_images");
+ if (!Directory.Exists (path))
+ return;
+
+#if NET_2_0
+ foreach (var img in Directory.GetFiles (path))
+#else
+ foreach (var img in Directory.EnumerateFiles (path))
+#endif
+ hs.PackFile (img, Path.GetFileName (img));
+ }
+ }
+
+ Hashtable/*<string, List<TypeInfo>>*/ class_summaries = new Hashtable ();
+ Hashtable/*<string, XmlNode>*/ namespace_summaries = new Hashtable ();
+ Hashtable/*<string, XmlNode>*/ namespace_remarks = new Hashtable ();
+ Hashtable/*<string, string -- path>*/ namespace_realpath = new Hashtable ();
+
+ XmlDocument detached = new XmlDocument ();
void PopulateClass (Tree tree, string ns, Node ns_node, string file)
{
- doc = new XmlDocument ();
+ XmlDocument doc = new XmlDocument ();
doc.Load (file);
string name = EcmaDoc.GetClassName (doc);
Node class_node;
string file_code = ns_node.tree.HelpSource.PackFile (file);
- XmlNode class_summary = doc.SelectSingleNode ("/Type/Docs/summary");
+ XmlNode class_summary = detached.ImportNode (doc.SelectSingleNode ("/Type/Docs/summary"), true);
ArrayList l = (ArrayList) class_summaries [ns];
if (l == null){
l = new ArrayList ();
//
class_node.CreateNode ("Members", "*");
- PopulateMember (name, class_node, "Constructor", "Constructors");
- PopulateMember (name, class_node, "Method", "Methods");
- PopulateMember (name, class_node, "Property", "Properties");
- PopulateMember (name, class_node, "Field", "Fields");
- PopulateMember (name, class_node, "Event", "Events");
- PopulateMember (name, class_node, "Operator", "Operators");
+ PopulateMember (doc, name, class_node, "Constructor", "Constructors");
+ PopulateMember (doc, name, class_node, "Method", "Methods");
+ PopulateMember (doc, name, class_node, "Property", "Properties");
+ PopulateMember (doc, name, class_node, "Field", "Fields");
+ PopulateMember (doc, name, class_node, "Event", "Events");
+ PopulateMember (doc, name, class_node, "Operator", "Operators");
}
class NodeIndex {
// Performs an XPath query on the document to extract the nodes for the various members
// we also use some extra text to pluralize the caption
//
- void PopulateMember (string typename, Node node, string type, string caption)
+ void PopulateMember (XmlDocument doc, string typename, Node node, string type, string caption)
{
string select = type;
if (select == "Operator") select = "Method";
get {return js_code + base.InlineJavaScript;}
}
+ public override string GetPublicUrl (string url)
+ {
+ if (url == null || url.Length == 0)
+ return url;
+ try {
+ string rest;
+ XmlDocument d = GetXmlFromUrl (url, out rest);
+ if (rest == "")
+ return EcmaDoc.GetCref (d.DocumentElement);
+ XmlElement e = GetDocElement (d, rest);
+ if (e == null)
+ return EcmaDoc.GetCref (d.DocumentElement) + "/" + rest;
+ return EcmaDoc.GetCref (e);
+ }
+ catch (Exception e) {
+ return url;
+ }
+ }
+
+ private static XmlElement GetDocElement (XmlDocument d, string rest)
+ {
+ string memberType = null;
+ string memberIndex = null;
+
+ string [] nodes = rest.Split (new char [] {'/'});
+
+ switch (nodes.Length) {
+ // e.g. C; not supported.
+ case 1:
+ return null;
+ // e.g. C/0 or M/MethodName; the latter isn't supported.
+ case 2:
+ try {
+ // XPath wants 1-based indexes, while the url uses 0-based values.
+ memberIndex = (int.Parse (nodes [1]) + 1).ToString ();
+ memberType = GetMemberType (nodes [0]);
+ } catch {
+ return null;
+ }
+ break;
+ // e.g. M/MethodName/0
+ case 3:
+ memberIndex = (int.Parse (nodes [2]) + 1).ToString ();
+ memberType = GetMemberType (nodes [0]);
+ break;
+ // not supported
+ default:
+ return null;
+ }
+ string xpath = "/Type/Members/Member[MemberType=\"" + memberType + "\"]" +
+ "[position()=" + memberIndex + "]";
+ return (XmlElement) d.SelectSingleNode (xpath);
+ }
+
+ private static string GetMemberType (string type)
+ {
+ switch (type) {
+ case "C": return "Constructor";
+ case "E": return "Event";
+ case "F": return "Field";
+ case "M": return "Method";
+ case "P": return "Property";
+ default:
+ throw new NotSupportedException ("Member Type: '" + type + "'.");
+ }
+ }
+
public override string GetText (string url, out Node match_node)
{
match_node = null;
XsltArgumentList args = new XsltArgumentList();
args.AddExtensionObject("monodoc:///extensions", ExtObject);
args.AddParam("show", "", "masteroverview");
- string s = Htmlize(new XPathDocument (summary), args);
+ string s = Htmlize(summary, args);
return BuildHtml (css_ecma_code, js_code, s);
}
if ((membername == "op_Implicit" || membername == "op_Explicit") && argtypes.Length == 2) {
isoperator = true;
- membername = "Conversion";
+ membername = membername.EndsWith ("Implicit") ? "ImplicitConversion" : "ExplicitConversion";
member = argtypes[0] + " to " + argtypes[1];
} else if (membername.StartsWith("op_")) {
isoperator = true;
nicename = name.Substring(3);
switch (name) {
- // unary operators: no overloading possible
- case "op_UnaryPlus": case "op_UnaryNegation": case "op_LogicalNot": case "op_OnesComplement":
- case "op_Increment": case "op_Decrement":
- case "op_True": case "op_False":
+ // unary operators: no overloading possible [ECMA-335 §10.3.1]
+ case "op_UnaryPlus": // static R operator+ (T)
+ case "op_UnaryNegation": // static R operator- (T)
+ case "op_LogicalNot": // static R operator! (T)
+ case "op_OnesComplement": // static R operator~ (T)
+ case "op_Increment": // static R operator++ (T)
+ case "op_Decrement": // static R operator-- (T)
+ case "op_True": // static bool operator true (T)
+ case "op_False": // static bool operator false (T)
+ case "op_AddressOf": // static R operator& (T)
+ case "op_PointerDereference": // static R operator* (T)
sig = nicename;
break;
- // binary operators: overloading is possible based on parameter types
- case "op_Addition": case "op_Subtraction": case "op_Multiply": case "op_Division": case "op_Modulus":
- case "op_BitwiseAnd": case "op_BitwiseOr": case "op_ExclusiveOr":
- case "op_LeftShift": case "op_RightShift":
- case "op_Equality": case "op_Inequality":
- case "op_GreaterThan": case "op_LessThan": case "op_GreaterThanOrEqual": case "op_LessThanOrEqual":
+ // binary operators: overloading is possible [ECMA-335 §10.3.2]
+ case "op_Addition": // static R operator+ (T1, T2)
+ case "op_Subtraction": // static R operator- (T1, T2)
+ case "op_Multiply": // static R operator* (T1, T2)
+ case "op_Division": // static R operator/ (T1, T2)
+ case "op_Modulus": // static R operator% (T1, T2)
+ case "op_ExclusiveOr": // static R operator^ (T1, T2)
+ case "op_BitwiseAnd": // static R operator& (T1, T2)
+ case "op_BitwiseOr": // static R operator| (T1, T2)
+ case "op_LogicalAnd": // static R operator&& (T1, T2)
+ case "op_LogicalOr": // static R operator|| (T1, T2)
+ case "op_Assign": // static R operator= (T1, T2)
+ case "op_LeftShift": // static R operator<< (T1, T2)
+ case "op_RightShift": // static R operator>> (T1, T2)
+ case "op_SignedRightShift": // static R operator>> (T1, T2)
+ case "op_UnsignedRightShift": // static R operator>>> (T1, T2)
+ case "op_Equality": // static bool operator== (T1, T2)
+ case "op_GreaterThan": // static bool operator> (T1, T2)
+ case "op_LessThan": // static bool operator< (T1, T2)
+ case "op_Inequality": // static bool operator!= (T1, T2)
+ case "op_GreaterThanOrEqual": // static bool operator>= (T1, T2)
+ case "op_LessThanOrEqual": // static bool operator<= (T1, T2)
+ case "op_UnsignedRightShiftAssignment": // static R operator>>>= (T1, T2)
+ case "op_MemberSelection": // static R operator-> (T1, T2)
+ case "op_RightShiftAssignment": // static R operator>>= (T1, T2)
+ case "op_MultiplicationAssignment": // static R operator*= (T1, T2)
+ case "op_PointerToMemberSelection": // static R operator->* (T1, T2)
+ case "op_SubtractionAssignment": // static R operator-= (T1, T2)
+ case "op_ExclusiveOrAssignment": // static R operator^= (T1, T2)
+ case "op_LeftShiftAssignment": // static R operator<<= (T1, T2)
+ case "op_ModulusAssignment": // static R operator%= (T1, T2)
+ case "op_AdditionAssignment": // static R operator+= (T1, T2)
+ case "op_BitwiseAndAssignment": // static R operator&= (T1, T2)
+ case "op_BitwiseOrAssignment": // static R operator|= (T1, T2)
+ case "op_Comma": // static R operator, (T1, T2)
+ case "op_DivisionAssignment": // static R operator/= (T1, T2)
+ default: // If all else fails, assume it can be overridden...whatever it is.
XmlNodeList paramnodes = n.SelectNodes("Parameters/Parameter");
sig = nicename + "(";
bool first = true;
sig += ")";
break;
- // overloading based on parameter and return type
- case "op_Implicit": case "op_Explicit":
- nicename = "Conversion";
+ // conversion operators: overloading based on parameter and return type [ECMA-335 §10.3.3]
+ case "op_Implicit": // static implicit operator R (T)
+ case "op_Explicit": // static explicit operator R (T)
+ nicename = name.EndsWith ("Implicit") ? "ImplicitConversion" : "ExplicitConversion";
string arg = n.SelectSingleNode("Parameters/Parameter/@Type").InnerText;
string ret = n.SelectSingleNode("ReturnValue/ReturnType").InnerText;
sig = EcmaDoc.ConvertCTSName(arg) + " to " + EcmaDoc.ConvertCTSName(ret);
break;
-
- default:
- throw new InvalidOperationException();
}
}
static string ToEscapedMemberName (string membername)
{
- return ToEscapedName (membername, "``");
+ return ToEscapedName (membername, "`");
}
public override string GetNodeXPath (XPathNavigator n)
args.AddExtensionObject("monodoc:///extensions", ExtObject);
args.AddParam("show", "", "namespace");
args.AddParam("namespace", "", ns_name);
- string s = Htmlize(doc, args);
+ args.AddParam ("source-id", "", SourceID.ToString ());
+ string s = Htmlize(new XmlNodeReader (doc), args);
return BuildHtml (css_ecma_code, js_code, s);
}
string GetTextFromUrl (string url)
{
+ if (nozip) {
+ string path = XmlDocUtils.GetCachedFileName (base_dir, url);
+ if (File.Exists (path))
+ return File.OpenText (path).ReadToEnd ();
+ return null;
+ }
+
string rest, rest2;
Node node;
basetype = basetypedoc.SelectSingleNode("Type/Base/BaseTypeName");
}
ArrayList extensions = new ArrayList ();
+ AddExtensionMethodsFromHelpSource (extensions, this);
foreach (HelpSource hs in RootTree.HelpSources) {
EcmaHelpSource es = hs as EcmaHelpSource;
if (es == null)
continue;
- Stream s = es.GetHelpStream ("ExtensionMethods.xml");
- if (s != null) {
- XmlDocument d = new XmlDocument ();
- d.Load (s);
- foreach (XmlNode n in d.SelectNodes ("/ExtensionMethods/*")) {
- extensions.Add (n);
- }
- }
+ if (es == this)
+ continue;
+ AddExtensionMethodsFromHelpSource (extensions, es);
}
XmlDocUtils.AddExtensionMethods (doc, extensions, delegate (string s) {
s = s.StartsWith ("T:") ? s : "T:" + s;
XsltArgumentList args = new XsltArgumentList();
args.AddExtensionObject("monodoc:///extensions", ExtObject);
+
+ args.AddParam ("source-id", "", SourceID.ToString ());
if (rest == "") {
args.AddParam("show", "", "typeoverview");
- string s = Htmlize(doc, args);
+ string s = Htmlize(new XmlNodeReader (doc), args);
return BuildHtml (css_ecma_code, js_code, s);
}
return "Unknown url: " + url;
}
- string html = Htmlize(doc, args);
+ string html = Htmlize(new XmlNodeReader (doc), args);
return BuildHtml (css_ecma_code, js_code, html);
}
+ void AddExtensionMethodsFromHelpSource (ArrayList extensions, EcmaHelpSource es)
+ {
+ Stream s = es.GetHelpStream ("ExtensionMethods.xml");
+ if (s != null) {
+ XmlDocument d = new XmlDocument ();
+ d.Load (s);
+ foreach (XmlNode n in d.SelectNodes ("/ExtensionMethods/*")) {
+ extensions.Add (n);
+ }
+ }
+ }
+
public override void RenderPreviewDocs (XmlNode newNode, XmlWriter writer)
{
XsltArgumentList args = new XsltArgumentList ();
args.AddExtensionObject ("monodoc:///extensions", ExtObject);
+ args.AddParam ("source-id", "", SourceID.ToString ());
- Htmlize (newNode, args, writer);
+ Htmlize (new XmlNodeReader (newNode), args, writer);
}
- static XslTransform ecma_transform;
+ static XslCompiledTransform ecma_transform;
- public string Htmlize (IXPathNavigable ecma_xml)
+ public string Htmlize (XmlReader ecma_xml)
{
return Htmlize(ecma_xml, null);
}
- public string Htmlize (IXPathNavigable ecma_xml, XsltArgumentList args)
+ public string Htmlize (XmlReader ecma_xml, XsltArgumentList args)
{
EnsureTransform ();
- StringWriter output = new StringWriter ();
- ecma_transform.Transform (ecma_xml, args, output, CreateDocumentResolver ());
+ var output = new StringBuilder ();
+ ecma_transform.Transform (ecma_xml,
+ args,
+ XmlWriter.Create (output, ecma_transform.OutputSettings),
+ CreateDocumentResolver ());
return output.ToString ();
}
return null;
}
- static void Htmlize (IXPathNavigable ecma_xml, XsltArgumentList args, XmlWriter w)
+ static void Htmlize (XmlReader ecma_xml, XsltArgumentList args, XmlWriter w)
{
EnsureTransform ();
ecma_transform.Transform (ecma_xml, args, w, null);
}
- static XslTransform ecma_transform_css, ecma_transform_no_css;
+ static XslCompiledTransform ecma_transform_css, ecma_transform_no_css;
static void EnsureTransform ()
{
if (ecma_transform == null) {
- ecma_transform_css = new XslTransform ();
- ecma_transform_no_css = new XslTransform ();
+ ecma_transform_css = new XslCompiledTransform ();
+ ecma_transform_no_css = new XslCompiledTransform ();
Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
Stream stream = assembly.GetManifestResourceStream ("mono-ecma-css.xsl");
XmlReader xml_reader = new XmlTextReader (stream);
XmlResolver r = new ManifestResourceResolver (".");
- ecma_transform_css.Load (xml_reader, r, null);
+ ecma_transform_css.Load (xml_reader, XsltSettings.TrustedXslt, r);
stream = assembly.GetManifestResourceStream ("mono-ecma.xsl");
xml_reader = new XmlTextReader (stream);
- ecma_transform_no_css.Load (xml_reader, r, null);
+ ecma_transform_no_css.Load (xml_reader, XsltSettings.TrustedXslt, r);
}
if (use_css)
ecma_transform = ecma_transform_css;
return name.Replace("+", ".");
}
- public string MonoImpInfo(string assemblyname, string typename, string membername, string arglist, bool strlong)
+ string MonoImpInfo(string assemblyname, string typename, string membername, string arglist, bool strlong)
{
if (quiet)
return "";
return MonoImpInfo(assemblyname, typename, membername, a, strlong);
}
- public string MonoImpInfo(string assemblyname, string typename, string membername, XPathNodeIterator itr, bool strlong)
+ string MonoImpInfo(string assemblyname, string typename, string membername, XPathNodeIterator itr, bool strlong)
{
if (quiet)
return "";
return MonoImpInfo (assemblyname, typename, membername, rgs, strlong);
}
- public string MonoImpInfo(string assemblyname, string typename, string membername, ArrayList arglist, bool strlong)
+ string MonoImpInfo(string assemblyname, string typename, string membername, ArrayList arglist, bool strlong)
{
try {
Assembly assembly = null;
}
}
- public string MonoImpInfo(System.Reflection.MemberInfo mi, string itemtype, bool strlong)
+ string MonoImpInfo(System.Reflection.MemberInfo mi, string itemtype, bool strlong)
{
if (quiet)
return "";
return node.URL[idx+1] + ":" + full + "." + node.Caption;
}
}
+
+ public override Stream GetImage (string url)
+ {
+ if (url.Contains ("/"))
+ url = url.Substring (url.LastIndexOf ('/') + 1);
+ return GetHelpStream (url);
+ }
//
- // Populates the index.
+ // Populates the searchable index.
+ //
+ // The idea of this index is to capture the most common search terms, the UI for this
+ // usually updates automatically as the user types.
//
public override void PopulateIndex (IndexMaker index_maker)
{
string doc_tag = GetKindFromCaption (type_node.Caption);
string url = "T:" + full;
-
+
+
+ //
+ // Add MonoMac/MonoTouch [Export] attributes, those live only in classes
+ //
+ if (doc_tag == "Class" && (ns_node.Caption.StartsWith ("MonoTouch") || ns_node.Caption.StartsWith ("MonoMac"))){
+ try {
+ string rest;
+ var xdoc = GetXmlFromUrl (type_node.URL, out rest);
+ if (xdoc != null){
+ var nodesWithExports = xdoc.SelectNodes ("/Type/Members/Member[contains (Attributes/Attribute/AttributeName, 'Foundation.Export') and (MemberType='Property' or MemberType='Method' or MemberType='Constructor')]");
+
+ foreach (XmlNode n in nodesWithExports){
+ string cref = EcmaDoc.GetCref ((XmlElement) n);
+
+ var exports = n.SelectNodes ("Attributes/Attribute/AttributeName");
+ foreach (XmlNode exportNode in exports){
+ var inner = exportNode.InnerText;
+ int p = inner.IndexOf ("Foundation.Export(\"");
+ if (p == -1){
+ Console.WriteLine ("Not found the Export attribute in {0}", inner);
+ continue;
+ }
+ var pa = inner.IndexOf ("\"", p);
+ if (pa == -1){
+ Console.WriteLine ("Export has no target in {0}", inner);
+ continue;
+ }
+ var end = inner.IndexOf ("\"", pa+1);
+
+ var export = end == -1 ? inner.Substring (pa+1) : inner.Substring (pa+1, end-(pa+1));
+
+ index_maker.Add (export + " selector", export, cref);
+ }
+ }
+ }
+ } catch (Exception e){
+ Console.WriteLine ("Problem processing {0} for MonoTouch/MonoMac exports\n\n{0}", e);
+ }
+ }
+
if (doc_tag == "Class" || doc_tag == "Structure" || doc_tag == "Interface"){
index_maker.Add (type_node.Caption, typename, url);
}
}
}
+
+ IEnumerable<string> ExtractArguments (string rawArgList)
+ {
+ var sb = new System.Text.StringBuilder ();
+ int genericDepth = 0;
+ int arrayDepth = 0;
+
+ for (int i = 0; i < rawArgList.Length; i++) {
+ char c = rawArgList[i];
+
+ switch (c) {
+ case ',':
+ if (genericDepth == 0 && arrayDepth == 0) {
+ yield return sb.ToString ();
+ sb.Clear ();
+ continue;
+ }
+ break;
+ case '<':
+ genericDepth++;
+ break;
+ case '>':
+ genericDepth--;
+ break;
+ case '[':
+ arrayDepth++;
+ break;
+ case ']':
+ arrayDepth--;
+ break;
+ }
+ sb.Append (c);
+ }
+ if (sb.Length > 0)
+ yield return sb.ToString ();
+ }
+
+ // Caption is what you see on a tree node, either SomeName or SomeName(ArgList)
+ void TryCreateXPathPredicateFragment (string caption, out string name, out string argListPredicate)
+ {
+ name = argListPredicate = null;
+ int parenIdx = caption.IndexOf ('(');
+ // In case of simple name, there is no need for processing
+ if (parenIdx == -1) {
+ name = caption;
+ return;
+ }
+ name = caption.Substring (0, parenIdx);
+ // Now we create a xpath predicate which will check for all the args in the argsList
+ var rawArgList = caption.Substring (parenIdx + 1, caption.Length - parenIdx - 2); // Only take what's inside the parens
+ if (string.IsNullOrEmpty (rawArgList))
+ return;
+
+ var argList = ExtractArguments (rawArgList).Select (arg => arg.Trim ()).Select (type => EcmaDoc.ConvertFromCTSName (type));
+ argListPredicate = "and " + argList.Select (type => string.Format ("Parameters/Parameter[@Type='{0}']", type)).Aggregate ((e1, e2) => e1 + " and " + e2);
+ }
+
//
// Create list of documents for searching
//
doc.title = type_node.Caption;
doc.hottext = typename;
doc.url = url;
+ doc.fulltitle = full;
XmlNode node_sel = xdoc.SelectSingleNode ("/Type/Docs");
text = new StringBuilder ();
doc.examples = text.ToString ();
writer.AddDocument (doc.LuceneDoc);
+ var exportParsable = doc_tag == "Class" && (ns_node.Caption.StartsWith ("MonoTouch") || ns_node.Caption.StartsWith ("MonoMac"));
//Add docs for contructors, methods, etc.
foreach (Node c in type_node.Nodes) { // c = Constructors || Fields || Events || Properties || Methods || Operators
if (c.Element == "*")
continue;
- int i = 1;
- foreach (Node nc in c.Nodes) {
+ const float innerTypeBoost = 0.2f;
+
+ var ncnodes = c.Nodes.Cast<Node> ();
+ // 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.Nodes == null || n.Nodes.Count == 0)
+ .Concat (ncnodes.Where (n => n.Nodes.Count > 0).SelectMany (n => n.Nodes.Cast<Node> ()));
+ } else if (c.Caption == "Operators") {
+ ncnodes = ncnodes
+ .Where (n => !n.Caption.EndsWith ("Conversion"))
+ .Concat (ncnodes.Where (n => n.Caption.EndsWith ("Conversion")).SelectMany (n => n.Nodes.Cast<Node> ()));
+ }
+ foreach (Node nc in ncnodes) {
//xpath to the docs xml node
string xpath;
- if (c.Caption == "Constructors")
- xpath = String.Format ("/Type/Members/Member[{0}]/Docs", i++);
- else if (c.Caption == "Operators")
- xpath = String.Format ("/Type/Members/Member[@MemberName='op_{0}']/Docs", nc.Caption);
- else
+ string name, argListPredicate;
+
+ switch (c.Caption) {
+ case "Constructors":
+ TryCreateXPathPredicateFragment (nc.Caption, out name, out argListPredicate);
+ xpath = String.Format ("/Type/Members/Member[@MemberName='.ctor'{0}]/Docs", argListPredicate ?? string.Empty);
+ break;
+ case "Operators":
+ // The first case are explicit and implicit conversion operators which are grouped specifically
+ if (nc.Caption.IndexOf (" to ") != -1) {
+ var convArgs = nc.Caption.Split (new[] { " to " }, StringSplitOptions.None);
+ xpath = String.Format ("/Type/Members/Member[(@MemberName='op_Explicit' or @MemberName='op_Implicit')" +
+ " and ReturnValue/ReturnType='{0}'" +
+ " and Parameters/Parameter[@Type='{1}']]/Docs",
+ EcmaDoc.ConvertFromCTSName (convArgs[1]), EcmaDoc.ConvertFromCTSName (convArgs[0]));
+ } else {
+ xpath = String.Format ("/Type/Members/Member[@MemberName='op_{0}']/Docs", nc.Caption);
+ }
+ break;
+ case "Methods":
+ TryCreateXPathPredicateFragment (nc.Caption, out name, out argListPredicate);
+ xpath = String.Format ("/Type/Members/Member[@MemberName='{0}'{1}]/Docs", name, argListPredicate ?? string.Empty);
+ break;
+ default:
xpath = String.Format ("/Type/Members/Member[@MemberName='{0}']/Docs", nc.Caption);
+ break;
+ }
//construct url of the form M:Array.Sort
string urlnc;
if (c.Caption == "Constructors")
//create the doc
SearchableDocument doc_nod = new SearchableDocument ();
doc_nod.title = LargeName (nc);
- //dont add the parameters to the hottext
- int ppos = nc.Caption.IndexOf ('(');
- if (ppos != -1)
- doc_nod.hottext = nc.Caption.Substring (0, ppos);
- else
- doc_nod.hottext = nc.Caption;
+ switch (c.Caption[0]) {
+ case 'M':
+ doc_nod.title += " Method";
+ break;
+ case 'P':
+ doc_nod.title += " Property";
+ break;
+ case 'E':
+ doc_nod.title += " Event";
+ break;
+ case 'O':
+ doc_nod.title += " Operator";
+ break;
+ case 'C':
+ doc_nod.title += " Constructor";
+ break;
+ default:
+ break;
+ }
+ doc_nod.fulltitle = string.Format ("{0}.{1}::{2}", ns_node.Caption, typename, nc.Caption);
+ // 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 ('(');
+ if (ppos != -1)
+ doc_nod.hottext = nc.Caption.Substring (0, ppos);
+ else
+ doc_nod.hottext = nc.Caption;
+ } else {
+ doc_nod.hottext = string.Empty;
+ }
doc_nod.url = urlnc;
GetTextFromNode (xmln, text);
doc_nod.text = text.ToString ();
- text = new StringBuilder ();
+ text.Clear ();
GetExamples (xmln, text);
doc_nod.examples = text.ToString ();
- writer.AddDocument (doc_nod.LuceneDoc);
+ Document lucene_doc = doc_nod.LuceneDoc;
+ lucene_doc.SetBoost (innerTypeBoost);
+ writer.AddDocument (lucene_doc);
+
+ // MonoTouch/Monomac specific parsing of [Export] attributes
+ if (exportParsable) {
+ try {
+ var exports =
+ xdoc.SelectNodes (string.Format ("/Type/Members/Member[@MemberName='{0}']/Attributes/Attribute/AttributeName[contains(text(), 'Foundation.Export')]", nc.Caption));
+ foreach (XmlNode exportNode in exports) {
+ var inner = exportNode.InnerText;
+ var parts = inner.Split ('"');
+ if (parts.Length != 3) {
+ Console.WriteLine ("Export attribute not found or not usable in {0}", inner);
+ continue;
+ }
+
+ var export = parts[1];
+ var export_node = new SearchableDocument ();
+ export_node.title = export + " Export";
+ export_node.fulltitle = string.Format ("{0}.{1}::{2}", 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.SetBoost (innerTypeBoost);
+ writer.AddDocument (lucene_doc);
+ }
+ } catch (Exception e){
+ Console.WriteLine ("Problem processing {0} for MonoTouch/MonoMac exports\n\n{0}", e);
+ }
+ }
}
}
//
doc.title = type_node.Caption;
doc.hottext = xdoc.DocumentElement.Attributes["Name"].Value;
+ doc.fulltitle = full;
doc.url = url;
doc.text = text.ToString();
writer.AddDocument (doc.LuceneDoc);
SearchableDocument doc = new SearchableDocument ();
doc.title = type_node.Caption;
doc.hottext = xdoc.DocumentElement.Attributes["Name"].Value;
+ doc.fulltitle = full;
doc.url = url;
XmlNode node_sel = xdoc.SelectSingleNode ("/Type/Docs");
doc.examples = text.ToString();
writer.AddDocument (doc.LuceneDoc);
- }
+ }
}
}
}
XsltArgumentList args = new XsltArgumentList();
args.AddExtensionObject("monodoc:///extensions", ExtObject);
args.AddParam("show", "", "masteroverview");
- string s = Htmlize(new XPathDocument (reader), args);
+ string s = Htmlize(reader, args);
return BuildHtml (css_ecma_code, js_code, s);
}
return base.GetText(url, out match_node);
doc.Load (id);
return doc;
}
+
+ public virtual Stream GetImage (string url)
+ {
+ string path = EcmaDoc.GetImageFile (basedir.FullName, url);
+ if (path == null)
+ return null;
+ return File.OpenRead (path);
+ }
class UncompiledResolver : XmlResolver {
public override Uri ResolveUri (Uri baseUri, string relativeUri)