Browse Source

Display tooltips when hovering over member references.

pull/129/head
Daniel Grunwald 14 years ago
parent
commit
1255f87696
  1. 23
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 31
      ILSpy/CSharpLanguage.cs
  3. 7
      ILSpy/ILSpy.csproj
  4. 14
      ILSpy/Language.cs
  5. 2
      ILSpy/MainWindow.xaml.cs
  6. 104
      ILSpy/TextView/DecompilerTextView.cs
  7. 9
      ILSpy/XmlDoc/XmlDocKeyProvider.cs
  8. 117
      ILSpy/XmlDoc/XmlDocLoader.cs
  9. 122
      ILSpy/XmlDoc/XmlDocRenderer.cs

23
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.Ast
if (context == null) if (context == null)
throw new ArgumentNullException("context"); throw new ArgumentNullException("context");
this.context = context; this.context = context;
this.DecompileMethodBodies = true;
} }
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings) public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
@ -629,7 +630,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
} else } else
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType); astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context, astMethod.Parameters); astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
} }
ConvertAttributes(astMethod, methodDef); ConvertAttributes(astMethod, methodDef);
if (methodDef.HasCustomAttributes && astMethod.Parameters.Count > 0) { if (methodDef.HasCustomAttributes && astMethod.Parameters.Count > 0) {
@ -707,7 +708,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
astMethod.Name = CleanName(methodDef.DeclaringType.Name); astMethod.Name = CleanName(methodDef.DeclaringType.Name);
astMethod.Parameters.AddRange(MakeParameters(methodDef)); astMethod.Parameters.AddRange(MakeParameters(methodDef));
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context, astMethod.Parameters); astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef); ConvertAttributes(astMethod, methodDef);
return astMethod; return astMethod;
} }
@ -755,7 +756,7 @@ namespace ICSharpCode.Decompiler.Ast
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
astProp.Getter = new Accessor(); astProp.Getter = new Accessor();
astProp.Getter.Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context); astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
astProp.AddAnnotation(propDef.GetMethod); astProp.AddAnnotation(propDef.GetMethod);
ConvertAttributes(astProp.Getter, propDef.GetMethod); ConvertAttributes(astProp.Getter, propDef.GetMethod);
@ -764,7 +765,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
if (propDef.SetMethod != null) { if (propDef.SetMethod != null) {
astProp.Setter = new Accessor(); astProp.Setter = new Accessor();
astProp.Setter.Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context); astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
astProp.Setter.AddAnnotation(propDef.SetMethod); astProp.Setter.AddAnnotation(propDef.SetMethod);
ConvertAttributes(astProp.Setter, propDef.SetMethod); ConvertAttributes(astProp.Setter, propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param); ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param);
@ -819,19 +820,29 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType); astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
if (eventDef.AddMethod != null) { if (eventDef.AddMethod != null) {
astEvent.AddAccessor = new Accessor { astEvent.AddAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, context) Body = CreateMethodBody(eventDef.AddMethod)
}.WithAnnotation(eventDef.AddMethod); }.WithAnnotation(eventDef.AddMethod);
ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod); ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod);
} }
if (eventDef.RemoveMethod != null) { if (eventDef.RemoveMethod != null) {
astEvent.RemoveAccessor = new Accessor { astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, context) Body = CreateMethodBody(eventDef.RemoveMethod)
}.WithAnnotation(eventDef.RemoveMethod); }.WithAnnotation(eventDef.RemoveMethod);
ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod); ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod);
} }
return astEvent; return astEvent;
} }
} }
public bool DecompileMethodBodies { get; set; }
BlockStatement CreateMethodBody(MethodDefinition method, IEnumerable<ParameterDeclaration> parameters = null)
{
if (DecompileMethodBodies)
return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters);
else
return null;
}
FieldDeclaration CreateField(FieldDefinition fieldDef) FieldDeclaration CreateField(FieldDefinition fieldDef)
{ {

31
ILSpy/CSharpLanguage.cs

@ -23,6 +23,8 @@ using System.ComponentModel.Composition;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Resources; using System.Resources;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xaml; using System.Xaml;
using System.Xml; using System.Xml;
@ -462,5 +464,34 @@ namespace ICSharpCode.ILSpy
{ {
return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings); return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings);
} }
public override string GetTooltip(MemberReference member)
{
MethodDefinition md = member as MethodDefinition;
PropertyDefinition pd = member as PropertyDefinition;
EventDefinition ed = member as EventDefinition;
FieldDefinition fd = member as FieldDefinition;
if (md != null || pd != null || ed != null || fd != null) {
AstBuilder b = new AstBuilder(new DecompilerContext(member.Module) { Settings = new DecompilerSettings { UsingDeclarations = false } });
b.DecompileMethodBodies = false;
if (md != null)
b.AddMethod(md);
else if (pd != null)
b.AddProperty(pd);
else if (ed != null)
b.AddEvent(ed);
else
b.AddField(fd);
b.RunTransformations();
foreach (var attribute in b.CompilationUnit.Descendants.OfType<AttributeSection>())
attribute.Remove();
StringWriter w = new StringWriter();
b.GenerateCode(new PlainTextOutput(w));
return Regex.Replace(w.ToString(), @"\s+", " ").TrimEnd();
}
return base.GetTooltip(member);
}
} }
} }

7
ILSpy/ILSpy.csproj

@ -132,10 +132,12 @@
<Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\IMemberTreeNode.cs" /> <Compile Include="TreeNodes\IMemberTreeNode.cs" />
<Compile Include="TreeNodes\XamlResourceNode.cs" /> <Compile Include="TreeNodes\XamlResourceNode.cs" />
<Compile Include="XmlDocKeyProvider.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorsTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />
<Compile Include="XmlDoc\XmlDocKeyProvider.cs" />
<Compile Include="XmlDoc\XmlDocLoader.cs" />
<Compile Include="XmlDoc\XmlDocRenderer.cs" />
<EmbeddedResource Include="..\README.txt"> <EmbeddedResource Include="..\README.txt">
<Link>README.txt</Link> <Link>README.txt</Link>
</EmbeddedResource> </EmbeddedResource>
@ -266,5 +268,8 @@
<Name>ICSharpCode.TreeView</Name> <Name>ICSharpCode.TreeView</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="XmlDoc" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> </Project>

14
ILSpy/Language.cs

@ -105,7 +105,19 @@ namespace ICSharpCode.ILSpy
else else
return type.Name; return type.Name;
} }
/// <summary>
/// Converts a member signature to a string.
/// This is used for displaying the tooltip on a member reference.
/// </summary>
public virtual string GetTooltip(MemberReference member)
{
if (member is TypeReference)
return TypeToString((TypeReference)member, true);
else
return member.ToString();
}
public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null) public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null)
{ {
if (property == null) if (property == null)

2
ILSpy/MainWindow.xaml.cs

@ -30,9 +30,11 @@ using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.TreeNodes.Analyzer; using ICSharpCode.ILSpy.TreeNodes.Analyzer;
using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Microsoft.Win32; using Microsoft.Win32;
using Mono.Cecil; using Mono.Cecil;

104
ILSpy/TextView/DecompilerTextView.cs

@ -40,7 +40,9 @@ using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd; using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.NRefactory.Documentation; using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
using Microsoft.Win32; using Microsoft.Win32;
using Mono.Cecil; using Mono.Cecil;
@ -115,85 +117,39 @@ namespace ICSharpCode.ILSpy.TextView
Mono.Cecil.Cil.OpCode code = (Mono.Cecil.Cil.OpCode)segment.Reference; Mono.Cecil.Cil.OpCode code = (Mono.Cecil.Cil.OpCode)segment.Reference;
string encodedName = code.Code.ToString(); string encodedName = code.Code.ToString();
string opCodeHex = code.Size > 1 ? string.Format("0x{0:x2}{1:x2}", code.Op1, code.Op2) : string.Format("0x{0:x2}", code.Op2); string opCodeHex = code.Size > 1 ? string.Format("0x{0:x2}{1:x2}", code.Op1, code.Op2) : string.Format("0x{0:x2}", code.Op2);
string documentationFile = FindDocumentation("mscorlib.xml"); XmlDocumentationProvider docProvider = XmlDocLoader.MscorlibDocumentation;
string text = ""; if (docProvider != null){
if (documentationFile != null){ string documentation = docProvider.GetDocumentation("F:System.Reflection.Emit.OpCodes." + encodedName);
XmlDocumentationProvider provider = new XmlDocumentationProvider(documentationFile); if (documentation != null) {
string documentation = provider.GetDocumentation("F:System.Reflection.Emit.OpCodes." + encodedName); XmlDocRenderer renderer = new XmlDocRenderer();
if (documentation != null) renderer.AppendText(string.Format("{0} ({1}) - ", code.Name, opCodeHex));
text = StripXml(documentation); renderer.AddXmlDocumentation(documentation);
return renderer.CreateTextBlock();
}
} }
return string.Format("{0} ({1}): {2}", code.Name, opCodeHex, text); return string.Format("{0} ({1})", code.Name, opCodeHex);
} } else if (segment.Reference is MemberReference) {
MemberReference mr = (MemberReference)segment.Reference;
return null; // if possible, resolve the reference
} if (mr is TypeReference) {
mr = ((TypeReference)mr).Resolve() ?? mr;
string StripXml(string xmlText) } else if (mr is MethodReference) {
{ mr = ((MethodReference)mr).Resolve() ?? mr;
try { }
using (XmlTextReader xml = new XmlTextReader(new StringReader(xmlText))) { XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module);
StringBuilder ret = new StringBuilder(); if (docProvider != null) {
while (xml.Read()) { XmlDocRenderer renderer = new XmlDocRenderer();
if (xml.NodeType == XmlNodeType.Element) { renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr));
string elname = xml.Name.ToLowerInvariant(); string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
switch (elname) { if (documentation != null) {
case "summary": renderer.AppendText(Environment.NewLine);
break; renderer.AddXmlDocumentation(documentation);
case "br":
case "para":
ret.AppendLine();
break;
default:
xml.Skip();
break;
}
} else if (xml.NodeType == XmlNodeType.Text) {
ret.Append(Regex.Replace(xml.Value, @"\s+", " "));
}
} }
return ret.ToString(); return renderer.CreateTextBlock();
} }
} catch (XmlException) {
return null; // invalid XML docu
} }
}
string FindDocumentation(string fileName)
{
string path = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
List<string> names = new List<string>();
EnumerateCultures(CultureInfo.CurrentCulture, names);
names.Add("en");
names.Add("en-US");
names.Add("en-GB");
foreach (string name in names) {
string location = Path.Combine(path, name, fileName);
if (File.Exists(location))
return location;
}
path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0");
string loc = Path.Combine(path, fileName);
if (File.Exists(loc)) {
return loc;
}
return null; return null;
} }
void EnumerateCultures(CultureInfo info, List<string> names)
{
while (info != null) {
names.Add(info.Name);
info = info.Parent;
if (info == info.Parent)
return;
}
}
#endregion #endregion
#region RunWithCancellation #region RunWithCancellation
@ -269,7 +225,7 @@ namespace ICSharpCode.ILSpy.TextView
/// </summary> /// </summary>
void ShowOutput(AvalonEditTextOutput textOutput, IHighlightingDefinition highlighting = null, DecompilerTextViewState state = null) void ShowOutput(AvalonEditTextOutput textOutput, IHighlightingDefinition highlighting = null, DecompilerTextViewState state = null)
{ {
Debug.WriteLine("Showing {0} characters of output", textOutput.TextLength); Debug.WriteLine("Showing {0} characters of output", textOutput.TextLength);
Stopwatch w = Stopwatch.StartNew(); Stopwatch w = Stopwatch.StartNew();
textEditor.ScrollToHome(); textEditor.ScrollToHome();

9
ILSpy/XmlDocKeyProvider.cs → ILSpy/XmlDoc/XmlDocKeyProvider.cs

@ -8,12 +8,12 @@ using System.Linq;
using System.Text; using System.Text;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy.XmlDoc
{ {
/// <summary> /// <summary>
/// Provides XML documentation tags. /// Provides XML documentation tags.
/// </summary> /// </summary>
sealed class XmlDocKeyProvider public sealed class XmlDocKeyProvider
{ {
#region GetKey #region GetKey
public static string GetKey(MemberReference member) public static string GetKey(MemberReference member)
@ -33,7 +33,10 @@ namespace ICSharpCode.ILSpy
b.Append("M:"); b.Append("M:");
AppendTypeName(b, member.DeclaringType); AppendTypeName(b, member.DeclaringType);
b.Append('.'); b.Append('.');
b.Append(member.Name); if (member.Name == ".ctor")
b.Append("#ctor");
else
b.Append(member.Name);
IList<ParameterDefinition> parameters; IList<ParameterDefinition> parameters;
if (member is PropertyDefinition) { if (member is PropertyDefinition) {
parameters = ((PropertyDefinition)member).Parameters; parameters = ((PropertyDefinition)member).Parameters;

117
ILSpy/XmlDoc/XmlDocLoader.cs

@ -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;
}
}
}

122
ILSpy/XmlDoc/XmlDocRenderer.cs

@ -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…
Cancel
Save