mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
Assisted-by: Claude:claude-opus-4-7:Claude Code Assisted-by: Claude:claude-opus-4-7:Claude Codepull/3755/head
8 changed files with 318 additions and 58 deletions
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2026 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 Avalonia.Headless.NUnit; |
||||
|
||||
using AwesomeAssertions; |
||||
|
||||
using Dock.Model.Controls; |
||||
|
||||
using ILSpy.Analyzers; |
||||
using ILSpy.AppEnv; |
||||
using ILSpy.AssemblyTree; |
||||
using ILSpy.Commands; |
||||
using ILSpy.Docking; |
||||
using ILSpy.Search; |
||||
|
||||
using NUnit.Framework; |
||||
|
||||
namespace ICSharpCode.ILSpy.Tests; |
||||
|
||||
[TestFixture] |
||||
public class ToolPaneRegistryTests |
||||
{ |
||||
[AvaloniaTest] |
||||
public void Registry_Lists_All_Three_Built_In_Tool_Panes() |
||||
{ |
||||
// AssemblyTreeModel, SearchPaneModel, AnalyzerTreeViewModel each carry [ExportToolPane]
|
||||
// so plugins can drop additional panes into the registry without modifying the dock
|
||||
// factory or DockWorkspace's constructor.
|
||||
|
||||
// Arrange + Act — pull the registry from the composition host.
|
||||
var registry = AppComposition.Current.GetExport<ToolPaneRegistry>(); |
||||
|
||||
// Assert — three entries, one per built-in pane type.
|
||||
var paneTypes = registry.Panes.Select(p => p.Pane.GetType()).ToArray(); |
||||
paneTypes.Should().Contain(typeof(AssemblyTreeModel)); |
||||
paneTypes.Should().Contain(typeof(SearchPaneModel)); |
||||
paneTypes.Should().Contain(typeof(AnalyzerTreeViewModel)); |
||||
} |
||||
|
||||
[AvaloniaTest] |
||||
public void Registry_Honours_Alignment_Metadata_From_The_Export_Attribute() |
||||
{ |
||||
// Each pane's [ExportToolPane(Alignment = …)] declares which dock zone it belongs in.
|
||||
// DockFactory groups panes by Alignment when building the layout.
|
||||
|
||||
// Arrange + Act — read alignments off the registry.
|
||||
var registry = AppComposition.Current.GetExport<ToolPaneRegistry>(); |
||||
var byType = registry.Panes.ToDictionary(p => p.Pane.GetType(), p => p.Metadata); |
||||
|
||||
// Assert — Assembly tree on the left, Search on top, Analyzer on the bottom.
|
||||
byType[typeof(AssemblyTreeModel)].Alignment.Should().Be(ToolPaneAlignment.Left); |
||||
byType[typeof(SearchPaneModel)].Alignment.Should().Be(ToolPaneAlignment.Top); |
||||
byType[typeof(AnalyzerTreeViewModel)].Alignment.Should().Be(ToolPaneAlignment.Bottom); |
||||
} |
||||
|
||||
[AvaloniaTest] |
||||
public void DockFactory_Builds_Layout_Zones_Driven_By_The_Registry() |
||||
{ |
||||
// ILSpyDockFactory iterates the registry instead of taking each pane in its ctor —
|
||||
// verifies via the live DockWorkspace that the same three docks (Left/Top/Bottom)
|
||||
// still get created and contain the right panes.
|
||||
|
||||
// Arrange + Act — DockWorkspace is constructed by the composition host; its layout is
|
||||
// built eagerly in the constructor.
|
||||
var workspace = AppComposition.Current.GetExport<DockWorkspace>(); |
||||
var allDockables = FlattenDockables(workspace.Layout).ToArray(); |
||||
|
||||
// Assert — each pane is registered as a dockable inside the layout.
|
||||
allDockables.OfType<AssemblyTreeModel>().Should().ContainSingle(); |
||||
allDockables.OfType<SearchPaneModel>().Should().ContainSingle(); |
||||
allDockables.OfType<AnalyzerTreeViewModel>().Should().ContainSingle(); |
||||
} |
||||
|
||||
static System.Collections.Generic.IEnumerable<Dock.Model.Core.IDockable> FlattenDockables(Dock.Model.Core.IDockable root) |
||||
{ |
||||
yield return root; |
||||
if (root is Dock.Model.Core.IDock dock && dock.VisibleDockables != null) |
||||
{ |
||||
foreach (var child in dock.VisibleDockables) |
||||
foreach (var nested in FlattenDockables(child)) |
||||
yield return nested; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2026 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 ILSpy.ViewModels; |
||||
|
||||
namespace ILSpy.Commands |
||||
{ |
||||
/// <summary>
|
||||
/// Identifies which dock zone a tool pane belongs to. The dock factory groups exported
|
||||
/// panes by alignment when building the default layout.
|
||||
/// </summary>
|
||||
public enum ToolPaneAlignment |
||||
{ |
||||
Left, |
||||
Top, |
||||
Right, |
||||
Bottom, |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Metadata view consumed by <see cref="ToolPaneRegistry"/>. System.Composition needs a
|
||||
/// concrete metadata class with public settable properties matching the attribute's.
|
||||
/// </summary>
|
||||
public class ToolPaneMetadata |
||||
{ |
||||
public string? ContentId { get; set; } |
||||
public ToolPaneAlignment Alignment { get; set; } = ToolPaneAlignment.Left; |
||||
public double Order { get; set; } |
||||
public bool IsVisibleByDefault { get; set; } = true; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Marks a <see cref="ToolPaneModel"/>-derived class as a discoverable tool pane. The
|
||||
/// dock factory iterates all such exports to build the default layout, so plugins can
|
||||
/// drop additional panes in without modifying core wiring.
|
||||
/// </summary>
|
||||
[MetadataAttribute] |
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] |
||||
public class ExportToolPaneAttribute : ExportAttribute |
||||
{ |
||||
public ExportToolPaneAttribute() |
||||
: base("ToolPane", typeof(ToolPaneModel)) |
||||
{ |
||||
} |
||||
|
||||
public string? ContentId { get; set; } |
||||
public ToolPaneAlignment Alignment { get; set; } = ToolPaneAlignment.Left; |
||||
public double Order { get; set; } |
||||
public bool IsVisibleByDefault { get; set; } = true; |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Composition; |
||||
using System.Linq; |
||||
|
||||
using ILSpy.ViewModels; |
||||
|
||||
namespace ILSpy.Commands |
||||
{ |
||||
/// <summary>
|
||||
/// Concrete tool-pane entry returned by <see cref="ToolPaneRegistry"/>. Holds the resolved
|
||||
/// pane instance together with the metadata that describes where in the layout it should
|
||||
/// land. Each pane is materialised once at registry construction so consumers see the
|
||||
/// same singleton the rest of the composition host sees (panes are <c>[Shared]</c>).
|
||||
/// </summary>
|
||||
public sealed record ToolPaneEntry(ToolPaneModel Pane, ToolPaneMetadata Metadata); |
||||
|
||||
/// <summary>
|
||||
/// MEF aggregator for <see cref="ExportToolPaneAttribute"/>-tagged tool panes. The dock
|
||||
/// factory iterates this registry to build the default layout, so adding a new pane
|
||||
/// reduces to <c>[ExportToolPane]</c> on the model with no central wiring change.
|
||||
/// </summary>
|
||||
[Export] |
||||
[Shared] |
||||
public sealed class ToolPaneRegistry |
||||
{ |
||||
[ImportingConstructor] |
||||
public ToolPaneRegistry( |
||||
[ImportMany("ToolPane")] IEnumerable<ExportFactory<ToolPaneModel, ToolPaneMetadata>> panes) |
||||
{ |
||||
Panes = panes |
||||
.OrderBy(p => p.Metadata.Order) |
||||
.Select(p => new ToolPaneEntry(p.CreateExport().Value, p.Metadata)) |
||||
.ToArray(); |
||||
} |
||||
|
||||
public IReadOnlyList<ToolPaneEntry> Panes { get; } |
||||
} |
||||
} |
||||
Loading…
Reference in new issue