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
117 public string Colorize(string code, string lang)
119 return Mono.Utilities.Colorizer.Colorize(code,lang);
122 // Used by stylesheet to nicely reformat the <see cref=> tags.
123 public string MakeNiceSignature(string sig, string contexttype)
131 sig = sig.Substring(2);
134 case 'N': return sig;
135 case 'T': return ShortTypeName (sig, contexttype);
137 case 'C': case 'M': case 'P': case 'F': case 'E':
138 string type, mem, arg;
142 if (s == 'C' || s == 'M')
143 paren = sig.IndexOf("(");
145 paren = sig.IndexOf("[");
149 if (paren > 0 && paren < sig.Length-1) {
150 string[] args = sig.Substring(paren+1, sig.Length-paren-2).Split(',');
151 for (int i = 0; i < args.Length; i++)
152 args[i] = ShortTypeName(args[i], contexttype);
153 arg = "(" + String.Join(", ", args) + ")";
154 sig = sig.Substring(0, paren);
159 // Get type and member names
160 int dot = sig.LastIndexOf(".");
161 if (s == 'C' || dot <= 0 || dot == sig.Length-1) {
165 type = sig.Substring(0, dot);
166 mem = sig.Substring(dot);
169 type = ShortTypeName(type, contexttype);
171 return type + mem + arg;
178 static string ShortTypeName(string name, string contexttype)
180 int dot = contexttype.LastIndexOf(".");
181 if (dot < 0) return name;
182 string contextns = contexttype.Substring(0, dot+1);
184 if (name == contexttype)
185 return name.Substring(dot+1);
187 if (name.StartsWith(contextns))
188 return name.Substring(contextns.Length);
190 return name.Replace("+", ".");
193 string MonoImpInfo(string assemblyname, string typename, string membername, string arglist, bool strlong)
198 var a = new List<string> ();
199 if (!string.IsNullOrEmpty (arglist)) a.Add (arglist);
200 return MonoImpInfo(assemblyname, typename, membername, a, strlong);
203 string MonoImpInfo(string assemblyname, string typename, string membername, XPathNodeIterator itr, bool strlong)
208 var rgs = itr.Cast<XPathNavigator> ().Select (nav => nav.Value).ToList ();
210 return MonoImpInfo (assemblyname, typename, membername, rgs, strlong);
213 string MonoImpInfo(string assemblyname, string typename, string membername, List<string> arglist, bool strlong)
216 System.Reflection.Assembly assembly = null;
219 assembly = System.Reflection.Assembly.LoadWithPartialName(assemblyname);
220 } catch (Exception) {
224 if (assembly == null) {
225 /*if (strlong) return "The assembly " + assemblyname + " is not available to MonoDoc.";
226 else return string.Empty;*/
227 return string.Empty; // silently ignore
230 Type t = assembly.GetType(typename, false);
233 return typename + " has not been implemented.";
235 return "Not implemented.";
238 // The following code is flakey and fails to find existing members
240 } catch (Exception) {
245 string MonoImpInfo(System.Reflection.MemberInfo mi, string itemtype, bool strlong)
250 string s = string.Empty;
252 object[] atts = mi.GetCustomAttributes(true);
254 foreach (object att in atts) if (att.GetType().Name == "MonoTODOAttribute") todoctr++;
258 s = "This " + itemtype + " is marked as being unfinished.<BR/>\n";
266 public string MonoImpInfo(string assemblyname, string typename, bool strlong)
272 if (assemblyname == string.Empty)
275 var assembly = System.Reflection.Assembly.LoadWithPartialName(assemblyname);
276 if (assembly == null)
279 Type t = assembly.GetType(typename, false);
282 return typename + " has not been implemented.";
284 return "Not implemented.";
287 string s = MonoImpInfo(t, "type", strlong);
290 var mis = t.GetMembers (BF.Static | BF.Instance | BF.Public | BF.NonPublic);
292 // Scan members for MonoTODO attributes
294 foreach (var mi in mis) {
295 string mii = MonoImpInfo(mi, null, false);
296 if (mii != string.Empty) mctr++;
299 s += "This type has " + mctr + " members that are marked as unfinished.<BR/>";
305 } catch (Exception) {
310 public bool MonoEditing ()
315 public bool IsToBeAdded(string text)
317 return text.StartsWith ("To be added");
322 public class AvoidCDataTextReader : TextReader
324 static readonly char[] CDataPattern = new[] {
325 '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '['
327 static readonly char[] CDataClosingPattern = new[] {
330 TextReader wrappedReader;
331 char[] backingArray = new char[9]; // "<![CDATA[".Length
332 int currentIndex = -1;
336 public AvoidCDataTextReader (TextReader wrappedReader)
338 this.wrappedReader = wrappedReader;
341 public override int Peek ()
343 if (!EnsureBuffer ())
345 return (int)backingArray[currentIndex];
348 public override int Read ()
350 if (!EnsureBuffer ())
352 var result = (int)backingArray[currentIndex];
353 var next = wrappedReader.Read ();
354 if (next == -1 && eofIndex == -1)
355 eofIndex = currentIndex;
357 backingArray[currentIndex] = (char)next;
358 currentIndex = (currentIndex + 1) % backingArray.Length;
362 void ReadLength (int length)
364 for (int i = 0; i < length; i++)
370 if (currentIndex == -1) {
372 var read = wrappedReader.ReadBlock (backingArray, 0, backingArray.Length);
373 if (read < backingArray.Length)
376 } else if (currentIndex == eofIndex) {
379 if (!inCData && PatternDetect (CDataPattern)) {
381 ReadLength (CDataPattern.Length);
382 return EnsureBuffer ();
384 if (inCData && PatternDetect (CDataClosingPattern)) {
386 ReadLength (CDataClosingPattern.Length);
387 return EnsureBuffer ();
393 bool PatternDetect (char[] pattern)
395 return backingArray[currentIndex] == pattern[0] && Enumerable.Range (1, pattern.Length - 1).All (i => backingArray[(currentIndex + i) % backingArray.Length] == pattern[i]);