7 using System.Xml.XPath;
8 using System.Collections.Generic;
10 using Mono.Documentation;
11 using BF = System.Reflection.BindingFlags;
13 namespace Monodoc.Generators.Html
15 public class Ecma2Html : IHtmlExporter
17 static string css_ecma;
19 static XslCompiledTransform ecma_transform;
20 readonly ExtensionObject ExtObject = new ExtensionObject ();
26 public string CssCode {
30 var assembly = typeof(Ecma2Html).Assembly;
31 Stream str_css = assembly.GetManifestResourceStream ("mono-ecma.css");
32 css_ecma = (new StreamReader (str_css)).ReadToEnd();
37 public string JsCode {
41 var assembly = typeof(Ecma2Html).Assembly;
42 Stream str_js = assembly.GetManifestResourceStream ("helper.js");
43 js = (new StreamReader (str_js)).ReadToEnd();
48 public string Htmlize (XmlReader ecma_xml, Dictionary<string, string> extraArgs)
50 var args = new XsltArgumentList ();
51 args.AddExtensionObject("monodoc:///extensions", ExtObject);
53 if (extraArgs.TryGetValue ("specialpage", out specialPage) && specialPage == "root") {
54 extraArgs.Remove ("specialpage");
55 extraArgs["show"] = "masteroverview";
58 foreach (var kvp in extraArgs)
59 args.AddParam (kvp.Key, string.Empty, kvp.Value);
61 return Htmlize (ecma_xml, args);
64 public string Htmlize (XmlReader ecma_xml, XsltArgumentList args)
68 var output = new StringBuilder ();
69 ecma_transform.Transform (ecma_xml,
71 XmlWriter.Create (output, ecma_transform.OutputSettings),
72 CreateDocumentResolver ());
73 return output.ToString ();
76 protected virtual XmlResolver CreateDocumentResolver ()
78 // results in using XmlUrlResolver
82 public string Export (Stream stream, Dictionary<string, string> extraArgs)
84 return Htmlize (XmlReader.Create (WrapStream (new StreamReader (stream), extraArgs)), extraArgs);
87 public string Export (string input, Dictionary<string, string> extraArgs)
89 return Htmlize (XmlReader.Create (WrapStream (new StringReader (input), extraArgs)), extraArgs);
92 TextReader WrapStream (TextReader initialReader, Dictionary<string, string> renderArgs)
95 if (renderArgs.TryGetValue ("show", out show) && show == "namespace")
96 return new AvoidCDataTextReader (initialReader);
100 static void EnsureTransform ()
102 if (ecma_transform == null) {
103 ecma_transform = new XslCompiledTransform ();
104 var assembly = System.Reflection.Assembly.GetCallingAssembly ();
106 Stream stream = assembly.GetManifestResourceStream ("mono-ecma-css.xsl");
107 XmlReader xml_reader = new XmlTextReader (stream);
108 XmlResolver r = new ManifestResourceResolver (".");
109 ecma_transform.Load (xml_reader, XsltSettings.TrustedXslt, r);
113 public class ExtensionObject
116 Dictionary<string, System.Reflection.Assembly> assemblyCache = new Dictionary<string, System.Reflection.Assembly> ();
118 public string Colorize(string code, string lang)
120 return Mono.Utilities.Colorizer.Colorize(code,lang);
123 // Used by stylesheet to nicely reformat the <see cref=> tags.
124 public string MakeNiceSignature(string sig, string contexttype)
132 sig = sig.Substring(2);
135 case 'N': return sig;
136 case 'T': return ShortTypeName (sig, contexttype);
138 case 'C': case 'M': case 'P': case 'F': case 'E':
139 string type, mem, arg;
143 if (s == 'C' || s == 'M')
144 paren = sig.IndexOf("(");
146 paren = sig.IndexOf("[");
150 if (paren > 0 && paren < sig.Length-1) {
151 string[] args = sig.Substring(paren+1, sig.Length-paren-2).Split(',');
152 for (int i = 0; i < args.Length; i++)
153 args[i] = ShortTypeName(args[i], contexttype);
154 arg = "(" + String.Join(", ", args) + ")";
155 sig = sig.Substring(0, paren);
160 // Get type and member names
161 int dot = sig.LastIndexOf(".");
162 if (s == 'C' || dot <= 0 || dot == sig.Length-1) {
166 type = sig.Substring(0, dot);
167 mem = sig.Substring(dot);
170 type = ShortTypeName(type, contexttype);
172 return type + mem + arg;
179 static string ShortTypeName(string name, string contexttype)
181 int dot = contexttype.LastIndexOf(".");
182 if (dot < 0) return name;
183 string contextns = contexttype.Substring(0, dot+1);
185 if (name == contexttype)
186 return name.Substring(dot+1);
188 if (name.StartsWith(contextns))
189 return name.Substring(contextns.Length);
191 return name.Replace("+", ".");
194 string MonoImpInfo(string assemblyname, string typename, string membername, string arglist, bool strlong)
199 var a = new List<string> ();
200 if (!string.IsNullOrEmpty (arglist)) a.Add (arglist);
201 return MonoImpInfo(assemblyname, typename, membername, a, strlong);
204 string MonoImpInfo(string assemblyname, string typename, string membername, XPathNodeIterator itr, bool strlong)
209 var rgs = itr.Cast<XPathNavigator> ().Select (nav => nav.Value).ToList ();
211 return MonoImpInfo (assemblyname, typename, membername, rgs, strlong);
214 string MonoImpInfo(string assemblyname, string typename, string membername, List<string> arglist, bool strlong)
217 System.Reflection.Assembly assembly = null;
220 if (!assemblyCache.TryGetValue (assemblyname, out assembly)) {
221 assembly = System.Reflection.Assembly.LoadWithPartialName(assemblyname);
222 if (assembly != null)
223 assemblyCache[assemblyname] = assembly;
225 } catch (Exception) {
229 if (assembly == null) {
230 /*if (strlong) return "The assembly " + assemblyname + " is not available to MonoDoc.";
231 else return string.Empty;*/
232 return string.Empty; // silently ignore
235 Type t = assembly.GetType(typename, false);
238 return typename + " has not been implemented.";
240 return "Not implemented.";
243 // The following code is flakey and fails to find existing members
245 } catch (Exception) {
250 string MonoImpInfo(System.Reflection.MemberInfo mi, string itemtype, bool strlong)
255 string s = string.Empty;
257 object[] atts = mi.GetCustomAttributes(true);
259 foreach (object att in atts) if (att.GetType().Name == "MonoTODOAttribute") todoctr++;
263 s = "This " + itemtype + " is marked as being unfinished.<BR/>\n";
271 public string MonoImpInfo(string assemblyname, string typename, bool strlong)
277 if (assemblyname == string.Empty)
280 System.Reflection.Assembly assembly;
281 if (!assemblyCache.TryGetValue (assemblyname, out assembly)) {
282 assembly = System.Reflection.Assembly.LoadWithPartialName(assemblyname);
283 if (assembly != null)
284 assemblyCache[assemblyname] = assembly;
287 if (assembly == null)
290 Type t = assembly.GetType(typename, false);
293 return typename + " has not been implemented.";
295 return "Not implemented.";
298 string s = MonoImpInfo(t, "type", strlong);
301 var mis = t.GetMembers (BF.Static | BF.Instance | BF.Public | BF.NonPublic);
303 // Scan members for MonoTODO attributes
305 foreach (var mi in mis) {
306 string mii = MonoImpInfo(mi, null, false);
307 if (mii != string.Empty) mctr++;
310 s += "This type has " + mctr + " members that are marked as unfinished.<BR/>";
316 } catch (Exception) {
321 public bool MonoEditing ()
326 public bool IsToBeAdded(string text)
328 return text.StartsWith ("To be added");
333 public class AvoidCDataTextReader : TextReader
335 static readonly char[] CDataPattern = new[] {
336 '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '['
338 static readonly char[] CDataClosingPattern = new[] {
341 TextReader wrappedReader;
342 char[] backingArray = new char[9]; // "<![CDATA[".Length
343 int currentIndex = -1;
347 public AvoidCDataTextReader (TextReader wrappedReader)
349 this.wrappedReader = wrappedReader;
352 public override int Peek ()
354 if (!EnsureBuffer ())
356 return (int)backingArray[currentIndex];
359 public override int Read ()
361 if (!EnsureBuffer ())
363 var result = (int)backingArray[currentIndex];
364 var next = wrappedReader.Read ();
365 if (next == -1 && eofIndex == -1)
366 eofIndex = currentIndex;
368 backingArray[currentIndex] = (char)next;
369 currentIndex = (currentIndex + 1) % backingArray.Length;
373 void ReadLength (int length)
375 for (int i = 0; i < length; i++)
381 if (currentIndex == -1) {
383 var read = wrappedReader.ReadBlock (backingArray, 0, backingArray.Length);
384 if (read < backingArray.Length)
387 } else if (currentIndex == eofIndex) {
390 if (!inCData && PatternDetect (CDataPattern)) {
392 ReadLength (CDataPattern.Length);
393 return EnsureBuffer ();
395 if (inCData && PatternDetect (CDataClosingPattern)) {
397 ReadLength (CDataClosingPattern.Length);
398 return EnsureBuffer ();
404 bool PatternDetect (char[] pattern)
406 return backingArray[currentIndex] == pattern[0] && Enumerable.Range (1, pattern.Length - 1).All (i => backingArray[(currentIndex + i) % backingArray.Length] == pattern[i]);