LT-22625 Phase-1 base: Avalonia migration spine (UIMode defaults Legacy) - #964
LT-22625 Phase-1 base: Avalonia migration spine (UIMode defaults Legacy)#964johnml1135 wants to merge 50 commits into
Conversation
3a905c6 to
b423a19
Compare
This comment has been minimized.
This comment has been minimized.
…ing docs Per deep review of the Phase-1 base PR, this removes ~10,300 lines of openspec content that does not belong in the base PR: Deleted entirely (self-declared superseded, or already implemented on a sibling branch with no home needed here): - openspec/changes/graphite-transition-support/ (self-labeled superseded throughout; content restated elsewhere) - openspec/changes/fieldworks-avalonia-shell-migration/ (self-labeled folded into/superseded by avalonia-end-game) - openspec/changes/avalonia-interlinear-editor/ (implemented on phase1-followup-interlinear, commit 3c5893e) - openspec/changes/avalonia-rule-formula-editor/ (implemented on phase1-followup-rule, commit 2c142bc) Deleted here for relocation to phase1-docs (speculative future-phase planning with real future value, not needed to review/merge this PR): - openspec/changes/avalonia-migration-roadmap/complete-migration-program.md, epics/**, reviews/** (JIRA-epic drafting for unstarted stages 5-13) - openspec/changes/legacy-screenshot-capture/ (dev tooling supporting a Docs/migration/ effort this PR isn't carrying) - openspec/changes/avalonia-end-game/ (depends on a Phase-1 burn-down this PR hasn't finished) Trimmed/deleted within datatree-model-view-separation (this change's own proposal.md/hybrid-alignment.md already carry a 2026-06-09 supersession note saying DataTreeModel/SliceSpec/IDataTreeView "should not be built"; these were the pieces that never caught up to that note): - Deleted specs/datatree-model/spec.md (asserted the abandoned DataTreeModel/SliceSpec/IDataTreeView requirements as live ADDED reqs); kept specs/datatree-partial-split/spec.md (the partial-class-split slice the proposal says remains valid as optional legacy maintenance) - Deleted three overlapping draft test plans for the abandoned design: testing-approach-2.md, test-plan-forms.md, test-plan-forms-future.md - Deleted stale coverage-gap planning docs: specs/changes-from-test-before-refactor/coverage-wave2-test-matrix.md and ".../tests to fix coverage gaps.md" - Trimmed datatree-mental-model.md to the current-state description only, removing the "target shape after split" section describing the abandoned architecture Fixed two stale artifacts that never caught up to their sibling supersession notes: - avalonia-migration-roadmap/specs/avalonia-migration-roadmap/spec.md: added a supersession note to the "DataTree split is the first migrated region" requirement and added an as-built scenario describing the actual region-model path (ViewDefinitionModel/LexicalEditRegionModel), matching the note already in this change's own design.md - lexical-edit-avalonia-migration/architecture-diagrams.md: removed the IPropertyStateStore port node (never built per task 18.6; state flows through IRecordNavigationContext + host PropertyTable), annotating the Navigation port instead Kept as-is per review: avalonia-migration-roadmap/{proposal,design, tasks}.md + specs/ (the ordered roadmap every later stack PR needs), avalonia-multi-writing-system-text-foundation/ (substantially shipped, not speculative), and the rest of datatree-model-view-separation (design.md/tasks.md/proposal.md already carry accurate snapshot framing). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
10d7181 to
af20c5b
Compare
This comment has been minimized.
This comment has been minimized.
…ss, openspec Records accumulated phase-1 working-tree changes not part of the Options-dialog work: adoption of the shared AvaloniaDialogTestHarness across the dialog test suites, LexicalBrowse* / ViewDefinition test updates, the FwAvalonia Preview/** compile exclusion (PR #964 review §4 finding F), preview-host project ref, and openspec roadmap edits (incl. removing the superseded datatree-model-view- separation change). Bundled as one checkpoint; the tree builds and all touched test suites pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Records accumulated phase-1 working-tree changes not part of the Options-dialog work: adoption of the shared AvaloniaDialogTestHarness across the dialog test suites, LexicalBrowse* / ViewDefinition test updates, the FwAvalonia Preview/** compile exclusion (PR #964 review §4 finding F), preview-host project ref, and openspec roadmap edits (incl. removing the superseded datatree-model-view- separation change). Bundled as one checkpoint; the tree builds and all touched test suites pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6636e17 to
40ae9d1
Compare
Stacked on the interlinear follow-up. Restore the rule-formula surface and activate it: - add back the 29 rule-formula files (the 5 plugins, RuleFormulaModel/RegionEditor + RuleCellCommands, PhEnvironment + BasicIPASymbol editors, projector/sinks/options + deriver, and all their tests incl. SupportingEditorComposeTests) - restore the 5 plugin registrations in RegionEditorPlugins - restore the 5 rule class names in the burn-down census - FLIP: register the 6 rule tools (PhonologicalRuleEdit, EnvironmentEdit, compoundRuleAdvancedEdit, naturalClassedit, phonemeEdit, AdhocCoprohibEdit) in LexicalEditFeatureCatalog under a new "Grammar rule editors" group (restoring the canonical pre-split active set + parity notes); Phase1FollowUpSurfaceTools is now empty (both edit follow-ups landed; browse table gated separately) - add the 6 rule TestCase rows to RegisteredRecordEditTools_ResolveToAvalonia Rebased onto the squashed phase1-base (post PR #964 review): tool registration is now catalog-driven, so this flip also adds a new "Grammar rule editors" group (6 rows) to the Tools->Options "Manage Individual Features" dialog under UIMode=New. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore the interlinear surface on top of phase1-base and activate it: - add back the 11 interlinear files (InterlinearRegionEditor + analysis model + projector/write-back + plugin + their tests, incl. the FwAvalonia model and Visual tests) - restore the InterlinearSlicePlugin registration in RegionEditorPlugins - restore the interlinear class name + resolve assertion in the burn-down census - FLIP: register "Analyses" in LexicalEditFeatureCatalog (with new display-name/description strings), so it flows into the catalog- sourced DefaultSupportedTools and the Words Analyses detail editor resolves to Avalonia under UIMode=New; removed from Phase1FollowUpSurfaceTools - add the "Analyses" TestCase back to RegisteredRecordEditTools_ResolveToAvalonia The browse "Analyses" list pane stays inert (table follow-up territory). Rebased onto the squashed phase1-base (post PR #964 review): the base PR had since refactored tool registration to be catalog-driven, so this flip now also adds a "Words Analyses" row to the Tools->Options "Manage Individual Features" dialog under UIMode=New. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stacked on the interlinear follow-up. Restore the rule-formula surface and activate it: - add back the 29 rule-formula files (the 5 plugins, RuleFormulaModel/RegionEditor + RuleCellCommands, PhEnvironment + BasicIPASymbol editors, projector/sinks/options + deriver, and all their tests incl. SupportingEditorComposeTests) - restore the 5 plugin registrations in RegionEditorPlugins - restore the 5 rule class names in the burn-down census - FLIP: register the 6 rule tools (PhonologicalRuleEdit, EnvironmentEdit, compoundRuleAdvancedEdit, naturalClassedit, phonemeEdit, AdhocCoprohibEdit) in LexicalEditFeatureCatalog under a new "Grammar rule editors" group (restoring the canonical pre-split active set + parity notes); Phase1FollowUpSurfaceTools is now empty (both edit follow-ups landed; browse table gated separately) - add the 6 rule TestCase rows to RegisteredRecordEditTools_ResolveToAvalonia Rebased onto the squashed phase1-base (post PR #964 review): tool registration is now catalog-driven, so this flip also adds a new "Grammar rule editors" group (6 rows) to the Tools->Options "Manage Individual Features" dialog under UIMode=New. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore the interlinear surface on top of phase1-base and activate it: - add back the 11 interlinear files (InterlinearRegionEditor + analysis model + projector/write-back + plugin + their tests, incl. the FwAvalonia model and Visual tests) - restore the InterlinearSlicePlugin registration in RegionEditorPlugins - restore the interlinear class name + resolve assertion in the burn-down census - FLIP: register "Analyses" in LexicalEditFeatureCatalog (with new display-name/description strings), so it flows into the catalog- sourced DefaultSupportedTools and the Words Analyses detail editor resolves to Avalonia under UIMode=New; removed from Phase1FollowUpSurfaceTools - add the "Analyses" TestCase back to RegisteredRecordEditTools_ResolveToAvalonia The browse "Analyses" list pane stays inert (table follow-up territory). Rebased onto the squashed phase1-base (post PR #964 review): the base PR had since refactored tool registration to be catalog-driven, so this flip now also adds a "Words Analyses" row to the Tools->Options "Manage Individual Features" dialog under UIMode=New. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stacked on the interlinear follow-up. Restore the rule-formula surface and activate it: - add back the 29 rule-formula files (the 5 plugins, RuleFormulaModel/RegionEditor + RuleCellCommands, PhEnvironment + BasicIPASymbol editors, projector/sinks/options + deriver, and all their tests incl. SupportingEditorComposeTests) - restore the 5 plugin registrations in RegionEditorPlugins - restore the 5 rule class names in the burn-down census - FLIP: register the 6 rule tools (PhonologicalRuleEdit, EnvironmentEdit, compoundRuleAdvancedEdit, naturalClassedit, phonemeEdit, AdhocCoprohibEdit) in LexicalEditFeatureCatalog under a new "Grammar rule editors" group (restoring the canonical pre-split active set + parity notes); Phase1FollowUpSurfaceTools is now empty (both edit follow-ups landed; browse table gated separately) - add the 6 rule TestCase rows to RegisteredRecordEditTools_ResolveToAvalonia Rebased onto the squashed phase1-base (post PR #964 review): tool registration is now catalog-driven, so this flip also adds a new "Grammar rule editors" group (6 rows) to the Tools->Options "Manage Individual Features" dialog under UIMode=New. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- VersionInfoProvider: copyright year no longer freezes at whatever year the constant was last edited, ApplicationVersion resolves from the correct assembly instead of always falling back to the entry assembly, and MajorVersion/ParseInformationalVersion index defensively instead of assuming a fixed part count. Covered by new VersionInfoProviderTests.cs. - RegFree.targets: removes a dangling ManagedVwWindow.dll entry; the project was already retired in #904/#906, so the entry pointed at nothing. - opsx-*.prompt.md: replace inlined instructions with delegation to the existing .claude/skills/openspec-*/SKILL.md files, per this repo's skills-over-inline-prompts convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Six EXE projects (FieldWorks, LCMBrowser, UnicodeCharEditor, GenerateHCConfig, ComManifestTestHost, NativeBuild) each import RegFree.targets and generate manifests for the same shared managed assemblies (FwUtils.dll, SimpleRootSite.dll, ManagedVwWindow.dll) into the same $(OutDir). Under a parallel MSBuild build, their CreateComponentManifests targets can run in different MSBuild worker processes at the same time and race to read/write the exact same manifest file, throwing an IOException that fails the whole build (observed intermittently in CI, e.g. FieldWorks PR #964). Wrap RegFree.Execute()'s read-modify-write of the manifest file in a cross-process named Mutex keyed by the resolved output path, so concurrent invocations targeting the same file serialize instead of racing; invocations for different manifest files are unaffected and still run fully in parallel. string.GetHashCode() is deliberately not used for the mutex name since .NET randomizes it per process, which would defeat cross-process synchronization - MD5 is used instead as a deterministic fingerprint. Added a regression test that runs 12 concurrent RegFree.Execute() calls against the same manifest path and asserts they all succeed and produce valid, uncorrupted XML. Verified it actually catches the regression: temporarily reverted the mutex fix, confirmed the test fails reliably (3/3 runs), then restored the fix and confirmed it passes reliably (5/5 runs). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
|
commit 8d21d03385: commit ac50ecc427: commit 896e92dc58: commit 5f56b0b794: commit d82088fe43: commit f409b5aad6: commit d200a34016: commit de9fe70e99: commit 45a569a188: commit 88d4a587c8: commit df74847c7c: commit ca58e388f6: commit 32c925b51c: commit de52e69131: commit 02e14541af: |
InputKeyClaimingAvaloniaHost had two consecutive <summary> blocks above InputKeyClaimPolicy: the first (host-describing) was misattributed to the policy class and made a duplicate summary, while the host class itself had no doc. Moved the host-describing summary onto InputKeyClaimingAvaloniaHost, left exactly one summary on InputKeyClaimPolicy, and added a summary to the host constructor (it had a <param> but no summary). Trimmed three over-long class summaries that narrated mechanism (HOW) down to purpose plus the non-obvious contracts: EntryGoDialogViewModel (kept commit-on-select single-stage and the opt-in two-stage auxiliary/description contracts), EntryGoDialogView code-behind (condensed to the MVVM-boundary statement), and FwMultiWsTextField (kept the "so a bold value can't crowd or overlap the abbreviation" rationale, dropped the two-column-Grid detail). Also de-jargoned residual inline section markers in FwFieldControls.cs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FwAvaloniaPlatform.IsHeadless resolves Avalonia internals by string name (AvaloniaLocator in Avalonia.Base; IWindowingPlatform in Avalonia.Controls; AvaloniaLocator.Current and its GetService method). Because these are not public API, a version bump can relocate them with no compile break, leaving the reflection returning null forever - silently reporting "not headless" and disabling the headless-embed no-op guard for the entire suite. Added a pin test mirroring the existing MicroCom namespace pin: it asserts each reflected type/member still resolves in the referenced Avalonia (the AvaloniaLocator type, the IWindowingPlatform type, the static Current property, and the GetService(Type) method), failing loudly with a message telling the maintainer to update FwAvaloniaPlatform if a bump moved them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The core edit-context interface carried every specialized edit gesture, so adding a field kind's ops meant a widening edit that forced every implementer (base, in-memory, composed, preview, reversal, the test fake) to stub a new method. Factor the specialized clusters out. - Move the four StText paragraph-CRUD methods (TrySetParagraphText, TrySetParagraphStyle, TryInsertParagraph, TryDeleteParagraph) into a new optional IStructuredTextEditing interface. The one caller (FwStructuredTextField) queries `ctx as IStructuredTextEditing` and treats null as "unsupported" - the same rejection the core methods returned on a context with no StText rows. Only the composed context and the preview/test doubles implement it; the base and the in-memory/reversal contexts drop their stubs. Adding a future kind's ops is now a new sub-interface plus one implementer, not a shotgun edit across every context. - Remove the five picture methods (TryInsertPicture, TryReplacePictureFile, TryDeletePicture, TrySetPictureMetadata, TryInsertPictureOrc). Picture editing was removed from the Avalonia region (the picture slice renders the Unsupported row), no caller invoked them, and the composed context did not override them - they were dead stubs in every implementer. Wrapping dead surface in an IPictureEditing that nothing implements or consumes would be empty ceremony, so the cluster is removed instead. RegionPictureMetadata (used by the picture-properties dialog) is unaffected. Behavior-preserving: no gesture that succeeded before is rejected now. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The composed edit context routed writes through nine parallel Dictionary<stableId, Func<...>> maps (text, rich-text, option, reference add/remove, and four paragraph maps). Each field's edit behavior was scattered across up to nine untyped Func maps that all had to be kept in sync by matching the same string stable id - the flagged #1 maintainability concern. - Replace the nine maps with a single Dictionary<stableId, FieldEditHandler>. FieldEditHandler carries one field's text/rich-text/option/reference/paragraph write delegates together (null where the field's kind does not support a gesture). A walker builds up a field's handler via ComposeState.HandlerFor; ComposedRegionEditContext looks up the one handler and calls the relevant slot, rejecting an unsupported gesture by finding a null slot - the same rejection the nine-map lookups produced on a missing key. The nine-argument constructor collapses to one handler-map argument. - Decompose the two long walkers by concern (pure mechanical extraction, no logic change): WalkTextField (~200 lines) now delegates writing-system resolution, per-WS value/audio building, and edit-handler registration to ResolveTextRowWritingSystems / BuildTextRowValues / RegisterTextRowEditHandler; WalkOtherField's three switch-case bodies move to WalkReferenceAtomicField / WalkOwningAtomicField / WalkReferenceVectorField, leaving a thin dispatcher. Behavior-preserving: staging, undo labels, and rejection semantics are unchanged. The three xWorks tests that construct ComposedRegionEditContext directly were updated to build handler maps; their assertions are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The three filterable region controls each carried their own copy of the same filter-box-over-list machinery. FwOptionPicker (flat list + optional flyout), FwPosChooser (tree + flyout), and FwFeatureStructureEditor (inline tree) duplicated the pointer-release-over-own-item guard and the compact ListBoxItem theme; the two tree controls additionally duplicated the name-contains filter (the tree/flat-list visibility swap), the highlight-move helper, and the compact TreeViewItem theme; the two flyout controls duplicated the chromeless FlyoutPresenter theme. A new FilterableDropdownSupport static helper in FwAvalonia factors out only that genuine overlap: IsReleaseOverOwnItem and CompactListItemTheme (all three), ApplyNameFilter, MoveListHighlight and CompactTreeItemTheme (the two tree controls), and ChromelessPresenterTheme (the two flyout controls). A static helper rather than a shared base class: the three differ in content shape, popup hosting, and selection model, so a common base would fight the divergent parts; shared state is passed in per call instead. What stayed per control: FwOptionPicker keeps its own ApplyFilter and MoveHighlight (search-delegate results and unavailable-option skipping are genuinely different from the tree controls' name filter), plus its multi-select, dropdown, and option-template logic; the tree controls keep their tree building, selection, and create-row behavior. Behavior-preserving. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ~770-line constructor built every writing-system row inline. It now loops over field.Values calling a private BuildValueRow, which reads as a short sequence: BuildWsAbbrev, BuildValueBox, WireGhostPrompt, WireBridgeContextMenu (returns hasBridge), the rich-text editing region, WireWritingSystemKeyboard, the local context menu, and BuildRowPanel. The self-contained construction and handler-wiring blocks moved into those focused private methods verbatim. The rich-text editing region (bidi caret navigation, pointer normalization, TextChanged staging, Ctrl+B/I/U, the character-style / writing-system / insert-link / delete-ORC menu items, and clipboard) stays inline in BuildValueRow rather than splitting into further Wire methods: its handlers and the value box's context-menu Copy share the same mutable per-row state (currentRich, lastStaged, pendingRichOverride) through their closures, so separating them would require a per-row state holder and rewriting the caret handlers to read that holder instead of the locals. The selection/caret logic is unchanged, including the D1 caret-ordering fix (CaretIndex set BEFORE SelectionStart/SelectionEnd on Shift+Arrow); every selection/caret handler is byte-identical to before. D2 remains out of scope. The manual List<Action> _teardown is replaced by a CompositeDisposable (a new local type, since Avalonia 11 on net48 ships no CompositeDisposable and the repo pulls in no System.Reactive): Dispose delegates to it, and its Count still backs AttachedHandlerCount for the recycling assertions. Behavior-preserving. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…notes
Comment-only pass over the PR's added/changed code comments against the
revised review standard. No behavior change.
- Migration phase/stage framing stripped: "Phase N", "Stage N",
"MSA-port Stage N", "Phase-1 §19b Stage N", "DATA-SAFETY (Phase 1, test a)"
and similar temporal-position/future-stage prefixes and dividers; surviving
behavior text kept and re-evaluated, comments with only process removed.
- Internal-doc and section markers removed: design/skill .md filenames
(winforms-free-lexeme-editor.md, canonical-view-definition-design.md,
dialog-ownership.md, native-views-audit.md, etc.) and pointers into them
(§19a-§19g, §20.x, §8.3, D1/D3, F-1/F-7, LE-4, T-rubric tags, "task N.N",
"(6.3/B8)", "(B7)", "19i.x"). Genuine WHY rewritten self-contained.
LT-##### Jira refs preserved.
- Absence/stale narration deleted or rephrased to current fact
("no longer forces read-only" -> "does not force read-only";
"replacement for the old detached DTO mapping" clause dropped).
- Creation-process / forward-work removed ("is deferred", "once other tools
are wired", "before a second region reuses this", review-cleanup notes).
- Legacy temporal framing trimmed to plain current behavior; legacy parity
WHY (naming the legacy equivalent) kept.
- String literals, code identifiers (e.g. Phase1FollowUpSurfaceTools),
and pre-existing legacy comments left untouched.
Build: build.ps1 -SkipNative -BuildTests -> 0 errors, 0 warnings.
Tests: FwAvaloniaTests 634 (633 pass / 1 skip); FwAvaloniaDialogsTests 298/298.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the migration-invented 'Lexical' prefix from the region data/model types (settled vocabulary); behavior-preserving identifier rename only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the migration-invented 'Lexical' prefix from the region view control (LexicalEditRegionView -> RegionDataTree, per the settled vocabulary) and retire the colliding xWorks LexicalEditRegionEditingTests name in favor of RegionEditContextEditingTests; behavior-preserving identifier rename only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename the Avalonia region field-control factory to the Slice* vocabulary; qualified as RegionSliceFactory(/Context/Tests) because a legacy SliceFactory already exists in Common.Framework.DetailControls. Behavior-preserving identifier rename only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the migration-invented 'Lexical' prefix from the edit-surface family (enum, resolver, registry, factory, selection service, and the RecordEditView surface helpers), per the settled vocabulary; behavior-preserving identifier rename only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the migration-invented 'Lexical' prefix from the feature catalog and feature-manager dialog family, moving them to the Lexicon* vocabulary (Lexicon-area scope); behavior-preserving identifier rename only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the migration-invented 'Lexical' prefix from the Lexicon-tool-specific region types (first slice, first-slice edit context, host control, and the region builder now named LexiconEditErrorFallback), per the settled vocabulary. Extract the writing-system keyboard activation into a dedicated RegionKeyboard.ActivateForWritingSystem helper and repoint its two callers. The helper stays in xWorks (not FwAvalonia/Region) because it needs the LCModel cache and the FwAvalonia view layer is intentionally LCModel-free. Behavior-preserving. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the migration-invented 'Lexical' prefix from the remaining region support types (preview window/scenario/data-provider, refresh-coordinator interface, override migration, and the headless editor driver), moving them to the generic Region* vocabulary; behavior-preserving identifier rename only. LexicalEditUiLabel (an options-dialog UI label, not a migration type) is left as-is. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Apply the legacy stem + role suffix uniformly across each converted dialog's
type-set (Input/View/ViewModel/Payload/State), renaming files to match:
InsertEntryDialog* -> InsertEntryDlg* (InsertEntryPayload -> InsertEntryDlgPayload)
AddNewSenseDialog* -> AddNewSenseDlg* (AddNewSensePayload -> AddNewSenseDlgPayload)
MsaCreatorDialog* -> MsaCreatorDlg* (MsaCreatorPayload -> MsaCreatorDlgPayload)
OptionsDialog* -> LexOptionsDlg* (OptionsState -> LexOptionsDlgState)
FwMsaGroupBox -> MSAGroupBox (the control; no suffix)
These deliberately reuse legacy stems that also live in LexTextControls; the
suffixed names stay unique simple names and MSAGroupBox is an intentional
cross-namespace twin (FwAvaloniaDialogs vs LexTextControls). x:Class /
x:DataType and doc-comment crefs move with the types. The LexTextControls
launchers that construct these dialogs are updated to the new names.
Notes on the twin:
- LcmInflectionFeatureCreateWiring lives in the LexTextControls namespace, so
its unqualified references to the Avalonia MSAGroupBox now collide with the
legacy WinForms MSAGroupBox (same-namespace wins). Its two method parameters
and the type cref are qualified to FwAvaloniaDialogs.MSAGroupBox to keep them
bound to the Avalonia control. This is required for compilation.
- Test fixture class/file names (InsertEntryDialogTests, FwMsaGroupBoxTests,
etc.) are left unchanged since they are not part of the enumerated type-set;
only the type references inside them are updated. The gitignored
DialogSnapshot label literals ("FwMsaGroupBox-NN-...") are preserved as stable
ids (they are not committed baselines).
Behavior-preserving. build.ps1 -SkipNative -BuildTests: 0 errors, 0 warnings.
Tests: FwAvaloniaDialogsTests 298/298; FwAvaloniaTests 634/633 passed/1 skipped;
LexTextControlsTests 351 total/348 passed/3 skipped (pre-existing skips).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move the xWorks region-bridge files out of the project root into a dedicated
Avalonia/ tree with coarse role subfolders, so the Avalonia region-editing
bridge reads as one area instead of being scattered among the legacy xWorks
files. Pure git mv (R100); xWorks.csproj is SDK-glob (only Compile Remove is
xWorksTests/**), so no compile-item edits are needed.
Avalonia/ RegionEditContextBase, RegionEditContextHolder,
ISettlePendingEdits, RegionOverrideMigration
Avalonia/Composer/ RegionComposer, RegionValueFactory, LcmRegionEditSession,
LexiconFirstSliceEditContext, LexiconEditErrorFallback
Avalonia/Plugins/ RegionEditorPlugins, ReversalIndexEntryPlugin
Avalonia/Hosting/ RecordEditView.Avalonia, AvaloniaRegionRefreshController,
XCoreMenuBridge, RecordClerkNavigationContext,
FwDragDropData, FwTsStringClipboard, RegionKeyboard
LexiconFirstSlice.cs is left in Src/Common/FwAvalonia/Region (not an xWorks
file). RecordEditView.Avalonia.cs stays a partial of RecordEditView (same
assembly/namespace, so the pairing is unaffected by the folder move) - verified
by the build.
Behavior-preserving folder move. build.ps1 -SkipNative -BuildTests: 0 errors,
0 warnings (xWorks + xWorksTests compile from the new layout).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move the 17 LexTextControls files that bridge to the Avalonia dialog kit out of
the project root into a flat Avalonia/ folder, so the Avalonia launchers/adapters
read as one area instead of being interleaved with the legacy WinForms controls.
Every moved file references FwAvaloniaDialogs; EntryGoDlg.cs and
EntryGoSearchEngine.cs (no Avalonia-kit reference) stay in the root.
Avalonia/ AvaloniaOptionsDialogLauncher, EntryGoLauncherShared,
FwFeatureStructureAdapter, LcmInflectionFeatureCreateWiring,
LcmAddAllomorphDialogLauncher, LcmAddNewSenseDialogLauncher,
LcmCreateFeatureLauncher, LcmCreatePartOfSpeechLauncher,
LcmGoToEntryDialogLauncher, LcmInflectionFeatureChooserLauncher,
LcmInsertEntryDialogLauncher, LcmLinkAllomorphDialogLauncher,
LcmLinkEntryOrSenseDialogLauncher, LcmLinkMsaDialogLauncher,
LcmMergeEntryDialogLauncher, LcmMsaCreatorDialogLauncher,
LcmPhonologicalFeatureChooserLauncher
Pure git mv (R100); LexTextControls.csproj is SDK-glob (only Compile Remove is
LexTextControlsTests/**), so no compile-item edits are needed.
Behavior-preserving folder move. build.ps1 -SkipNative -BuildTests: 0 errors,
0 warnings (LexTextControls + LexTextControlsTests compile from the new layout).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move the region-bridge and Avalonia-launcher test files into Avalonia/ trees
that mirror the source reorg (3A/3B), so each test sits next to the area it
covers. The moved sets are exactly the test files added on this branch relative
to main (35 in xWorksTests, 17 in LexTextControlsTests); the two pre-existing
files touched on the branch (xWorksTests/XWorksAppTestBase, BulkEditBarTests)
stay in their roots.
xWorksTests/Avalonia/ mirrors 3A (best-fit by SUT):
Composer/ FieldTypeComposerTests, FullEntryRegionOverrideTests,
FullEntryRegionReferenceChooserTests, FullEntryRegionVoiceWsTests,
LexiconFirstSliceEditContextEdgeCaseTests, RegionEditContextEditingTests,
RegionEditSessionLifecycleTests, StructuredText{Adapter,Integration,
Workflow}Tests, BackRefVectorTests, EntryReferenceVectorTests,
GhostLexRefSliceTests, LexReferenceMultiSliceTests,
AdhocCoProhibComposeTests, CompoundRuleComposeTests,
NaturalClassComposeTests, RegionConsolidationTests,
RegionOverrideMigrationTests
Plugins/ LexemeEditorBurnDownTests
Hosting/ RecordEditViewActiveHostContractTests, RecordEditViewSwitchTests,
RecordClerkNavigationContextTests, FwTsStringClipboardTests,
FwXWindowUIModeSeedingTests, RegionCommandAdapterHardeningTests,
RegionContextMenuCompositionTests, RegionObjectCommandExecutionTests,
RegionEditLinkDispatchTests, RegionEditGuardAndSchedulingTests,
RegionDataTreeMoveReachabilityTests, WinFormsUiaSmokeTests,
AvaloniaHeadlessPlatformTests, AvaloniaHeadlessSetUpFixture,
TestLocalizationManagerBootstrap
LexTextControlsTests/Avalonia/ (flat) mirrors 3B: the 15 launcher/adapter test
files plus LexOptionsDlgTests and ScreenshotHarnessTests (the other two new
Avalonia-dialog test files).
Slotting notes (folder-only, no behavior effect):
- Root-level SUT tests (RegionEditContext*/RegionOverrideMigration) are placed
in the closest of Composer/Hosting since the test mirror uses only the three
subfolders.
- Cross-cutting test infrastructure (AvaloniaHeadlessSetUpFixture,
AvaloniaHeadlessPlatformTests, TestLocalizationManagerBootstrap) is parked in
Hosting. The [SetUpFixture] keeps its code-declared namespace, so its scope is
unchanged by the move.
Pure git mv (R100); both test projects are SDK-glob, so no compile-item edits.
Behavior-preserving. build.ps1 -SkipNative -BuildTests: 0 errors, 0 warnings.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reviewer chose the bare legacy stem over the qualified RegionSliceFactory, making the FwAvalonia.Region type a deliberate cross-namespace twin of DetailControls.SliceFactory; no CS0104 alias was needed (no site references the bare stem while importing DetailControls), and the engine-isolation audit's source denylist drops SliceFactory since FwAvalonia.Region now owns the twin while the assembly-level guard still enforces isolation; behavior-preserving. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Seams namespace keeps only true substitution seams, their implementations, and boundary data contracts: - FinalizerSafeSynchronizationContext moves to the FwAvalonia root beside FwAvaloniaRuntime, which installs it (a hosting crash guard, not a seam). - MorphTypeSwapLogic (with MorphTypeKind) moves to FwAvalonia.Region beside its RegionComposer consumer; the DetailControls pointer comment now names the new location. - EditSurfaceKind is extracted from ActiveHostContract.cs into its own file at the FwAvalonia root, anchoring the EditSurface* family. - ISeams.cs (a grab-bag named after no type) splits into one file per interface: IEditSession, IRegionRefreshCoordinator, IUiScheduler, IRegionLifetime, IXCoreCommandBridge, IRecordNavigationContext. Behavior preserving; doc comments carried verbatim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three whole-identifier renames, no behavior change: - ISettlePendingEdits -> IPrepareToGoAway (method SettlePendingEdits -> PrepareToGoAway, still void). Named for the legacy DataTree/ BrowseViewer PrepareToGoAway idiom; the summaries now spell out the deliberate contract difference — this seam cannot veto and always settles the open edit. RecordEditView implements it explicitly because the class already carries the legacy vetoing bool PrepareToGoAway() override. - FwOptionPicker -> FwOptionChooser, unifying on the FieldWorks "chooser" vocabulary (FwOptionPickerTests -> FwOptionChooserTests). Diagnostic string literals keep the old name: the "FwOptionPicker" TraceSwitch id (paired with FieldWorks.Diagnostics.dev.config), the [FwOptionPicker] trace prefixes, the FwOptionPicker-NN dialog snapshot names, and three assertion-message mentions. - LexemeEditorBurnDownTests -> LexemeEditorInventoryTests, dropping task-management vocabulary from the census fixture; the xWorksTests.csproj pointer comment follows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Options label for the lexical-edit UI mode chooser said "Lexical Edit UI", which names the internal migration rather than what the user is choosing. Both twins now read "New UI (preview)": - Avalonia: FwAvaloniaDialogsStrings.LexicalEditUiLabel -> NewUiPreviewLabel (resx key FwAvaloniaDialogs.NewUiPreviewLabel, renamed in place to keep the append-only order), value "New UI (preview)"; LexOptionsDlgView.axaml follows the accessor. - Legacy WinForms twin (PR-added entry): LexTextControls.resx UiModeGroupTitle keeps its neutral key, value becomes "New UI (preview):"; the LexOptionsDlg in-code fallback copy of the label follows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stage (a) of the Region->Detail rename: the FwAvalonia core model/view types (DetailModel, DetailField, DetailTextRun, DetailRichTextValue, DetailWsValue, DetailChoiceOption, DetailMenu*, DetailViewing*, and the rest of the mechanical table), IDetailEditContext, the seams (IDetailRefreshCoordinator, IDetailLifetime/DetailLifetime), the host pair (AvaloniaHostControlBase / DetailHostControl), DetailEditorCategory with ClassifyDetailFieldKind, and RegionDataTree as the bare legacy twin DataTree. The namespace moves from FwAvalonia.Region to FwAvalonia.Detail and the folder follows via git mv. RecordEditView's two partials pin bare DataTree to the legacy DetailControls type with a using alias (the anticipated CS0104 twin). The engine-isolation audit's forbidden-symbol list drops DataTree under the same reclaimed-twin exemption it already documents for SliceFactory; assembly-level isolation still enforces the real dependency ban. A stale SetRegionContent cref now points at the real member, SetHostContent. String literals (automation ids, trace text, snapshot capture names) are deliberately unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ocabulary
Stage (b) of the Region->Detail rename: DetailComposer, ComposedDetail,
ComposedDetailEditContext, DetailEditContextBase/Holder,
DetailValueFactory (with its DetailRichTextAdapter helper),
LcmDetailEditSession, DetailOverrideMigration,
AvaloniaDetailRefreshController, and ReversalDetailEditContext; the
slice-plugin family becomes ISlicePlugin / SlicePluginRegistry /
SlicePluginBuildContext (file SlicePlugins.cs). Members and methods
follow: ShowDetail, SettleDetailEdits, RefreshAvaloniaDetail,
OnAvaloniaDetailEditCompleted, OnDetailMenuRequested,
OnDetailLinkRequested, RaiseDetailEditCompleted, DetailEditCompleted,
RefreshedDetailFieldCount, m_detailEditContext, and the bare
region/regionField locals.
The one reflection literal on the renamed method
(GetMethod("RefreshAvaloniaRegion")) chases the new name so the
private-invoke test keeps binding; trace-message literals that embed the
old type names stay unchanged by the literal rule. The two csproj
comments naming the plugin contract now say ISlicePlugin.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stage (c) of the Region->Detail rename: the preview support family
(DetailPreviewWindow / DetailPreviewScenario / DetailPreviewDataProvider
in DetailPreviewSupport.cs), the workflow driver DetailEditorDriver, the
test doubles (PreviewDetailEditContext, InMemoryDetailEditContext,
FakeDetailEditContext, Rich/UnsupportedRich/Fake DetailValueProvider,
RealisticDetailModel, DetailDefinition), and the EntryGo dialog's
DescriptionPane family (HasDescriptionPane,
OnDataContextChangedRemoveDescriptionPaneIfUnused, the DescriptionPane_*
test names, and the axaml comments' "description pane" wording).
RegionKeyboard becomes WritingSystemKeyboards.Activate, joining the
writing-system-centered keyboard vocabulary; its summary now describes
the per-WS keyboard activation for editor rows on the Avalonia surface
and keeps the lives-in-xWorks-because-LCModel note. Both callers
(RecordEditView.Avalonia.cs, ReversalIndexEntryPlugin.cs) follow. The
EntryGo automation ids ("EntryGo.DescriptionRegion",
"EntryGo.ResultsRegion") and snapshot capture names stay unchanged by
the literal rule.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stage (d) of the Region->Detail rename: every Region-named test fixture follows its subject (DetailEditingTests, DetailModelTests, DetailMenuTests, DetailOrcTests, DetailEditContextEditingTests, DetailComposerTests, DetailConsolidationTests, the Detail* hosting fixtures, DataTreeTests / DataTreeMoveReachabilityTests for the bare twin, EditorKindMapDetailCategoryTests, SlicePluginResolutionOrderTests, and the FullEntryRegion* fixtures as DetailComposer*Tests), along with every Region-bearing test method name (DetailEditView_*, Detail_ScrollsLikeLegacyAutoScroll, ClassifyDetailFieldKind_*, and the rest). Files rename to match their fixtures; the two csproj comments naming RegionPreviewTests.cs now say DetailPreviewTests.cs, and stale comment references to the old fixture names are updated. Snapshot artifacts are transient (*.received.png / *.diff.png are gitignored) and no committed baseline embeds a renamed test name. Automation-id and assertion-message literals that mention the old names stay unchanged by the literal rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stage (e), the final pass of the Region->Detail rename: the resx row FwAvalonia.RegionName becomes FwAvalonia.DetailAreaName with the value "Detail area" (in place, order preserved), the FwAvaloniaStrings accessor follows, and DataTree's automation Name consumer reads the new accessor. Comment prose across FwAvalonia, FwAvaloniaDialogs, xWorks/Avalonia, and the launcher files drops the region coinage for "detail view" / "detail area" / "detail surface" wording (sentence-level), and the EntryGo dialog family says "description pane". Project-file and axaml comments follow. Left deliberately unchanged: runtime string literals (the RegionDataTree/RegionEditor automation ids and their test lookups, the DetailComposer/DetailEditContextHolder trace prefixes that still say RegionComposer/RegionEditContextHolder, DialogSnapshot capture names, assertion messages, the avalonia-region-first-slice.png artifact name, and the EntryGo.*Region automation ids), the region-manifest.md document references, geographic "region" test data, and #region pragmas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Region->Detail identifier sweep deliberately left type-derived string literals unchanged; this commit moves them, keeping every literal and every lookup/assertion that reads it in the same change: - Automation ids: RegionDataTree(.Scroll/.Splitter) -> DataTree(...), RegionEditor.* -> DetailEditor.*, RegionPreviewWindow -> DetailPreviewWindow, EntryGo.DescriptionRegion/ResultsRegion -> EntryGo.DescriptionPane/ResultsPane, with all test lookups. - WinForms identity: Name "RegionHostControl" -> "DetailHostControl"; DataTree Name/id "RegionDataTree" -> "DataTree". AccessibleName "RecordEditView.AvaloniaHost" is intentionally unchanged. - Log/exception text: "RegionComposer:" -> "DetailComposer:", "RegionEditContextHolder.Settle:" -> "DetailEditContextHolder. Settle:", "A region editor plugin must claim..." -> "A slice plugin must claim...", the Region-worded Logger messages in RecordEditView.Avalonia.cs, and SliceFactory's "Custom region field" traces -> "Custom slice field". - DialogSnapshot capture names (gitignored artifacts): Region-* -> Detail-*, EntryGo-09-no-description-region -> ...-pane, avalonia-region-first-slice.png -> avalonia-detail-first-slice.png. - Assertion messages and the DetailViewingServices descriptors that said "region" in the detail sense now use detail wording; stale type mentions RegionLinkRequest/RefreshAvaloniaRegion/RegionSelectionRange now name DetailLinkRequest/RefreshAvaloniaDetail/DetailSelectionRange. - IFwClipboard.cs: reworded the fidelity note so "legacy" no longer reads as describing TsString itself; the shared format is the existing "TsString" clipboard format native-Views copy/paste uses. Deliberately untouched: FwOptionPicker trace-switch id and FieldWorks.Diagnostics.dev.config, BCP-47 Region* (writing systems), RegionsOC/LIFT/morphology XSL, #region pragmas, region-manifest.md references, image-diff "region" wording in RenderVerification, and geographic test data. Gates: build 0 errors; FwAvaloniaTests 633/634 (1 skip); FwAvaloniaDialogsTests 298/298; FwAvaloniaPreviewHostTests 3/3 (UIA); xWorksTests ~Detail|~Composer|~RecordEditView|~Slice|~DataTree 225/225 (226/226 with ~Region, matching the pre-rename baseline set); LexTextControlsTests 348/351 (3 skips). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mechanical name/path staleness fixes across .claude/skills/**: every
old type/file/path token is swapped for its verified landed equivalent
(each target confirmed to exist in the tree before writing):
- LexicalEditRegion{Model,Mapper,View,Field} -> DetailModel,
DetailModelProjector, DataTree, DetailField;
FullEntryRegionComposer -> DetailComposer (with its
Src/xWorks/Avalonia/Composer/ path); ComposedEntryRegion ->
ComposedDetail; RegionEditContext{Base,Holder} ->
DetailEditContext{Base,Holder}; ComposedRegionEditContext ->
ComposedDetailEditContext; IRegionEditContext -> IDetailEditContext;
IRegionValueProvider -> IDetailValueProvider; LcmRegionEditSession ->
LcmDetailEditSession.
- Plugin registry: RegionEditorPlugins(.cs) -> SlicePlugins(.cs) at
Src/xWorks/Avalonia/Plugins/; IRegionEditorPlugin -> ISlicePlugin;
RegionEditorBuildContext -> SlicePluginBuildContext;
RegionEditorPluginRegistry -> SlicePluginRegistry;
RegionFieldControlFactory -> SliceFactory; RegionFieldKind ->
DetailFieldKind; LexemeEditorBurnDownTests ->
LexemeEditorInventoryTests (Avalonia/Plugins path).
- Surfaces and features: LexicalEditSurface* -> EditSurface*;
LexicalEditFeature* -> LexiconFeature*; LexicalEditorDriver ->
DetailEditorDriver.
- Controls and seams: FwOptionPicker -> FwOptionChooser;
RegionMenuFlyout -> DetailMenuFlyout; RegionFocusMemory(Tests) ->
DetailFocusMemory(Tests); RegionWsValue -> DetailWsValue;
IRegionLifetime -> IDetailLifetime; ILexicalRefreshCoordinator ->
IDetailRefreshCoordinator; ISettlePendingEdits -> IPrepareToGoAway;
Region*Tests -> Detail*Tests.
- Dialog kit files: OptionsDialogView/ViewModel + OptionsState ->
LexOptionsDlgView/ViewModel/State; InsertEntryDialogView/ViewModel ->
InsertEntryDlgView/ViewModel; AddNewSenseDialogView/ViewModel and
MsaCreatorDialogView/ViewModel -> the *Dlg* names; FwMsaGroupBox.cs
-> MSAGroupBox.cs. Landed test/launcher names that keep the old
spelling (OptionsDialogTests, InsertEntryDialogTests,
AvaloniaOptionsDialogLauncher, Lcm*DialogLauncher) are untouched.
- Paths: Src/Common/FwAvalonia/Region/ -> .../Detail/; the moved
launcher (LexTextControls/Avalonia/), preview-host tests
(FwAvaloniaPreviewHost/FwAvaloniaPreviewHostTests/), and relocated
xWorks tests (Avalonia/Hosting/ for WinFormsUiaSmokeTests and
RecordEditViewActiveHostContractTests); ISeams.cs citations now point
at Src/Common/FwAvalonia/Seams/ (the file was split per interface).
Deliberately left (no landed equivalent to swap to; for the separate
alignment pass): browse-table machinery mentions
(SupportedAvaloniaBrowseToolNames, Phase1FollowUpBrowseTools,
ResolveBrowse_* tests, BrowseTableDriver, BrowseEditorIntegrationTests,
ClerkRoutedFilterTests), backed-out feature references (media seams,
RegionPictureEditor, FwGenDateField, rule-formula/interlinear types,
TreeSpikeAndRtlTests), prose uses of "region", and openspec/** by
decision.
Docs-only change; no code touched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase-1 base: Avalonia migration spine
https://jira.sil.org/browse/LT-22625
First of a 4-PR stack landing Phase 1 of the WinForms→Avalonia migration. It introduces the seam that lets FieldWorks host either the legacy WinForms editing surface or the new Avalonia one, gated entirely on a
UIModesetting that defaults toLegacy. At that default every call site added here resolves to its original, unchanged WinForms path; the Avalonia surface activates only when a user explicitly opts in via Tools → Options.What this PR contains
FullEntryRegionComposer), view-definition IR, owned controls, framework-neutral seam contracts, and the plugin registry.UIMode=New:lexiconEdit,lexiconEditPopup,notebookEdit,posEdit.FwUtils.UIModeGates.ShouldUseAvaloniaUI(uiMode)predicate.FwAvalonia/FwAvaloniaDialogsinfrastructure and the landed openspec change specs, plus the migration skills.RecordBrowseView/BrowseViewergained a full table overlay for list/browse tools — Configure Columns, Filter For/Restrict Date/Choose List flyouts, and a completeIBulkEditBarHost(bulk edit/copy/clear, Delete Rows, replace) — sitting on a large additiveBrowseViewerAPI (IBrowseColumnSource+ ~20 new methods). It activates per-tool throughLexicalEditSurfaceResolver.SupportedAvaloniaBrowseToolNames, which is empty in this PR, so every browse/list tool falls back to the legacyBrowseViewerregardless ofUIMode— asserted byInertFollowUpSurfacesFallBackToLegacy_BrowseTable.phase1-followup-table(see Stack) activates it one tool at a time.How Legacy stays safe
ShouldUseAvaloniaUIreturnstrueonly for an ordinal-ignore-case"New";null, empty, whitespace, or any other value → Legacy. Every one of the ~26 gate sites uses this single predicate.FwUtils, which references no Avalonia type, and every gated branch that touches an Avalonia launcher is extracted into a[MethodImpl(NoInlining)]helper. Legacy execution therefore never resolves an Avalonia type unless a gate actually passes. Startup localization method-lookup has its owntry/catch, so a missing/corruptFwAvalonia.dllcosts only the Avalonia dynamic strings, never the Chorus/Palaso localization managers.main(including theLexReferenceMultiSlicerestructure, traced case-by-case); the settings migration path is untouched; no static-init or reflection route reaches the new launchers ungated.DTMenuHandler.OnDisplayDataTreeInsert's enablement check gained|| m_dataEntryForm.IsExternalCommandAdapter.DataTree.IsExternalCommandAdapterdefaults tofalseand is settrueonly by New-mode's hidden command-routing adapter (RecordEditView.Avalonia.cs, tasks 13.4/15.4), which exists purely to keep a legacyDataTreealive for right-click menu routing while the Avalonia surface is on screen. Legacy never sets it, so the added clause never fires there — the check evaluates identically tomain— but it's a textual change to shared code outside the ~26 gate sites, so it's called out here rather than left implicit.InstallNewColumnsgained one line,m_avaloniaColumnFinders = null;, invalidating a cache field that only the (currently unreachable — see the Stage-3 browse mirror above) new methods ever read. Everything elseBrowseViewergained is new members bolted onto the class; no other existing method body changed.TsStringWrapperwidened frominternaltopublic, plus an additiveFromXmlfactory/Xmlproperty, so the cross-framework clipboard bridge (FwTsStringClipboard, task 3.13) can carry rich-text XML between the WinForms and Avalonia clipboard paths. No existing member's behavior changed.Legacy-visible changes (things existing users see even at the default)
The gate keeps behavior on Legacy identical, but this PR does make a few changes visible to all users, called out here so review isn't surprised:
LexOptionsDlg) and Avalonia (OptionsDialogView) dialogs, each carrying a "Beta: the New mode is incomplete" note.UIMode(defaultLegacy) andUIModeDisabledTools(default empty — a per-tool opt-out list read only after New mode is active).Name/AccessibleNamevalues instead of a uniform"FwComboBox"literal — an intentional screen-reader improvement, pinned by a WinForms UIA test.FieldWorks/xWorks/LexTextControlsreferenceFwAvalonia/FwAvaloniaDialogs, so the Avalonia binary stack deploys with every build andFwAvalonia.dllloads on core paths (behindFuncindirection + theNoInlininggates). "Legacy installs don't need Avalonia" is no longer true.New-mode parity deferrals
The New-mode (opt-in) path is narrower than the legacy dialogs it replaces in ~8 places, each marked
// PARITYin-code (e.g. allomorph type-mismatch warning, link-allomorph/MSA first-item pickers, Insert Entry duplicate search not matching gloss, MGA catalog import unported). Legacy is unaffected.LcmChooserDialogLauncherships with no production caller (private ctor, unreachable by design) — it is tested staging infrastructure for the futureReallySimpleListChoosermigration (~54 sites), documented as STAGING in its doc comment.Split out for separate assessment
A shared layout part (
LexSense-Detail-Pictures) would make sense pictures appear in the legacy Lexicon Edit pane (they have been silently omitted there for over a decade). It is a plausible legacy bug-fix but an ungated, legacy-visible behavior change, so it is not in this PR — it is proposed separately so the team can decide on it independently.Stack (each merges into the one above)
mainphase1-followup-interlinear→phase1-basephase1-followup-rule→phase1-followup-interlinearphase1-followup-table→phase1-followup-ruleVerification
Whole-solution build green; full CI-equivalent test run passes (7/7 CI checks). All ~26 gate sites verified fail-closed; every legacy else-branch verified equivalent to
main; TonePars/XAmpleParserare byte-identical tomain(this PR does not touch ParserCore/pcpatrflex). Draft until the stack is reviewed top-to-bottom.This change is