MetadataCellTooltip resolves `{ColumnName}Tooltip` on the bound row by
reflection. The view subscribes to PointerMoved, walks up to the
DataGridCell under the pointer, and applies the resolved string via
ToolTip.SetTip whenever the cell changes.
Assisted-by: Claude:claude-opus-4-7:Claude Code
FilterText on MetadataTablePageModel drives a case-insensitive Contains
predicate over each row's stringified property values; the view wraps
Items in a DataGridCollectionView so the filter applies without rebinding.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds MetadataTokenReference(MetadataFile, Handle). DockWorkspace
subscribes to a metadata page's NavigateToCellRequested when its
Content is attached; the click handler reads the row's MetadataFile
and the column's int token via reflection, walks to the matching
MetadataTableTreeNode under the assembly's Tables container (mapping
HandleKind → TableIndex by value), selects it, and seeds ScrollToRow
on the freshly-bound MetadataTablePageModel. The view's ApplyScrollTarget
already honours ScrollToRow by scrolling + selecting the row.
Assisted-by: Claude:claude-opus-4-7:Claude Code
[ColumnInfo(Kind=Token)] properties now produce a DataGridTemplateColumn
whose cell is a transparent-background, blue-foreground Button — the
hyperlink affordance the user clicks to jump to the target table row.
Click raises NavigateToCellRequested(Row, ColumnName) on the owning
MetadataTablePageModel; Phase 3c subscribes from the dock workspace,
resolves the token to its target table tree node, and scrolls into view.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The generic MetadataTableTreeNode<TEntry> base now overrides
CreateTab() to return a MetadataTablePageModel populated from
LoadTable() + reflected columns. Every typed CorTable / DebugTable
inherits the grid behaviour for free; the per-table text dump is gone.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Tree-node selection now updates the inner Content of one persistent
ContentTabPage instead of swapping the dockable in the dock. The
wrapper view (ContentTabPageView) keeps both inner views — the
decompiler text editor and the metadata grid — pre-realised in the
visual tree from construction time and toggles which is visible based
on Content's runtime type.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Close-then-add in the same dispatcher tick was leaving the previous
view rendered until a layout pass caught up — the user saw the
"Decompiling" spinner from the closed decompiler tab persist after
switching to a metadata node, and going back to an entity node from
metadata didn't bring the text view forward. Replacing the dockable
in the VisibleDockables list as a single mutation fires
INotifyCollectionChanged.Replace, which Dock translates into a clean
visual swap.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Tree-node selections always operate on whatever document tab is
currently active. If the active tab is the wrong concrete type for the
new selection (e.g. a decompiler tab is up and the user picks a
metadata node, or vice-versa), the active dockable is replaced in
place — close the old, add the new, no sibling tab left behind.
Previously the host added a sibling tab and switched focus, which
piled up dockables and made "back to entity from metadata" feel
broken because the user could see two tabs competing for the slot.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Picking DOS Header → COFF Header → DOS Header was opening three
dockables because ShowCustomTab unconditionally added a fresh tab. The
docking host now searches for an open tab of the same concrete type,
copies the new node's tab state onto it, and re-activates it — same
shape as how the single decompiler tab gets reused across tree-node
selections.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The grid view's row-virtualisation handles the full heap (CoreLib's
truncation-footer wording are gone. Existing heap tests are rewritten
to assert against MetadataTablePageModel; the obsolete
MetadataHeapTreeNode.PreviewLimit constant follows the cap into the
deleted set.
Assisted-by: Claude:claude-opus-4-7:Claude Code
DOS / COFF / Optional / DataDirectories / DebugDirectory now expose
their entries through CreateTab() instead of writing a fixed-width text
table from Decompile. The grid view shows each entry's columns
reflected directly off the row shape — Phase 1's text table was a
stand-in until this view shipped. The existing PE-header tests are
rewritten to assert against MetadataTablePageModel.Items / Columns;
adds a Waiters.WaitForMetadataTabAsync helper used by every grid-tab
test.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Lays the rails for Phase 2 without flipping any existing nodes onto the
new path: MetadataTablePageModel + MetadataTablePage view +
MetadataColumnBuilder (cached per row type), an ILSpyTreeNode.CreateTab()
hook the docking host now consults before falling through to the
decompiler tab, and an App.axaml DataTemplate routing the model to the
view. PE-header / heap / table nodes still decompile as text — they get
flipped to CreateTab() one batch at a time in subsequent commits.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Closes out Phase 1e: every CLI metadata table now has its own typed
leaf. Bytes-level table walking goes through MetadataReader.AsBlobReader
(public API) instead of the WPF Helpers' AsReadOnlySpan path; coded-token
columns are decoded by the new MetadataReaderHelpers shim, which
reflects against the same private TypeDefOrRefTag / HasFieldMarshalTag /
MemberForwardedTag.ConvertToHandle methods + ComputeCodedTokenSize that
the WPF host uses (a known forward-compatibility risk per the plan's
risk register).
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the universal placeholder for the 8 PDB-only metadata tables:
Document, MethodDebugInformation, LocalScope, LocalVariable,
LocalConstant, ImportScope, StateMachineMethod, CustomDebugInformation.
StateMachineMethod reads its rows directly via MetadataReader.AsBlobReader
(public API, no internals reflection); the rest follow the typed-handle
pattern used by the CorTables.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the universal placeholder for StandAloneSig, DeclSecurity, and
File. These three are the last CorTables that System.Reflection.Metadata
exposes as direct enumerations / typed handles. The remaining ~12 tables
(InterfaceImpl, NestedClass, ClassLayout, FieldLayout, FieldRva,
FieldMarshal, ImplMap, MethodImpl, MethodSemantics, EventMap,
PropertyMap, the *Ptr family) read raw little-endian metadata bytes via
Helpers.GetValueLittleEndian + coded-token reflection helpers in the
WPF tree, so they wait for the Helpers infrastructure port.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the universal placeholder for ModuleRef, TypeSpec, Constant,
Property, Event, GenericParam, GenericParamConstraint, MethodSpec,
ManifestResource, and ExportedType with their own typed leaves. Same
pattern as the prior CorTables batch — RID / Token / Offset followed
by the table's own column shape.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the universal placeholder for Field, MethodDef, Param,
MemberRef, CustomAttribute, and Assembly with their own typed leaves.
Each carries the columns the WPF view shows (RID / Token / Offset / row
data) — the analogous tooltips and click handlers stay deferred to the
Phase-3 navigation work since Phase 1 only renders text. The remaining
25 CorTables continue to land as placeholders until the next pass.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the generic MetadataTableTreeNode<TEntry> base — caches LoadTable's
result and runs it through MetadataTextWriter for the Phase 1 text dump.
Ports Module / TypeRef / TypeDef / AssemblyRef as the first concrete
leaves; the remaining 31 CorTables and 8 DebugTables continue to land
through the universal placeholder until subsequent commits replace
them. Also fixes MetadataTextWriter to convert enum values to their
underlying integer before applying digit-bearing format strings, since
Enum.ToString rejects "X8".
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the synthetic "Tables" folder that lazy-loads one leaf per
non-empty CLI metadata table, sitting between the PE headers and the
heaps to match WPF tree shape. The leaves are universal placeholders for
now — typed per-table viewers (35 CorTables + 8 DebugTables) replace
them in the next commit.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the four CLI heap views (#Strings, #US, #GUID, #Blob) under each
assembly's Metadata folder. Phase 1 caps each heap's text dump at 200
preview rows with a truncation footer; the full set arrives with the
DataGrid view in Phase 2. Heap rows are materialised lazily on first
demand so opening the Metadata folder doesn't pay for heaps the user
never visits.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the five PE-format leaves (DOS / COFF / Optional / DataDirectories
/ DebugDirectory) under each assembly's Metadata folder. Phase 1 renders
them as fixed-width text tables via Decompile; Phase 2 will swap to a
DataGrid tab. Introduces Entry / BitEntry / ColumnInfoAttribute and a
MetadataTextWriter helper that the heap and table nodes reuse.
Assisted-by: Claude:claude-opus-4-7:Claude Code
First slice of the Metadata Explorer port (Task 31). Adds a synthetic
MetadataTreeNode child to every loaded PE assembly, slotted before the
References folder to mirror WPF's AssemblyTreeNode ordering. The container
itself decompiles to the same metadata-summary text WPF's DumpMetadataInfo
emits — kind, version, debug header (if any), per-table row counts.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Mirrors the WPF AssemblyTreeNode.SetPublicAPI recursive walk: a namespace
counts as public-API iff at least one type it contains is public-API. Inline
on NamespaceTreeNode itself as a lazy-evaluated cached aggregate (types don't
change accessibility at runtime), so the cell template's gray-foreground
binding picks up the right value on first render.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the brittle root.GetVisualDescendants().OfType<T>().Single() / .First()
pattern with a new WaitForComponent<T>() extension that polls until the requested
control is in the visual tree, then returns it. Avalonia.Headless tests routinely
queried the visual tree before lazily-templated panes (DataGrid, dock content)
had materialised, surfacing as intermittent 'Sequence contains no elements'
failures across the suite.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Right-click on a Type / Method / Field / Property / Event / Namespace row
opens the MS-Docs landing page for the selected entity in the default
browser. URL shape:
https://learn.microsoft.com/dotnet/api/<reflection-name>
with backticks (generic arity) → hyphens, '+' (nested types) → '.', and
'.ctor' → '-ctor' so constructors resolve correctly.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Reveals the assembly's file in the OS file manager. Walks the selection's
parent chain to the enclosing AssemblyTreeNode so the entry works on
members / namespaces too, not just the assembly row.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the IMemberTreeNode interface (the same contract WPF uses) and makes
the five entity-bearing tree-node types — Type / Method / Field / Property /
Event — implement it so generic tooling can reach the underlying IEntity
without knowing which concrete tree node it has on hand.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Mirrors the WPF host's nested ReloadAssembly entry. Same visibility shape
as Remove (every selected node must be an AssemblyTreeNode). Execute calls
AssemblyList.ReloadAssembly on each selection's path, snapshots the
pre-reload tree paths so that after the LoadedAssembly instances are swapped
out the model can re-select an equivalent node via FindNodeByPath. The
existing SelectedItem -> ShowSelectedNode plumbing then re-decompiles into
the active tab.
Assisted-by: Claude:claude-opus-4-7:Claude Code
- Suppress MEF002/CA1001/CA2213 in the csproj (intentional System.Composition
use and CTS-on-tab-page lifetime; CA1001/CA2213 already suppressed in
the WPF csproj).
- Drop the unused dockWorkspace parameter on the SaveCommand primary ctor.
- Add Language.MemberDescription helper that handles a null
DeclaringTypeDefinition — FakeMember-derived entities (the decompiler's
fallback for unresolved members) can carry one — so the four
DecompileMethod/Field/Property/Event fallbacks no longer pass null to
TypeToString.
- App.axaml.cs / ResourcesFileTreeNode.cs: small null-handling fixes.
- CSharpHighlightingTokenWriter.cs: nullable-annotate the optional
textOutput/locatable ctor params and the few helpers that legitimately
return null (GetCurrentDefinition, GetCurrentMemberReference,
ApplyTypeColor's color out-param).
Assisted-by: Claude:claude-opus-4-7:Claude Code
AvaloniaEdit's TextEditorOptions.RequireControlModifierForHyperlinkClick
only flows into its *built-in* LinkElementGenerator (via the
IBuiltinElementGenerator.FetchOptions hook the editor calls from
UpdateBuiltinElementGeneratorsFromOptions). Subclasses added to
ElementGenerators by hand inherit whatever the parameterless base
constructor sets — which is "true" — so the editor-level flag flipped in
DecompilerTextView didn't actually reach our generator.
Assisted-by: Claude:claude-opus-4-7:Claude Code
[ExportContextMenuEntry(Header = "DecompileToNewPanel")] sitting in the
Analyze category — opens a fresh DecompilerTabPageModel, asks the dock
workspace to put it next to the existing tab, and assigns the selected
tree-node(s) as its CurrentNodes (which fires the decompile pipeline the
same way a regular selection change does).
Assisted-by: Claude:claude-opus-4-7:Claude Code
Each tree-expansion, selection change, command execution, async wait and
key/mouse injection inside an [AvaloniaTest] now carries a short imperative
comment on the line above (e.g. "// expand typeNode", "// select methodA",
"// wait for assemblies to load", "// execute aboutCmd"). The comments are
the same scaffolding the manual debug-with-screenshot workflow uses to
follow what's happening at each breakpoint, surfaced into the committed
source so the tests are readable without the breakpoint markers attached.
Assisted-by: Claude:claude-opus-4-7:Claude Code
AssemblyTreeNode now overrides CanDelete / Delete / DeleteCore (matching
the WPF host: Delete unloads the assembly via AssemblyList.Unload, with
package-nested entries opting out via CanDelete=false) and exports a
nested RemoveAssembly context-menu entry tagged Header="_Remove".
Assisted-by: Claude:claude-opus-4-7:Claude Code
AssemblyListPane attaches a ContextMenu to its TreeGrid at construction
time. The menu's Opening handler builds entries from the
ContextMenuEntryRegistry against a fresh TextViewContext (the live
selection + the grid as OriginalSource), and cancels Opening when no
entry would be visible so an empty popup never flashes up.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the MEF extension surface that lets commands contribute right-click
entries the same way they contribute main-menu and toolbar items today:
Assisted-by: Claude:claude-opus-4-7:Claude Code
CommandLineArguments was already parsed at App.OnFrameworkInitializationCompleted
but never read. AssemblyTreeModel grows HandleCommandLineArgumentsAsync that
applies the parsed values:
Assisted-by: Claude:claude-opus-4-7:Claude Code
Flips Editor.Options.RequireControlModifierForHyperlinkClick to false in
DecompilerTextView's constructor — that's the value AvaloniaEdit's built-in
LinkElementGenerator forwards onto every VisualLineLinkText it constructs,
so toggling it once at the editor level removes the Ctrl requirement for
every hyperlink in the decompiled output (in-app references, About-page
resource links, future external URLs alike).
Assisted-by: Claude:claude-opus-4-7:Claude Code
Generalises NavigationHistory<SharpTreeNode> into NavigationHistory<NavigationEntry>
with two subtypes — TreeNodeEntry (a tree-node selection in a specific tab)
and StaticPageEntry (a static page like About in a specific tab) — mirroring
the WPF host's NavigationState/ViewState pair.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the previous WriteReference(string, Uri) approach with a
LinkElementGenerator subclass that scans the rendered document for the
target phrases ("MIT License" / "third-party notices"), matching the
WPF host's MyLinkElementGenerator pattern. The custom generator collection
travels through AvaloniaEditTextOutput → DecompilerTabPageModel.
CustomElementGenerators → DecompilerTextView (which installs and tears
them down per ApplyDocument).
Assisted-by: Claude:claude-opus-4-7:Claude Code
The "MIT License" and "third-party notices" phrases inside the About blurb
now write as ReferenceSegments carrying resource: URIs instead of plain
text. The new tab subscribes to NavigateRequested and opens the embedded
LICENSE / third-party-notices.txt content in a new tab on click.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the NotImplementedDialog stub with a real AboutCommand that builds
an AvaloniaEditTextOutput (ILSpy version, .NET version, embedded
ILSpyAboutPage.txt) and routes it through DockWorkspace.OpenNewTab as a
DecompilerTabPageModel. Adds an IAboutPageAddition extension point so future
plugins can append to the page. ILSpyAboutPage.txt / third-party-notices.txt
/ LICENSE are embedded via the same shape WPF uses.
Assisted-by: Claude:claude-opus-4-7:Claude Code