Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / tools / monkeydoc / Monkeydoc / providers / ecmaspec-provider.cs
1 //
2 // The ecmaspec provider is for ECMA specifications
3 //
4 // Authors:
5 //      John Luke (jluke@cfl.rr.com)
6 //      Ben Maurer (bmaurer@users.sourceforge.net)
7 //
8 // Use like this:
9 //   mono assembler.exe --ecmaspec DIRECTORY --out name
10 //
11
12 using System;
13 using System.Diagnostics;
14 using System.IO;
15 using System.Text;
16 using System.Xml.XPath;
17 using System.Xml.Xsl;
18 using System.Xml;
19 using System.Collections.Generic;
20 using Mono.Lucene.Net.Index;
21 using Mono.Lucene.Net.Documents;
22
23 namespace MonkeyDoc.Providers
24 {
25         public class EcmaSpecProvider : Provider
26         {
27                 string basedir;
28         
29                 public EcmaSpecProvider (string base_directory)
30                 {
31                         basedir = base_directory;
32                         if (!Directory.Exists (basedir))
33                                 throw new DirectoryNotFoundException (String.Format ("The directory `{0}' does not exist", basedir));
34                 }
35         
36                 public override void PopulateTree (Tree tree)
37                 {
38                         XPathNavigator n = new XPathDocument (Path.Combine (basedir, "toc.xml")).CreateNavigator ();
39                         n.MoveToRoot ();
40                         n.MoveToFirstChild ();
41                         PopulateNode (n.SelectChildren ("node", ""), tree.RootNode);
42                 }
43         
44                 void PopulateNode (XPathNodeIterator nodes, Node treeNode)
45                 {
46                         foreach (XPathNavigator n in nodes) {
47                                 string secNumber = n.GetAttribute ("number", "");
48                                 string secName = n.GetAttribute ("name", "");
49
50                                 var storage = treeNode.Tree.HelpSource.Storage;
51                                 using (var file = File.OpenRead (Path.Combine (basedir, secNumber + ".xml")))
52                                         storage.Store (secNumber, file);
53
54                                 Node thisNode = treeNode.GetOrCreateNode (secNumber + ": " + secName, "ecmaspec:" + secNumber);
55                         
56                                 if (n.HasChildren)
57                                         PopulateNode (n.SelectChildren ("node", ""), thisNode);
58                         }
59                 }
60
61                 public override void CloseTree (HelpSource hs, Tree tree)
62                 {
63                 }
64         }
65
66         public class EcmaSpecHelpSource : HelpSource
67         {
68                 const string EcmaspecPrefix = "ecmaspec:";
69                 const string TocPart = "%toc"; // What is returned as TocXml
70                 const string SpecPart = "%spec"; // What is returned as Ecmaspec
71
72                 public EcmaSpecHelpSource (string base_file, bool create) : base (base_file, create)
73                 {
74                 }
75
76                 public override DocumentType GetDocumentTypeForId (string id, out Dictionary<string, string> extraParams)
77                 {
78                         extraParams = null;
79                         return id.EndsWith (TocPart) ? DocumentType.TocXml : DocumentType.EcmaSpecXml;
80                 }
81
82                 public override bool IsGeneratedContent (string id)
83                 {
84                         return id == "root:" || id.EndsWith (TocPart);
85                 }
86
87                 public override bool IsMultiPart (string id, out IEnumerable<string> parts)
88                 {
89                         if (id == "root:" || id.EndsWith (TocPart) || id.EndsWith (SpecPart)) {
90                                 parts = null;
91                                 return false;
92                         }
93                         parts = MakeMultiPart (id);
94                         return true;
95                 }
96
97                 IEnumerable<string> MakeMultiPart (string baseId)
98                 {
99                         yield return baseId + SpecPart;
100                         yield return baseId + TocPart;
101                 }
102
103                 public override string GetText (string id)
104                 {
105                         Node n = id == "root:" ? Tree.RootNode : MatchNode (EcmaspecPrefix + id.Substring (0, id.Length - TocPart.Length));
106                         if (n == null)
107                                 throw new ArgumentException ("id", string.Format ("{0} -> {1}", id, EcmaspecPrefix + id.Substring (0, id.Length - TocPart.Length)));
108                         return TreeDumper.ExportToTocXml (n, "C# Language Specification", "In this section:");
109                 }
110
111                 public override Stream GetHelpStream (string id)
112                 {
113                         return id.EndsWith (SpecPart) ? base.GetHelpStream (id.Substring (0, id.IndexOf (SpecPart))) : base.GetHelpStream (id);
114                 }
115         
116                 public override void PopulateSearchableIndex (IndexWriter writer) 
117                 {
118                         foreach (Node n in Tree.RootNode.Nodes)
119                                 AddDocuments (writer, n);
120                 }
121
122                 protected override string UriPrefix {
123                         get {
124                                 return EcmaspecPrefix;
125                         }
126                 }
127
128                 void AddDocuments (IndexWriter writer, Node node) 
129                 {
130                         string url = node.PublicUrl;
131                         Stream file_stream = GetHelpStream (url.Substring (9));
132                         if (file_stream == null) //Error
133                                 return;
134                         XmlDocument xdoc = new XmlDocument ();
135                         xdoc.Load (new XmlTextReader (file_stream));
136
137                         //Obtain the title
138                         XmlNode nelem = xdoc.DocumentElement;
139                         string title = nelem.Attributes["number"].Value + ": " + nelem.Attributes["title"].Value;
140
141                         //Obtain the text
142                         StringBuilder s = new StringBuilder ();
143                         GetTextNode (nelem, s);
144                         string text = s.ToString ();
145
146                         //Obtain the examples
147                         StringBuilder s2 = new StringBuilder ();
148                         GetExamples (nelem, s2);
149                         string examples = s2.ToString ();
150
151                         //Write to the Lucene Index all the parts
152                         SearchableDocument doc = new SearchableDocument ();
153                         doc.title = title;
154                         doc.hottext = title.Substring (title.IndexOf (':')); 
155                         doc.url = url;
156                         doc.text = text;
157                         doc.examples = examples;
158                         writer.AddDocument (doc.LuceneDoc);
159                 
160                         if (node.IsLeaf)
161                                 return;
162
163                         foreach (Node n in node.Nodes)
164                                 AddDocuments (writer, n);
165                 }
166
167                 void GetTextNode (XmlNode n, StringBuilder s) 
168                 {
169                         //dont include c# code
170                         if (n.Name == "code_example")
171                                 return;
172                         //include all text from nodes
173                         if (n.NodeType == XmlNodeType.Text)
174                                 s.Append (n.Value);
175                 
176                         //recursively explore all nodes
177                         if (n.HasChildNodes)
178                                 foreach (XmlNode n_child in n.ChildNodes)
179                                         GetTextNode (n_child, s);
180                 }
181
182                 void GetExamples (XmlNode n, StringBuilder s)
183                 {
184                         if (n.Name == "code_example") {
185                                 if (n.FirstChild.Name == "#cdata-section")
186                                         s.Append (n.FirstChild.Value);
187                         } else {
188                                 if (n.HasChildNodes)
189                                         foreach (XmlNode n_child in n.ChildNodes)
190                                                 GetExamples (n_child, s);
191                         }
192                 }
193         }
194 }