Browse Source

Clean up files.

pull/1654/head
Siegfried Pammer 6 years ago
parent
commit
527dacf1b6
  1. 3
      ILSpy/ILSpy.csproj
  2. 215
      ILSpy/TextView/DocumentationUIBuilder.cs
  3. 448
      ILSpy/TextView/ReadOnlyDocument.cs
  4. 99
      ILSpy/TextView/XmlDocFormatter.cs
  5. 551
      ILSpy/TextView/XmlDocRenderer.cs

3
ILSpy/ILSpy.csproj

@ -226,8 +226,7 @@ @@ -226,8 +226,7 @@
<Compile Include="TextView\EditorCommands.cs" />
<Compile Include="TextView\FoldingCommands.cs" />
<Compile Include="Commands\SaveCodeContextMenuEntry.cs" />
<Compile Include="TextView\ReadOnlyDocument.cs" />
<Compile Include="TextView\XmlDocRenderer.cs" />
<Compile Include="TextView\DocumentationUIBuilder.cs" />
<Compile Include="Analyzers\AnalyzeCommand.cs" />
<Compile Include="Analyzers\Builtin\FieldAccessAnalyzer.cs" />
<Compile Include="Analyzers\TreeNodes\AnalyzedFieldTreeNode.cs" />

215
ILSpy/TextView/DocumentationUIBuilder.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
@ -18,16 +18,21 @@ @@ -18,16 +18,21 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Options;
@ -35,20 +40,22 @@ using ICSharpCode.ILSpy.Options; @@ -35,20 +40,22 @@ using ICSharpCode.ILSpy.Options;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// Builds a FlowDocument for XML documentation.
/// Renders XML documentation into a WPF <see cref="FlowDocument"/>.
/// </summary>
public class DocumentationUIBuilder
{
FlowDocument flowDocument;
readonly IAmbience ambience;
readonly IHighlightingDefinition highlightingDefinition;
readonly FlowDocument document;
BlockCollection blockCollection;
InlineCollection inlineCollection;
IAmbience ambience;
public DocumentationUIBuilder(IAmbience ambience)
public DocumentationUIBuilder(IAmbience ambience, IHighlightingDefinition highlightingDefinition)
{
this.ambience = ambience;
this.flowDocument = new FlowDocument();
this.blockCollection = flowDocument.Blocks;
this.highlightingDefinition = highlightingDefinition;
this.document = new FlowDocument();
this.blockCollection = document.Blocks;
this.ShowSummary = true;
this.ShowAllParameters = true;
@ -65,11 +72,10 @@ namespace ICSharpCode.ILSpy.TextView @@ -65,11 +72,10 @@ namespace ICSharpCode.ILSpy.TextView
this.ShowRemarks = true;
}
public FlowDocument CreateFlowDocument()
public FlowDocument CreateDocument()
{
FlushAddedText(true);
flowDocument.FontSize = DisplaySettingsPanel.CurrentDisplaySettings.SelectedFontSize;
return flowDocument;
return document;
}
public bool ShowExceptions { get; set; }
@ -85,33 +91,76 @@ namespace ICSharpCode.ILSpy.TextView @@ -85,33 +91,76 @@ namespace ICSharpCode.ILSpy.TextView
public bool ShowValue { get; set; }
public bool ShowAllParameters { get; set; }
public void AddCodeBlock(string textContent, bool keepLargeMargin = false)
{
var document = new TextDocument(textContent);
var highlighter = new DocumentHighlighter(document, highlightingDefinition);
var richText = DocumentPrinter.ConvertTextDocumentToRichText(document, highlighter).ToRichTextModel();
var block = new Paragraph();
block.Inlines.AddRange(richText.CreateRuns(document));
block.FontFamily = GetCodeFont();
if (!keepLargeMargin)
block.Margin = new Thickness(0, 6, 0, 6);
AddBlock(block);
}
public void AddSignatureBlock(string signature, RichTextModel highlighting = null)
{
var document = new TextDocument(signature);
var richText = highlighting ?? DocumentPrinter.ConvertTextDocumentToRichText(document, new DocumentHighlighter(document, highlightingDefinition)).ToRichTextModel();
var block = new Paragraph();
// HACK: measure width of signature using a TextBlock
// Paragraph sadly does not support TextWrapping.NoWrap
var text = new TextBlock {
FontFamily = GetCodeFont(),
FontSize = DisplaySettingsPanel.CurrentDisplaySettings.SelectedFontSize,
TextAlignment = TextAlignment.Left
};
text.Inlines.AddRange(richText.CreateRuns(document));
text.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
this.document.MinPageWidth = Math.Min(text.DesiredSize.Width, MainWindow.Instance.ActualWidth);
block.Inlines.AddRange(richText.CreateRuns(document));
block.FontFamily = GetCodeFont();
block.TextAlignment = TextAlignment.Left;
AddBlock(block);
}
public void AddXmlDocumentation(string xmlDocumentation, IEntity declaringEntity, Func<string, IEntity> resolver)
{
if (xmlDocumentation == null)
return;
Debug.WriteLine(xmlDocumentation);
var xml = XElement.Parse("<doc>" + xmlDocumentation + "</doc>");
AddDocumentationElement(new XmlDocumentationElement(xml, declaringEntity, resolver));
}
/// <summary>
/// Gets/Sets the name of the parameter that should be shown.
/// </summary>
public string ParameterName { get; set; }
public void AddDocumentationElement(XNode node)
public void AddDocumentationElement(XmlDocumentationElement element)
{
if (node == null)
throw new ArgumentNullException(nameof(node));
if (node is XText text) {
AddText(text.Value);
if (element == null)
throw new ArgumentNullException("element");
if (element.IsTextNode) {
AddText(element.TextContent);
return;
}
if (!(node is XElement element))
throw new NotImplementedException();
switch (element.Name.ToString()) {
switch (element.Name) {
case "b":
AddSpan(new Bold(), element.Elements());
AddSpan(new Bold(), element.Children);
break;
case "i":
AddSpan(new Italic(), element.ele);
AddSpan(new Italic(), element.Children);
break;
case "c":
AddSpan(new Span { FontFamily = GetCodeFont() }, element.Children);
break;
case "code":
AddCodeBlock(element.Value);
AddCodeBlock(element.TextContent);
break;
case "example":
if (ShowExample)
@ -195,7 +244,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -195,7 +244,7 @@ namespace ICSharpCode.ILSpy.TextView
}
}
void AddList(string type, IEnumerable<XNode> items)
void AddList(string type, IEnumerable<XmlDocumentationElement> items)
{
List list = new List();
AddBlock(list);
@ -223,43 +272,15 @@ namespace ICSharpCode.ILSpy.TextView @@ -223,43 +272,15 @@ namespace ICSharpCode.ILSpy.TextView
}
}
public void AddCodeBlock(string textContent, bool keepLargeMargin = false)
{
var document = new ReadOnlyDocument(textContent);
var highlightingDefinition = HighlightingManager.Instance.GetDefinition("C#");
var block = DocumentPrinter.ConvertTextDocumentToBlock(document, highlightingDefinition);
block.FontFamily = GetCodeFont();
if (!keepLargeMargin)
block.Margin = new Thickness(0, 6, 0, 6);
AddBlock(block);
}
public void AddSignatureBlock(string signature, int currentParameterOffset, int currentParameterLength, string currentParameterName)
{
ParameterName = currentParameterName;
var document = new ReadOnlyDocument(signature);
var highlightingDefinition = HighlightingManager.Instance.GetDefinition("C#");
var richText = DocumentPrinter.ConvertTextDocumentToRichText(document, highlightingDefinition).ToRichTextModel();
richText.SetFontWeight(currentParameterOffset, currentParameterLength, FontWeights.Bold);
var block = new Paragraph();
block.Inlines.AddRange(richText.CreateRuns(document));
block.FontFamily = GetCodeFont();
block.TextAlignment = TextAlignment.Left;
AddBlock(block);
}
bool? ParseBool(string input)
{
bool result;
if (bool.TryParse(input, out result))
if (bool.TryParse(input, out bool result))
return result;
else
return null;
}
void AddThreadSafety(bool? staticThreadSafe, bool? instanceThreadSafe, IEnumerable<XNode> children)
void AddThreadSafety(bool? staticThreadSafe, bool? instanceThreadSafe, IEnumerable<XmlDocumentationElement> children)
{
AddSection(
new Run("Thread-safety: "),
@ -279,12 +300,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -279,12 +300,7 @@ namespace ICSharpCode.ILSpy.TextView
});
}
FontFamily GetCodeFont()
{
return new FontFamily(SD.EditorControlService.GlobalOptions.FontFamily);
}
void AddException(IEntity referencedEntity, IList<XNode> children)
void AddException(IEntity referencedEntity, IList<XmlDocumentationElement> children)
{
Span span = new Span();
if (referencedEntity != null)
@ -296,7 +312,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -296,7 +312,7 @@ namespace ICSharpCode.ILSpy.TextView
}
void AddPermission(IEntity referencedEntity, IList<XNode> children)
void AddPermission(IEntity referencedEntity, IList<XmlDocumentationElement> children)
{
Span span = new Span();
span.Inlines.Add("Permission");
@ -311,11 +327,13 @@ namespace ICSharpCode.ILSpy.TextView @@ -311,11 +327,13 @@ namespace ICSharpCode.ILSpy.TextView
Inline ConvertReference(IEntity referencedEntity)
{
var h = new Hyperlink(new Run(ambience.ConvertSymbol(referencedEntity)));
h.Click += CreateNavigateOnClickHandler(referencedEntity);
h.Click += (sender, e) => {
MainWindow.Instance.JumpToReference(referencedEntity);
};
return h;
}
void AddParam(string name, IEnumerable<XNode> children)
void AddParam(string name, IEnumerable<XmlDocumentationElement> children)
{
Span span = new Span();
span.Inlines.Add(new Run(name ?? string.Empty) { FontStyle = FontStyles.Italic });
@ -330,7 +348,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -330,7 +348,7 @@ namespace ICSharpCode.ILSpy.TextView
}
}
void AddPreliminary(IEnumerable<XNode> children)
void AddPreliminary(IEnumerable<XmlDocumentationElement> children)
{
if (children.Any()) {
foreach (var child in children)
@ -340,13 +358,15 @@ namespace ICSharpCode.ILSpy.TextView @@ -340,13 +358,15 @@ namespace ICSharpCode.ILSpy.TextView
}
}
void AddSee(XNode element)
void AddSee(XmlDocumentationElement element)
{
IEntity referencedEntity = element.ReferencedEntity;
if (referencedEntity != null) {
if (element.Children.Any()) {
Hyperlink link = new Hyperlink();
link.Click += CreateNavigateOnClickHandler(referencedEntity);
link.Click += (sender, e) => {
MainWindow.Instance.JumpToReference(referencedEntity);
};
AddSpan(link, element.Children);
} else {
AddInline(ConvertReference(referencedEntity));
@ -368,30 +388,44 @@ namespace ICSharpCode.ILSpy.TextView @@ -368,30 +388,44 @@ namespace ICSharpCode.ILSpy.TextView
}
}
RoutedEventHandler CreateNavigateOnClickHandler(IEntity referencedEntity)
static string GetCref(string cref)
{
// Don't let the anonymous method capture the referenced entity
// (we don't want to keep the whole compilation in memory)
// Use the IEntityModel instead.
var model = referencedEntity.GetModel();
return delegate (object sender, RoutedEventArgs e) {
IEntity resolvedEntity = model != null ? model.Resolve() : null;
if (resolvedEntity != null) {
bool shouldDisplayHelp = CodeCompletionOptions.TooltipLinkTarget == TooltipLinkTarget.Documentation
&& resolvedEntity.ParentAssembly.IsPartOfDotnetFramework();
if (!shouldDisplayHelp || !HelpProvider.ShowHelp(resolvedEntity))
NavigationService.NavigateTo(resolvedEntity);
}
e.Handled = true;
};
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;
}
FontFamily GetCodeFont()
{
return DisplaySettingsPanel.CurrentDisplaySettings.SelectedFont;
}
public void AddInline(Inline inline)
{
FlushAddedText(false);
if (inlineCollection == null) {
var para = new Paragraph();
para.Margin = new Thickness(0, 0, 0, 5);
inlineCollection = para.Inlines;
AddBlock(para);
}
inlineCollection.Add(inline);
ignoreWhitespace = false;
}
void AddSection(string title, IEnumerable<XNode> children)
void AddSection(string title, IEnumerable<XmlDocumentationElement> children)
{
AddSection(new Run(title), children);
}
void AddSection(Inline title, IEnumerable<XNode> children)
void AddSection(Inline title, IEnumerable<XmlDocumentationElement> children)
{
AddSection(
title, delegate {
@ -420,7 +454,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -420,7 +454,7 @@ namespace ICSharpCode.ILSpy.TextView
}
}
void AddParagraph(Paragraph para, IEnumerable<XNode> children)
void AddParagraph(Paragraph para, IEnumerable<XmlDocumentationElement> children)
{
AddBlock(para);
try {
@ -434,7 +468,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -434,7 +468,7 @@ namespace ICSharpCode.ILSpy.TextView
}
}
void AddSpan(Span span, IEnumerable<XNode> children)
void AddSpan(Span span, IEnumerable<XmlDocumentationElement> children)
{
AddInline(span);
var oldInlineCollection = inlineCollection;
@ -448,19 +482,6 @@ namespace ICSharpCode.ILSpy.TextView @@ -448,19 +482,6 @@ namespace ICSharpCode.ILSpy.TextView
}
}
public void AddInline(Inline inline)
{
FlushAddedText(false);
if (inlineCollection == null) {
var para = new Paragraph();
para.Margin = new Thickness(0, 0, 0, 5);
inlineCollection = para.Inlines;
AddBlock(para);
}
inlineCollection.Add(inline);
ignoreWhitespace = false;
}
public void AddBlock(Block block)
{
FlushAddedText(true);

448
ILSpy/TextView/ReadOnlyDocument.cs

@ -1,448 +0,0 @@ @@ -1,448 +0,0 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// Read-only implementation of <see cref="IDocument"/>.
/// </summary>
[Serializable]
public sealed class ReadOnlyDocument : IDocument
{
readonly ITextSource textSource;
readonly string fileName;
int[] lines;
static readonly char[] newline = { '\r', '\n' };
/// <summary>
/// Creates a new ReadOnlyDocument from the given text source.
/// </summary>
public ReadOnlyDocument(ITextSource textSource)
{
if (textSource == null)
throw new ArgumentNullException("textSource");
// ensure that underlying buffer is immutable
this.textSource = textSource.CreateSnapshot();
List<int> lines = new List<int>();
lines.Add(0);
int offset = 0;
int textLength = textSource.TextLength;
while ((offset = textSource.IndexOfAny(newline, offset, textLength - offset)) >= 0) {
offset++;
if (textSource.GetCharAt(offset - 1) == '\r' && offset < textLength && textSource.GetCharAt(offset) == '\n') {
offset++;
}
lines.Add(offset);
}
this.lines = lines.ToArray();
}
/// <summary>
/// Creates a new ReadOnlyDocument from the given string.
/// </summary>
public ReadOnlyDocument(string text)
: this(new StringTextSource(text))
{
}
/// <summary>
/// Creates a new ReadOnlyDocument from the given text source;
/// and sets IDocument.FileName to the specified file name.
/// </summary>
public ReadOnlyDocument(ITextSource textSource, string fileName)
: this(textSource)
{
this.fileName = fileName;
}
/// <inheritdoc/>
public IDocumentLine GetLineByNumber(int lineNumber)
{
if (lineNumber < 1 || lineNumber > lines.Length)
throw new ArgumentOutOfRangeException("lineNumber", lineNumber, "Value must be between 1 and " + lines.Length);
return new ReadOnlyDocumentLine(this, lineNumber);
}
sealed class ReadOnlyDocumentLine : IDocumentLine
{
readonly ReadOnlyDocument doc;
readonly int lineNumber;
readonly int offset, endOffset;
public ReadOnlyDocumentLine(ReadOnlyDocument doc, int lineNumber)
{
this.doc = doc;
this.lineNumber = lineNumber;
this.offset = doc.GetStartOffset(lineNumber);
this.endOffset = doc.GetEndOffset(lineNumber);
}
public override int GetHashCode()
{
return doc.GetHashCode() ^ lineNumber;
}
public override bool Equals(object obj)
{
ReadOnlyDocumentLine other = obj as ReadOnlyDocumentLine;
return other != null && doc == other.doc && lineNumber == other.lineNumber;
}
public int Offset {
get { return offset; }
}
public int Length {
get { return endOffset - offset; }
}
public int EndOffset {
get { return endOffset; }
}
public int TotalLength {
get {
return doc.GetTotalEndOffset(lineNumber) - offset;
}
}
public int DelimiterLength {
get {
return doc.GetTotalEndOffset(lineNumber) - endOffset;
}
}
public int LineNumber {
get { return lineNumber; }
}
public IDocumentLine PreviousLine {
get {
if (lineNumber == 1)
return null;
else
return new ReadOnlyDocumentLine(doc, lineNumber - 1);
}
}
public IDocumentLine NextLine {
get {
if (lineNumber == doc.LineCount)
return null;
else
return new ReadOnlyDocumentLine(doc, lineNumber + 1);
}
}
public bool IsDeleted {
get { return false; }
}
}
int GetStartOffset(int lineNumber)
{
return lines[lineNumber - 1];
}
int GetTotalEndOffset(int lineNumber)
{
return lineNumber < lines.Length ? lines[lineNumber] : textSource.TextLength;
}
int GetEndOffset(int lineNumber)
{
if (lineNumber == lines.Length)
return textSource.TextLength;
int off = lines[lineNumber] - 1;
if (off > 0 && textSource.GetCharAt(off - 1) == '\r' && textSource.GetCharAt(off) == '\n')
off--;
return off;
}
/// <inheritdoc/>
public IDocumentLine GetLineByOffset(int offset)
{
return GetLineByNumber(GetLineNumberForOffset(offset));
}
int GetLineNumberForOffset(int offset)
{
int r = Array.BinarySearch(lines, offset);
return r < 0 ? ~r : r + 1;
}
/// <inheritdoc/>
public int GetOffset(int line, int column)
{
if (line < 1 || line > lines.Length)
throw new ArgumentOutOfRangeException("line", line, "Value must be between 1 and " + lines.Length);
int lineStart = GetStartOffset(line);
if (column <= 1)
return lineStart;
int lineEnd = GetEndOffset(line);
if (column - 1 >= lineEnd - lineStart)
return lineEnd;
return lineStart + column - 1;
}
/// <inheritdoc/>
public int GetOffset(TextLocation location)
{
return GetOffset(location.Line, location.Column);
}
/// <inheritdoc/>
public TextLocation GetLocation(int offset)
{
if (offset < 0 || offset > textSource.TextLength)
throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + textSource.TextLength);
int line = GetLineNumberForOffset(offset);
return new TextLocation(line, offset - GetStartOffset(line) + 1);
}
/// <inheritdoc/>
public string Text {
get { return textSource.Text; }
set {
throw new NotSupportedException();
}
}
/// <inheritdoc/>
public int LineCount {
get { return lines.Length; }
}
/// <inheritdoc/>
public ITextSourceVersion Version {
get { return textSource.Version; }
}
/// <inheritdoc/>
public int TextLength {
get { return textSource.TextLength; }
}
event EventHandler<TextChangeEventArgs> IDocument.TextChanging { add { } remove { } }
event EventHandler<TextChangeEventArgs> IDocument.TextChanged { add { } remove { } }
event EventHandler IDocument.ChangeCompleted { add { } remove { } }
void IDocument.Insert(int offset, string text)
{
throw new NotSupportedException();
}
void IDocument.Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType)
{
throw new NotSupportedException();
}
void IDocument.Remove(int offset, int length)
{
throw new NotSupportedException();
}
void IDocument.Replace(int offset, int length, string newText)
{
throw new NotSupportedException();
}
void IDocument.Insert(int offset, ITextSource text)
{
throw new NotSupportedException();
}
void IDocument.Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType)
{
throw new NotSupportedException();
}
void IDocument.Replace(int offset, int length, ITextSource newText)
{
throw new NotSupportedException();
}
void IDocument.StartUndoableAction()
{
}
void IDocument.EndUndoableAction()
{
}
IDisposable IDocument.OpenUndoGroup()
{
return null;
}
/// <inheritdoc/>
public ITextAnchor CreateAnchor(int offset)
{
return new ReadOnlyDocumentTextAnchor(GetLocation(offset), offset);
}
sealed class ReadOnlyDocumentTextAnchor : ITextAnchor
{
readonly TextLocation location;
readonly int offset;
public ReadOnlyDocumentTextAnchor(TextLocation location, int offset)
{
this.location = location;
this.offset = offset;
}
public event EventHandler Deleted { add { } remove { } }
public TextLocation Location {
get { return location; }
}
public int Offset {
get { return offset; }
}
public AnchorMovementType MovementType { get; set; }
public bool SurviveDeletion { get; set; }
public bool IsDeleted {
get { return false; }
}
public int Line {
get { return location.Line; }
}
public int Column {
get { return location.Column; }
}
}
/// <inheritdoc/>
public ITextSource CreateSnapshot()
{
return textSource; // textBuffer is immutable
}
/// <inheritdoc/>
public ITextSource CreateSnapshot(int offset, int length)
{
return textSource.CreateSnapshot(offset, length);
}
/// <inheritdoc/>
public IDocument CreateDocumentSnapshot()
{
return this; // ReadOnlyDocument is immutable
}
/// <inheritdoc/>
public System.IO.TextReader CreateReader()
{
return textSource.CreateReader();
}
/// <inheritdoc/>
public System.IO.TextReader CreateReader(int offset, int length)
{
return textSource.CreateReader(offset, length);
}
/// <inheritdoc/>
public void WriteTextTo(System.IO.TextWriter writer)
{
textSource.WriteTextTo(writer);
}
/// <inheritdoc/>
public void WriteTextTo(System.IO.TextWriter writer, int offset, int length)
{
textSource.WriteTextTo(writer, offset, length);
}
/// <inheritdoc/>
public char GetCharAt(int offset)
{
return textSource.GetCharAt(offset);
}
/// <inheritdoc/>
public string GetText(int offset, int length)
{
return textSource.GetText(offset, length);
}
/// <inheritdoc/>
public string GetText(ISegment segment)
{
return textSource.GetText(segment);
}
/// <inheritdoc/>
public int IndexOf(char c, int startIndex, int count)
{
return textSource.IndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return textSource.IndexOfAny(anyOf, startIndex, count);
}
/// <inheritdoc/>
public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
return textSource.IndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public int LastIndexOf(char c, int startIndex, int count)
{
return textSource.LastIndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
return textSource.LastIndexOf(searchText, startIndex, count, comparisonType);
}
object IServiceProvider.GetService(Type serviceType)
{
return null;
}
/// <inheritdoc/>
/// <remarks>Will never be raised on <see cref="ReadOnlyDocument" />.</remarks>
public event EventHandler FileNameChanged { add { } remove { } }
/// <inheritdoc/>
public string FileName {
get { return fileName; }
}
}
}

99
ILSpy/TextView/XmlDocFormatter.cs

@ -1,99 +0,0 @@ @@ -1,99 +0,0 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Documents;
using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Xml;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// Provides helper methods to create nicely formatted FlowDocuments from NRefactory XmlDoc.
/// </summary>
public static class XmlDocFormatter
{
public static FlowDocument CreateTooltip(IType type, bool useFullyQualifiedMemberNames = true)
{
var ambience = AmbienceService.GetCurrentAmbience();
ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.ShowDeclaringType;
if (useFullyQualifiedMemberNames)
ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedEntityNames;
string header;
if (type is ITypeDefinition)
header = ambience.ConvertSymbol((ITypeDefinition)type);
else
header = ambience.ConvertType(type);
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList;
DocumentationUIBuilder b = new DocumentationUIBuilder(ambience);
b.AddCodeBlock(header, keepLargeMargin: true);
ITypeDefinition entity = type.GetDefinition();/*
if (entity != null) {
var documentation = XmlDocumentationElement.Get(entity);
if (documentation != null) {
foreach (var child in documentation.Children) {
b.AddDocumentationElement(child);
}
}
}*/
return b.CreateFlowDocument();
}
public static FlowDocument CreateTooltip(IEntity entity, bool useFullyQualifiedMemberNames = true)
{
var ambience = AmbienceService.GetCurrentAmbience();
ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.ShowDeclaringType;
if (useFullyQualifiedMemberNames)
ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedEntityNames;
string header = ambience.ConvertSymbol(entity);
var documentation = XmlDocumentationElement.Get(entity);
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList;
DocumentationUIBuilder b = new DocumentationUIBuilder(ambience);
b.AddCodeBlock(header, keepLargeMargin: true);
if (documentation != null) {
foreach (var child in documentation.Children) {
b.AddDocumentationElement(child);
}
}
return b.CreateFlowDocument();
}
public static FlowDocument CreateTooltip(ISymbol symbol)
{
var ambience = AmbienceService.GetCurrentAmbience();
ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.ShowDeclaringType;
string header = ambience.ConvertSymbol(symbol);
if (symbol is IParameter) {
header = "parameter " + header;
} else if (symbol is IVariable) {
header = "local variable " + header;
}
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList;
DocumentationUIBuilder b = new DocumentationUIBuilder(ambience);
b.AddCodeBlock(header, keepLargeMargin: true);
return b.CreateFlowDocument();
}
}
}

551
ILSpy/TextView/XmlDocRenderer.cs

@ -1,551 +0,0 @@ @@ -1,551 +0,0 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Options;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// Renders XML documentation into a WPF <see cref="FlowDocument"/>.
/// </summary>
public class DocumentationUIBuilder
{
readonly IAmbience ambience;
readonly IHighlightingDefinition highlightingDefinition;
readonly FlowDocument document;
BlockCollection blockCollection;
InlineCollection inlineCollection;
public DocumentationUIBuilder(IAmbience ambience, IHighlightingDefinition highlightingDefinition)
{
this.ambience = ambience;
this.highlightingDefinition = highlightingDefinition;
this.document = new FlowDocument();
this.blockCollection = document.Blocks;
this.ShowSummary = true;
this.ShowAllParameters = true;
this.ShowReturns = true;
this.ShowThreadSafety = true;
this.ShowExceptions = true;
this.ShowTypeParameters = true;
this.ShowExample = true;
this.ShowPreliminary = true;
this.ShowSeeAlso = true;
this.ShowValue = true;
this.ShowPermissions = true;
this.ShowRemarks = true;
}
public FlowDocument CreateDocument()
{
FlushAddedText(true);
return document;
}
public bool ShowExceptions { get; set; }
public bool ShowPermissions { get; set; }
public bool ShowExample { get; set; }
public bool ShowPreliminary { get; set; }
public bool ShowRemarks { get; set; }
public bool ShowSummary { get; set; }
public bool ShowReturns { get; set; }
public bool ShowSeeAlso { get; set; }
public bool ShowThreadSafety { get; set; }
public bool ShowTypeParameters { get; set; }
public bool ShowValue { get; set; }
public bool ShowAllParameters { get; set; }
public void AddCodeBlock(string textContent, bool keepLargeMargin = false)
{
var document = new TextDocument(textContent);
var highlighter = new DocumentHighlighter(document, highlightingDefinition);
var richText = DocumentPrinter.ConvertTextDocumentToRichText(document, highlighter).ToRichTextModel();
var block = new Paragraph();
block.Inlines.AddRange(richText.CreateRuns(document));
block.FontFamily = GetCodeFont();
if (!keepLargeMargin)
block.Margin = new Thickness(0, 6, 0, 6);
AddBlock(block);
}
public void AddSignatureBlock(string signature, RichTextModel highlighting = null)
{
var document = new TextDocument(signature);
var richText = highlighting ?? DocumentPrinter.ConvertTextDocumentToRichText(document, new DocumentHighlighter(document, highlightingDefinition)).ToRichTextModel();
var block = new Paragraph();
// HACK: measure width of signature using a TextBlock
// Paragraph sadly does not support TextWrapping.NoWrap
var text = new TextBlock {
FontFamily = GetCodeFont(),
FontSize = DisplaySettingsPanel.CurrentDisplaySettings.SelectedFontSize,
TextAlignment = TextAlignment.Left
};
text.Inlines.AddRange(richText.CreateRuns(document));
text.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
this.document.MinPageWidth = Math.Min(text.DesiredSize.Width, MainWindow.Instance.ActualWidth);
block.Inlines.AddRange(richText.CreateRuns(document));
block.FontFamily = GetCodeFont();
block.TextAlignment = TextAlignment.Left;
AddBlock(block);
}
public void AddXmlDocumentation(string xmlDocumentation, IEntity declaringEntity, Func<string, IEntity> resolver)
{
if (xmlDocumentation == null)
return;
Debug.WriteLine(xmlDocumentation);
var xml = XElement.Parse("<doc>" + xmlDocumentation + "</doc>");
AddDocumentationElement(new XmlDocumentationElement(xml, declaringEntity, resolver));
}
/// <summary>
/// Gets/Sets the name of the parameter that should be shown.
/// </summary>
public string ParameterName { get; set; }
public void AddDocumentationElement(XmlDocumentationElement element)
{
if (element == null)
throw new ArgumentNullException("element");
if (element.IsTextNode) {
AddText(element.TextContent);
return;
}
switch (element.Name) {
case "b":
AddSpan(new Bold(), element.Children);
break;
case "i":
AddSpan(new Italic(), element.Children);
break;
case "c":
AddSpan(new Span { FontFamily = GetCodeFont() }, element.Children);
break;
case "code":
AddCodeBlock(element.TextContent);
break;
case "example":
if (ShowExample)
AddSection("Example: ", element.Children);
break;
case "exception":
if (ShowExceptions)
AddException(element.ReferencedEntity, element.Children);
break;
case "list":
AddList(element.GetAttribute("type"), element.Children);
break;
//case "note":
// throw new NotImplementedException();
case "para":
AddParagraph(new Paragraph { Margin = new Thickness(0, 5, 0, 5) }, element.Children);
break;
case "param":
if (ShowAllParameters || (ParameterName != null && ParameterName == element.GetAttribute("name")))
AddParam(element.GetAttribute("name"), element.Children);
break;
case "paramref":
AddParamRef(element.GetAttribute("name"));
break;
case "permission":
if (ShowPermissions)
AddPermission(element.ReferencedEntity, element.Children);
break;
case "preliminary":
if (ShowPreliminary)
AddPreliminary(element.Children);
break;
case "remarks":
if (ShowRemarks)
AddSection("Remarks: ", element.Children);
break;
case "returns":
if (ShowReturns)
AddSection("Returns: ", element.Children);
break;
case "see":
AddSee(element);
break;
case "seealso":
if (inlineCollection != null)
AddSee(element);
else if (ShowSeeAlso)
AddSection(new Run("See also: "), () => AddSee(element));
break;
case "summary":
if (ShowSummary)
AddSection("Summary: ", element.Children);
break;
case "threadsafety":
if (ShowThreadSafety)
AddThreadSafety(ParseBool(element.GetAttribute("static")), ParseBool(element.GetAttribute("instance")), element.Children);
break;
case "typeparam":
if (ShowTypeParameters)
AddSection("Type parameter " + element.GetAttribute("name") + ": ", element.Children);
break;
case "typeparamref":
AddText(element.GetAttribute("name"));
break;
case "value":
if (ShowValue)
AddSection("Value: ", element.Children);
break;
case "exclude":
case "filterpriority":
case "overloads":
// ignore children
break;
case "br":
AddLineBreak();
break;
default:
foreach (var child in element.Children)
AddDocumentationElement(child);
break;
}
}
void AddList(string type, IEnumerable<XmlDocumentationElement> items)
{
List list = new List();
AddBlock(list);
list.Margin = new Thickness(0, 5, 0, 5);
if (type == "number")
list.MarkerStyle = TextMarkerStyle.Decimal;
else if (type == "bullet")
list.MarkerStyle = TextMarkerStyle.Disc;
var oldBlockCollection = blockCollection;
try {
foreach (var itemElement in items) {
if (itemElement.Name == "listheader" || itemElement.Name == "item") {
ListItem item = new ListItem();
blockCollection = item.Blocks;
inlineCollection = null;
foreach (var prop in itemElement.Children) {
AddDocumentationElement(prop);
}
FlushAddedText(false);
list.ListItems.Add(item);
}
}
} finally {
blockCollection = oldBlockCollection;
}
}
bool? ParseBool(string input)
{
if (bool.TryParse(input, out bool result))
return result;
else
return null;
}
void AddThreadSafety(bool? staticThreadSafe, bool? instanceThreadSafe, IEnumerable<XmlDocumentationElement> children)
{
AddSection(
new Run("Thread-safety: "),
delegate {
if (staticThreadSafe == true)
AddText("Any public static members of this type are thread safe. ");
else if (staticThreadSafe == false)
AddText("The static members of this type are not thread safe. ");
if (instanceThreadSafe == true)
AddText("Any public instance members of this type are thread safe. ");
else if (instanceThreadSafe == false)
AddText("Any instance members are not guaranteed to be thread safe. ");
foreach (var child in children)
AddDocumentationElement(child);
});
}
void AddException(IEntity referencedEntity, IList<XmlDocumentationElement> children)
{
Span span = new Span();
if (referencedEntity != null)
span.Inlines.Add(ConvertReference(referencedEntity));
else
span.Inlines.Add("Exception");
span.Inlines.Add(": ");
AddSection(span, children);
}
void AddPermission(IEntity referencedEntity, IList<XmlDocumentationElement> children)
{
Span span = new Span();
span.Inlines.Add("Permission");
if (referencedEntity != null) {
span.Inlines.Add(" ");
span.Inlines.Add(ConvertReference(referencedEntity));
}
span.Inlines.Add(": ");
AddSection(span, children);
}
Inline ConvertReference(IEntity referencedEntity)
{
var h = new Hyperlink(new Run(ambience.ConvertSymbol(referencedEntity)));
h.Click += (sender, e) => {
MainWindow.Instance.JumpToReference(referencedEntity);
};
return h;
}
void AddParam(string name, IEnumerable<XmlDocumentationElement> children)
{
Span span = new Span();
span.Inlines.Add(new Run(name ?? string.Empty) { FontStyle = FontStyles.Italic });
span.Inlines.Add(": ");
AddSection(span, children);
}
void AddParamRef(string name)
{
if (name != null) {
AddInline(new Run(name) { FontStyle = FontStyles.Italic });
}
}
void AddPreliminary(IEnumerable<XmlDocumentationElement> children)
{
if (children.Any()) {
foreach (var child in children)
AddDocumentationElement(child);
} else {
AddText("[This is preliminary documentation and subject to change.]");
}
}
void AddSee(XmlDocumentationElement element)
{
IEntity referencedEntity = element.ReferencedEntity;
if (referencedEntity != null) {
if (element.Children.Any()) {
Hyperlink link = new Hyperlink();
link.Click += (sender, e) => {
MainWindow.Instance.JumpToReference(referencedEntity);
};
AddSpan(link, element.Children);
} else {
AddInline(ConvertReference(referencedEntity));
}
} else if (element.GetAttribute("langword") != null) {
AddInline(new Run(element.GetAttribute("langword")) { FontFamily = GetCodeFont() });
} else if (element.GetAttribute("href") != null) {
Uri uri;
if (Uri.TryCreate(element.GetAttribute("href"), UriKind.Absolute, out uri)) {
if (element.Children.Any()) {
AddSpan(new Hyperlink { NavigateUri = uri }, element.Children);
} else {
AddInline(new Hyperlink(new Run(element.GetAttribute("href"))) { NavigateUri = uri });
}
}
} else {
// Invalid reference: print the cref value
AddText(element.GetAttribute("cref"));
}
}
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;
}
FontFamily GetCodeFont()
{
return DisplaySettingsPanel.CurrentDisplaySettings.SelectedFont;
}
public void AddInline(Inline inline)
{
FlushAddedText(false);
if (inlineCollection == null) {
var para = new Paragraph();
para.Margin = new Thickness(0, 0, 0, 5);
inlineCollection = para.Inlines;
AddBlock(para);
}
inlineCollection.Add(inline);
ignoreWhitespace = false;
}
void AddSection(string title, IEnumerable<XmlDocumentationElement> children)
{
AddSection(new Run(title), children);
}
void AddSection(Inline title, IEnumerable<XmlDocumentationElement> children)
{
AddSection(
title, delegate {
foreach (var child in children)
AddDocumentationElement(child);
});
}
void AddSection(Inline title, Action addChildren)
{
var section = new Section();
AddBlock(section);
var oldBlockCollection = blockCollection;
try {
blockCollection = section.Blocks;
inlineCollection = null;
if (title != null)
AddInline(new Bold(title));
addChildren();
FlushAddedText(false);
} finally {
blockCollection = oldBlockCollection;
inlineCollection = null;
}
}
void AddParagraph(Paragraph para, IEnumerable<XmlDocumentationElement> children)
{
AddBlock(para);
try {
inlineCollection = para.Inlines;
foreach (var child in children)
AddDocumentationElement(child);
FlushAddedText(false);
} finally {
inlineCollection = null;
}
}
void AddSpan(Span span, IEnumerable<XmlDocumentationElement> children)
{
AddInline(span);
var oldInlineCollection = inlineCollection;
try {
inlineCollection = span.Inlines;
foreach (var child in children)
AddDocumentationElement(child);
FlushAddedText(false);
} finally {
inlineCollection = oldInlineCollection;
}
}
public void AddBlock(Block block)
{
FlushAddedText(true);
blockCollection.Add(block);
}
StringBuilder addedText = new StringBuilder();
bool ignoreWhitespace;
public void AddLineBreak()
{
TrimEndOfAddedText();
addedText.AppendLine();
ignoreWhitespace = true;
}
public void AddText(string textContent)
{
if (string.IsNullOrEmpty(textContent))
return;
for (int i = 0; i < textContent.Length; i++) {
char c = textContent[i];
if (c == '\n' && IsEmptyLineBefore(textContent, i)) {
AddLineBreak(); // empty line -> line break
} else if (char.IsWhiteSpace(c)) {
// any whitespace sequence gets converted to a single space (like HTML)
if (!ignoreWhitespace) {
addedText.Append(' ');
ignoreWhitespace = true;
}
} else {
addedText.Append(c);
ignoreWhitespace = false;
}
}
}
bool IsEmptyLineBefore(string text, int i)
{
// Skip previous whitespace
do {
i--;
} while (i >= 0 && (text[i] == ' ' || text[i] == '\r'));
// Check if previous non-whitespace char is \n
return i >= 0 && text[i] == '\n';
}
void TrimEndOfAddedText()
{
while (addedText.Length > 0 && addedText[addedText.Length - 1] == ' ') {
addedText.Length--;
}
}
void FlushAddedText(bool trim)
{
if (trim) // trim end of current text element
TrimEndOfAddedText();
if (addedText.Length == 0)
return;
string text = addedText.ToString();
addedText.Length = 0;
AddInline(new Run(text));
ignoreWhitespace = trim; // trim start of next text element
}
}
}
Loading…
Cancel
Save