[monodoc] Refactor more code from ecma-provider to the common EcmaDoc
authorJeremie Laval <jeremie.laval@gmail.com>
Fri, 25 Jan 2013 15:10:13 +0000 (15:10 +0000)
committerJeremie Laval <jeremie.laval@gmail.com>
Fri, 25 Jan 2013 16:27:37 +0000 (16:27 +0000)
mcs/class/monodoc/Monodoc/providers/EcmaDoc.cs
mcs/class/monodoc/Monodoc/providers/ecma-provider.cs

index 53e1740af36970db54181d17f99cc655a6e8d1cc..62dab9e0b8a0f1f263e333fc9e014d27c57d1617 100644 (file)
@@ -6,12 +6,25 @@ using System.Xml;
 using System.Xml.Linq;
 using System.Collections.Generic;
 
+using Monodoc.Ecma;
+
 namespace Monodoc.Providers
 {
+       public enum EcmaNodeType {
+               Invalid,
+               Namespace,
+               Type,
+               Member,
+               Meta, // A node that's here to serve as a header for other node
+       }
+
        // Common functionality between ecma-provider and ecmauncompiled-provider
        internal class EcmaDoc
        {
+               static EcmaUrlParser parser = new EcmaUrlParser ();
+
                public static void PopulateTreeFromIndexFile (string indexFilePath,
+                                                             string idPrefix,
                                                              Tree tree,
                                                              IDocStorage storage,
                                                              Dictionary<string, XElement> nsSummaries,
@@ -54,7 +67,7 @@ namespace Monodoc.Providers
                                                nsElements.Add (ExtractClassSummary (typeFilePath));
 
                                                var typeCaption = EcmaDoc.GetTypeCaptionFromIndex (type);
-                                               var url = "ecma:" + id + '#' + typeCaption + '/';
+                                               var url = idPrefix + id + '#' + typeCaption + '/';
                                                typeCaption = EcmaDoc.GetTypeCaptionFromIndex (type, true);
                                                var typeNode = nsNode.CreateNode (typeCaption, url);
 
@@ -179,6 +192,250 @@ namespace Monodoc.Providers
                        return caption;
                }
 
+               public static Node MatchNodeWithEcmaUrl (string url, Tree tree)
+               {
+                       Node result = null;
+                       EcmaDesc desc;
+                       if (!parser.TryParse (url, out desc))
+                               return null;
+
+                       // Namespace search
+                       Node currentNode = tree.RootNode;
+                       Node searchNode = new Node () { Caption = desc.Namespace };
+                       int index = currentNode.Nodes.BinarySearch (searchNode, EcmaGenericNodeComparer.Instance);
+                       if (index >= 0)
+                               result = currentNode.Nodes[index];
+                       if (desc.DescKind == EcmaDesc.Kind.Namespace || index < 0)
+                               return result;
+
+                       // Type search
+                       currentNode = result;
+                       result = null;
+                       searchNode.Caption = desc.ToCompleteTypeName ();
+                       index = currentNode.Nodes.BinarySearch (searchNode, EcmaTypeNodeComparer.Instance);
+                       if (index >= 0)
+                               result = currentNode.Nodes[index];
+                       if ((desc.DescKind == EcmaDesc.Kind.Type && !desc.IsEtc) || index < 0)
+                               return result;
+
+                       // Member selection
+                       currentNode = result;
+                       result = null;
+                       var caption = desc.IsEtc ? EtcKindToCaption (desc.Etc) : MemberKindToCaption (desc.DescKind);
+                       currentNode = FindNodeForCaption (currentNode.Nodes, caption);
+                       if (currentNode == null
+                           || (desc.IsEtc && desc.DescKind == EcmaDesc.Kind.Type && string.IsNullOrEmpty (desc.EtcFilter)))
+                               return currentNode;
+
+                       // Member search
+                       result = null;
+                       var format = desc.DescKind == EcmaDesc.Kind.Constructor ? EcmaDesc.Format.WithArgs : EcmaDesc.Format.WithoutArgs;
+                       searchNode.Caption = desc.ToCompleteMemberName (format);
+                       index = currentNode.Nodes.BinarySearch (searchNode, EcmaGenericNodeComparer.Instance);
+                       if (index < 0)
+                               return null;
+                       result = currentNode.Nodes[index];
+                       if (result.Nodes.Count == 0 || desc.IsEtc)
+                               return result;
+
+                       // Overloads search
+                       currentNode = result;
+                       searchNode.Caption = desc.ToCompleteMemberName (EcmaDesc.Format.WithArgs);
+                       index = currentNode.Nodes.BinarySearch (searchNode, EcmaGenericNodeComparer.Instance);
+                       if (index < 0)
+                               return result;
+                       result = result.Nodes[index];
+
+                       return result;
+               }
+
+               // This comparer returns the answer straight from caption comparison
+               class EcmaGenericNodeComparer : IComparer<Node>
+               {
+                       public static readonly EcmaGenericNodeComparer Instance = new EcmaGenericNodeComparer ();
+
+                       public int Compare (Node n1, Node n2)
+                       {
+                               return string.Compare (n1.Caption, n2.Caption, StringComparison.Ordinal);
+                       }
+               }
+
+               // This comparer take into account the space in the caption
+               class EcmaTypeNodeComparer : IComparer<Node>
+               {
+                       public static readonly EcmaTypeNodeComparer Instance = new EcmaTypeNodeComparer ();
+
+                       public int Compare (Node n1, Node n2)
+                       {
+                               int length1 = CaptionLength (n1.Caption);
+                               int length2 = CaptionLength (n2.Caption);
+
+                               return string.Compare (n1.Caption, 0, n2.Caption, 0, Math.Max (length1, length2), StringComparison.Ordinal);
+                       }
+
+                       int CaptionLength (string caption)
+                       {
+                               var length = caption.LastIndexOf (' ');
+                               return length == -1 ? caption.Length : length;
+                       }
+               }
+
+               public static Dictionary<string, string> GetContextForEcmaNode (string hash, string sourceID, Node node)
+               {
+                       var args = new Dictionary<string, string> ();
+
+                       args["source-id"] = sourceID;
+
+                       if (node != null) {
+                               var nodeType = GetNodeType (node);
+                               switch (nodeType) {
+                               case EcmaNodeType.Namespace:
+                                       args["show"] = "namespace";
+                                       args["namespace"] = node.Element.Substring ("N:".Length);
+                                       break;
+                               case EcmaNodeType.Type:
+                                       args["show"] = "typeoverview";
+                                       break;
+                               case EcmaNodeType.Member:
+                               case EcmaNodeType.Meta:
+                                       switch (GetNodeMemberTypeChar (node)){
+                                       case 'C':
+                                               args["membertype"] = "Constructor";
+                                               break;
+                                       case 'M':
+                                               args["membertype"] = "Method";
+                                               break;
+                                       case 'P':
+                                               args["membertype"] = "Property";
+                                               break;
+                                       case 'F':
+                                               args["membertype"] = "Field";
+                                               break;
+                                       case 'E':
+                                               args["membertype"] = "Event";
+                                               break;
+                                       case 'O':
+                                               args["membertype"] = "Operator";
+                                               break;
+                                       case 'X':
+                                               args["membertype"] = "ExtensionMethod";
+                                               break;
+                                       case '*':
+                                               args["membertype"] = "All";
+                                               break;
+                                       }
+
+                                       if (nodeType == EcmaNodeType.Meta) {
+                                               args["show"] = "members";
+                                               args["index"] = "all";
+                                       } else {
+                                               args["show"] = "member";
+                                               args["index"] = node.Element;
+                                       }
+                                       break;
+                               }
+                       }
+
+                       if (!string.IsNullOrEmpty (hash))
+                               args["hash"] = hash;
+
+                       return args;
+               }
+
+               public static EcmaNodeType GetNodeType (Node node)
+               {
+                       // We guess the node type by checking the depth level it's at in the tree
+                       int level = GetNodeLevel (node);
+                       switch (level) {
+                       case 0:
+                               return EcmaNodeType.Namespace;
+                       case 1:
+                               return EcmaNodeType.Type;
+                       case 2:
+                               return EcmaNodeType.Meta;
+                       case 3: // Here it's either a member or, in case of overload, a meta
+                               return node.IsLeaf ? EcmaNodeType.Member : EcmaNodeType.Meta;
+                       case 4: // At this level, everything is necessarily a member
+                               return EcmaNodeType.Member;
+                       default:
+                               return EcmaNodeType.Invalid;
+                       }
+               }
+
+               public static char GetNodeMemberTypeChar (Node node)
+               {
+                       int level = GetNodeLevel (node);
+                       // We try to reach the member group node depending on node nested level
+                       switch (level) {
+                       case 2:
+                               return node.Element[0];
+                       case 3:
+                               return node.Parent.Element[0];
+                       case 4:
+                               return node.Parent.Parent.Element[0];
+                       default:
+                               throw new ArgumentException ("node", "Couldn't determine member type of node `" + node.Caption + "'");
+                       }
+               }
+
+               public static int GetNodeLevel (Node node)
+               {
+                       int i = 0;
+                       for (; !node.Element.StartsWith ("root:/", StringComparison.OrdinalIgnoreCase); i++)
+                               node = node.Parent;
+                       return i - 1;
+               }
+
+               public static string EtcKindToCaption (char etc)
+               {
+                       switch (etc) {
+                       case 'M':
+                               return "Methods";
+                       case 'P':
+                               return "Properties";
+                       case 'C':
+                               return "Constructors";
+                       case 'F':
+                               return "Fields";
+                       case 'E':
+                               return "Events";
+                       case 'O':
+                               return "Operators";
+                       case '*':
+                               return "Members";
+                       default:
+                               return null;
+                       }
+               }
+
+               public static string MemberKindToCaption (EcmaDesc.Kind kind)
+               {
+                       switch (kind) {
+                       case EcmaDesc.Kind.Method:
+                               return "Methods";
+                       case EcmaDesc.Kind.Property:
+                               return "Properties";
+                       case EcmaDesc.Kind.Constructor:
+                               return "Constructors";
+                       case EcmaDesc.Kind.Field:
+                               return "Fields";
+                       case EcmaDesc.Kind.Event:
+                               return "Events";
+                       case EcmaDesc.Kind.Operator:
+                               return "Operators";
+                       default:
+                               return null;
+                       }
+               }
+
+               public static Node FindNodeForCaption (List<Node> nodes, string caption)
+               {
+                       foreach (var node in nodes)
+                               if (node.Caption.Equals (caption, StringComparison.OrdinalIgnoreCase))
+                                       return node;
+                       return null;
+               }
+
                internal static string MakeOperatorSignature (XElement member, out string memberSignature)
                {
                        string name = (string)member.Attribute ("MemberName");
index 284b661b6831be17c86cf46fd375428a63c12ee4..50057f379379cc8b8829adaeefa558300914a33f 100644 (file)
@@ -25,14 +25,6 @@ using Mono.Utilities;
 
 namespace Monodoc.Providers
 {
-       public enum EcmaNodeType {
-               Invalid,
-               Namespace,
-               Type,
-               Member,
-               Meta, // A node that's here to serve as a header for other node
-       }
-
        public class EcmaProvider : Provider
        {
                HashSet<string> directories = new HashSet<string> ();
@@ -67,7 +59,7 @@ namespace Monodoc.Providers
                                        continue;
                                }
 
-                               EcmaDoc.PopulateTreeFromIndexFile (indexFilePath, tree, storage, nsSummaries, _ => resID++.ToString ());
+                               EcmaDoc.PopulateTreeFromIndexFile (indexFilePath, EcmaHelpSource.EcmaPrefix, tree, storage, nsSummaries, _ => resID++.ToString ());
                        }
 
                        foreach (var summary in nsSummaries)
@@ -161,7 +153,7 @@ namespace Monodoc.Providers
 
        public class EcmaHelpSource : HelpSource
        {
-               const string EcmaPrefix = "ecma:";
+               internal const string EcmaPrefix = "ecma:";
                EcmaUrlParser parser = new EcmaUrlParser ();
                LRUCache<string, Node> cache = new LRUCache<string, Node> (4);
 
@@ -228,7 +220,7 @@ namespace Monodoc.Providers
                public override string GetPublicUrl (Node node)
                {
                        string url = string.Empty;
-                       var type = GetNodeType (node);
+                       var type = EcmaDoc.GetNodeType (node);
                        //Console.WriteLine ("GetPublicUrl {0} : {1} [{2}]", node.Element, node.Caption, type.ToString ());
                        switch (type) {
                        case EcmaNodeType.Namespace:
@@ -238,7 +230,7 @@ namespace Monodoc.Providers
                        case EcmaNodeType.Meta:
                                return MakeTypeNodeUrl (GetNodeTypeParent (node)) + GenerateMetaSuffix (node);
                        case EcmaNodeType.Member:
-                               var typeChar = GetNodeMemberTypeChar (node);
+                               var typeChar = EcmaDoc.GetNodeMemberTypeChar (node);
                                var parentNode = GetNodeTypeParent (node);
                                var typeNode = MakeTypeNodeUrl (parentNode).Substring (2);
                                return typeChar + ":" + typeNode + MakeMemberNodeUrl (typeChar, node);
@@ -289,52 +281,6 @@ namespace Monodoc.Providers
                        return "." + caption;
                }
 
-               EcmaNodeType GetNodeType (Node node)
-               {
-                       // We guess the node type by checking the depth level it's at in the tree
-                       int level = GetNodeLevel (node);
-                       switch (level) {
-                       case 0:
-                               return EcmaNodeType.Namespace;
-                       case 1:
-                               return EcmaNodeType.Type;
-                       case 2:
-                               return EcmaNodeType.Meta;
-                       case 3: // Here it's either a member or, in case of overload, a meta
-                               return node.IsLeaf ? EcmaNodeType.Member : EcmaNodeType.Meta;
-                       case 4: // At this level, everything is necessarily a member
-                               return EcmaNodeType.Member;
-                       default:
-                               return EcmaNodeType.Invalid;
-                       }
-               }
-
-               int GetNodeLevel (Node node)
-               {
-                       int i = 0;
-                       for (; !node.Element.StartsWith ("root:/", StringComparison.OrdinalIgnoreCase); i++) {
-                               //Console.WriteLine ("\tLevel {0} : {1} {2}", i, node.Element, node.Caption);
-                               node = node.Parent;
-                       }
-                       return i - 1;
-               }
-
-               char GetNodeMemberTypeChar (Node node)
-               {
-                       int level = GetNodeLevel (node);
-                       // We try to reach the member group node depending on node nested level
-                       switch (level) {
-                       case 2:
-                               return node.Element[0];
-                       case 3:
-                               return node.Parent.Element[0];
-                       case 4:
-                               return node.Parent.Parent.Element[0];
-                       default:
-                               throw new ArgumentException ("node", "Couldn't determine member type of node `" + node.Caption + "'");
-                       }
-               }
-
                Node GetNodeTypeParent (Node node)
                {
                        // Type nodes are always at level 2 so we just need to get there
@@ -347,7 +293,7 @@ namespace Monodoc.Providers
                {
                        string suffix = string.Empty;
                        // A meta node has always a type element to begin with
-                       while (GetNodeType (node) != EcmaNodeType.Type) {
+                       while (EcmaDoc.GetNodeType (node) != EcmaNodeType.Type) {
                                suffix = '/' + node.Element + suffix;
                                node = node.Parent;
                        }
@@ -394,213 +340,13 @@ namespace Monodoc.Providers
                {
                        Node node = null;
                        if ((node = cache.Get (url)) == null) {
-                               node = InternalMatchNode (url);
+                               node = EcmaDoc.MatchNodeWithEcmaUrl (url, Tree);
                                if (node != null)
                                        cache.Put (url, node);
                        }
                        return node;
                }
 
-               public Node InternalMatchNode (string url)
-               {
-                       Node result = null;
-                       EcmaDesc desc;
-                       if (!parser.TryParse (url, out desc))
-                               return null;
-
-                       // Namespace search
-                       Node currentNode = Tree.RootNode;
-                       Node searchNode = new Node () { Caption = desc.Namespace };
-                       int index = currentNode.Nodes.BinarySearch (searchNode, EcmaGenericNodeComparer.Instance);
-                       if (index >= 0)
-                               result = currentNode.Nodes[index];
-                       if (desc.DescKind == EcmaDesc.Kind.Namespace || index < 0)
-                               return result;
-
-                       // Type search
-                       currentNode = result;
-                       result = null;
-                       searchNode.Caption = desc.ToCompleteTypeName ();
-                       index = currentNode.Nodes.BinarySearch (searchNode, EcmaTypeNodeComparer.Instance);
-                       if (index >= 0)
-                               result = currentNode.Nodes[index];
-                       if ((desc.DescKind == EcmaDesc.Kind.Type && !desc.IsEtc) || index < 0)
-                               return result;
-
-                       // Member selection
-                       currentNode = result;
-                       result = null;
-                       var caption = desc.IsEtc ? EtcKindToCaption (desc.Etc) : MemberKindToCaption (desc.DescKind);
-                       currentNode = FindNodeForCaption (currentNode.Nodes, caption);
-                       if (currentNode == null 
-                           || (desc.IsEtc && desc.DescKind == EcmaDesc.Kind.Type && string.IsNullOrEmpty (desc.EtcFilter)))
-                               return currentNode;
-
-                       // Member search
-                       result = null;
-                       var format = desc.DescKind == EcmaDesc.Kind.Constructor ? EcmaDesc.Format.WithArgs : EcmaDesc.Format.WithoutArgs;
-                       searchNode.Caption = desc.ToCompleteMemberName (format);
-                       index = currentNode.Nodes.BinarySearch (searchNode, EcmaGenericNodeComparer.Instance);
-                       if (index < 0)
-                               return null;
-                       result = currentNode.Nodes[index];
-                       if (result.Nodes.Count == 0 || desc.IsEtc)
-                               return result;
-
-                       // Overloads search
-                       currentNode = result;
-                       searchNode.Caption = desc.ToCompleteMemberName (EcmaDesc.Format.WithArgs);
-                       index = currentNode.Nodes.BinarySearch (searchNode, EcmaGenericNodeComparer.Instance);
-                       if (index < 0)
-                               return result;
-                       result = result.Nodes[index];
-                       
-                       return result;
-               }
-
-               // This comparer returns the answer straight from caption comparison
-               class EcmaGenericNodeComparer : IComparer<Node>
-               {
-                       public static readonly EcmaGenericNodeComparer Instance = new EcmaGenericNodeComparer ();
-
-                       public int Compare (Node n1, Node n2)
-                       {
-                               return string.Compare (n1.Caption, n2.Caption, StringComparison.Ordinal);
-                       }
-               }
-
-               // This comparer take into account the space in the caption
-               class EcmaTypeNodeComparer : IComparer<Node>
-               {
-                       public static readonly EcmaTypeNodeComparer Instance = new EcmaTypeNodeComparer ();
-
-                       public int Compare (Node n1, Node n2)
-                       {
-                               int length1 = CaptionLength (n1.Caption);
-                               int length2 = CaptionLength (n2.Caption);
-
-                               return string.Compare (n1.Caption, 0, n2.Caption, 0, Math.Max (length1, length2), StringComparison.Ordinal);
-                       }
-
-                       int CaptionLength (string caption)
-                       {
-                               var length = caption.LastIndexOf (' ');
-                               return length == -1 ? caption.Length : length;
-                       }
-               }
-
-               string EtcKindToCaption (char etc)
-               {
-                       switch (etc) {
-                       case 'M':
-                               return "Methods";
-                       case 'P':
-                               return "Properties";
-                       case 'C':
-                               return "Constructors";
-                       case 'F':
-                               return "Fields";
-                       case 'E':
-                               return "Events";
-                       case 'O':
-                               return "Operators";
-                       case '*':
-                               return "Members";
-                       default:
-                               return null;
-                       }
-               }
-
-               string MemberKindToCaption (EcmaDesc.Kind kind)
-               {
-                       switch (kind) {
-                       case EcmaDesc.Kind.Method:
-                               return "Methods";
-                       case EcmaDesc.Kind.Property:
-                               return "Properties";
-                       case EcmaDesc.Kind.Constructor:
-                               return "Constructors";
-                       case EcmaDesc.Kind.Field:
-                               return "Fields";
-                       case EcmaDesc.Kind.Event:
-                               return "Events";
-                       case EcmaDesc.Kind.Operator:
-                               return "Operators";
-                       default:
-                               return null;
-                       }
-               }
-
-               Node FindNodeForCaption (List<Node> nodes, string caption)
-               {
-                       foreach (var node in nodes)
-                               if (node.Caption.Equals (caption, StringComparison.OrdinalIgnoreCase))
-                                       return node;
-                       return null;
-               }
-
-               string GetArgs (string hash, Node node)
-               {
-                       var args = new Dictionary<string, string> ();
-                       
-                       args["source-id"] = SourceID.ToString ();
-                       
-                       if (node != null) {
-                               var nodeType = GetNodeType (node);
-                               switch (nodeType) {
-                               case EcmaNodeType.Namespace:
-                                       args["show"] = "namespace";
-                                       args["namespace"] = node.Element.Substring ("N:".Length);
-                                       break;
-                               case EcmaNodeType.Type:
-                                       args["show"] = "typeoverview";
-                                       break;
-                               case EcmaNodeType.Member:
-                               case EcmaNodeType.Meta:
-                                       switch (GetNodeMemberTypeChar (node)){
-                                       case 'C':
-                                               args["membertype"] = "Constructor";
-                                               break;
-                                       case 'M':
-                                               args["membertype"] = "Method";
-                                               break;
-                                       case 'P':
-                                               args["membertype"] = "Property";
-                                               break;
-                                       case 'F':
-                                               args["membertype"] = "Field";
-                                               break;
-                                       case 'E':
-                                               args["membertype"] = "Event";
-                                               break;
-                                       case 'O':
-                                               args["membertype"] = "Operator";
-                                               break;
-                                       case 'X':
-                                               args["membertype"] = "ExtensionMethod";
-                                               break;
-                                       case '*':
-                                               args["membertype"] = "All";
-                                               break;
-                                       }
-
-                                       if (nodeType == EcmaNodeType.Meta) {
-                                               args["show"] = "members";
-                                               args["index"] = "all";
-                                       } else {
-                                               args["show"] = "member";
-                                               args["index"] = node.Element;
-                                       }
-                                       break;
-                               }
-                       }
-
-                       if (!string.IsNullOrEmpty (hash))
-                               args["hash"] = hash;
-
-                       return "?" + string.Join ("&", args.Select (kvp => kvp.Key == kvp.Value ? kvp.Key : kvp.Key + '=' + kvp.Value));
-               }
-
                public override void PopulateIndex (IndexMaker index_maker)
                {
                        foreach (Node ns_node in Tree.RootNode.Nodes){
@@ -824,7 +570,7 @@ namespace Monodoc.Providers
                                                                }
 
                                                                SearchableDocument doc_nod = searchDoc.Reset ();
-                                                               doc_nod.Title = LargeName (nc) + " " + EtcKindToCaption (c.Caption[0]);
+                                                               doc_nod.Title = LargeName (nc) + " " + EcmaDoc.EtcKindToCaption (c.Caption[0]);
                                                                doc_nod.FullTitle = ns_node.Caption + '.' + typename + "::" + nc.Caption;
                                                                doc_nod.HotText = string.Empty;