mirror of https://github.com/icsharpcode/ILSpy.git
9 changed files with 344 additions and 85 deletions
@ -0,0 +1,117 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.IO; |
||||||
|
using System.Runtime.CompilerServices; |
||||||
|
using ICSharpCode.NRefactory.Documentation; |
||||||
|
using Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.ILSpy.XmlDoc |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Helps finding and loading .xml documentation.
|
||||||
|
/// </summary>
|
||||||
|
public static class XmlDocLoader |
||||||
|
{ |
||||||
|
static readonly Lazy<XmlDocumentationProvider> mscorlibDocumentation = new Lazy<XmlDocumentationProvider>(LoadMscorlibDocumentation); |
||||||
|
static readonly ConditionalWeakTable<ModuleDefinition, XmlDocumentationProvider> cache = new ConditionalWeakTable<ModuleDefinition, XmlDocumentationProvider>(); |
||||||
|
|
||||||
|
static XmlDocumentationProvider LoadMscorlibDocumentation() |
||||||
|
{ |
||||||
|
string xmlDocFile = FindXmlDocumentation("mscorlib.dll", TargetRuntime.Net_4_0) |
||||||
|
?? FindXmlDocumentation("mscorlib.dll", TargetRuntime.Net_2_0); |
||||||
|
if (xmlDocFile != null) |
||||||
|
return new XmlDocumentationProvider(xmlDocFile); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public static XmlDocumentationProvider MscorlibDocumentation { |
||||||
|
get { return mscorlibDocumentation.Value; } |
||||||
|
} |
||||||
|
|
||||||
|
public static XmlDocumentationProvider LoadDocumentation(ModuleDefinition module) |
||||||
|
{ |
||||||
|
if (module == null) |
||||||
|
throw new ArgumentNullException("module"); |
||||||
|
lock (cache) { |
||||||
|
XmlDocumentationProvider xmlDoc; |
||||||
|
if (!cache.TryGetValue(module, out xmlDoc)) { |
||||||
|
string xmlDocFile = LookupLocalizedXmlDoc(module.FullyQualifiedName); |
||||||
|
if (xmlDocFile == null) { |
||||||
|
xmlDocFile = FindXmlDocumentation(Path.GetFileName(module.FullyQualifiedName), module.Runtime); |
||||||
|
} |
||||||
|
if (xmlDocFile != null) { |
||||||
|
xmlDoc = new XmlDocumentationProvider(xmlDocFile); |
||||||
|
cache.Add(module, xmlDoc); |
||||||
|
} else { |
||||||
|
xmlDoc = null; |
||||||
|
} |
||||||
|
} |
||||||
|
return xmlDoc; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static readonly string referenceAssembliesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Reference Assemblies\Microsoft\\Framework"); |
||||||
|
static readonly string frameworkPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"Microsoft.NET\Framework"); |
||||||
|
|
||||||
|
static string FindXmlDocumentation(string assemblyFileName, TargetRuntime runtime) |
||||||
|
{ |
||||||
|
string fileName; |
||||||
|
switch (runtime) { |
||||||
|
case TargetRuntime.Net_1_0: |
||||||
|
fileName = LookupLocalizedXmlDoc(Path.Combine(frameworkPath, "v1.0.3705", assemblyFileName)); |
||||||
|
break; |
||||||
|
case TargetRuntime.Net_1_1: |
||||||
|
fileName = LookupLocalizedXmlDoc(Path.Combine(frameworkPath, "v1.1.4322", assemblyFileName)); |
||||||
|
break; |
||||||
|
case TargetRuntime.Net_2_0: |
||||||
|
fileName = LookupLocalizedXmlDoc(Path.Combine(frameworkPath, "v2.0.50727", assemblyFileName)) |
||||||
|
?? LookupLocalizedXmlDoc(Path.Combine(referenceAssembliesPath, "v3.5")) |
||||||
|
?? LookupLocalizedXmlDoc(Path.Combine(referenceAssembliesPath, "v3.0")) |
||||||
|
?? LookupLocalizedXmlDoc(Path.Combine(referenceAssembliesPath, @".NETFramework\v3.5\Profile\Client")); |
||||||
|
break; |
||||||
|
case TargetRuntime.Net_4_0: |
||||||
|
default: |
||||||
|
fileName = LookupLocalizedXmlDoc(Path.Combine(referenceAssembliesPath, @".NETFramework\v4.0", assemblyFileName)) |
||||||
|
?? LookupLocalizedXmlDoc(Path.Combine(frameworkPath, "v4.0.30319", assemblyFileName)); |
||||||
|
break; |
||||||
|
} |
||||||
|
return fileName; |
||||||
|
} |
||||||
|
|
||||||
|
static string LookupLocalizedXmlDoc(string fileName) |
||||||
|
{ |
||||||
|
string xmlFileName = Path.ChangeExtension(fileName, ".xml"); |
||||||
|
string currentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; |
||||||
|
string localizedXmlDocFile = GetLocalizedName(xmlFileName, currentCulture); |
||||||
|
|
||||||
|
Debug.WriteLine("Try find XMLDoc @" + localizedXmlDocFile); |
||||||
|
if (File.Exists(localizedXmlDocFile)) { |
||||||
|
return localizedXmlDocFile; |
||||||
|
} |
||||||
|
Debug.WriteLine("Try find XMLDoc @" + xmlFileName); |
||||||
|
if (File.Exists(xmlFileName)) { |
||||||
|
return xmlFileName; |
||||||
|
} |
||||||
|
if (currentCulture != "en") { |
||||||
|
string englishXmlDocFile = GetLocalizedName(xmlFileName, "en"); |
||||||
|
Debug.WriteLine("Try find XMLDoc @" + englishXmlDocFile); |
||||||
|
if (File.Exists(englishXmlDocFile)) { |
||||||
|
return englishXmlDocFile; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
static string GetLocalizedName(string fileName, string language) |
||||||
|
{ |
||||||
|
string localizedXmlDocFile = Path.GetDirectoryName(fileName); |
||||||
|
localizedXmlDocFile = Path.Combine(localizedXmlDocFile, language); |
||||||
|
localizedXmlDocFile = Path.Combine(localizedXmlDocFile, Path.GetFileName(fileName)); |
||||||
|
return localizedXmlDocFile; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,122 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.IO; |
||||||
|
using System.Text; |
||||||
|
using System.Text.RegularExpressions; |
||||||
|
using System.Windows.Controls; |
||||||
|
using System.Xml; |
||||||
|
|
||||||
|
namespace ICSharpCode.ILSpy.XmlDoc |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Renders XML documentation into a WPF <see cref="TextBlock"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class XmlDocRenderer |
||||||
|
{ |
||||||
|
StringBuilder ret = new StringBuilder(); |
||||||
|
|
||||||
|
public void AppendText(string text) |
||||||
|
{ |
||||||
|
ret.Append(text); |
||||||
|
} |
||||||
|
|
||||||
|
public void AddXmlDocumentation(string xmlDocumentation) |
||||||
|
{ |
||||||
|
if (xmlDocumentation == null) |
||||||
|
return; |
||||||
|
Debug.WriteLine(xmlDocumentation); |
||||||
|
try { |
||||||
|
XmlTextReader r = new XmlTextReader(new StringReader("<docroot>" + xmlDocumentation + "</docroot>")); |
||||||
|
r.XmlResolver = null; |
||||||
|
AddXmlDocumentation(r); |
||||||
|
} catch (XmlException) { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static readonly Regex whitespace = new Regex(@"\s+"); |
||||||
|
|
||||||
|
public void AddXmlDocumentation(XmlReader xml) |
||||||
|
{ |
||||||
|
while (xml.Read()) { |
||||||
|
if (xml.NodeType == XmlNodeType.Element) { |
||||||
|
string elname = xml.Name.ToLowerInvariant(); |
||||||
|
switch (elname) { |
||||||
|
case "filterpriority": |
||||||
|
case "remarks": |
||||||
|
xml.Skip(); |
||||||
|
break; |
||||||
|
case "example": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
ret.Append("Example:"); |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
break; |
||||||
|
case "exception": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
ret.Append(GetCref(xml["cref"])); |
||||||
|
ret.Append(": "); |
||||||
|
break; |
||||||
|
case "returns": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
ret.Append("Returns: "); |
||||||
|
break; |
||||||
|
case "see": |
||||||
|
ret.Append(GetCref(xml["cref"])); |
||||||
|
ret.Append(xml["langword"]); |
||||||
|
break; |
||||||
|
case "seealso": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
ret.Append("See also: "); |
||||||
|
ret.Append(GetCref(xml["cref"])); |
||||||
|
break; |
||||||
|
case "paramref": |
||||||
|
ret.Append(xml["name"]); |
||||||
|
break; |
||||||
|
case "param": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
ret.Append(whitespace.Replace(xml["name"].Trim()," ")); |
||||||
|
ret.Append(": "); |
||||||
|
break; |
||||||
|
case "typeparam": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
ret.Append(whitespace.Replace(xml["name"].Trim()," ")); |
||||||
|
ret.Append(": "); |
||||||
|
break; |
||||||
|
case "value": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
ret.Append("Value: "); |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
break; |
||||||
|
case "br": |
||||||
|
case "para": |
||||||
|
ret.Append(Environment.NewLine); |
||||||
|
break; |
||||||
|
} |
||||||
|
} else if (xml.NodeType == XmlNodeType.Text) { |
||||||
|
ret.Append(whitespace.Replace(xml.Value, " ")); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static string GetCref(string cref) |
||||||
|
{ |
||||||
|
if (cref == null || cref.Trim().Length==0) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
if (cref.Length < 2) { |
||||||
|
return cref; |
||||||
|
} |
||||||
|
if (cref.Substring(1, 1) == ":") { |
||||||
|
return cref.Substring(2, cref.Length - 2); |
||||||
|
} |
||||||
|
return cref; |
||||||
|
} |
||||||
|
|
||||||
|
public TextBlock CreateTextBlock() |
||||||
|
{ |
||||||
|
return new TextBlock { Text = ret.ToString() }; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue