// Miguel de Icaza (miguel@ximian.com)
//
// (C) 2002, Ximian, Inc.
+// Copyright 2003-2011 Novell
+// Copyright 2011 Xamarin Inc
//
// TODO:
// Each node should have a provider link
//
namespace Monodoc {
using System;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Diagnostics;
using System.Configuration;
-using System.Text.RegularExpressions;
+using System.Reflection;
using System.Xml;
using System.Xml.XPath;
using ICSharpCode.SharpZipLib.Zip;
-using Monodoc.Lucene.Net.Index;
-using Monodoc.Lucene.Net.Analysis.Standard;
+using Mono.Lucene.Net.Index;
+using Mono.Lucene.Net.Analysis.Standard;
+
+using Mono.Documentation;
+
/// <summary>
/// This tree is populated by the documentation providers, or populated
/// from a binary encoding of the tree. The format of the tree is designed
protected ArrayList nodes;
protected internal int position;
+ static ArrayList empty = ArrayList.ReadOnly(new ArrayList(0));
+
/// <summary>
/// Creates a node, called by the Tree.
/// </summary>
get {
if (position < 0)
LoadNode ();
- return nodes;
+ return nodes != null ? nodes : empty;
}
}
public static void PrintTree (Node node)
{
Indent ();
- Console.WriteLine ("{0},{1}", node.Element, node.Caption);
- if (node.Nodes == null)
+ Console.WriteLine ("{0},{1}\t[PublicUrl: {2}]", node.Element, node.Caption, node.PublicUrl);
+ if (node.Nodes.Count == 0)
return;
indent++;
- foreach (Node n in node.nodes)
+ foreach (Node n in node.Nodes)
PrintTree (n);
indent--;
}
nodes.Sort ();
}
+ [Obsolete("Use PublicUrl")]
public string URL {
get {
if (position < 0)
}
}
+ public string PublicUrl {
+ get {
+ return tree.HelpSource != null
+ ? tree.HelpSource.GetPublicUrl (URL)
+ : URL;
+ }
+ }
+
int IComparable.CompareTo (object obj)
{
Node other = obj as Node;
if (other.position < 0)
other.LoadNode ();
- Regex digits = new Regex (@"([\d]+)|([^\d]+)");
- MatchEvaluator eval = delegate (Match m) {
- return (m.Value.Length > 0 && char.IsDigit (m.Value [0]))
- ? m.Value.PadLeft (System.Math.Max (caption.Length, other.caption.Length))
- : m.Value;
- };
- return digits.Replace (caption, eval).CompareTo (digits.Replace (other.caption, eval));
+ var cap1 = caption;
+ var cap2 = other.caption;
+
+ /* Some node (notably from ecmaspec) have number prepended to them
+ * which we need to sort better by padding them to the same number
+ * of digits
+ */
+ if (char.IsDigit (cap1[0]) && char.IsDigit (cap2[0])) {
+ int c1 = cap1.TakeWhile (char.IsDigit).Count ();
+ int c2 = cap2.TakeWhile (char.IsDigit).Count ();
+
+ if (c1 != c2) {
+ cap1 = cap1.PadLeft (cap1.Length + Math.Max (0, c2 - c1), '0');
+ cap2 = cap2.PadLeft (cap2.Length + Math.Max (0, c1 - c2), '0');
+ }
+ }
+
+ return string.Compare (cap1, cap2, StringComparison.OrdinalIgnoreCase);
}
}
public static bool FullHtml = true;
+ // should only be enabled by ASP.NET webdoc
+ public static bool UseWebdocCache;
+
//
// The unique ID for this HelpSource.
//
int source_id;
DateTime zipFileWriteTime;
string name;
+ string basepath;
TraceLevel trace_level = TraceLevel.Warning;
+ protected bool nozip;
+ protected string base_dir;
public HelpSource (string base_filename, bool create)
{
this.name = Path.GetFileName (base_filename);
+ this.basepath = Path.GetDirectoryName (base_filename);
tree_filename = base_filename + ".tree";
zip_filename = base_filename + ".zip";
+ base_dir = XmlDocUtils.GetCacheDirectory (base_filename);
+ if (UseWebdocCache && !create && Directory.Exists (base_dir)) {
+ nozip = true;
+ }
if (create)
SetupForOutput ();
}
}
+ /* This gives the full path of the source/ directory */
+ public string BaseFilePath {
+ get {
+ return basepath;
+ }
+ }
+
public TraceLevel TraceLevel {
get { return trace_level; }
set { trace_level = value; }
}
+
+ public string BaseDir {
+ get {
+ return base_dir;
+ }
+ }
ZipFile zip_file;
/// <summary>
/// Returns a stream from the packaged help source archive
/// </summary>
- public Stream GetHelpStream (string id)
+ public virtual Stream GetHelpStream (string id)
{
+ if (nozip) {
+ string path = XmlDocUtils.GetCachedFileName (base_dir, id);
+ if (File.Exists (path))
+ return File.OpenRead (path);
+ return null;
+ }
+
if (zip_file == null)
zip_file = new ZipFile (zip_filename);
public XmlReader GetHelpXml (string id)
{
+ if (nozip) {
+ Stream s = File.OpenRead (XmlDocUtils.GetCachedFileName (base_dir, id));
+ string url = "monodoc:///" + SourceID + "@" + Uri.EscapeUriString (id) + "@";
+ return new XmlTextReader (url, s);
+ }
+
if (zip_file == null)
zip_file = new ZipFile (zip_filename);
ZipEntry entry = zip_file.GetEntry (id);
if (entry != null) {
Stream s = zip_file.GetInputStream (entry);
- string url = "monodoc:///" + SourceID + "@" + System.Web.HttpUtility.UrlEncode (id) + "@";
+ string url = "monodoc:///" + SourceID + "@" + Uri.EscapeUriString (id) + "@";
return new XmlTextReader (url, s);
}
return null;
}
- public XmlDocument GetHelpXmlWithChanges (string id)
+ public virtual XmlDocument GetHelpXmlWithChanges (string id)
{
+ if (nozip) {
+ Stream s = File.OpenRead (XmlDocUtils.GetCachedFileName (base_dir, id));
+ string url = "monodoc:///" + SourceID + "@" + Uri.EscapeUriString (id) + "@";
+ XmlReader r = new XmlTextReader (url, s);
+ XmlDocument ret = new XmlDocument ();
+ ret.Load (r);
+ return ret;
+ }
+
if (zip_file == null)
zip_file = new ZipFile (zip_filename);
ZipEntry entry = zip_file.GetEntry (id);
if (entry != null) {
Stream s = zip_file.GetInputStream (entry);
- string url = "monodoc:///" + SourceID + "@" + System.Web.HttpUtility.UrlEncode (id) + "@";
+ string url = "monodoc:///" + SourceID + "@" + Uri.EscapeUriString (id) + "@";
XmlReader r = new XmlTextReader (url, s);
XmlDocument ret = new XmlDocument ();
ret.Load (r);
{
throw new NotImplementedException ();
}
+
+ public virtual string GetPublicUrl (string id)
+ {
+ return id;
+ }
public virtual string GetText (string url, out Node n)
{
return null;
}
+ protected string GetCachedText (string url)
+ {
+ if (!nozip)
+ return null;
+ string file = XmlDocUtils.GetCachedFileName (base_dir, url);
+ if (!File.Exists (file))
+ return null;
+ return File.OpenText (file).ReadToEnd ();
+ }
+
public virtual Stream GetImage (string url)
{
return null;
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
Stream str_js = assembly.GetManifestResourceStream ("helper.js");
StringBuilder sb = new StringBuilder ((new StreamReader (str_js)).ReadToEnd());
+ output.Write ("<script type=\"text/JavaScript\">\n");
output.Write (sb.ToString ());
+ output.Write ("</script>\n");
if (js != null) {
output.Write ("<script type=\"text/JavaScript\">\n");
public static RootTree LoadTree ()
{
- string basedir;
- string myPath = System.Reflection.Assembly.GetExecutingAssembly ().Location;
- string cfgFile = myPath + ".config";
- if (!File.Exists (cfgFile)) {
- basedir = ".";
- return LoadTree (basedir);
- }
-
- XmlDocument d = new XmlDocument ();
- d.Load (cfgFile);
- basedir = d.SelectSingleNode ("config/path").Attributes ["docsPath"].Value;
-
- return LoadTree (basedir);
+ return LoadTree (null);
}
+
+ const string MacMonoDocDir = "/Library/Frameworks/Mono.framework/Versions/Current/lib/monodoc";
//
// Loads the tree layout
//
public static RootTree LoadTree (string basedir)
{
- XmlDocument doc = new XmlDocument ();
+ if (basedir == null) {
+ string myPath = System.Reflection.Assembly.GetExecutingAssembly ().Location;
+ string cfgFile = myPath + ".config";
+ if (!File.Exists (cfgFile)) {
+ basedir = ".";
+ }
+ else {
+ XmlDocument d = new XmlDocument ();
+ d.Load (cfgFile);
+ basedir = d.SelectSingleNode ("config/path").Attributes ["docsPath"].Value;
+ }
+ // Temporary workaround for developers distributing a monodoc.dll themselves on Mac
+ if (Directory.Exists (MacMonoDocDir)){
+ Console.WriteLine ("MacDir exists");
+ if (!File.Exists (Path.Combine (basedir, "monodoc.xml"))){
+ basedir = MacMonoDocDir;
+ }
+ }
+ }
- RootTree root = new RootTree ();
- root.basedir = basedir;
-
//
// Load the layout
//
+ XmlDocument doc = new XmlDocument ();
string layout = Path.Combine (basedir, "monodoc.xml");
doc.Load (layout);
- XmlNodeList nodes = doc.SelectNodes ("/node/node");
+
+ string osxExternalDir = "/Library/Frameworks/Mono.framework/External/monodoc";
+ string[] osxExternalSources = Directory.Exists (osxExternalDir)
+ ? Directory.GetFiles (osxExternalDir, "*.source")
+ : new string[0];
+
+ return LoadTree (basedir, doc,
+ Directory.GetFiles (Path.Combine (basedir, "sources"), "*.source")
+ .Concat (osxExternalSources));
+ }
+
+ // Compatibility shim w/ Mono 2.6
+ public static RootTree LoadTree (string indexDir, XmlDocument docTree, IEnumerable sourceFiles)
+ {
+ return LoadTree (indexDir, docTree, sourceFiles.Cast<string>());
+ }
+
+ public static RootTree LoadTree (string indexDir, XmlDocument docTree, IEnumerable<string> sourceFiles)
+ {
+ if (docTree == null) {
+ docTree = new XmlDocument ();
+ using (var defTree = typeof(RootTree).Assembly.GetManifestResourceStream ("monodoc.xml"))
+ docTree.Load (defTree);
+ }
+
+
+ sourceFiles = sourceFiles ?? new string [0];
+
+ //
+ // Load the layout
+ //
+
+ RootTree root = new RootTree ();
+ root.basedir = indexDir;
+
+ XmlNodeList nodes = docTree.SelectNodes ("/node/node");
root.name_to_node ["root"] = root;
root.name_to_node ["libraries"] = root;
//
// Load the sources
//
- string sources_dir = Path.Combine (basedir, "sources");
-
- string [] files = Directory.GetFiles (sources_dir);
- foreach (string file in files){
- if (!file.EndsWith (".source"))
- continue;
-
- doc = new XmlDocument ();
- try {
- doc.Load (file);
- } catch {
- Console.Error.WriteLine ("Error: Could not load source file {0}", file);
- continue;
- }
-
- XmlNodeList extra_nodes = doc.SelectNodes ("/monodoc/node");
- if (extra_nodes.Count > 0)
- root.Populate (third_party, extra_nodes);
-
- XmlNodeList sources = doc.SelectNodes ("/monodoc/source");
- if (sources == null){
- Console.Error.WriteLine ("Error: No <source> section found in the {0} file", file);
- continue;
- }
- foreach (XmlNode source in sources){
- XmlAttribute a = source.Attributes ["provider"];
- if (a == null){
- Console.Error.WriteLine ("Error: no provider in <source>");
- continue;
- }
- string provider = a.InnerText;
- a = source.Attributes ["basefile"];
- if (a == null){
- Console.Error.WriteLine ("Error: no basefile in <source>");
- continue;
- }
- string basefile = a.InnerText;
- a = source.Attributes ["path"];
- if (a == null){
- Console.Error.WriteLine ("Error: no path in <source>");
- continue;
- }
- string path = a.InnerText;
-
- string basefilepath = Path.Combine (sources_dir, basefile);
- HelpSource hs = GetHelpSource (provider, basefilepath);
- if (hs == null)
- continue;
- hs.RootTree = root;
- root.help_sources.Add (hs);
- root.name_to_hs [path] = hs;
-
- Node parent = root.LookupEntryPoint (path);
- if (parent == null){
- Console.Error.WriteLine ("node `{0}' is not defined on the documentation map", path);
- parent = third_party;
- }
-
- foreach (Node n in hs.Tree.Nodes){
- parent.AddNode (n);
- }
- parent.Sort ();
- }
- }
+ foreach (var sourceFile in sourceFiles)
+ root.AddSourceFile (sourceFile);
foreach (string path in UncompiledHelpSources) {
EcmaUncompiledHelpSource hs = new EcmaUncompiledHelpSource(path);
+ hs.RootTree = root;
root.help_sources.Add (hs);
string epath = "extra-help-source-" + hs.Name;
Node hsn = root.CreateNode (hs.Name, "root:/" + epath);
return root;
}
+
+ public void AddSource (string sources_dir)
+ {
+ string [] files = Directory.GetFiles (sources_dir);
+
+ foreach (string file in files){
+ if (!file.EndsWith (".source"))
+ continue;
+ AddSourceFile (file);
+ }
+ }
+
+ Dictionary<string,string> loadedSourceFiles = new Dictionary<string,string> ();
+
+ public void AddSourceFile (string sourceFile)
+ {
+ if (loadedSourceFiles.ContainsKey (sourceFile))
+ return;
+
+ Node third_party = LookupEntryPoint ("various") ?? this;
+
+ XmlDocument doc = new XmlDocument ();
+ try {
+ doc.Load (sourceFile);
+ }
+ catch {
+ Console.Error.WriteLine ("Error: Could not load source file {0}", sourceFile);
+ return;
+ }
+
+ XmlNodeList extra_nodes = doc.SelectNodes ("/monodoc/node");
+ if (extra_nodes.Count > 0)
+ Populate (third_party, extra_nodes);
+
+ XmlNodeList sources = doc.SelectNodes ("/monodoc/source");
+ if (sources == null){
+ Console.Error.WriteLine ("Error: No <source> section found in the {0} file", sourceFile);
+ return;
+ }
+ loadedSourceFiles [sourceFile] = sourceFile;
+ foreach (XmlNode source in sources){
+ XmlAttribute a = source.Attributes ["provider"];
+ if (a == null){
+ Console.Error.WriteLine ("Error: no provider in <source>");
+ continue;
+ }
+ string provider = a.InnerText;
+ a = source.Attributes ["basefile"];
+ if (a == null){
+ Console.Error.WriteLine ("Error: no basefile in <source>");
+ continue;
+ }
+ string basefile = a.InnerText;
+ a = source.Attributes ["path"];
+ if (a == null){
+ Console.Error.WriteLine ("Error: no path in <source>");
+ continue;
+ }
+ string path = a.InnerText;
+
+ string basefilepath = Path.Combine (Path.GetDirectoryName (sourceFile), basefile);
+ HelpSource hs = GetHelpSource (provider, basefilepath);
+ if (hs == null)
+ continue;
+ hs.RootTree = this;
+ help_sources.Add (hs);
+ name_to_hs [path] = hs;
+
+ Node parent = LookupEntryPoint (path);
+ if (parent == null){
+ Console.Error.WriteLine ("node `{0}' is not defined on the documentation map", path);
+ parent = third_party;
+ }
+
+ foreach (Node n in hs.Tree.Nodes){
+ parent.AddNode (n);
+ }
+ parent.Sort ();
+ }
+ }
// Delete nodes which does not have documentaiton (source)
static bool PurgeNode(Node node)
return purge;
}
-
+
+ public static string[] GetSupportedFormats ()
+ {
+ return new string[]{
+ "ecma",
+ "ecmaspec",
+ "error",
+ "hb",
+ "man",
+ "simple",
+ "xhtml"
+ };
+ }
- static HelpSource GetHelpSource (string provider, string basefilepath)
+ public static HelpSource GetHelpSource (string provider, string basefilepath)
{
try {
switch (provider){
return new EcmaUncompiledHelpSource (basefilepath);
case "monohb":
return new MonoHBHelpSource(basefilepath, false);
- case "xhtml":
+ case "xhtml": case "hb":
return new XhtmlHelpSource (basefilepath, false);
case "man":
return new ManHelpSource (basefilepath, false);
return null;
}
}
-
+
+ public static Provider GetProvider (string provider, params string[] basefilepaths)
+ {
+ switch (provider) {
+ case "addins":
+ return new AddinsProvider (basefilepaths [0]);
+ case "ecma": {
+ EcmaProvider p = new EcmaProvider ();
+ foreach (string d in basefilepaths)
+ p.AddDirectory (d);
+ return p;
+ }
+ case "ecmaspec":
+ return new EcmaSpecProvider (basefilepaths [0]);
+ case "error":
+ return new ErrorProvider (basefilepaths [0]);
+ case "man":
+ return new ManProvider (basefilepaths);
+ case "simple":
+ return new SimpleProvider (basefilepaths [0]);
+ case "xhtml":
+ case "hb":
+ return new XhtmlProvider (basefilepaths [0]);
+ default:
+ throw new NotSupportedException (provider);
+ }
+ }
//
// Maintains the name to node mapping
return lastHelpSourceTime;
}
}
-
+
public static bool GetNamespaceAndType (string url, out string ns, out string type)
{
int nsidx = -1;
}
if (nsidx == -1) {
- Console.Error.WriteLine ("Did not find dot in: " + url);
ns = null;
type = null;
return false;
return (HelpSource) help_sources [id];
}
+ //
+ // Fetches the node title
+ //
+ public string GetTitle (string url)
+ {
+ Node match_node;
+
+ if (url == null || url.StartsWith ("root:"))
+ return "Mono Documentation";
+
+ if (url.Length > 2 && url [1] == ':'){
+ switch (url [0]){
+ case 'N':
+ return url.Substring (2) + " Namespace";
+
+ case 'T':
+ string s = TypeLookup (url, out match_node);
+ if (match_node != null)
+ return match_node.Caption;
+ return url.Substring (2) + " type";
+
+ case 'M':
+ case 'F':
+ case 'P':
+ case 'E':
+ case 'C':
+ case 'O':
+ MemberLookup (url.Substring (0,2), url, out match_node);
+ if (match_node != null)
+ return match_node.Caption;
+ break;
+ }
+ }
+
+ return "Mono Documentation";
+ }
+
string home_cache;
/// <summary>
/// Allows every HelpSource to try to provide the content for this
sb.Replace ("@@FONT_FAMILY@@", SettingsHandler.Settings.preferred_font_family);
sb.Replace ("@@FONT_SIZE@@", SettingsHandler.Settings.preferred_font_size.ToString());
//contributions
+ var visible = SettingsHandler.Settings.EnableEditing ? "block;" : "none;";
if ((oldContrib + contribs) == 0) {
sb.Replace ("@@CONTRIB_DISP@@", "display: none;");
+ sb.Replace ("@@NO_CONTRIB_DISP@@", "display: " + visible);
} else {
+ sb.Replace ("@@CONTRIB_DISP@@", "display: " + visible);
sb.Replace ("@@NO_CONTRIB_DISP@@", "display: none;");
sb.Replace ("@@CONTRIBS@@", con.ToString ());
}
+ sb.Replace ("@@EDITING_ENABLED@@", "display: " + visible);
// load the url of nodes
String add_str;
public static void MakeIndex ()
{
- RootTree root = LoadTree ();
+ MakeIndex (LoadTree ());
+ }
+
+ public static void MakeIndex (RootTree root)
+ {
if (root == null)
return;
// No octal in C#, how lame is that
chmod (path, 0x1a4);
}
- Console.WriteLine ("Documentation index updated");
+ Console.WriteLine ("Documentation index at {0} updated", path);
}
static bool IsUnix {
get {
int p = (int) Environment.OSVersion.Platform;
- return ((p == 4) || (p == 128));
+ return ((p == 4) || (p == 128) || (p == 6));
}
}
}
public static void MakeSearchIndex ()
+ {
+ MakeSearchIndex (LoadTree ());
+ }
+
+ public static void MakeSearchIndex (RootTree root)
{
// Loads the RootTree
Console.WriteLine ("Loading the monodoc tree...");
- RootTree root = LoadTree ();
+
if (root == null)
return;
if (!Directory.Exists (dir))
Directory.CreateDirectory (dir);
- writer = new IndexWriter(Lucene.Net.Store.FSDirectory.GetDirectory(dir, true), new StandardAnalyzer(), true);
+ writer = new IndexWriter(Mono.Lucene.Net.Store.FSDirectory.GetDirectory(dir, true), new StandardAnalyzer(), true);
} catch (UnauthorizedAccessException) {
//try in the .config directory
try {
if (!Directory.Exists (dir))
Directory.CreateDirectory (dir);
- writer = new IndexWriter(Lucene.Net.Store.FSDirectory.GetDirectory(dir, true), new StandardAnalyzer(), true);
+ writer = new IndexWriter(Mono.Lucene.Net.Store.FSDirectory.GetDirectory(dir, true), new StandardAnalyzer(), true);
} catch (UnauthorizedAccessException) {
Console.WriteLine ("You don't have permissions to write on " + dir);
return;