Browse Source

Fix #3521: Add API to set an initially highlighted entity after navigation.

pull/3550/head
Siegfried Pammer 4 months ago
parent
commit
d6ab43d839
  1. 13
      ILSpy/Analyzers/AnalyzerEntityTreeNode.cs
  2. 22
      ILSpy/Analyzers/AnalyzerSearchTreeNode.cs
  3. 10
      ILSpy/Analyzers/AnalyzerTreeViewModel.cs
  4. 4
      ILSpy/Analyzers/TreeNodes/AnalyzedAccessorTreeNode.cs
  5. 11
      ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs
  6. 5
      ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs
  7. 5
      ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs
  8. 5
      ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs
  9. 9
      ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs
  10. 5
      ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs
  11. 14
      ILSpy/AssemblyTree/AssemblyTreeModel.cs
  12. 7
      ILSpy/TextView/AvalonEditTextOutput.cs
  13. 43
      ILSpy/TextView/DecompilerTextView.cs
  14. 4
      ILSpy/Util/MessageBus.cs
  15. 2
      ILSpy/Views/DebugSteps.xaml.cs

13
ILSpy/Analyzers/AnalyzerEntityTreeNode.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Windows; using System.Windows;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -25,6 +26,8 @@ using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
#nullable enable
namespace ICSharpCode.ILSpy.Analyzers namespace ICSharpCode.ILSpy.Analyzers
{ {
/// <summary> /// <summary>
@ -34,6 +37,8 @@ namespace ICSharpCode.ILSpy.Analyzers
{ {
public abstract IEntity Member { get; } public abstract IEntity Member { get; }
public IEntity? SourceMember { get; protected set; }
public override void ActivateItem(IPlatformRoutedEventArgs e) public override void ActivateItem(IPlatformRoutedEventArgs e)
{ {
e.Handled = true; e.Handled = true;
@ -43,10 +48,14 @@ namespace ICSharpCode.ILSpy.Analyzers
return; return;
} }
MessageBus.Send(this, new NavigateToReferenceEventArgs(new EntityReference(this.Member.ParentModule?.MetadataFile, this.Member.MetadataToken))); var module = this.Member.ParentModule?.MetadataFile;
Debug.Assert(module != null);
MessageBus.Send(this, new NavigateToReferenceEventArgs(new EntityReference(module, this.Member.MetadataToken), this.SourceMember));
} }
public override object ToolTip => Member?.ParentModule?.MetadataFile?.FileName; public override object? ToolTip => Member?.ParentModule?.MetadataFile?.FileName;
public override bool HandleAssemblyListChanged(ICollection<LoadedAssembly> removedAssemblies, ICollection<LoadedAssembly> addedAssemblies) public override bool HandleAssemblyListChanged(ICollection<LoadedAssembly> removedAssemblies, ICollection<LoadedAssembly> addedAssemblies)
{ {

22
ILSpy/Analyzers/AnalyzerSearchTreeNode.cs

@ -76,29 +76,29 @@ namespace ICSharpCode.ILSpy.Analyzers
} }
} }
AnalyzerTreeNode SymbolTreeNodeFactory(ISymbol symbol) AnalyzerTreeNode SymbolTreeNodeFactory(ISymbol resultSymbol)
{ {
if (symbol == null) if (resultSymbol == null)
{ {
throw new ArgumentNullException(nameof(symbol)); throw new ArgumentNullException(nameof(resultSymbol));
} }
switch (symbol) switch (resultSymbol)
{ {
case IModule module: case IModule module:
return new AnalyzedModuleTreeNode(module) { }; return new AnalyzedModuleTreeNode(module, (IEntity)this.symbol);
case ITypeDefinition td: case ITypeDefinition td:
return new AnalyzedTypeTreeNode(td) { }; return new AnalyzedTypeTreeNode(td, (IEntity)this.symbol);
case IField fd: case IField fd:
return new AnalyzedFieldTreeNode(fd) { }; return new AnalyzedFieldTreeNode(fd, (IEntity)this.symbol);
case IMethod md: case IMethod md:
return new AnalyzedMethodTreeNode(md) { }; return new AnalyzedMethodTreeNode(md, (IEntity)this.symbol);
case IProperty pd: case IProperty pd:
return new AnalyzedPropertyTreeNode(pd) { }; return new AnalyzedPropertyTreeNode(pd, (IEntity)this.symbol);
case IEvent ed: case IEvent ed:
return new AnalyzedEventTreeNode(ed) { }; return new AnalyzedEventTreeNode(ed, (IEntity)this.symbol);
default: default:
throw new ArgumentOutOfRangeException(nameof(symbol), $"Symbol {symbol.GetType().FullName} is not supported."); throw new ArgumentOutOfRangeException(nameof(resultSymbol), $"Symbol {resultSymbol.GetType().FullName} is not supported.");
} }
} }

10
ILSpy/Analyzers/AnalyzerTreeViewModel.cs

@ -109,20 +109,20 @@ namespace ICSharpCode.ILSpy.Analyzers
switch (entity) switch (entity)
{ {
case ITypeDefinition td: case ITypeDefinition td:
AddOrSelect(new AnalyzedTypeTreeNode(td)); AddOrSelect(new AnalyzedTypeTreeNode(td, null));
break; break;
case IField fd: case IField fd:
if (!fd.IsConst) if (!fd.IsConst)
AddOrSelect(new AnalyzedFieldTreeNode(fd)); AddOrSelect(new AnalyzedFieldTreeNode(fd, null));
break; break;
case IMethod md: case IMethod md:
AddOrSelect(new AnalyzedMethodTreeNode(md)); AddOrSelect(new AnalyzedMethodTreeNode(md, null));
break; break;
case IProperty pd: case IProperty pd:
AddOrSelect(new AnalyzedPropertyTreeNode(pd)); AddOrSelect(new AnalyzedPropertyTreeNode(pd, null));
break; break;
case IEvent ed: case IEvent ed:
AddOrSelect(new AnalyzedEventTreeNode(ed)); AddOrSelect(new AnalyzedEventTreeNode(ed, null));
break; break;
default: default:
throw new ArgumentOutOfRangeException(nameof(entity), $@"Entity {entity.GetType().FullName} is not supported."); throw new ArgumentOutOfRangeException(nameof(entity), $@"Entity {entity.GetType().FullName} is not supported.");

4
ILSpy/Analyzers/TreeNodes/AnalyzedAccessorTreeNode.cs

@ -24,8 +24,8 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
readonly string name; readonly string name;
public AnalyzedAccessorTreeNode(IMethod analyzedMethod, string name) public AnalyzedAccessorTreeNode(IMethod analyzedMethod, IEntity source, string name)
: base(analyzedMethod) : base(analyzedMethod, source)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
{ {

11
ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs

@ -21,6 +21,8 @@ using System;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
#nullable enable
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode
@ -28,11 +30,12 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
readonly IEvent analyzedEvent; readonly IEvent analyzedEvent;
readonly string prefix; readonly string prefix;
public AnalyzedEventTreeNode(IEvent analyzedEvent, string prefix = "") public AnalyzedEventTreeNode(IEvent analyzedEvent, IEntity? source, string prefix = "")
{ {
this.analyzedEvent = analyzedEvent ?? throw new ArgumentNullException(nameof(analyzedEvent)); this.analyzedEvent = analyzedEvent ?? throw new ArgumentNullException(nameof(analyzedEvent));
this.prefix = prefix; this.prefix = prefix;
this.LazyLoading = true; this.LazyLoading = true;
this.SourceMember = source;
} }
public override IEntity Member => analyzedEvent; public override IEntity Member => analyzedEvent;
@ -45,11 +48,11 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
if (analyzedEvent.CanAdd) if (analyzedEvent.CanAdd)
this.Children.Add(new AnalyzedAccessorTreeNode(analyzedEvent.AddAccessor, "add")); this.Children.Add(new AnalyzedAccessorTreeNode(analyzedEvent.AddAccessor, this.SourceMember, "add"));
if (analyzedEvent.CanRemove) if (analyzedEvent.CanRemove)
this.Children.Add(new AnalyzedAccessorTreeNode(analyzedEvent.RemoveAccessor, "remove")); this.Children.Add(new AnalyzedAccessorTreeNode(analyzedEvent.RemoveAccessor, this.SourceMember, "remove"));
if (TryFindBackingField(analyzedEvent, out var backingField)) if (TryFindBackingField(analyzedEvent, out var backingField))
this.Children.Add(new AnalyzedFieldTreeNode(backingField)); this.Children.Add(new AnalyzedFieldTreeNode(backingField, this.SourceMember));
foreach (var lazy in Analyzers) foreach (var lazy in Analyzers)
{ {

5
ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs

@ -21,15 +21,18 @@ using System;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
#nullable enable
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
class AnalyzedFieldTreeNode : AnalyzerEntityTreeNode class AnalyzedFieldTreeNode : AnalyzerEntityTreeNode
{ {
readonly IField analyzedField; readonly IField analyzedField;
public AnalyzedFieldTreeNode(IField analyzedField) public AnalyzedFieldTreeNode(IField analyzedField, IEntity? source)
{ {
this.analyzedField = analyzedField ?? throw new ArgumentNullException(nameof(analyzedField)); this.analyzedField = analyzedField ?? throw new ArgumentNullException(nameof(analyzedField));
this.SourceMember = source;
this.LazyLoading = true; this.LazyLoading = true;
} }

5
ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs

@ -21,6 +21,8 @@ using System;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
#nullable enable
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
internal class AnalyzedMethodTreeNode : AnalyzerEntityTreeNode internal class AnalyzedMethodTreeNode : AnalyzerEntityTreeNode
@ -28,9 +30,10 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
readonly IMethod analyzedMethod; readonly IMethod analyzedMethod;
readonly string prefix; readonly string prefix;
public AnalyzedMethodTreeNode(IMethod analyzedMethod, string prefix = "") public AnalyzedMethodTreeNode(IMethod analyzedMethod, IEntity? source, string prefix = "")
{ {
this.analyzedMethod = analyzedMethod ?? throw new ArgumentNullException(nameof(analyzedMethod)); this.analyzedMethod = analyzedMethod ?? throw new ArgumentNullException(nameof(analyzedMethod));
this.SourceMember = source;
this.prefix = prefix; this.prefix = prefix;
this.LazyLoading = true; this.LazyLoading = true;
} }

5
ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs

@ -25,15 +25,18 @@ using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
#nullable enable
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
internal class AnalyzedModuleTreeNode : AnalyzerEntityTreeNode internal class AnalyzedModuleTreeNode : AnalyzerEntityTreeNode
{ {
readonly IModule analyzedModule; readonly IModule analyzedModule;
public AnalyzedModuleTreeNode(IModule analyzedModule) public AnalyzedModuleTreeNode(IModule analyzedModule, IEntity? source)
{ {
this.analyzedModule = analyzedModule ?? throw new ArgumentNullException(nameof(analyzedModule)); this.analyzedModule = analyzedModule ?? throw new ArgumentNullException(nameof(analyzedModule));
this.SourceMember = source;
this.LazyLoading = true; this.LazyLoading = true;
} }

9
ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs

@ -21,6 +21,8 @@ using System;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
#nullable enable
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
sealed class AnalyzedPropertyTreeNode : AnalyzerEntityTreeNode sealed class AnalyzedPropertyTreeNode : AnalyzerEntityTreeNode
@ -28,11 +30,12 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
readonly IProperty analyzedProperty; readonly IProperty analyzedProperty;
readonly string prefix; readonly string prefix;
public AnalyzedPropertyTreeNode(IProperty analyzedProperty, string prefix = "") public AnalyzedPropertyTreeNode(IProperty analyzedProperty, IEntity? source, string prefix = "")
{ {
this.analyzedProperty = analyzedProperty ?? throw new ArgumentNullException(nameof(analyzedProperty)); this.analyzedProperty = analyzedProperty ?? throw new ArgumentNullException(nameof(analyzedProperty));
this.prefix = prefix; this.prefix = prefix;
this.LazyLoading = true; this.LazyLoading = true;
this.SourceMember = source;
} }
public override object Icon => PropertyTreeNode.GetIcon(analyzedProperty); public override object Icon => PropertyTreeNode.GetIcon(analyzedProperty);
@ -43,9 +46,9 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
if (analyzedProperty.CanGet) if (analyzedProperty.CanGet)
this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Getter, "get")); this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Getter, this.SourceMember, "get"));
if (analyzedProperty.CanSet) if (analyzedProperty.CanSet)
this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Setter, "set")); this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Setter, this.SourceMember, "set"));
foreach (var lazy in Analyzers) foreach (var lazy in Analyzers)
{ {

5
ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs

@ -21,15 +21,18 @@ using System;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
#nullable enable
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
internal class AnalyzedTypeTreeNode : AnalyzerEntityTreeNode internal class AnalyzedTypeTreeNode : AnalyzerEntityTreeNode
{ {
readonly ITypeDefinition analyzedType; readonly ITypeDefinition analyzedType;
public AnalyzedTypeTreeNode(ITypeDefinition analyzedType) public AnalyzedTypeTreeNode(ITypeDefinition analyzedType, IEntity? source)
{ {
this.analyzedType = analyzedType ?? throw new ArgumentNullException(nameof(analyzedType)); this.analyzedType = analyzedType ?? throw new ArgumentNullException(nameof(analyzedType));
this.SourceMember = source;
this.LazyLoading = true; this.LazyLoading = true;
} }

14
ILSpy/AssemblyTree/AssemblyTreeModel.cs

@ -67,6 +67,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
private readonly NavigationHistory<NavigationState> history = new(); private readonly NavigationHistory<NavigationState> history = new();
private NavigationState? navigatingToState; private NavigationState? navigatingToState;
private object? sourceOfReference;
private readonly SettingsService settingsService; private readonly SettingsService settingsService;
private readonly LanguageService languageService; private readonly LanguageService languageService;
private readonly IExportProvider exportProvider; private readonly IExportProvider exportProvider;
@ -262,7 +263,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
found = true; found = true;
if (SelectedItem == initialSelection) if (SelectedItem == initialSelection)
{ {
await JumpToReferenceAsync(mr); await JumpToReferenceAsync(mr, null);
} }
} }
} }
@ -642,7 +643,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
private void JumpToReference(object? sender, NavigateToReferenceEventArgs e) private void JumpToReference(object? sender, NavigateToReferenceEventArgs e)
{ {
JumpToReferenceAsync(e.Reference, e.InNewTabPage).HandleExceptions(); JumpToReferenceAsync(e.Reference, e.Source, e.InNewTabPage).HandleExceptions();
IsActive = true; IsActive = true;
} }
@ -653,8 +654,9 @@ namespace ICSharpCode.ILSpy.AssemblyTree
/// Returns a task that will signal completion when the decompilation of the jump target has finished. /// Returns a task that will signal completion when the decompilation of the jump target has finished.
/// The task will be marked as canceled if the decompilation is canceled. /// The task will be marked as canceled if the decompilation is canceled.
/// </returns> /// </returns>
private Task JumpToReferenceAsync(object? reference, bool inNewTabPage = false) private Task JumpToReferenceAsync(object? reference, object? source, bool inNewTabPage = false)
{ {
this.sourceOfReference = source;
var decompilationTask = Task.CompletedTask; var decompilationTask = Task.CompletedTask;
switch (reference) switch (reference)
@ -804,6 +806,8 @@ namespace ICSharpCode.ILSpy.AssemblyTree
public void DecompileSelectedNodes(ViewState? newState = null) public void DecompileSelectedNodes(ViewState? newState = null)
{ {
object? source = this.sourceOfReference;
this.sourceOfReference = null;
var activeTabPage = DockWorkspace.ActiveTabPage; var activeTabPage = DockWorkspace.ActiveTabPage;
if (activeTabPage.FrozenContent) if (activeTabPage.FrozenContent)
@ -831,7 +835,9 @@ namespace ICSharpCode.ILSpy.AssemblyTree
var options = activeTabPage.CreateDecompilationOptions(); var options = activeTabPage.CreateDecompilationOptions();
options.TextViewState = newState as DecompilerTextViewState; options.TextViewState = newState as DecompilerTextViewState;
activeTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, options)); activeTabPage.ShowTextViewAsync(textView => {
return textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, source, options);
});
} }
public void RefreshDecompiledView() public void RefreshDecompiledView()

7
ILSpy/TextView/AvalonEditTextOutput.cs

@ -312,6 +312,13 @@ namespace ICSharpCode.ILSpy.TextView
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = true, IsDefinition = isDefinition }); references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = true, IsDefinition = isDefinition });
} }
internal object InitialHighlightReference = null;
public void SetInitialHighlight(object reference)
{
this.InitialHighlightReference = reference;
}
public void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false, bool isDefinition = false) public void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false, bool isDefinition = false)
{ {
WriteIndent(); WriteIndent();

43
ILSpy/TextView/DecompilerTextView.cs

@ -802,6 +802,7 @@ namespace ICSharpCode.ILSpy.TextView
currentAddress = textOutput.Address; currentAddress = textOutput.Address;
currentTitle = textOutput.Title; currentTitle = textOutput.Title;
expandMemberDefinitions = settingsService.DisplaySettings.ExpandMemberDefinitions; expandMemberDefinitions = settingsService.DisplaySettings.ExpandMemberDefinitions;
SetLocalReferenceMarks(textOutput.InitialHighlightReference);
} }
#endregion #endregion
@ -817,7 +818,7 @@ namespace ICSharpCode.ILSpy.TextView
[Obsolete("Use DecompileAsync() instead")] [Obsolete("Use DecompileAsync() instead")]
public void Decompile(ILSpy.Language language, IEnumerable<ILSpyTreeNode> treeNodes, DecompilationOptions options) public void Decompile(ILSpy.Language language, IEnumerable<ILSpyTreeNode> treeNodes, DecompilationOptions options)
{ {
DecompileAsync(language, treeNodes, options).HandleExceptions(); DecompileAsync(language, treeNodes, null, options).HandleExceptions();
} }
/// <summary> /// <summary>
@ -826,7 +827,7 @@ namespace ICSharpCode.ILSpy.TextView
/// If any errors occur, the error message is displayed in the text view, and the task returned by this method completes successfully. /// If any errors occur, the error message is displayed in the text view, and the task returned by this method completes successfully.
/// If the operation is cancelled (by starting another decompilation action); the returned task is marked as cancelled. /// If the operation is cancelled (by starting another decompilation action); the returned task is marked as cancelled.
/// </summary> /// </summary>
public Task DecompileAsync(ILSpy.Language language, IEnumerable<ILSpyTreeNode> treeNodes, DecompilationOptions options) public Task DecompileAsync(ILSpy.Language language, IEnumerable<ILSpyTreeNode> treeNodes, object? source, DecompilationOptions options)
{ {
// Some actions like loading an assembly list cause several selection changes in the tree view, // Some actions like loading an assembly list cause several selection changes in the tree view,
// and each of those will start a decompilation action. // and each of those will start a decompilation action.
@ -834,7 +835,7 @@ namespace ICSharpCode.ILSpy.TextView
bool isDecompilationScheduled = this.nextDecompilationRun != null; bool isDecompilationScheduled = this.nextDecompilationRun != null;
if (this.nextDecompilationRun != null) if (this.nextDecompilationRun != null)
this.nextDecompilationRun.TaskCompletionSource.TrySetCanceled(); this.nextDecompilationRun.TaskCompletionSource.TrySetCanceled();
this.nextDecompilationRun = new DecompilationContext(language, treeNodes.ToArray(), options); this.nextDecompilationRun = new DecompilationContext(language, treeNodes.ToArray(), options, source);
var task = this.nextDecompilationRun.TaskCompletionSource.Task; var task = this.nextDecompilationRun.TaskCompletionSource.Task;
if (!isDecompilationScheduled) if (!isDecompilationScheduled)
{ {
@ -857,12 +858,14 @@ namespace ICSharpCode.ILSpy.TextView
public readonly ILSpyTreeNode[] TreeNodes; public readonly ILSpyTreeNode[] TreeNodes;
public readonly DecompilationOptions Options; public readonly DecompilationOptions Options;
public readonly TaskCompletionSource<object?> TaskCompletionSource = new TaskCompletionSource<object?>(); public readonly TaskCompletionSource<object?> TaskCompletionSource = new TaskCompletionSource<object?>();
public readonly object? Source;
public DecompilationContext(ILSpy.Language language, ILSpyTreeNode[] treeNodes, DecompilationOptions options) public DecompilationContext(ILSpy.Language language, ILSpyTreeNode[] treeNodes, DecompilationOptions options, object? source = null)
{ {
this.Language = language; this.Language = language;
this.TreeNodes = treeNodes; this.TreeNodes = treeNodes;
this.Options = options; this.Options = options;
this.Source = source;
} }
} }
@ -914,6 +917,7 @@ namespace ICSharpCode.ILSpy.TextView
{ {
AvalonEditTextOutput textOutput = new AvalonEditTextOutput(); AvalonEditTextOutput textOutput = new AvalonEditTextOutput();
textOutput.LengthLimit = outputLengthLimit; textOutput.LengthLimit = outputLengthLimit;
textOutput.SetInitialHighlight(context.Source);
DecompileNodes(context, textOutput); DecompileNodes(context, textOutput);
textOutput.PrepareDocument(); textOutput.PrepareDocument();
tcs.SetResult(textOutput); tcs.SetResult(textOutput);
@ -994,19 +998,7 @@ namespace ICSharpCode.ILSpy.TextView
if (referenceSegment.IsLocal) if (referenceSegment.IsLocal)
{ {
ClearLocalReferenceMarks(); ClearLocalReferenceMarks();
if (references != null) SetLocalReferenceMarks(reference);
{
foreach (var r in references)
{
if (reference.Equals(r.Reference))
{
var mark = textMarkerService.Create(r.StartOffset, r.Length);
mark.BackgroundColor = (Color)(r.IsDefinition ? FindResource(ResourceKeys.TextMarkerDefinitionBackgroundColor) : FindResource(ResourceKeys.TextMarkerBackgroundColor));
localReferenceMarks.Add(mark);
}
}
}
return; return;
} }
if (definitionLookup != null) if (definitionLookup != null)
@ -1027,6 +1019,23 @@ namespace ICSharpCode.ILSpy.TextView
MessageBus.Send(this, new NavigateToReferenceEventArgs(reference, openInNewTab)); MessageBus.Send(this, new NavigateToReferenceEventArgs(reference, openInNewTab));
} }
private void SetLocalReferenceMarks(object reference)
{
if (references == null || reference == null)
{
return;
}
foreach (var r in references)
{
if (reference.Equals(r.Reference))
{
var mark = textMarkerService.Create(r.StartOffset, r.Length);
mark.BackgroundColor = (Color)(r.IsDefinition ? FindResource(ResourceKeys.TextMarkerDefinitionBackgroundColor) : FindResource(ResourceKeys.TextMarkerBackgroundColor));
localReferenceMarks.Add(mark);
}
}
}
Point? mouseDownPos; Point? mouseDownPos;
void TextAreaMouseDown(object sender, MouseButtonEventArgs e) void TextAreaMouseDown(object sender, MouseButtonEventArgs e)

4
ILSpy/Util/MessageBus.cs

@ -79,10 +79,10 @@ namespace ICSharpCode.ILSpy.Util
public class SettingsChangedEventArgs(PropertyChangedEventArgs e) : WrappedEventArgs<PropertyChangedEventArgs>(e); public class SettingsChangedEventArgs(PropertyChangedEventArgs e) : WrappedEventArgs<PropertyChangedEventArgs>(e);
public class NavigateToReferenceEventArgs(object reference, bool inNewTabPage = false) : EventArgs public class NavigateToReferenceEventArgs(object reference, object? source = null, bool inNewTabPage = false) : EventArgs
{ {
public object Reference { get; } = reference; public object Reference { get; } = reference;
public object? Source { get; } = source;
public bool InNewTabPage { get; } = inNewTabPage; public bool InNewTabPage { get; } = inNewTabPage;
} }

2
ILSpy/Views/DebugSteps.xaml.cs

@ -140,7 +140,7 @@ namespace ICSharpCode.ILSpy
} }
var state = dockWorkspace.ActiveTabPage.GetState(); var state = dockWorkspace.ActiveTabPage.GetState();
dockWorkspace.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(assemblyTreeModel.CurrentLanguage, assemblyTreeModel.SelectedNodes, dockWorkspace.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(assemblyTreeModel.CurrentLanguage, assemblyTreeModel.SelectedNodes, null,
new DecompilationOptions(assemblyTreeModel.CurrentLanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { new DecompilationOptions(assemblyTreeModel.CurrentLanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) {
StepLimit = step, StepLimit = step,
IsDebug = isDebug, IsDebug = isDebug,

Loading…
Cancel
Save