Imports the three SVG assets that were missing from `ILSpy.Avalonia/Assets/Icons/`
and registers them in `Images/Images.cs`, so the MEF-injected toolbar buttons
for "Reload all assemblies", "Sort assembly list by name", and "Collapse all
tree nodes" now render their icons instead of falling back to the tooltip text
(`MainToolBar.axaml.cs:226` `ResolveIcon` returned null for these). Adds a
regression test asserting every `[ExportToolbarCommand]`'s `ToolbarIcon`
resolves to a real `IImage` field on the registry.
Two missing toolbar buttons (Manage Assembly Lists, Show Search) and an
incorrect button order; the layout now mirrors WPF MainToolBar.xaml +
InitToolbar exactly. Also fixes an InitializeButtons no-op under
Avalonia.Headless (Loaded never fired; switched to AttachedToVisualTree).
Assisted-by: Claude:claude-opus-4-7:Claude Code
Persists the live dock layout to ILSpy.Layout.json next to ILSpy.xml on
MainWindow.OnClosing; loads it on DockWorkspace ctor; falls back to
factory.CreateLayout when the file is absent or fails to deserialize.
WPF stays XML in ILSpy.xml — this is Avalonia-side only.
Assisted-by: Claude:claude-opus-4-7:Claude Code
1) post-refresh-redecompile: AssemblyTreeModel.RefreshInternalAsync now calls
DockWorkspace.ForceRefreshActiveTab() after SelectNode. F5 on the same
assembly list doesn't rebuild the tree → FindNodeByPath returns the same
tree-node reference → SelectedItem setter early-outs → ShowSelectedNode's
lastShownNodes dedup short-circuits, leaving stale decompiled text. The
force path resets lastShownNodes and re-runs the decompile pipeline.
Mirrors WPF's RefreshDecompiledView() call.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Cherry-picked from master commits 4c8e606a6 + 4c347ef6b. Refresh (F5) on a
selection inside a lazy-loaded resource tree (e.g. a .baml entry inside an
embedded .resources file) was collapsing the selection back to the resources
folder because FindNodeByPath ran before the assembly's metadata-file
finished loading and the resource children hadn't materialised yet.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Splits Windows-only tests out of the cross-platform ILSpy.Avalonia.Tests
project so the Pdb2Xml / OpenFromGac code paths (which compile only on
Windows) can be exercised without conditional `#if WINDOWS` blocks inside
the main test suite.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Lets non-decompile-protocol EntityReference hyperlinks route through plug-in
resolvers instead of always falling into FindTreeNode. The dispatcher in
DockWorkspace.OnNavigateRequested checks `entity.Protocol != "decompile"`,
walks every IProtocolHandler MEF export, and lands the user on the first
non-null tree node returned.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the NotImplementedDialog stub in OpenFromGacCommand with a real
dialog. CanExecute gates on OperatingSystem.IsWindows() since the Windows
Global Assembly Cache doesn't exist on Linux/macOS (matches WPF's
AppEnvironment.IsWindows gate). The actual GAC enumeration uses the shared
UniversalAssemblyResolver.EnumerateGac() + GetAssemblyInGac() pair from
ICSharpCode.Decompiler — no platform-specific code in the Avalonia tree.
Assisted-by: Claude:claude-opus-4-7:Claude Code
WPF ships Pdb2XmlCommand behind `#if DEBUG && WINDOWS` because
Microsoft.DiaSymReader uses native COM interop. Avalonia parity uses the
same gate, with the package references conditional on the build host being
Windows + Debug, and the consuming command file `#if DEBUG && WINDOWS`.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the NotImplementedDialog stub in FileCommands.cs's
ManageAssemblyListsCommand with a real File → Manage Assembly Lists dialog.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Right-click an assembly → Select PDB. File-pick a portable / Windows PDB,
call LoadedAssembly.LoadDebugInfo, and refresh the active tree selection
so the new debug symbols feed back into the decompiler output.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds BindTree_With_Small_AssemblyList_Settles_In_Reasonable_Time alongside
the existing 200-assembly [Explicit] benchmark. Not [Explicit] so it runs
in the regular suite; 8 copies of CoreLib with a 15s threshold catches
order-of-magnitude regressions in the open+settle pipeline without the
30s+ cost of the full benchmark.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Single assertion guarding the existing IDeferredContentPresentation.DeferContentPresentation
override that keeps tool panes (search, analyzers, debug-steps, …) hot at
startup. Without the opt-out, headless tests can't reach pane descendants
until focus-activation, and the search pane's startup tasks (assembly index
scan etc.) wouldn't kick off until first user interaction.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Same shape as DecompileAllCommand but routes through ILLanguage. Writes to
c:\temp\disassembled\<safe-name>.il in parallel, reports per-assembly time
and exception type, with CanExecute gating on the output dir existing.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the NotImplementedDialog stubs in FileCommands.cs with real
implementations. Both are DEBUG-only File-menu entries for decompiler dev:
Assisted-by: Claude:claude-opus-4-7:Claude Code
Right-click one or more assemblies with CodeView debug-directory entries →
Generate Portable PDB. Folder picker for output, then PortablePdbWriter
runs per assembly under DockWorkspace.RunWithCancellation; the report tab
lists per-file success / fail / unsupported plus total elapsed time + an
Open Explorer button.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Ctrl+M toggles the innermost fold containing the caret. Ctrl+Shift+M collapses
all when any fold is open and expands all otherwise (parity-based toggle).
Assisted-by: Claude:claude-opus-4-7:Claude Code
Standard popup convention; the chips/pills inside don't override KeyDown so
the Tunnel-routed handler on the popup root catches the key before any
inner control. Arrow-key navigation between chips is a bigger lift (chip
groups don't share a focus container) — leaving as a follow-up.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The funnel glyph is a hand-drawn 10×9 trapezoid with no associated text, so
its purpose isn't obvious to a user who hasn't seen the active state. Adding
a tooltip on the funnel's hit-area Border surfaces the column name when the
user hovers (Avalonia 11+ ToolTip.SetTip).
Assisted-by: Claude:claude-opus-4-7:Claude Code
When a tree node becomes visible for the first time, its already-realised
children might carry stale IsHidden state — OnChildrenChanged only fires
for newly-added children, and only when the parent was visible at the time.
The visible result: a property's accessor children read as visible the first
time the user expands the property even under ShowApiLevel=PublicOnly, until
something else (refresh / language flip) forces a cascade.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Pair to ea56a80cd. When DecompilerSettings.ExtensionMembers is on and the
active language is C#, methods that the decompiler identifies as implementation
methods for an extension block are filtered out of the outer static class —
they surface as ExtensionTreeNode children of the containing static class
instead. Without this gate the user would see each extension member twice:
once as a regular method on the static container, once under the extension
block. Mirrors WPF MethodTreeNode.Filter lines 95-104 verbatim.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Each `extension<T>(ReceiverType source) { ... }` block inside a static class
now appears as its own tree node sibling to the regular methods/properties.
Expanding the node lists the block's declared methods + properties as
PropertyTreeNode / MethodTreeNode children sorted by name.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Mirrors WPF's `ShowCFGContextMenuEntry` and `GraphVizGraph` utility behind
`#if DEBUG`. Right-click a `BlockContainer` reference in the IL output
("DEBUG -- Show CFG") → builds the ControlFlowGraph for the method, writes
a `.gv` file in the temp dir, shells out to `dot` (Graphviz) to render PNG,
opens the result with the OS default image viewer.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Right-click → "Extract Package Entry" on items inside a NuGet zip or .NET
single-file bundle. Single-item selection (an AssemblyTreeNode or a
ResourceTreeNode) pops a SaveFileDialog; multi-item or PackageFolderTreeNode
selection pops a folder-picker. Runs the extraction on a background thread
through the new DockWorkspace.RunWithCancellation infrastructure, then
ShowText reports per-entry write paths + total elapsed time + an "Open
Explorer" button that selects the result in the OS file manager.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Right-click an assembly tree node → Create Diagram. Prompts for an output
folder via the new FilePickers.PickFolderAsync helper, then runs the shared
ICSharpCode.ILSpyX.MermaidDiagrammer.GenerateHtmlDiagrammer engine on a
background thread under DockWorkspace.RunWithCancellation (the new wait UI
with a custom "Creating diagram…" title). On completion, pushes a report
into the active tab via ShowText — elapsed time, learn-more link, and an
"Open Explorer" button that selects the generated index.html in the OS file
manager (xdg-open / open -R / explorer.exe per platform).
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the WPF-equivalent "run a long-running task with the wait UI showing a
custom title, then display the resulting text in the editor" primitives. Both
methods live on DecompilerTabPageModel (the natural owner — it's where the
wait adorner and editor state already live); DockWorkspace exposes thin
delegates that forward to the active tab.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Mirrors WPF's ZoomScrollViewer behaviour without templating AvaloniaEdit's
TextEditor. The Avalonia path scales the editor's FontSize (which feeds
DisplaySettings.SelectedFontSize) on Ctrl+Wheel; AvaloniaEdit lays out at the
new size on the next render. WPF's full-content-tree LayoutTransform approach
doesn't fit AvaloniaEdit's architecture, but the font-scale result is what
users actually expect from "editor zoom".
Assisted-by: Claude:claude-opus-4-7:Claude Code
Foldings persistence rounds out the view-state work that landed in 185e0551d
(caret + scroll). Mirrors WPF's DecompilerTextViewState.SaveFoldingsState /
RestoreFoldings semantics verbatim — including the layout-checksum gate that
refuses restoration when the new document's foldings don't match the captured
layout, so a stale snapshot can't accidentally expand random regions of a
shifted document.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds ICSharpCode.BamlDecompiler as a ProjectReference, ports IResourceFileHandler +
ResourceFileHandlerContext from WPF, and plumbs both through:
Assisted-by: Claude:claude-opus-4-7:Claude Code
Closes two tracker items in one commit:
- `BrowseForwardCommand` was already wired end-to-end (command, toolbar
button, Alt+Right key binding). New test pins the wiring so a future
regression to any of the three surfaces is caught.
- `ViewState (caret + scroll persistence across navigation)` was missing.
Navigating back to a previously-visited node landed the caret at offset
0 / scroll at top instead of where the user was looking before they
moved away.
Promotes the modern .NET XML-doc lookup from the Avalonia port into the
shared ICSharpCode.Decompiler library so every host (WPF, Avalonia, any
third-party consumer of XmlDocLoader) gets hover/tooltip documentation
for system entities without per-host fallback wiring.
The decompiler-view hover tooltip's XML-documentation lookup goes through
the shared ICSharpCode.Decompiler.Documentation.XmlDocLoader. That helper
only knows two layouts: .xml beside the .dll, and the .NET Framework
reference-assemblies paths (Program Files (x86)\Reference Assemblies\
Microsoft\Framework\v1.0 … v4.8.1). Modern .NET runtime DLLs
(System.Private.CoreLib.dll, System.Linq.dll, …) ship without any .xml
beside them — the XML files live in the parallel reference pack at
Closes the third logged analyzer follow-up. When the user double-clicks an
analyzer result (e.g. one of the methods listed under "Used By" on Foo.Bar),
the decompiled-output view now paints local-reference marks on every
mention of the originally-analysed entity inside the navigated-to body —
so the user can spot the exact call site the result row corresponds to.
Two of the three analyzer follow-ups I'd logged from earlier live-testing.
Both are tiny, both close gaps that made the analyzer feature feel
half-finished:
Brings the assembly-comparison feature across. Right-click two valid
managed assemblies in the tree → "Compare..." → fresh tab opens with a
diff tree: identical entries hidden by default, additions tinted green,
removals pink, signature-matched-but-different rows blue. Identical
entries surface via the "Show identical entries" toolbar checkbox.
Brings the assembly-to-project export across. Right-click an assembly in
the tree (or use the existing File → Save Code / Ctrl+S that calls into
`node.Save()`) and choose between two filters in the save picker:
Brings the WPF decompiler-pipeline-stepper feature across. Available only
in Debug builds — the entire feature set is gated behind `#if DEBUG`, so
Release users see neither the pane nor the ILAst languages in the picker.
The user reported that expanding an enum (System.DayOfWeek) with a search
term active showed only Base/Derived nodes — every FieldTreeNode child
hidden. This is NOT a recent regression. It traces back to commit
45461ddde, which made LanguageSettings.SearchTermMatches honour the
SearchTerm and wired SearchPaneModel to push its term into
LanguageSettings on every keystroke.