Override Save on ResourcesFileTreeNode to present a dual-format file picker
("Resources file" / "Resource XML") and dispatch by chosen extension; .resx
re-emits the entries via the bundled ICSharpCode.Decompiler.Util.ResXResourceWriter
while .resources copies the original byte stream. The base ResourceTreeNode's
inline Save button now dispatches through the virtual Save() so this override
is actually reached — previously it called the private SaveAsync directly,
making subclass overrides unreachable from the inline button. Tests pin the
WriteResX output and the FilePickers filter parsing.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replace the comment-line dump in ResourcesFileTreeNode.Decompile with two
AvaloniaUI DataGrid views — ResourceStringTable for string entries (Name/Value)
and ResourceObjectTable for everything else (Name/Value/Type, including
ResourceSerializedObject and primitive-typed values). otherEntries collection
plus SerializedObjectRepresentation row model are added on the node so
ResX export (next commit) can iterate the same shape. Test pins the behaviour:
a synthetic .resources stream produces three UIElements (Save button + two
grids) where the prior implementation produced one.
Assisted-by: Claude:claude-opus-4-7:Claude Code
XML / XSD / XSLT / XAML resources don't go through the C# decompiler so the
DecompilerTabPageModel has no pre-collected foldings — only HighlightingService
was kicking in. Run AvaloniaEdit's bundled XmlFoldingStrategy when the active
syntax extension is .xml so multi-line elements collapse from the gutter.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Clicking an already-visible row was running ScrollIntoView+CenterRowInView via
the SelectionChanged → model PropertyChanged round-trip, yanking the viewport.
Add a clickInProgress flag separate from syncingSelection: clickInProgress is
set in OnTreeGridSelectionChanged and cleared at Background priority alongside
syncingSelection, so the model's two PropertyChanged notifications (Clear+Add
on SelectedItems) both bail out — but hyperlink / Back/Forward / search-hit
navigation, which never enters OnTreeGridSelectionChanged, still scrolls the
target into view.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Five new IResourceNodeFactory implementations route .xml/.xsd/.xslt to a shared
XmlResourceEntryNode (text + XML highlighting via SyntaxExtensionOverride on the
output), .xaml to XamlResourceEntryNode (same pattern), and .png/.gif/.bmp/.jpg /
.ico / .cur to image-rendering nodes that inline the bitmap with a Save button.
SyntaxExtensionOverride is read after Decompile to switch the editor's highlighter
without changing the active language. Cursor handling flips byte 2 of the on-disk
header so Skia decodes the .cur as an icon for preview while Save preserves the
original bytes. ResourceFactoryTests pin the dispatch — including .xsd — and the
existing assembly-tree assertion is relaxed since typed entries are no longer all
ResourceTreeNodes.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Move IResourceNodeFactory to ILSpyX.Abstractions and GuessFileType to ILSpyX.Util
so both UIs can consume them. Wire ResourceEntryNode.Create(Resource) to walk the
MEF-discovered IResourceNodeFactory list (falls back to the generic node), make
Avalonia's ILSpyTreeNode implement ITreeNode for that contract, and register a
ResourcesFileTreeNodeFactory to keep .resources files routed correctly. Adds the
Save virtual on ILSpyTreeNode plus inline "Save" buttons + SaveAsync on
ResourceEntryNode/ResourceTreeNode using a new FilePickers helper around
StorageProvider.SaveFilePickerAsync.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replace the static Back/Forward buttons with SplitButtons whose chevron drops a
menu of recent navigation history entries (up to 20, newest first), letting the
user jump multiple steps in one click. Adds GoTo + entry views to NavigationHistory
and a NavigateToHistoryCommand on DockWorkspace. Recolors the SplitButton chevron
and the Simple-theme ComboBox toggle's pressed/checked/flyout-open states with
the toolbar accent palette so neither flips to a dark fill on click.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the special-cased OverlayImage (accessibility/static/extension)
and the two-layer PairOverlayImage (Reference/Export overlays) with one
N-layer LayeredImage that supports an optional base scale.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Existing assembly fixtures (BCL System.Linq, System.Net.Http, mscorlib)
do not have module references, so this slice is wired and exercised by
the existing References-folder tests but not directly asserted.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Added two new headless tests in MainWindowTests:
- Back_Navigation_Restores_Previously_Selected_Node — selects two methods on
Enumerable, executes DockWorkspace.NavigateBackCommand, asserts the original
node is reselected, decompiled text reverts, and the row is centred.
- Opening_Assembly_Adds_It_To_The_Tree — drives the production OpenCommand via
MainMenuCommandRegistry (matched by Resources._Open header), confirms the
new LoadedAssembly appears, the AssemblyTreeNode is reachable by short name,
and SharpTreeNode.IsSelected is set on the freshly opened node.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Restructure the Avalonia AssemblyTreeModel so its task layout matches the WPF
host, both for readability when cross-referencing the two trees during the
port and so future WPF changes can be ported mechanically. New surface (all
mirrored from ILSpy/AssemblyTree/AssemblyTreeModel.cs):
Assisted-by: Claude:claude-opus-4-7:Claude Code
CenterRowInView calls DataGrid.ScrollIntoView and then reads the row's bounds
to compute the offset that puts it on the viewport mid-line. ScrollIntoView
only updates ScrollViewer.Offset though; the new DataGridRow shows up on the
next layout pass. When the target row was outside the current viewport (e.g.
back-navigation across distant selections), the lookup ran before that pass
and returned null, so the centring step bailed and the offset stayed where it
was. Force the layout pass with TreeGrid.UpdateLayout() so the row is realised
synchronously.
Assisted-by: Claude:claude-opus-4-7:Claude Code
DecompileAsEnumerableTest exercises the full path: open mscorlib, navigate
to Enumerable.AsEnumerable, render the decompilation, verify text and
verify the row centred in the assembly tree. Writing it surfaced two
pre-existing bugs the manual smoke-test missed:
File / View / Window / Help built from MEF main-menu commands plus a static
View submenu (API visibility, Theme = Light/Dark via Application.RequestedThemeVariant,
UI Language) bound to LanguageSettings on SessionSettings. Window menu also lists
the existing tool-pane toggles. Commands without ported deps (Options, About,
Updates, GAC, manage lists, save/PDB) surface a "not yet ported" stub dialog.
Open uses Avalonia StorageProvider; CloseAllDocs/ResetLayout call into DockWorkspace.
InputGestureText on the export attribute is parsed into MenuItem.HotKey, giving
Open Ctrl+O / Save Ctrl+S / Reload F5 as window-scoped accelerators.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The renamed Avalonia csproj was referencing the localized strings file
via a sibling-project relative path (..\ILSpy\Properties\Resources.resx)
that resolved into the WPF host's tree. The host is gone now, so the
reference is dangling.
Subscribes to AvaloniaEdit's PointerHoverEvent / PointerHoverStoppedEvent
on the inner TextView and resolves the segment under the live pointer at
hover-fire time. Same pattern WPF ILSpy uses on AvalonEdit's MouseHover.
Assisted-by: Claude:claude-opus-4-7:Claude Code