//
// The ecmaspec provider is for ECMA specifications
//
// Authors:
// John Luke (jluke@cfl.rr.com)
// Ben Maurer (bmaurer@users.sourceforge.net)
//
// Use like this:
// mono assembler.exe --ecmaspec DIRECTORY --out name
//
namespace Monodoc {
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Xml;
using System.Collections;
using Mono.Lucene.Net.Index;
using Mono.Lucene.Net.Documents;
public class EcmaSpecProvider : Provider {
string basedir;
public EcmaSpecProvider (string base_directory)
{
basedir = base_directory;
if (!Directory.Exists (basedir))
throw new FileNotFoundException (String.Format ("The directory `{0}' does not exist", basedir));
}
public override void PopulateTree (Tree tree)
{
XPathNavigator n = new XPathDocument (Path.Combine (basedir, "toc.xml")).CreateNavigator ();
n.MoveToRoot ();
n.MoveToFirstChild ();
PopulateNode (n.SelectChildren ("node", ""), tree);
}
void PopulateNode (XPathNodeIterator nodes, Node treeNode)
{
while (nodes.MoveNext ()) {
XPathNavigator n = nodes.Current;
string secNumber = n.GetAttribute ("number", ""),
secName = n.GetAttribute ("name", "");
treeNode.tree.HelpSource.Message (TraceLevel.Info, "\tSection: " + secNumber);
treeNode.tree.HelpSource.PackFile (Path.Combine (basedir, secNumber + ".xml"), secNumber);
Node thisNode = treeNode.LookupNode (secNumber + ": " + secName, "ecmaspec:" + secNumber);
if (n.HasChildren)
PopulateNode (n.SelectChildren ("node", ""), thisNode);
}
}
public override void CloseTree (HelpSource hs, Tree tree)
{
}
}
public class EcmaSpecHelpSource : HelpSource {
public EcmaSpecHelpSource (string base_file, bool create) : base (base_file, create)
{
}
public override string InlineCss {
get {return base.InlineCss + css_ecmaspec_code;}
}
public override string GetText (string url, out Node match_node)
{
string ret = null;
match_node = null;
if (url.StartsWith ("ecmaspec:")) {
match_node = MatchNode (Tree, url);
ret = GetTextFromUrl (url);
}
if (url == "root:") {
if (use_css)
ret = "
";
else
ret = "C# Language Specification |
";
match_node = Tree;
}
if (ret != null && match_node != null && match_node.Nodes != null && match_node.Nodes.Count > 0) {
ret += "In This Section:
\n";
}
if (ret != null)
return BuildHtml (css_ecmaspec_code, ret);
else
return null;
}
private Node MatchNode (Node node, string matchurl)
{
foreach (Node n in node.Nodes) {
if (matchurl == n.Element)
return n;
else if (matchurl.StartsWith (n.Element + ".") && !n.IsLeaf)
return MatchNode (n, matchurl);
}
return null;
}
string GetTextFromUrl (string url)
{
Stream file_stream = GetHelpStream (url.Substring (9));
if (file_stream == null)
return null;
return Htmlize (new XPathDocument (file_stream));
}
static string css_ecmaspec;
public static string css_ecmaspec_code {
get {
if (css_ecmaspec != null)
return css_ecmaspec;
if (use_css) {
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
Stream str_css = assembly.GetManifestResourceStream ("ecmaspec.css");
css_ecmaspec = (new StreamReader (str_css)).ReadToEnd();
} else {
css_ecmaspec = String.Empty;
}
return css_ecmaspec;
}
}
class ExtObj {
public string Colorize (string code, string lang) {
return (Mono.Utilities.Colorizer.Colorize(code,lang));
}
}
static XslTransform ecma_transform;
static XsltArgumentList args = new XsltArgumentList();
static string Htmlize (XPathDocument ecma_xml)
{
if (ecma_transform == null){
ecma_transform = new XslTransform ();
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
Stream stream;
if (use_css)
stream = assembly.GetManifestResourceStream ("ecmaspec-html-css.xsl");
else
stream = assembly.GetManifestResourceStream ("ecmaspec-html.xsl");
XmlReader xml_reader = new XmlTextReader (stream);
ecma_transform.Load (xml_reader, null, null);
args.AddExtensionObject ("monodoc:///extensions", new ExtObj());
}
if (ecma_xml == null) return "";
StringWriter output = new StringWriter ();
ecma_transform.Transform (ecma_xml, args, output, null);
return output.ToString ();
}
public override void PopulateSearchableIndex (IndexWriter writer)
{
foreach (Node n in Tree.Nodes)
AddDocuments (writer, n);
}
void AddDocuments (IndexWriter writer, Node node)
{
string url = node.URL;
Stream file_stream = GetHelpStream (url.Substring (9));
if (file_stream == null) //Error
return;
XmlDocument xdoc = new XmlDocument ();
xdoc.Load (new XmlTextReader (file_stream));
//Obtain the title
XmlNode nelem = xdoc.DocumentElement;
string title = nelem.Attributes["number"].Value + ": " + nelem.Attributes["title"].Value;
//Obtain the text
StringBuilder s = new StringBuilder ();
GetTextNode (nelem, s);
string text = s.ToString ();
//Obatin the examples
StringBuilder s2 = new StringBuilder ();
GetExamples (nelem, s2);
string examples = s2.ToString ();
//Write to the Lucene Index all the parts
SearchableDocument doc = new SearchableDocument ();
doc.title = title;
doc.hottext = title.Substring (title.IndexOf (':'));
doc.url = url;
doc.text = text;
doc.examples = examples;
writer.AddDocument (doc.LuceneDoc);
if (node.IsLeaf)
return;
foreach (Node n in node.Nodes)
AddDocuments (writer, n);
}
void GetTextNode (XmlNode n, StringBuilder s)
{
//dont include c# code
if (n.Name == "code_example")
return;
//include all text from nodes
if (n.NodeType == XmlNodeType.Text)
s.Append (n.Value);
//recursively explore all nodes
if (n.HasChildNodes)
foreach (XmlNode n_child in n.ChildNodes)
GetTextNode (n_child, s);
}
void GetExamples (XmlNode n, StringBuilder s)
{
if (n.Name == "code_example") {
if (n.FirstChild.Name == "#cdata-section")
s.Append (n.FirstChild.Value);
} else {
if (n.HasChildNodes)
foreach (XmlNode n_child in n.ChildNodes)
GetExamples (n_child, s);
}
}
}
}