Browse Source

Merge d5830147fd into 4a29de5a4e

pull/3642/merge
Lex Li 1 day ago committed by GitHub
parent
commit
c5308c60f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 17
      ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
  2. 47
      ICSharpCode.ILSpyX/TreeView/SharpTreeNodeCollection.cs
  3. 4
      ILSpy/AboutPage.cs
  4. 69
      ILSpy/AssemblyTree/AssemblyTreeModel.cs
  5. 83
      ILSpy/AssemblyTree/AssemblyTreeModel.wpf.cs
  6. 2
      ILSpy/Commands/Pdb2XmlCommand.cs
  7. 121
      ILSpy/Docking/DockWorkspace.cs
  8. 150
      ILSpy/Docking/DockWorkspace.wpf.cs
  9. 4
      ILSpy/ILSpy.csproj
  10. 38
      ILSpy/ISmartTextOutput.cs
  11. 40
      ILSpy/Languages/CSharpLanguage.cs
  12. 75
      ILSpy/Languages/CSharpLanguage.wpf.cs
  13. 6
      ILSpy/Metadata/DataDirectoriesTreeNode.cs
  14. 6
      ILSpy/Metadata/DebugDirectoryTreeNode.cs
  15. 22
      ILSpy/Metadata/FlagsContentFilter.cs
  16. 20
      ILSpy/Metadata/FlagsFilterControl.xaml.cs
  17. 43
      ILSpy/Metadata/Helper.wpf.cs
  18. 43
      ILSpy/Metadata/Helpers.cs
  19. 31
      ILSpy/Metadata/HexFilterControl.ContentFilter.cs
  20. 23
      ILSpy/Metadata/HexFilterControl.xaml.cs
  21. 27
      ILSpy/Metadata/MetadataTableTreeNode.cs
  22. 32
      ILSpy/Metadata/MetadataTableTreeNode.wpf.cs
  23. 3
      ILSpy/Metadata/MetadataTreeNode.cs
  24. 30
      ILSpy/Options/ExportOptionPageAttribute.cs
  25. 29
      ILSpy/Options/IOptionPage.cs
  26. 25
      ILSpy/Options/IOptionsMetadata.cs
  27. 38
      ILSpy/Options/OptionsDialog.xaml.cs
  28. 56
      ILSpy/Options/ShowOptionsCommand.cs
  29. 24
      ILSpy/Search/SearchPane.xaml.cs
  30. 3
      ILSpy/Search/SearchPaneModel.cs
  31. 51
      ILSpy/Search/ShowSearchCommand.cs
  32. 61
      ILSpy/SmartTextOutputExtensions.cs
  33. 54
      ILSpy/TextView/BracketHighlightRenderer.cs
  34. 43
      ILSpy/TextView/BracketSearchResult.cs
  35. 28
      ILSpy/TextView/DecompilerTextView.cs
  36. 32
      ILSpy/TextView/DefaultBracketSearcher.cs
  37. 34
      ILSpy/TextView/IBracketSearcher.cs
  38. 33
      ILSpy/TextView/ReferenceElementGenerator.cs
  39. 56
      ILSpy/TextView/ViewState.cs
  40. 50
      ILSpy/TextView/VisualLineReferenceText.cs
  41. 37
      ILSpy/TextView/VisualLineReferenceText.wpf.cs
  42. 22
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  43. 16
      ILSpy/TreeNodes/ResourceListTreeNode.cs
  44. 27
      ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs
  45. 55
      ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.wpf.cs
  46. 2
      ILSpy/Util/GlobalUtils.cs
  47. 28
      ILSpy/Util/GlobalUtils.wpf.cs
  48. 49
      ILSpy/ViewModels/Pane.cs
  49. 28
      ILSpy/ViewModels/PaneModel.cs
  50. 83
      ILSpy/ViewModels/TabPageModel.cs
  51. 89
      ILSpy/ViewModels/TabPageModelExtensions.cs
  52. 44
      ILSpy/ViewModels/TabPageModelExtensions.wpf.cs
  53. 9
      ILSpy/ViewModels/ToolPaneModel.cs
  54. 87
      ILSpy/Views/GacEntry.cs
  55. 59
      ILSpy/Views/OpenFromGacDialog.xaml.cs

17
ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs

@ -323,9 +323,26 @@ namespace ICSharpCode.ILSpyX.TreeView @@ -323,9 +323,26 @@ namespace ICSharpCode.ILSpyX.TreeView
}
RaisePropertyChanged(nameof(LazyLoading));
RaisePropertyChanged(nameof(ShowExpander));
RaisePropertyChanged(nameof(ViewChildren));
}
}
/// <summary>
/// Workaround for cross platform treeview bindings.
/// </summary>
public System.Collections.IEnumerable ViewChildren {
get {
if (LazyLoading && Children.Count == 0)
return new[] { new LoadingTreeNode() };
return Children;
}
}
class LoadingTreeNode : SharpTreeNode
{
public override object Text => "Loading...";
}
bool canExpandRecursively = true;
/// <summary>

47
ICSharpCode.ILSpyX/TreeView/SharpTreeNodeCollection.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
@ -29,7 +30,7 @@ namespace ICSharpCode.ILSpyX.TreeView @@ -29,7 +30,7 @@ namespace ICSharpCode.ILSpyX.TreeView
/// <summary>
/// Collection that validates that inserted nodes do not have another parent.
/// </summary>
public sealed class SharpTreeNodeCollection : IList<SharpTreeNode>, INotifyCollectionChanged
public sealed class SharpTreeNodeCollection : IList<SharpTreeNode>, IList, INotifyCollectionChanged
{
readonly SharpTreeNode parent;
List<SharpTreeNode> list = new List<SharpTreeNode>();
@ -94,6 +95,20 @@ namespace ICSharpCode.ILSpyX.TreeView @@ -94,6 +95,20 @@ namespace ICSharpCode.ILSpyX.TreeView
get { return false; }
}
#region IList Members
public bool IsFixedSize => ((IList)list).IsFixedSize;
public bool IsReadOnly => ((IList)list).IsReadOnly;
public bool IsSynchronized => ((ICollection)list).IsSynchronized;
public object SyncRoot => ((ICollection)list).SyncRoot;
object IList.this[int index] { get => ((IList)list)[index]; set => ((IList)list)[index] = value; }
#endregion
public int IndexOf(SharpTreeNode node)
{
if (node == null || node.modelParent != parent)
@ -236,5 +251,35 @@ namespace ICSharpCode.ILSpyX.TreeView @@ -236,5 +251,35 @@ namespace ICSharpCode.ILSpyX.TreeView
RemoveRange(firstToRemove, list.Count - firstToRemove);
}
}
public int Add(object value)
{
return ((IList)list).Add(value);
}
public bool Contains(object value)
{
return ((IList)list).Contains(value);
}
public int IndexOf(object value)
{
return ((IList)list).IndexOf(value);
}
public void Insert(int index, object value)
{
((IList)list).Insert(index, value);
}
public void Remove(object value)
{
((IList)list).Remove(value);
}
public void CopyTo(Array array, int index)
{
((ICollection)list).CopyTo(array, index);
}
}
}

4
ILSpy/AboutPage.cs

@ -192,7 +192,11 @@ namespace ICSharpCode.ILSpy @@ -192,7 +192,11 @@ namespace ICSharpCode.ILSpy
stackPanel.Children.Add(
new Image {
Width = 16, Height = 16,
#if CROSS_PLATFORM
Source = Images.LoadImage(Images.OK),
#else
Source = Images.OK,
#endif
Margin = new Thickness(4, 0, 4, 0)
});
stackPanel.Children.Add(

69
ILSpy/AssemblyTree/AssemblyTreeModel.cs

@ -29,7 +29,6 @@ using System.Reflection.Metadata; @@ -29,7 +29,6 @@ using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Threading;
@ -57,7 +56,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -57,7 +56,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{
[ExportToolPane]
[Shared]
public class AssemblyTreeModel : ToolPaneModel
public partial class AssemblyTreeModel : ToolPaneModel
{
public const string PaneContentId = "assemblyListPane";
@ -74,36 +73,6 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -74,36 +73,6 @@ namespace ICSharpCode.ILSpy.AssemblyTree
private static Dispatcher UIThreadDispatcher => Application.Current.Dispatcher;
public AssemblyTreeModel(SettingsService settingsService, LanguageService languageService, IExportProvider exportProvider)
{
this.settingsService = settingsService;
this.languageService = languageService;
this.exportProvider = exportProvider;
Title = Resources.Assemblies;
ContentId = PaneContentId;
IsCloseable = false;
ShortcutKey = new KeyGesture(Key.F6);
MessageBus<NavigateToReferenceEventArgs>.Subscribers += JumpToReference;
MessageBus<SettingsChangedEventArgs>.Subscribers += (sender, e) => Settings_PropertyChanged(sender, e);
MessageBus<ApplySessionSettingsEventArgs>.Subscribers += ApplySessionSettings;
MessageBus<ActiveTabPageChangedEventArgs>.Subscribers += ActiveTabPageChanged;
MessageBus<TabPagesCollectionChangedEventArgs>.Subscribers += (_, e) => history.RemoveAll(s => !DockWorkspace.TabPages.Contains(s.TabPage));
MessageBus<ResetLayoutEventArgs>.Subscribers += ResetLayout;
MessageBus<NavigateToEventArgs>.Subscribers += (_, e) => NavigateTo(e.Request, e.InNewTabPage);
MessageBus<MainWindowLoadedEventArgs>.Subscribers += (_, _) => {
Initialize();
Show();
};
EventManager.RegisterClassHandler(typeof(Window), Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler((_, e) => NavigateTo(e)));
refreshThrottle = new(DispatcherPriority.Background, RefreshInternal);
AssemblyList = settingsService.CreateEmptyAssemblyList();
}
private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (sender is SessionSettings sessionSettings)
@ -161,6 +130,9 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -161,6 +130,9 @@ namespace ICSharpCode.ILSpy.AssemblyTree
var oldSelection = selectedItems;
selectedItems = value;
OnPropertyChanged();
#if CROSS_PLATFORM
OnPropertyChanged(nameof(SelectedItem));
#endif
TreeView_SelectionChanged(oldSelection, selectedItems);
}
}
@ -494,24 +466,6 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -494,24 +466,6 @@ namespace ICSharpCode.ILSpy.AssemblyTree
MessageBus.Send(this, new CurrentAssemblyListChangedEventArgs(e));
}
private static void LoadInitialAssemblies(AssemblyList assemblyList)
{
// Called when loading an empty assembly list; so that
// the user can see something initially.
System.Reflection.Assembly[] initialAssemblies = {
typeof(object).Assembly,
typeof(Uri).Assembly,
typeof(System.Linq.Enumerable).Assembly,
typeof(System.Xml.XmlDocument).Assembly,
typeof(System.Windows.Markup.MarkupExtension).Assembly,
typeof(System.Windows.Rect).Assembly,
typeof(System.Windows.UIElement).Assembly,
typeof(System.Windows.FrameworkElement).Assembly
};
foreach (System.Reflection.Assembly asm in initialAssemblies)
assemblyList.OpenAssembly(asm.Location);
}
public AssemblyTreeNode? FindAssemblyNode(LoadedAssembly asm)
{
return assemblyListTreeNode?.FindAssemblyNode(asm);
@ -542,10 +496,16 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -542,10 +496,16 @@ namespace ICSharpCode.ILSpy.AssemblyTree
}
else
{
#if CROSS_PLATFORM
ExpandAncestors(node);
#endif
activeView?.ScrollIntoView(node);
SelectedItem = node;
UIThreadDispatcher.BeginInvoke(DispatcherPriority.Background, () => {
#if CROSS_PLATFORM
SelectedItem = node;
#endif
activeView?.ScrollIntoView(node);
});
}
@ -1011,6 +971,15 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -1011,6 +971,15 @@ namespace ICSharpCode.ILSpy.AssemblyTree
return selection.Where(item => item.Ancestors().All(a => !selectionHash.Contains(a)));
}
void ExpandAncestors(SharpTreeNode node)
{
foreach (var ancestor in node.Ancestors().Reverse())
{
ancestor.EnsureLazyChildren();
ancestor.IsExpanded = true;
}
}
public void SetActiveView(AssemblyListPane activeView)
{
this.activeView = activeView;

83
ILSpy/AssemblyTree/AssemblyTreeModel.wpf.cs

@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
// Copyright (c) 2019 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;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Threading;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpyX;
using TomsToolbox.Composition;
namespace ICSharpCode.ILSpy.AssemblyTree
{
public partial class AssemblyTreeModel
{
public AssemblyTreeModel(SettingsService settingsService, LanguageService languageService, IExportProvider exportProvider)
{
this.settingsService = settingsService;
this.languageService = languageService;
this.exportProvider = exportProvider;
Title = Resources.Assemblies;
ContentId = PaneContentId;
IsCloseable = false;
ShortcutKey = new KeyGesture(Key.F6);
MessageBus<NavigateToReferenceEventArgs>.Subscribers += JumpToReference;
MessageBus<SettingsChangedEventArgs>.Subscribers += (sender, e) => Settings_PropertyChanged(sender, e);
MessageBus<ApplySessionSettingsEventArgs>.Subscribers += ApplySessionSettings;
MessageBus<ActiveTabPageChangedEventArgs>.Subscribers += ActiveTabPageChanged;
MessageBus<TabPagesCollectionChangedEventArgs>.Subscribers += (_, e) => history.RemoveAll(s => !DockWorkspace.TabPages.Contains(s.TabPage));
MessageBus<ResetLayoutEventArgs>.Subscribers += ResetLayout;
MessageBus<NavigateToEventArgs>.Subscribers += (_, e) => NavigateTo(e.Request, e.InNewTabPage);
MessageBus<MainWindowLoadedEventArgs>.Subscribers += (_, _) => {
Initialize();
Show();
};
EventManager.RegisterClassHandler(typeof(Window), Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler((_, e) => NavigateTo(e)));
refreshThrottle = new(DispatcherPriority.Background, RefreshInternal);
AssemblyList = settingsService.CreateEmptyAssemblyList();
}
private static void LoadInitialAssemblies(AssemblyList assemblyList)
{
// Called when loading an empty assembly list; so that
// the user can see something initially.
System.Reflection.Assembly[] initialAssemblies = {
typeof(object).Assembly,
typeof(Uri).Assembly,
typeof(System.Linq.Enumerable).Assembly,
typeof(System.Xml.XmlDocument).Assembly,
typeof(System.Windows.Markup.MarkupExtension).Assembly,
typeof(System.Windows.Rect).Assembly,
typeof(System.Windows.UIElement).Assembly,
typeof(System.Windows.FrameworkElement).Assembly
};
foreach (System.Reflection.Assembly asm in initialAssemblies)
assemblyList.OpenAssembly(asm.Location);
}
}
}

2
ILSpy/Commands/Pdb2XmlCommand.cs

@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#if DEBUG
#if DEBUG && WINDOWS
using System.Collections.Generic;
using System.Composition;

121
ILSpy/Docking/DockWorkspace.cs

@ -22,19 +22,13 @@ using System.Collections.ObjectModel; @@ -22,19 +22,13 @@ using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Composition;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Threading;
using AvalonDock;
using AvalonDock.Layout;
using AvalonDock.Layout.Serialization;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
@ -44,9 +38,9 @@ using TomsToolbox.Wpf; @@ -44,9 +38,9 @@ using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy.Docking
{
[Export]
[Export(typeof(DockWorkspace))]
[Shared]
public class DockWorkspace : ObservableObjectBase, ILayoutUpdateStrategy
public partial class DockWorkspace : ObservableObjectBase, ILayoutUpdateStrategy
{
private readonly IExportProvider exportProvider;
@ -55,8 +49,6 @@ namespace ICSharpCode.ILSpy.Docking @@ -55,8 +49,6 @@ namespace ICSharpCode.ILSpy.Docking
readonly SessionSettings sessionSettings;
private DockingManager DockingManager => exportProvider.GetExportedValue<DockingManager>();
public DockWorkspace(SettingsService settingsService, IExportProvider exportProvider)
{
this.exportProvider = exportProvider;
@ -175,56 +167,6 @@ namespace ICSharpCode.ILSpy.Docking @@ -175,56 +167,6 @@ namespace ICSharpCode.ILSpy.Docking
MessageBus.Send(this, new ActiveTabPageChangedEventArgs(value?.GetState()));
}
}
public PaneModel ActivePane {
get => DockingManager.ActiveContent as PaneModel;
set => DockingManager.ActiveContent = value;
}
public void InitializeLayout()
{
if (tabPages.Count == 0)
{
// Make sure there is at least one tab open
AddTabPage();
}
DockingManager.LayoutUpdateStrategy = this;
XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager);
serializer.LayoutSerializationCallback += LayoutSerializationCallback;
try
{
sessionSettings.DockLayout.Deserialize(serializer);
}
finally
{
serializer.LayoutSerializationCallback -= LayoutSerializationCallback;
}
DockingManager.SetBinding(DockingManager.AnchorablesSourceProperty, new Binding(nameof(ToolPanes)));
DockingManager.SetBinding(DockingManager.DocumentsSourceProperty, new Binding(nameof(TabPages)));
}
void LayoutSerializationCallback(object sender, LayoutSerializationCallbackEventArgs e)
{
switch (e.Model)
{
case LayoutAnchorable la:
e.Content = this.ToolPanes.FirstOrDefault(p => p.ContentId == la.ContentId);
e.Cancel = e.Content == null;
la.CanDockAsTabbedDocument = false;
if (e.Content is ToolPaneModel toolPaneModel)
{
e.Cancel = toolPaneModel.IsVisible;
toolPaneModel.IsVisible = true;
}
break;
default:
e.Cancel = true;
break;
}
}
public void ShowText(AvalonEditTextOutput textOutput)
{
ActiveTabPage.ShowTextView(textView => textView.ShowText(textOutput));
@ -252,65 +194,6 @@ namespace ICSharpCode.ILSpy.Docking @@ -252,65 +194,6 @@ namespace ICSharpCode.ILSpy.Docking
tabPages.RemoveWhere(page => page != activePage);
}
internal void ResetLayout()
{
foreach (var pane in ToolPanes)
{
pane.IsVisible = false;
}
CloseAllTabs();
sessionSettings.DockLayout.Reset();
InitializeLayout();
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, () => MessageBus.Send(this, new ResetLayoutEventArgs()));
}
static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance);
public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer)
{
if (!(anchorableToShow.Content is LegacyToolPaneModel legacyContent))
return false;
anchorableToShow.CanDockAsTabbedDocument = false;
LayoutAnchorablePane previousContainer;
switch (legacyContent.Location)
{
case LegacyToolPaneLocation.Top:
previousContainer = GetContainer<SearchPaneModel>();
previousContainer.Children.Add(anchorableToShow);
return true;
case LegacyToolPaneLocation.Bottom:
previousContainer = GetContainer<AnalyzerTreeViewModel>();
previousContainer.Children.Add(anchorableToShow);
return true;
default:
return false;
}
LayoutAnchorablePane GetContainer<T>()
{
var anchorable = layout.Descendents().OfType<LayoutAnchorable>().FirstOrDefault(x => x.Content is T)
?? layout.Hidden.First(x => x.Content is T);
return (LayoutAnchorablePane)previousContainerProperty.GetValue(anchorable) ?? (LayoutAnchorablePane)anchorable.Parent;
}
}
public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown)
{
anchorableShown.IsActive = true;
anchorableShown.IsSelected = true;
}
public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer)
{
return false;
}
public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown)
{
}
// Dummy property to make the XAML designer happy, the model is provided by the AvalonDock PaneStyleSelectors, not by the DockWorkspace, but the designer assumes the data context in the PaneStyleSelectors is the DockWorkspace.
public PaneModel Model { get; } = null;
}

150
ILSpy/Docking/DockWorkspace.wpf.cs

@ -0,0 +1,150 @@ @@ -0,0 +1,150 @@
// Copyright (c) 2019 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.Linq;
using System.Reflection;
using System.Windows.Data;
using System.Windows.Threading;
using AvalonDock;
using AvalonDock.Layout;
using AvalonDock.Layout.Serialization;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
/// <summary>
/// WPF-specific extensions to <see cref="DockWorkspace"/>.
/// </summary>
partial class DockWorkspace
{
private DockingManager DockingManager => exportProvider.GetExportedValue<DockingManager>();
void LayoutSerializationCallback(object sender, LayoutSerializationCallbackEventArgs e)
{
switch (e.Model)
{
case LayoutAnchorable la:
e.Content = this.ToolPanes.FirstOrDefault(p => p.ContentId == la.ContentId);
e.Cancel = e.Content == null;
la.CanDockAsTabbedDocument = false;
if (e.Content is ToolPaneModel toolPaneModel)
{
e.Cancel = toolPaneModel.IsVisible;
toolPaneModel.IsVisible = true;
}
break;
default:
e.Cancel = true;
break;
}
}
public PaneModel ActivePane {
get => DockingManager.ActiveContent as PaneModel;
set => DockingManager.ActiveContent = value;
}
public void InitializeLayout()
{
if (tabPages.Count == 0)
{
// Make sure there is at least one tab open
AddTabPage();
}
DockingManager.LayoutUpdateStrategy = this;
XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager);
serializer.LayoutSerializationCallback += LayoutSerializationCallback;
try
{
sessionSettings.DockLayout.Deserialize(serializer);
}
finally
{
serializer.LayoutSerializationCallback -= LayoutSerializationCallback;
}
DockingManager.SetBinding(DockingManager.AnchorablesSourceProperty, new Binding(nameof(ToolPanes)));
DockingManager.SetBinding(DockingManager.DocumentsSourceProperty, new Binding(nameof(TabPages)));
}
internal void ResetLayout()
{
foreach (var pane in ToolPanes)
{
pane.IsVisible = false;
}
CloseAllTabs();
sessionSettings.DockLayout.Reset();
InitializeLayout();
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, () => MessageBus.Send(this, new ResetLayoutEventArgs()));
}
static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance);
public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer)
{
if (!(anchorableToShow.Content is LegacyToolPaneModel legacyContent))
return false;
anchorableToShow.CanDockAsTabbedDocument = false;
LayoutAnchorablePane previousContainer;
switch (legacyContent.Location)
{
case LegacyToolPaneLocation.Top:
previousContainer = GetContainer<SearchPaneModel>();
previousContainer.Children.Add(anchorableToShow);
return true;
case LegacyToolPaneLocation.Bottom:
previousContainer = GetContainer<AnalyzerTreeViewModel>();
previousContainer.Children.Add(anchorableToShow);
return true;
default:
return false;
}
LayoutAnchorablePane GetContainer<T>()
{
var anchorable = layout.Descendents().OfType<LayoutAnchorable>().FirstOrDefault(x => x.Content is T)
?? layout.Hidden.First(x => x.Content is T);
return (LayoutAnchorablePane)previousContainerProperty.GetValue(anchorable) ?? (LayoutAnchorablePane)anchorable.Parent;
}
}
public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown)
{
anchorableShown.IsActive = true;
anchorableShown.IsSelected = true;
}
public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer)
{
return false;
}
public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown)
{
}
}
}

4
ILSpy/ILSpy.csproj

@ -125,8 +125,8 @@ @@ -125,8 +125,8 @@
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
<SortResX>powershell -NoProfile -ExecutionPolicy Bypass -File BuildTools/sort-resx.ps1</SortResX>
</PropertyGroup>
<Exec WorkingDirectory=".." Command="$(SortResX)" Timeout="60000" />
<Touch Files="@(SortResXStamp)" AlwaysCreate="true" />
<Exec WorkingDirectory=".." Command="$(SortResX)" Timeout="60000" Condition="'$(SortResX)' != ''" />
<Touch Files="@(SortResXStamp)" AlwaysCreate="true" Condition="'$(SortResX)' != ''" />
</Target>
<Target Name="ApplyStackExtension" AfterTargets="PostBuildEvent" Condition="'$(VCToolsVersion)'!=''">

38
ILSpy/ISmartTextOutput.cs

@ -18,13 +18,9 @@ @@ -18,13 +18,9 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.Themes;
namespace ICSharpCode.ILSpy
{
@ -46,38 +42,4 @@ namespace ICSharpCode.ILSpy @@ -46,38 +42,4 @@ namespace ICSharpCode.ILSpy
/// </summary>
string Title { get; set; }
}
public static class SmartTextOutputExtensions
{
/// <summary>
/// Creates a button.
/// </summary>
public static void AddButton(this ISmartTextOutput output, ImageSource icon, string text, RoutedEventHandler click)
{
output.AddUIElement(
delegate {
Button button = ThemeManager.Current.CreateButton();
button.Cursor = Cursors.Arrow;
button.Margin = new Thickness(2);
button.Padding = new Thickness(9, 1, 9, 1);
button.MinWidth = 73;
if (icon != null)
{
button.Content = new StackPanel {
Orientation = Orientation.Horizontal,
Children = {
new Image { Width = 16, Height = 16, Source = icon, Margin = new Thickness(0, 0, 4, 0) },
new TextBlock { Text = text }
}
};
}
else
{
button.Content = text;
}
button.Click += click;
return button;
});
}
}
}

40
ILSpy/Languages/CSharpLanguage.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy @@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy
/// </summary>
[Export(typeof(Language))]
[Shared]
public class CSharpLanguage : Language
public partial class CSharpLanguage : Language
{
string name = "C#";
bool showAllMembers = false;
@ -387,44 +387,6 @@ namespace ICSharpCode.ILSpy @@ -387,44 +387,6 @@ namespace ICSharpCode.ILSpy
AddWarningMessage(module, output, line1);
}
void AddWarningMessage(MetadataFile module, ITextOutput output, string line1, string line2 = null,
string buttonText = null, System.Windows.Media.ImageSource buttonImage = null, RoutedEventHandler buttonClickHandler = null)
{
if (output is ISmartTextOutput fancyOutput)
{
string text = line1;
if (!string.IsNullOrEmpty(line2))
text += Environment.NewLine + line2;
fancyOutput.AddUIElement(() => new StackPanel {
Margin = new Thickness(5),
Orientation = Orientation.Horizontal,
Children = {
new Image {
Width = 32,
Height = 32,
Source = Images.Load(this, "Images/Warning")
},
new TextBlock {
Margin = new Thickness(5, 0, 0, 0),
Text = text
}
}
});
fancyOutput.WriteLine();
if (buttonText != null && buttonClickHandler != null)
{
fancyOutput.AddButton(buttonImage, buttonText, buttonClickHandler);
fancyOutput.WriteLine();
}
}
else
{
WriteCommentLine(output, line1);
if (!string.IsNullOrEmpty(line2))
WriteCommentLine(output, line2);
}
}
public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
var module = assembly.GetMetadataFileOrNull();

75
ILSpy/Languages/CSharpLanguage.wpf.cs

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
// 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.Windows;
using System.Windows.Controls;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// C# decompiler integration into ILSpy.
/// Note: if you're interested in using the decompiler without the ILSpy UI,
/// please directly use the CSharpDecompiler class.
/// </summary>
partial class CSharpLanguage
{
void AddWarningMessage(MetadataFile module, ITextOutput output, string line1, string line2 = null,
string buttonText = null, System.Windows.Media.ImageSource buttonImage = null, RoutedEventHandler buttonClickHandler = null)
{
if (output is ISmartTextOutput fancyOutput)
{
string text = line1;
if (!string.IsNullOrEmpty(line2))
text += Environment.NewLine + line2;
fancyOutput.AddUIElement(() => new StackPanel {
Margin = new Thickness(5),
Orientation = Orientation.Horizontal,
Children = {
new Image {
Width = 32,
Height = 32,
Source = Images.Load(this, "Images/Warning")
},
new TextBlock {
Margin = new Thickness(5, 0, 0, 0),
Text = text
}
}
});
fancyOutput.WriteLine();
if (buttonText != null && buttonClickHandler != null)
{
fancyOutput.AddButton(buttonImage, buttonText, buttonClickHandler);
fancyOutput.WriteLine();
}
}
else
{
WriteCommentLine(output, line1);
if (!string.IsNullOrEmpty(line2))
WriteCommentLine(output, line2);
}
}
}
}

6
ILSpy/Metadata/DataDirectoriesTreeNode.cs

@ -36,10 +36,12 @@ namespace ICSharpCode.ILSpy.Metadata @@ -36,10 +36,12 @@ namespace ICSharpCode.ILSpy.Metadata
public override object Text => "Data Directories";
public override object NavigationText => $"{Text} ({module.Name})";
#if CROSS_PLATFORM
public override object Icon => Images.DirectoryTable;
#else
public override object Icon => Images.ListFolder;
public override object ExpandedIcon => Images.ListFolderOpen;
#endif
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();

6
ILSpy/Metadata/DebugDirectoryTreeNode.cs

@ -41,10 +41,12 @@ namespace ICSharpCode.ILSpy.Metadata @@ -41,10 +41,12 @@ namespace ICSharpCode.ILSpy.Metadata
public override object Text => "Debug Directory";
public override object NavigationText => $"{Text} ({module.Name})";
#if CROSS_PLATFORM
public override object Icon => Images.DirectoryTable;
#else
public override object Icon => Images.ListFolder;
public override object ExpandedIcon => Images.ListFolderOpen;
#endif
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();

22
ILSpy/Metadata/FlagsContentFilter.cs

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
using DataGridExtensions;
namespace ICSharpCode.ILSpy.Metadata
{
public class FlagsContentFilter : IContentFilter
{
public int Mask { get; }
public FlagsContentFilter(int mask)
{
this.Mask = mask;
}
public bool IsMatch(object value)
{
if (value == null)
return true;
return Mask == -1 || (Mask & (int)value) != 0;
}
}
}

20
ILSpy/Metadata/FlagsFilterControl.xaml.cs

@ -3,8 +3,6 @@ using System.Linq; @@ -3,8 +3,6 @@ using System.Linq;
using System.Windows;
using System.Windows.Controls;
using DataGridExtensions;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.ILSpy.Metadata
@ -104,22 +102,4 @@ namespace ICSharpCode.ILSpy.Metadata @@ -104,22 +102,4 @@ namespace ICSharpCode.ILSpy.Metadata
Filter = new FlagsContentFilter(mask);
}
}
public class FlagsContentFilter : IContentFilter
{
public int Mask { get; }
public FlagsContentFilter(int mask)
{
this.Mask = mask;
}
public bool IsMatch(object value)
{
if (value == null)
return true;
return Mask == -1 || (Mask & (int)value) != 0;
}
}
}

43
ILSpy/Metadata/Helper.wpf.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
using System;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
namespace ICSharpCode.ILSpy.Metadata
{
static partial class Helpers
{
private static DataTemplate GetOrCreateLinkCellTemplate(string name, PropertyDescriptor descriptor, Binding binding)
{
if (linkCellTemplates.TryGetValue(name, out var template))
{
return template;
}
var tb = new FrameworkElementFactory(typeof(TextBlock));
var hyper = new FrameworkElementFactory(typeof(Hyperlink));
tb.AppendChild(hyper);
hyper.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(Hyperlink_Click));
var run = new FrameworkElementFactory(typeof(Run));
hyper.AppendChild(run);
run.SetBinding(Run.TextProperty, binding);
DataTemplate dataTemplate = new DataTemplate() { VisualTree = tb };
linkCellTemplates.Add(name, dataTemplate);
return dataTemplate;
void Hyperlink_Click(object sender, RoutedEventArgs e)
{
var hyperlink = (Hyperlink)sender;
var onClickMethod = descriptor.ComponentType.GetMethod("On" + name + "Click", BindingFlags.Instance | BindingFlags.Public);
if (onClickMethod != null)
{
onClickMethod.Invoke(hyperlink.DataContext, Array.Empty<object>());
}
}
}
}
}

43
ILSpy/Metadata/Helpers.cs

@ -46,7 +46,7 @@ using TomsToolbox.Wpf.Interactivity; @@ -46,7 +46,7 @@ using TomsToolbox.Wpf.Interactivity;
namespace ICSharpCode.ILSpy.Metadata
{
static class Helpers
static partial class Helpers
{
public static DataGrid PrepareDataGrid(TabPageModel tabPage, ILSpyTreeNode selectedNode)
{
@ -71,7 +71,9 @@ namespace ICSharpCode.ILSpy.Metadata @@ -71,7 +71,9 @@ namespace ICSharpCode.ILSpy.Metadata
ContextMenuProvider.Add(view);
DataGridFilter.SetIsAutoFilterEnabled(view, true);
DataGridFilter.SetContentFilterFactory(view, new RegexContentFilterFactory());
#if !CROSS_PLATFORM
AdvancedScrollWheelBehavior.SetAttach(view, AdvancedScrollWheelMode.WithoutAnimation);
#endif
}
DataGridFilter.GetFilter(view).Clear();
view.RowDetailsTemplateSelector = null;
@ -110,14 +112,23 @@ namespace ICSharpCode.ILSpy.Metadata @@ -110,14 +112,23 @@ namespace ICSharpCode.ILSpy.Metadata
case "RVA":
case "StartOffset":
case "Length":
#if CROSS_PLATFORM
binding.Converter = HexFormatConverter.Instance;
#else
binding.StringFormat = "X8";
#endif
e.Column.SetTemplate((ControlTemplate)MetadataTableViews.Instance["HexFilter"]);
break;
case "RowDetails":
e.Cancel = true;
break;
case "Value" when e.PropertyDescriptor is PropertyDescriptor dp && dp.ComponentType == typeof(Entry):
#if CROSS_PLATFORM
binding.Path = ".";
e.Column.SetTemplate((ControlTemplate)MetadataTableViews.Instance["DefaultFilter"]);
#else
binding.Path = new PropertyPath(".");
#endif
binding.Converter = ByteWidthConverter.Instance;
break;
default:
@ -165,36 +176,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -165,36 +176,6 @@ namespace ICSharpCode.ILSpy.Metadata
static readonly Dictionary<string, DataTemplate> linkCellTemplates = new Dictionary<string, DataTemplate>();
private static DataTemplate GetOrCreateLinkCellTemplate(string name, PropertyDescriptor descriptor, Binding binding)
{
if (linkCellTemplates.TryGetValue(name, out var template))
{
return template;
}
var tb = new FrameworkElementFactory(typeof(TextBlock));
var hyper = new FrameworkElementFactory(typeof(Hyperlink));
tb.AppendChild(hyper);
hyper.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(Hyperlink_Click));
var run = new FrameworkElementFactory(typeof(Run));
hyper.AppendChild(run);
run.SetBinding(Run.TextProperty, binding);
DataTemplate dataTemplate = new DataTemplate() { VisualTree = tb };
linkCellTemplates.Add(name, dataTemplate);
return dataTemplate;
void Hyperlink_Click(object sender, RoutedEventArgs e)
{
var hyperlink = (Hyperlink)sender;
var onClickMethod = descriptor.ComponentType.GetMethod("On" + name + "Click", BindingFlags.Instance | BindingFlags.Public);
if (onClickMethod != null)
{
onClickMethod.Invoke(hyperlink.DataContext, Array.Empty<object>());
}
}
}
static void ApplyAttributes(PropertyDescriptor descriptor, Binding binding, DataGridColumn column)
{
if (descriptor.PropertyType.IsEnum)

31
ILSpy/Metadata/HexFilterControl.ContentFilter.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
using System;
using DataGridExtensions;
namespace ICSharpCode.ILSpy.Metadata
{
public partial class HexFilterControl
{
class ContentFilter : IContentFilter
{
readonly string filter;
public ContentFilter(string filter)
{
this.filter = filter;
}
public bool IsMatch(object value)
{
if (string.IsNullOrWhiteSpace(filter))
return true;
if (value == null)
return false;
return string.Format("{0:x8}", value).IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
}
public string Value => filter;
}
}
}

23
ILSpy/Metadata/HexFilterControl.xaml.cs

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -61,27 +60,5 @@ namespace ICSharpCode.ILSpy.Metadata @@ -61,27 +60,5 @@ namespace ICSharpCode.ILSpy.Metadata
textBox.Text = (newValue as ContentFilter)?.Value ?? string.Empty;
}
class ContentFilter : IContentFilter
{
readonly string filter;
public ContentFilter(string filter)
{
this.filter = filter;
}
public bool IsMatch(object value)
{
if (string.IsNullOrWhiteSpace(filter))
return true;
if (value == null)
return false;
return string.Format("{0:x8}", value).IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
}
public string Value => filter;
}
}
}

27
ILSpy/Metadata/MetadataTableTreeNode.cs

@ -30,7 +30,7 @@ using ICSharpCode.ILSpy.ViewModels; @@ -30,7 +30,7 @@ using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Metadata
{
internal abstract class MetadataTableTreeNode : ILSpyTreeNode
internal abstract partial class MetadataTableTreeNode : ILSpyTreeNode
{
protected readonly MetadataFile metadataFile;
protected int scrollTarget;
@ -54,29 +54,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -54,29 +54,6 @@ namespace ICSharpCode.ILSpy.Metadata
this.scrollTarget = metadataFile.Metadata.GetRowNumber((EntityHandle)handle);
}
protected void ScrollRowIntoView(DataGrid view, int row)
{
if (!view.IsLoaded)
{
view.Loaded += View_Loaded;
}
else
{
View_Loaded(view, new System.Windows.RoutedEventArgs());
}
if (view.Items.Count > row && row >= 0)
view.Dispatcher.BeginInvoke(() => view.SelectItem(view.Items[row]), DispatcherPriority.Background);
}
private void View_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
DataGrid view = (DataGrid)sender;
var sv = view.FindVisualChild<ScrollViewer>();
sv.ScrollToVerticalOffset(scrollTarget - 1);
view.Loaded -= View_Loaded;
this.scrollTarget = default;
}
protected static string GenerateTooltip(ref string tooltip, MetadataFile module, EntityHandle handle)
{
if (tooltip == null)
@ -202,4 +179,4 @@ namespace ICSharpCode.ILSpy.Metadata @@ -202,4 +179,4 @@ namespace ICSharpCode.ILSpy.Metadata
output.WriteLine($"Unsupported table '{(int)Kind:X2} {Kind}' contains {metadataFile.Metadata.GetTableRowCount(Kind)} rows.");
}
}
}
}

32
ILSpy/Metadata/MetadataTableTreeNode.wpf.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
using System.Windows.Controls;
using System.Windows.Threading;
namespace ICSharpCode.ILSpy.Metadata
{
partial class MetadataTableTreeNode
{
protected void ScrollRowIntoView(DataGrid view, int row)
{
if (!view.IsLoaded)
{
view.Loaded += View_Loaded;
}
else
{
View_Loaded(view, new System.Windows.RoutedEventArgs());
}
if (view.Items.Count > row && row >= 0)
view.Dispatcher.BeginInvoke(() => view.SelectItem(view.Items[row]), DispatcherPriority.Background);
}
private void View_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
DataGrid view = (DataGrid)sender;
var sv = view.FindVisualChild<ScrollViewer>();
sv.ScrollToVerticalOffset(scrollTarget - 1);
view.Loaded -= View_Loaded;
this.scrollTarget = default;
}
}
}

3
ILSpy/Metadata/MetadataTreeNode.cs

@ -153,6 +153,9 @@ namespace ICSharpCode.ILSpy.Metadata @@ -153,6 +153,9 @@ namespace ICSharpCode.ILSpy.Metadata
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (object.ReferenceEquals(value, null))
return string.Empty;
return string.Format("{0:X" + 2 * ((Entry)value).Size + "}", ((Entry)value).Value);
}

30
ILSpy/Options/ExportOptionPageAttribute.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
// 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.Composition;
namespace ICSharpCode.ILSpy.Options
{
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public sealed class ExportOptionPageAttribute() : ExportAttribute("OptionPages", typeof(IOptionPage)), IOptionsMetadata
{
public int Order { get; set; }
}
}

29
ILSpy/Options/IOptionPage.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
// 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.
namespace ICSharpCode.ILSpy.Options
{
public interface IOptionPage
{
string Title { get; }
void Load(SettingsSnapshot settings);
void LoadDefaults();
}
}

25
ILSpy/Options/IOptionsMetadata.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// 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.
namespace ICSharpCode.ILSpy.Options
{
public interface IOptionsMetadata
{
int Order { get; }
}
}

38
ILSpy/Options/OptionsDialog.xaml.cs

@ -35,42 +35,4 @@ namespace ICSharpCode.ILSpy.Options @@ -35,42 +35,4 @@ namespace ICSharpCode.ILSpy.Options
InitializeComponent();
}
}
public interface IOptionsMetadata
{
int Order { get; }
}
public interface IOptionPage
{
string Title { get; }
void Load(SettingsSnapshot settings);
void LoadDefaults();
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public sealed class ExportOptionPageAttribute() : ExportAttribute("OptionPages", typeof(IOptionPage)), IOptionsMetadata
{
public int Order { get; set; }
}
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._Options), MenuCategory = nameof(Resources.Options), MenuOrder = 999)]
[Shared]
sealed class ShowOptionsCommand(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService, MainWindow mainWindow) : SimpleCommand
{
public override void Execute(object parameter)
{
OptionsDialog dlg = new(settingsService) {
Owner = mainWindow
};
if (dlg.ShowDialog() == true)
{
assemblyTreeModel.Refresh();
}
}
}
}

56
ILSpy/Options/ShowOptionsCommand.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// 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.Composition;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy.Options
{
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._Options), MenuCategory = nameof(Resources.Options), MenuOrder = 999)]
[Shared]
sealed class ShowOptionsCommand(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService, MainWindow mainWindow) : SimpleCommand
{
public override void Execute(object parameter)
{
OptionsDialog dlg = new(settingsService);
#if CROSS_PLATFORM
// On cross-platform schedule showing the dialog on the UI dispatcher
// and await its result asynchronously. Do not block the calling thread.
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(async () => {
bool? asyncResult = await dlg.ShowDialogAsync(mainWindow);
if (asyncResult == true)
{
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(() => assemblyTreeModel.Refresh());
}
});
#else
// WPF path: set owner and show dialog synchronously as before.
dlg.Owner = mainWindow;
bool? result = dlg.ShowDialog();
if (result == true)
{
assemblyTreeModel.Refresh();
}
#endif
}
}
}

24
ILSpy/Search/SearchPane.xaml.cs

@ -34,7 +34,6 @@ using System.Windows.Threading; @@ -34,7 +34,6 @@ using System.Windows.Threading;
using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Abstractions;
@ -579,27 +578,4 @@ namespace ICSharpCode.ILSpy.Search @@ -579,27 +578,4 @@ namespace ICSharpCode.ILSpy.Search
}
}
}
[ExportToolbarCommand(ToolTip = nameof(Properties.Resources.SearchCtrlShiftFOrCtrlE), ToolbarIcon = "Images/Search", ToolbarCategory = nameof(Properties.Resources.View), ToolbarOrder = 100)]
[Shared]
sealed class ShowSearchCommand : CommandWrapper
{
private readonly DockWorkspace dockWorkspace;
public ShowSearchCommand(DockWorkspace dockWorkspace)
: base(NavigationCommands.Search)
{
this.dockWorkspace = dockWorkspace;
var gestures = NavigationCommands.Search.InputGestures;
gestures.Clear();
gestures.Add(new KeyGesture(Key.F, ModifierKeys.Control | ModifierKeys.Shift));
gestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
dockWorkspace.ShowToolPane(SearchPaneModel.PaneContentId);
}
}
}

3
ILSpy/Search/SearchPaneModel.cs

@ -32,9 +32,10 @@ namespace ICSharpCode.ILSpy.Search @@ -32,9 +32,10 @@ namespace ICSharpCode.ILSpy.Search
public ImageSource Image { get; init; }
}
[Export]
[ExportToolPane]
[Shared]
public class SearchPaneModel : ToolPaneModel
public partial class SearchPaneModel : ToolPaneModel
{
public const string PaneContentId = "searchPane";

51
ILSpy/Search/ShowSearchCommand.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// 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.Composition;
using System.Windows.Input;
using ICSharpCode.ILSpy.Docking;
namespace ICSharpCode.ILSpy.Search
{
[ExportToolbarCommand(ToolTip = nameof(Properties.Resources.SearchCtrlShiftFOrCtrlE), ToolbarIcon = "Images/Search", ToolbarCategory = nameof(Properties.Resources.View), ToolbarOrder = 100)]
[Shared]
sealed class ShowSearchCommand : CommandWrapper
{
private readonly DockWorkspace dockWorkspace;
public ShowSearchCommand(DockWorkspace dockWorkspace)
: base(NavigationCommands.Search)
{
this.dockWorkspace = dockWorkspace;
var gestures = NavigationCommands.Search.InputGestures;
gestures.Clear();
gestures.Add(new KeyGesture(Key.F, ModifierKeys.Control | ModifierKeys.Shift));
gestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
Console.WriteLine($"ShowSearchCommand: Executing ShowToolPane for SearchPaneModel.PaneContentId using dockWorkspace type: {dockWorkspace?.GetType().FullName}");
var result = dockWorkspace.ShowToolPane(SearchPaneModel.PaneContentId);
Console.WriteLine($"ShowSearchCommand: ShowToolPane returned: {result}");
}
}
}

61
ILSpy/SmartTextOutputExtensions.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// 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.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.ILSpy.Themes;
namespace ICSharpCode.ILSpy
{
public static class SmartTextOutputExtensions
{
/// <summary>
/// Creates a button.
/// </summary>
public static void AddButton(this ISmartTextOutput output, ImageSource icon, string text, RoutedEventHandler click)
{
output.AddUIElement(
delegate {
Button button = ThemeManager.Current.CreateButton();
button.Cursor = Cursors.Arrow;
button.Margin = new Thickness(2);
button.Padding = new Thickness(9, 1, 9, 1);
button.MinWidth = 73;
if (icon != null)
{
button.Content = new StackPanel {
Orientation = Orientation.Horizontal,
Children = {
new Image { Width = 16, Height = 16, Source = icon, Margin = new Thickness(0, 0, 4, 0) },
new TextBlock { Text = text }
}
};
}
else
{
button.Content = text;
}
button.Click += click;
return button;
});
}
}
}

54
ILSpy/TextView/BracketHighlightRenderer.cs

@ -24,50 +24,6 @@ using ICSharpCode.AvalonEdit.Rendering; @@ -24,50 +24,6 @@ using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// Allows language specific search for matching brackets.
/// </summary>
public interface IBracketSearcher
{
/// <summary>
/// Searches for a matching bracket from the given offset to the start of the document.
/// </summary>
/// <returns>A BracketSearchResult that contains the positions and lengths of the brackets. Return null if there is nothing to highlight.</returns>
BracketSearchResult SearchBracket(IDocument document, int offset);
}
public class DefaultBracketSearcher : IBracketSearcher
{
public static readonly DefaultBracketSearcher DefaultInstance = new DefaultBracketSearcher();
public BracketSearchResult SearchBracket(IDocument document, int offset)
{
return null;
}
}
/// <summary>
/// Describes a pair of matching brackets found by <see cref="IBracketSearcher"/>.
/// </summary>
public class BracketSearchResult
{
public int OpeningBracketOffset { get; private set; }
public int OpeningBracketLength { get; private set; }
public int ClosingBracketOffset { get; private set; }
public int ClosingBracketLength { get; private set; }
public BracketSearchResult(int openingBracketOffset, int openingBracketLength,
int closingBracketOffset, int closingBracketLength)
{
this.OpeningBracketOffset = openingBracketOffset;
this.OpeningBracketLength = openingBracketLength;
this.ClosingBracketOffset = closingBracketOffset;
this.ClosingBracketLength = closingBracketLength;
}
}
public class BracketHighlightRenderer : IBackgroundRenderer
{
@ -92,8 +48,14 @@ namespace ICSharpCode.ILSpy.TextView @@ -92,8 +48,14 @@ namespace ICSharpCode.ILSpy.TextView
if (textView == null)
throw new ArgumentNullException("textView");
this.borderPen = (Pen)textView.FindResource(Themes.ResourceKeys.BracketHighlightBorderPen);
this.backgroundBrush = (SolidColorBrush)textView.FindResource(Themes.ResourceKeys.BracketHighlightBackgroundBrush);
// resource loading safe guard
var borderPenResource = textView.FindResource(Themes.ResourceKeys.BracketHighlightBorderPen);
if (borderPenResource is Pen p)
this.borderPen = p;
var backgroundBrushResource = textView.FindResource(Themes.ResourceKeys.BracketHighlightBackgroundBrush);
if (backgroundBrushResource is SolidColorBrush b)
this.backgroundBrush = b;
this.textView = textView;

43
ILSpy/TextView/BracketSearchResult.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// 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.
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// Describes a pair of matching brackets found by <see cref="IBracketSearcher"/>.
/// </summary>
public class BracketSearchResult
{
public int OpeningBracketOffset { get; private set; }
public int OpeningBracketLength { get; private set; }
public int ClosingBracketOffset { get; private set; }
public int ClosingBracketLength { get; private set; }
public BracketSearchResult(int openingBracketOffset, int openingBracketLength,
int closingBracketOffset, int closingBracketLength)
{
this.OpeningBracketOffset = openingBracketOffset;
this.OpeningBracketLength = openingBracketLength;
this.ClosingBracketOffset = closingBracketOffset;
this.ClosingBracketLength = closingBracketLength;
}
}
}

28
ILSpy/TextView/DecompilerTextView.cs

@ -1357,34 +1357,6 @@ namespace ICSharpCode.ILSpy.TextView @@ -1357,34 +1357,6 @@ namespace ICSharpCode.ILSpy.TextView
#endregion
}
[DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")]
public class ViewState : IEquatable<ViewState>
{
public HashSet<ILSpyTreeNode>? DecompiledNodes;
public Uri? ViewedUri;
public virtual bool Equals(ViewState? other)
{
return other != null
&& ViewedUri == other.ViewedUri
&& NullSafeSetEquals(DecompiledNodes, other.DecompiledNodes);
static bool NullSafeSetEquals(HashSet<ILSpyTreeNode>? a, HashSet<ILSpyTreeNode>? b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
return a.SetEquals(b);
}
}
protected virtual string GetDebuggerDisplay()
{
return $"Nodes = {DecompiledNodes?.Count.ToString() ?? "<null>"}, ViewedUri = {ViewedUri?.ToString() ?? "<null>"}";
}
}
public class DecompilerTextViewState : ViewState
{
private List<(int StartOffset, int EndOffset)>? ExpandedFoldings;

32
ILSpy/TextView/DefaultBracketSearcher.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
// 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 ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.ILSpy.TextView
{
public class DefaultBracketSearcher : IBracketSearcher
{
public static readonly DefaultBracketSearcher DefaultInstance = new DefaultBracketSearcher();
public BracketSearchResult SearchBracket(IDocument document, int offset)
{
return null;
}
}
}

34
ILSpy/TextView/IBracketSearcher.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
// 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 ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// Allows language specific search for matching brackets.
/// </summary>
public interface IBracketSearcher
{
/// <summary>
/// Searches for a matching bracket from the given offset to the start of the document.
/// </summary>
/// <returns>A BracketSearchResult that contains the positions and lengths of the brackets. Return null if there is nothing to highlight.</returns>
BracketSearchResult SearchBracket(IDocument document, int offset);
}
}

33
ILSpy/TextView/ReferenceElementGenerator.cs

@ -72,37 +72,4 @@ namespace ICSharpCode.ILSpy.TextView @@ -72,37 +72,4 @@ namespace ICSharpCode.ILSpy.TextView
return null;
}
}
/// <summary>
/// VisualLineElement that represents a piece of text and is a clickable link.
/// </summary>
sealed class VisualLineReferenceText : VisualLineText
{
readonly ReferenceElementGenerator parent;
readonly ReferenceSegment referenceSegment;
/// <summary>
/// Creates a visual line text element with the specified length.
/// It uses the <see cref="ITextRunConstructionContext.VisualLine"/> and its
/// <see cref="VisualLineElement.RelativeTextOffset"/> to find the actual text string.
/// </summary>
public VisualLineReferenceText(VisualLine parentVisualLine, int length, ReferenceElementGenerator parent, ReferenceSegment referenceSegment) : base(parentVisualLine, length)
{
this.parent = parent;
this.referenceSegment = referenceSegment;
}
/// <inheritdoc/>
protected override void OnQueryCursor(QueryCursorEventArgs e)
{
e.Handled = true;
e.Cursor = referenceSegment.IsLocal ? Cursors.Arrow : Cursors.Hand;
}
/// <inheritdoc/>
protected override VisualLineText CreateInstance(int length)
{
return new VisualLineReferenceText(ParentVisualLine, length, parent, referenceSegment);
}
}
}

56
ILSpy/TextView/ViewState.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// 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.
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.TextView
{
[DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")]
public class ViewState : IEquatable<ViewState>
{
public HashSet<ILSpyTreeNode>? DecompiledNodes;
public Uri? ViewedUri;
public virtual bool Equals(ViewState? other)
{
return other != null
&& ViewedUri == other.ViewedUri
&& NullSafeSetEquals(DecompiledNodes, other.DecompiledNodes);
static bool NullSafeSetEquals(HashSet<ILSpyTreeNode>? a, HashSet<ILSpyTreeNode>? b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
return a.SetEquals(b);
}
}
protected virtual string GetDebuggerDisplay()
{
return $"Nodes = {DecompiledNodes?.Count.ToString() ?? "<null>"}, ViewedUri = {ViewedUri?.ToString() ?? "<null>"}";
}
}
}

50
ILSpy/TextView/VisualLineReferenceText.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// 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.Windows.Input;
using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// VisualLineElement that represents a piece of text and is a clickable link.
/// </summary>
sealed partial class VisualLineReferenceText : VisualLineText
{
readonly ReferenceElementGenerator parent;
readonly ReferenceSegment referenceSegment;
/// <summary>
/// Creates a visual line text element with the specified length.
/// It uses the <see cref="ITextRunConstructionContext.VisualLine"/> and its
/// <see cref="VisualLineElement.RelativeTextOffset"/> to find the actual text string.
/// </summary>
public VisualLineReferenceText(VisualLine parentVisualLine, int length, ReferenceElementGenerator parent, ReferenceSegment referenceSegment) : base(parentVisualLine, length)
{
this.parent = parent;
this.referenceSegment = referenceSegment;
}
/// <inheritdoc/>
protected override VisualLineText CreateInstance(int length)
{
return new VisualLineReferenceText(ParentVisualLine, length, parent, referenceSegment);
}
}
}

37
ILSpy/TextView/VisualLineReferenceText.wpf.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
// 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.Windows.Input;
using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.ILSpy.TextView
{
/// <summary>
/// VisualLineElement that represents a piece of text and is a clickable link.
/// </summary>
partial class VisualLineReferenceText
{
/// <inheritdoc/>
protected override void OnQueryCursor(QueryCursorEventArgs e)
{
e.Handled = true;
e.Cursor = referenceSegment.IsLocal ? Cursors.Arrow : Cursors.Hand;
}
}
}

22
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -140,30 +140,50 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -140,30 +140,50 @@ namespace ICSharpCode.ILSpy.TreeNodes
var metadata = module?.Metadata;
if (metadata?.IsAssembly == true && metadata.TryGetFullAssemblyName(out var assemblyName))
{
#if CROSS_PLATFORM
tooltip.Inlines.Add(new Bold().Add(new Run("Name: ")));
#else
tooltip.Inlines.Add(new Bold(new Run("Name: ")));
#endif
tooltip.Inlines.Add(new Run(assemblyName));
tooltip.Inlines.Add(new LineBreak());
}
#if CROSS_PLATFORM
tooltip.Inlines.Add(new Bold().Add(new Run("Location: ")));
#else
tooltip.Inlines.Add(new Bold(new Run("Location: ")));
#endif
tooltip.Inlines.Add(new Run(LoadedAssembly.FileName));
if (module != null)
{
if (module is PEFile peFile)
{
tooltip.Inlines.Add(new LineBreak());
#if CROSS_PLATFORM
tooltip.Inlines.Add(new Bold().Add(new Run("Architecture: ")));
#else
tooltip.Inlines.Add(new Bold(new Run("Architecture: ")));
#endif
tooltip.Inlines.Add(new Run(Language.GetPlatformDisplayName(peFile)));
}
string runtimeName = Language.GetRuntimeDisplayName(module);
if (runtimeName != null)
{
tooltip.Inlines.Add(new LineBreak());
#if CROSS_PLATFORM
tooltip.Inlines.Add(new Bold().Add(new Run("Runtime: ")));
#else
tooltip.Inlines.Add(new Bold(new Run("Runtime: ")));
#endif
tooltip.Inlines.Add(new Run(runtimeName));
}
var debugInfo = LoadedAssembly.GetDebugInfoOrNull();
tooltip.Inlines.Add(new LineBreak());
#if CROSS_PLATFORM
tooltip.Inlines.Add(new Bold().Add(new Run("Debug info: ")));
#else
tooltip.Inlines.Add(new Bold(new Run("Debug info: ")));
#endif
tooltip.Inlines.Add(new Run(debugInfo?.Description ?? "none"));
}
}
@ -742,7 +762,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -742,7 +762,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
var path = Path.GetDirectoryName(node.LoadedAssembly.FileName);
if (Directory.Exists(path))
{
GlobalUtils.ExecuteCommand("cmd.exe", $"/k \"cd /d {path}\"");
GlobalUtils.OpenTerminalAt(path);
}
}
}

16
ILSpy/TreeNodes/ResourceListTreeNode.cs

@ -42,11 +42,25 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -42,11 +42,25 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override object Text => Resources._Resources;
public override object NavigationText => $"{Text} ({module.Name})";
#if CROSS_PLATFORM
public override object Icon => IsExpanded ? Images.FolderOpen : Images.FolderClosed;
protected override void OnExpanding()
{
base.OnExpanding();
RaisePropertyChanged(nameof(Icon));
}
protected override void OnCollapsing()
{
base.OnCollapsing();
RaisePropertyChanged(nameof(Icon));
}
#else
public override object Icon => Images.FolderClosed;
public override object ExpandedIcon => Images.FolderOpen;
#endif
protected override void LoadChildren()
{
foreach (Resource r in module.Resources.OrderBy(m => m.Name, NaturalStringComparer.Instance))

27
ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs

@ -20,7 +20,6 @@ using System; @@ -20,7 +20,6 @@ using System;
using System.Composition;
using System.IO;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Properties;
@ -48,7 +47,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -48,7 +47,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
sealed class ImageResourceEntryNode : ResourceEntryNode
sealed partial class ImageResourceEntryNode : ResourceEntryNode
{
public ImageResourceEntryNode(string key, Func<Stream> openStream)
: base(key, openStream)
@ -56,29 +55,5 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -56,29 +55,5 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
public override object Icon => Images.ResourceImage;
public override bool View(TabPageModel tabPage)
{
try
{
AvalonEditTextOutput output = new AvalonEditTextOutput();
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = OpenStream();
image.EndInit();
output.AddUIElement(() => new Image { Source = image });
output.WriteLine();
output.AddButton(Images.Save, Resources.Save, delegate {
Save(null);
});
tabPage.ShowTextView(textView => textView.ShowNode(output, this));
tabPage.SupportsLanguageSwitching = false;
return true;
}
catch (Exception)
{
return false;
}
}
}
}

55
ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.wpf.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// 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.Windows.Controls;
using System.Windows.Media.Imaging;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.TreeNodes
{
partial class ImageResourceEntryNode
{
public override bool View(TabPageModel tabPage)
{
try
{
AvalonEditTextOutput output = new AvalonEditTextOutput();
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = OpenStream();
image.EndInit();
output.AddUIElement(() => new Image { Source = image });
output.WriteLine();
output.AddButton(Images.Save, Resources.Save, delegate {
Save(null);
});
tabPage.ShowTextView(textView => textView.ShowNode(output, this));
tabPage.SupportsLanguageSwitching = false;
return true;
}
catch (Exception)
{
return false;
}
}
}
}

2
ILSpy/Util/GlobalUtils.cs

@ -21,7 +21,7 @@ using System.Diagnostics; @@ -21,7 +21,7 @@ using System.Diagnostics;
namespace ICSharpCode.ILSpy.Util
{
static class GlobalUtils
static partial class GlobalUtils
{
public static void OpenLink(string link)
{

28
ILSpy/Util/GlobalUtils.wpf.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
// Copyright (c) 2024 Tom Englert 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.
namespace ICSharpCode.ILSpy.Util
{
partial class GlobalUtils
{
public static void OpenTerminalAt(string path)
{
ExecuteCommand("cmd.exe", $"/k \"cd /d {path}\"");
}
}
}

49
ILSpy/ViewModels/Pane.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
// Copyright (c) 2019 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.Windows;
namespace ICSharpCode.ILSpy.ViewModels
{
public static class Pane
{
// Helper properties to enable binding state properties from the model to the view.
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
"IsActive", typeof(bool), typeof(Pane), new FrameworkPropertyMetadata(default(bool)));
public static void SetIsActive(DependencyObject element, bool value)
{
element.SetValue(IsActiveProperty, value);
}
public static bool GetIsActive(DependencyObject element)
{
return (bool)element.GetValue(IsActiveProperty);
}
public static readonly DependencyProperty IsVisibleProperty = DependencyProperty.RegisterAttached(
"IsVisible", typeof(bool), typeof(Pane), new FrameworkPropertyMetadata(default(bool)));
public static void SetIsVisible(DependencyObject element, bool value)
{
element.SetValue(IsVisibleProperty, value);
}
public static bool GetIsVisible(DependencyObject element)
{
return (bool)element.GetValue(IsVisibleProperty);
}
}
}

28
ILSpy/ViewModels/PaneModel.cs

@ -18,7 +18,6 @@ @@ -18,7 +18,6 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using ICSharpCode.ILSpy.Docking;
@ -122,31 +121,4 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -122,31 +121,4 @@ namespace ICSharpCode.ILSpy.ViewModels
}
}
}
public static class Pane
{
// Helper properties to enable binding state properties from the model to the view.
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
"IsActive", typeof(bool), typeof(Pane), new FrameworkPropertyMetadata(default(bool)));
public static void SetIsActive(DependencyObject element, bool value)
{
element.SetValue(IsActiveProperty, value);
}
public static bool GetIsActive(DependencyObject element)
{
return (bool)element.GetValue(IsActiveProperty);
}
public static readonly DependencyProperty IsVisibleProperty = DependencyProperty.RegisterAttached(
"IsVisible", typeof(bool), typeof(Pane), new FrameworkPropertyMetadata(default(bool)));
public static void SetIsVisible(DependencyObject element, bool value)
{
element.SetValue(IsVisibleProperty, value);
}
public static bool GetIsVisible(DependencyObject element)
{
return (bool)element.GetValue(IsVisibleProperty);
}
}
}

83
ILSpy/ViewModels/TabPageModel.cs

@ -16,13 +16,10 @@ @@ -16,13 +16,10 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
using TomsToolbox.Composition;
@ -34,8 +31,14 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -34,8 +31,14 @@ namespace ICSharpCode.ILSpy.ViewModels
{
[Export]
[NonShared]
#if CROSS_PLATFORM
public class TabPageModel : Dock.Model.TomsToolbox.Controls.Document
{
protected static DockWorkspace DockWorkspace => App.ExportProvider.GetExportedValue<DockWorkspace>();
#else
public class TabPageModel : PaneModel
{
#endif
public IExportProvider ExportProvider { get; }
public TabPageModel(IExportProvider exportProvider)
@ -71,80 +74,6 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -71,80 +74,6 @@ namespace ICSharpCode.ILSpy.ViewModels
}
}
public static class TabPageModelExtensions
{
public static Task<T> ShowTextViewAsync<T>(this TabPageModel tabPage, Func<DecompilerTextView, Task<T>> action)
{
if (tabPage.Content is not DecompilerTextView textView)
{
textView = new DecompilerTextView(tabPage.ExportProvider);
tabPage.Content = textView;
}
tabPage.Title = Properties.Resources.Decompiling;
return action(textView);
}
public static Task ShowTextViewAsync(this TabPageModel tabPage, Func<DecompilerTextView, Task> action)
{
if (tabPage.Content is not DecompilerTextView textView)
{
textView = new DecompilerTextView(tabPage.ExportProvider);
tabPage.Content = textView;
}
string oldTitle = tabPage.Title;
tabPage.Title = Properties.Resources.Decompiling;
try
{
return action(textView);
}
finally
{
if (tabPage.Title == Properties.Resources.Decompiling)
{
tabPage.Title = oldTitle;
}
}
}
public static void ShowTextView(this TabPageModel tabPage, Action<DecompilerTextView> action)
{
if (tabPage.Content is not DecompilerTextView textView)
{
textView = new DecompilerTextView(tabPage.ExportProvider);
tabPage.Content = textView;
}
string oldTitle = tabPage.Title;
tabPage.Title = Properties.Resources.Decompiling;
action(textView);
if (tabPage.Title == Properties.Resources.Decompiling)
{
tabPage.Title = oldTitle;
}
}
public static void Focus(this TabPageModel tabPage)
{
if (tabPage.Content is not FrameworkElement content)
return;
var focusable = content
.VisualDescendantsAndSelf()
.OfType<FrameworkElement>()
.FirstOrDefault(item => item.Focusable);
focusable?.Focus();
}
public static DecompilationOptions CreateDecompilationOptions(this TabPageModel tabPage)
{
var exportProvider = tabPage.ExportProvider;
var languageService = exportProvider.GetExportedValue<LanguageService>();
var settingsService = exportProvider.GetExportedValue<SettingsService>();
return new(languageService.LanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { Progress = tabPage.Content as IProgress<DecompilationProgress> };
}
}
public interface IHaveState
{
ViewState? GetState();

89
ILSpy/ViewModels/TabPageModelExtensions.cs

@ -0,0 +1,89 @@ @@ -0,0 +1,89 @@
// Copyright (c) 2019 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.Threading.Tasks;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
#nullable enable
namespace ICSharpCode.ILSpy.ViewModels
{
public static partial class TabPageModelExtensions
{
public static Task<T> ShowTextViewAsync<T>(this TabPageModel tabPage, Func<DecompilerTextView, Task<T>> action)
{
if (tabPage.Content is not DecompilerTextView textView)
{
textView = new DecompilerTextView(tabPage.ExportProvider);
tabPage.Content = textView;
}
tabPage.Title = Properties.Resources.Decompiling;
return action(textView);
}
public static Task ShowTextViewAsync(this TabPageModel tabPage, Func<DecompilerTextView, Task> action)
{
if (tabPage.Content is not DecompilerTextView textView)
{
textView = new DecompilerTextView(tabPage.ExportProvider);
tabPage.Content = textView;
}
string oldTitle = tabPage.Title;
tabPage.Title = Properties.Resources.Decompiling;
try
{
return action(textView);
}
finally
{
if (tabPage.Title == Properties.Resources.Decompiling)
{
tabPage.Title = oldTitle;
}
}
}
public static void ShowTextView(this TabPageModel tabPage, Action<DecompilerTextView> action)
{
if (tabPage.Content is not DecompilerTextView textView)
{
textView = new DecompilerTextView(tabPage.ExportProvider);
tabPage.Content = textView;
}
string oldTitle = tabPage.Title;
tabPage.Title = Properties.Resources.Decompiling;
action(textView);
if (tabPage.Title == Properties.Resources.Decompiling)
{
tabPage.Title = oldTitle;
}
}
public static DecompilationOptions CreateDecompilationOptions(this TabPageModel tabPage)
{
var exportProvider = tabPage.ExportProvider;
var languageService = exportProvider.GetExportedValue<LanguageService>();
var settingsService = exportProvider.GetExportedValue<SettingsService>();
return new(languageService.LanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { Progress = tabPage.Content as IProgress<DecompilationProgress> };
}
}
}

44
ILSpy/ViewModels/TabPageModelExtensions.wpf.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// Copyright (c) 2019 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.Linq;
using System.Windows;
using TomsToolbox.Wpf;
#nullable enable
namespace ICSharpCode.ILSpy.ViewModels
{
public static partial class TabPageModelExtensions
{
public static void Focus(this TabPageModel tabPage)
{
if (tabPage.Content is not FrameworkElement content)
return;
var focusable = content
.VisualDescendantsAndSelf()
.OfType<FrameworkElement>()
.FirstOrDefault(item => item.Focusable);
focusable?.Focus();
}
}
}

9
ILSpy/ViewModels/ToolPaneModel.cs

@ -20,12 +20,21 @@ using System.Windows.Input; @@ -20,12 +20,21 @@ using System.Windows.Input;
namespace ICSharpCode.ILSpy.ViewModels
{
#if CROSS_PLATFORM
public abstract class ToolPaneModel : Dock.Model.TomsToolbox.Controls.Tool
{
protected static DockWorkspace DockWorkspace => App.ExportProvider.GetExportedValue<DockWorkspace>();
#else
public abstract class ToolPaneModel : PaneModel
{
#endif
public virtual void Show()
{
this.IsActive = true;
this.IsVisible = true;
#if CROSS_PLATFORM
DockWorkspace.ActivateToolPane(ContentId);
#endif
}
public KeyGesture ShortcutKey { get; protected set; }

87
ILSpy/Views/GacEntry.cs

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
// 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.Text;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy
{
public partial class OpenFromGacDialog
{
sealed class GacEntry
{
readonly AssemblyNameReference r;
readonly string fileName;
string formattedVersion;
public GacEntry(AssemblyNameReference r, string fileName)
{
this.r = r;
this.fileName = fileName;
}
public string FullName {
get { return r.FullName; }
}
public string ShortName {
get { return r.Name; }
}
public string FileName {
get { return fileName; }
}
public Version Version {
get { return r.Version; }
}
public string FormattedVersion {
get {
if (formattedVersion == null)
formattedVersion = Version.ToString();
return formattedVersion;
}
}
public string Culture {
get {
if (string.IsNullOrEmpty(r.Culture))
return "neutral";
return r.Culture;
}
}
public string PublicKeyToken {
get {
StringBuilder s = new StringBuilder();
foreach (byte b in r.PublicKeyToken)
s.Append(b.ToString("x2"));
return s.ToString();
}
}
public override string ToString()
{
return r.FullName;
}
}
}
}

59
ILSpy/Views/OpenFromGacDialog.xaml.cs

@ -21,7 +21,6 @@ using System.Collections.Generic; @@ -21,7 +21,6 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
@ -62,64 +61,6 @@ namespace ICSharpCode.ILSpy @@ -62,64 +61,6 @@ namespace ICSharpCode.ILSpy
}
#region Fetch Gac Contents
sealed class GacEntry
{
readonly AssemblyNameReference r;
readonly string fileName;
string formattedVersion;
public GacEntry(AssemblyNameReference r, string fileName)
{
this.r = r;
this.fileName = fileName;
}
public string FullName {
get { return r.FullName; }
}
public string ShortName {
get { return r.Name; }
}
public string FileName {
get { return fileName; }
}
public Version Version {
get { return r.Version; }
}
public string FormattedVersion {
get {
if (formattedVersion == null)
formattedVersion = Version.ToString();
return formattedVersion;
}
}
public string Culture {
get {
if (string.IsNullOrEmpty(r.Culture))
return "neutral";
return r.Culture;
}
}
public string PublicKeyToken {
get {
StringBuilder s = new StringBuilder();
foreach (byte b in r.PublicKeyToken)
s.Append(b.ToString("x2"));
return s.ToString();
}
}
public override string ToString()
{
return r.FullName;
}
}
void FetchGacContents()
{

Loading…
Cancel
Save