Preview tab semantics. ContentTabPage gains IsPreview; the persistent MainTab
starts preview (tree-node clicks replace its Content in place). The user pins
via Window menu, right-click context menu, or inline pin icon — the
just-pinned tab keeps its content/identity and a fresh preview MainTab spawns.
Carve-out tabs (Open in new tab, Options) are born pinned and survive tree
selections.
Assisted-by: Claude:claude-opus-4-7:Claude Code
DisplaySettings.SortResults was persisted but unused — RunningSearch hardcoded
ComparerByFitness. Now SearchPaneModel.RestartSearch reads the setting at
start-of-search and passes either ComparerByFitness (default) or ComparerByName
into RunningSearch. Capturing at start matches WPF — mid-run toggles only
affect the next search.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds TabPageMenuItem (mirrors ToolPaneMenuItem) and a live ObservableCollection
on DockWorkspace kept in sync with factory.Documents.VisibleDockables. MainMenu
appends a separator + radio-style MenuItem per tab, with Header bound to Title
and IsChecked bound to IsActive. WPF parity for the previously-skipped tabs
section of the Window menu.
Assisted-by: Claude:claude-opus-4-7:Claude Code
WPF's Open-from-GAC dialog uses a ListView with five SortableGridViewColumns
(Reference Name / Version / Culture / Public Key Token / Location), each
click-to-sort, with the initial sort by name ascending. The Avalonia port
had reduced this to a one-column ListBox showing the raw ToString() —
all field-level information mashed into a single TextBlock, no per-field
sort, no Location column, no localised strings.
Assisted-by: Claude:claude-opus-4-7:Claude Code
User-reported: editor hover tooltips were not wide enough to show full
method signatures. Root cause was a three-way layout interaction —
DocumentationRenderer.AddSignatureBlock created the signature
SelectableTextBlock with TextWrapping.NoWrap, the outer Border capped
MaxWidth at 600px, and the wrapping ScrollViewer disabled horizontal
scrolling. So anything past 600px was simply clipped, with no way to
reveal the rest.
Assisted-by: Claude:claude-opus-4-7:Claude Code
WPF parity: under DEBUG, the language dropdown gains one extra entry per
C# AST transform — "C# - no transforms", "C# - after FirstTransformName",
… "C# - after LastTransformName" — so a developer can pick a step and
see the decompiler's mid-pipeline AST output.
Assisted-by: Claude:claude-opus-4-7:Claude Code
User-reported: Ctrl+LMB on an assembly-tree row both toggled the row in
the multi-selection AND opened a new decompiler tab. ProDataGrid's
Extended-selection mode treats Ctrl+LMB as a toggle, and
OnTreeGridPointerPressed also treated it as "open in new tab", so every
Ctrl+click fired both effects regardless of the e.Handled=true on our
handler — selection lives in the DataGrid template's own pre-bubble
pipeline.
Assisted-by: Claude:claude-opus-4-7:Claude Code
User-reported: opening multiple document tabs and restarting brings them
all back broken except the first one.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The "Compare..." right-click flow opened a tab that came up blank because
two stacked bugs masked each other.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Sweep-up commit. The dotnet-format pre-commit hook keeps re-ordering
these usings on every other commit; landing them once stops the hook
from grumbling at unrelated diffs going forward.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Generalises the existing internal StartupLog into a public AppLog with
named categories. The Startup category (default-on) keeps the existing
[startup +Nms] format and Mark/Phase API, so all 44 call sites get a
mechanical StartupLog. -> AppLog. rename without behavioural change.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The three editor-command tests (Copy_Entry_Reflects, Copy_Execute, SelectAll_Execute)
selected `System.Linq.Enumerable` (the whole type, 300+ LINQ methods) and waited
on `view.Editor.Document.TextLength > 0` — a 15s `WaitForAsync` poll. In suite
context this was sloppy: it could latch on stale editor content from a previous
test, and in isolation it occasionally raced past 15s on a slow system,
producing the intermittent `failed: 1` we saw earlier.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The user-reported "Debug Steps pane is empty after clicking Show Steps" bug
was a View-lifecycle issue: `DebugStepsPaneModel` declares
`IsVisibleByDefault = false`, so the `DebugSteps` UserControl was realised by
the dock factory only when its tab was first activated. By then
`BlockILLanguage.DecompileMethod` had already fired `OnStepperUpdated` into
the void — no subscriber existed yet.
LMB double-click is WPF's expand/collapse gesture, already wired through
`OnTreeGridDoubleTapped`. An earlier patch also added it as a third "open in
new tab" gesture in `OnTreeGridPointerPressed`, so users got BOTH effects on
every double-click (the row toggled *and* a new tab opened). Restore parity
by removing the `isDoubleClick` branch from `OnTreeGridPointerPressed`; MMB
single-click and Ctrl+LMB single-click remain the two new-tab gestures.
Regression test in `HeadlessMmbPointerTests`.
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
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
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
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 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
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.
Refactor of the MessageBus port: CurrentAssemblyListChangedEventArgs,
TabPagesCollectionChangedEventArgs, and SettingsChangedEventArgs now
share a generic base — abstract WrappedEventArgs<T>(T inner) : EventArgs
exposing an explicit `Inner` property. The three subclasses collapse to
one-liners with no extra body, and consumers read .Inner uniformly
across all three. No implicit conversion operator — the unwrap is
always visible at the read site.
Brings WPF's MessageBus pattern to the Avalonia port so future features
(updater banner, navigate-to-reference plumbing, cross-pane settings
notifications) can fan out without each subscriber importing every
publisher's class. Infrastructure only — no existing Avalonia code wires
the bus yet; this commit makes it available.
The pane's watermark advertises a prefix DSL that the parser didn't
implement — only inassembly: and innamespace: were honoured. Typing
"t:String" treated the whole thing as a literal keyword and matched
nothing useful.
The PE TypeDef table includes a <Module> pseudo-type plus any user-declared
top-level types in the empty namespace. Until now AssemblyTreeNode skipped
the empty namespace when building NamespaceTreeNodes and instead hung the
global types directly off the assembly node, breaking the long-standing
tree shape (every type lives under a namespace folder).