Fixes #4473 - Re-engineerCommand system and Fix Menus#4620
Merged
tig merged 236 commits intogui-cs:v2_developfrom Feb 25, 2026
Merged
Fixes #4473 - Re-engineerCommand system and Fix Menus#4620tig merged 236 commits intogui-cs:v2_developfrom
Command system and Fix Menus#4620tig merged 236 commits intogui-cs:v2_developfrom
Conversation
- Add POST-GENERATION-VALIDATION.md with comprehensive checklist for validating AI-generated code before commits - Add formatting.md with detailed spacing, brace, and blank line rules - Update REFRESH.md to reference the validation checklist - Update CLAUDE.md with references to new validation docs These additions address the most common formatting violations that AI agents make when writing code for Terminal.Gui. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add clean-code-review.md task guide for reimplementing branches with narrative-quality commit histories - Remove scenario-modernization.md (outdated task) The clean code review task provides a workflow for AI agents to reimplement messy branch histories into clean, reviewer-friendly commit sequences suitable for PR review. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addresses: gui-cs#4473 (Menu etc. with Selectors are broken) - Add command-propagation-plan.md with phased implementation plan - Remove command-propagation-analysis.md (superseded by plan) The plan introduces PropagatedCommands property to enable opt-in command propagation from SubViews to SuperViews, solving the issue where commands from nested views (e.g., FlagSelector in MenuBar) don't reach their containing views. Phase breakdown: 1. Foundation - PropagatedCommands infrastructure 2. WeakReference - Lifecycle-safe CommandContext.Source 3. Shortcut propagation - Enable Command.Activate for Shortcuts 4. Test cleanup - Re-enable skipped tests 5. MenuBar propagation - Full menu hierarchy support (deferred) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addresses: gui-cs#4473 (Menu etc. with Selectors are broken) This commit implements Phases 1 and 2 of the command propagation plan: Phase 1 - PropagatedCommands Infrastructure: - Add PropagatedCommands property to View (default: [Command.Accept]) - Add PropagateCommand helper method for command bubbling - Refactor RaiseAccepting to use PropagateCommand helper - Reorganize View.Command.cs regions for clarity Phase 2 - WeakReference for CommandContext.Source: - Change ICommandContext.Source from View? to WeakReference<View>? - Update CommandContext to use WeakReference for lifecycle safety - Update InvokeCommand overloads to wrap 'this' in WeakReference - Update all views using ctx.Source to use TryGetTarget pattern: - Dialog, DialogTResult - MenuBar, PopoverMenu - ComboBox, OptionSelector - ScrollSlider, Shortcut The PropagatedCommands property enables opt-in command propagation: when a SubView raises a command that isn't handled and the command is in the SuperView's PropagatedCommands list, the command bubbles up. BREAKING CHANGE: ICommandContext.Source is now WeakReference<View>? Code accessing ctx.Source must use TryGetTarget pattern: if (ctx?.Source?.TryGetTarget (out View? view) == true) { ... } Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a standalone test application for verifying Command.Activate propagation through the Shortcut → Window hierarchy. The example demonstrates: - CheckBox (CanFocus=false) in Shortcut → propagates to Window - CheckBox (CanFocus=true) in Shortcut → propagates to Window - Button in Shortcut → propagates to Window This serves as a manual test bed for the PropagatedCommands feature and helps verify that command context (Source) is properly preserved when commands bubble up through the view hierarchy. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tests to verify PropagatedCommands and WeakReference changes: CommandPropagationTests.cs (NEW - 588 lines): - Tests for command propagation through view hierarchies - Tests for WeakReference lifecycle safety - Tests for PropagatedCommands customization - Tests for Command.Accept and Command.Activate propagation ViewCommandTests.cs (updated): - Add tests for PropagatedCommands default value - Add tests for PropagateCommand helper behavior - Add tests for IsDefault button propagation CommandContextTests.cs (updated): - Update tests for WeakReference-based Source property - Add TryGetTarget pattern tests InputBindingTests.cs (updated): - Update tests for WeakReference compatibility All tests follow Terminal.Gui patterns and are added to UnitTestsParallelizable for parallel execution. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
command.md: - Document PropagatedCommands property - Explain command propagation behavior - Add examples for customizing propagated commands events.md: - Add section on command events and propagation - Document CommandEventArgs and ICommandContext - Explain WeakReference pattern for Source property Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update scenarios to use TryGetTarget pattern for accessing CommandContext.Source after the WeakReference change: Menus.cs: - Update command handlers to use TryGetTarget MouseTester.cs: - Update mouse event handlers for new pattern UICatalogRunnable.cs: - Update command context handling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change absolute path to relative path for cross-machine compatibility. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clarify and strengthen event forwarding between Shortcut and its CommandView, ensuring Activating and Accepting events propagate correctly without recursion. MouseHighlightStates now defaults to MouseState.In for better UI feedback. Refactor property implementations and clean up code. Add comprehensive unit tests verifying CheckBox state changes, event propagation, and default behaviors. Enhance ShortcutTestWindow to log detailed event info and demonstrate propagation scenarios.
- Updated Key equality operators to handle nulls safely and avoid NullReferenceExceptions. - ComboBox Accept command now uses non-nullable View in TryGetTarget and passes a WeakReference<View> to CommandContext for consistency. - Shortcut.Key property now always returns Key.Empty if unset, and setter no longer throws on null. - Simplified GetWidthDimAuto by removing unnecessary null-forgiving operators. - Fixed CommandViewOnActivating logic to prevent recursion and ensure correct event propagation. - Cleaned up redundant key initialization and clarified KeyView.Text assignment. - Overall, these changes improve code safety, event handling, and clarity.
Refactored the Shortcut class to replace explicit backing fields (_alignmentModes and _minimumKeyTextSize) with auto-implemented properties for AlignmentModes and MinimumKeyTextSize. Set default values directly in the property declarations and used the C# field keyword in setters. This streamlines property definitions and simplifies the codebase.
…/Terminal.Gui into copilot/fix-command-propagation-issue-clean
…/Terminal.Gui into copilot/fix-command-propagation-issue-clean
Improve command/event handling for menus and shortcuts Refactor Shortcut, Menu, MenuBar, and PopoverMenu to enhance command propagation, event handling, and resource management. Set PropagatedCommands by default, improve design-time support, and clarify event subscriptions. Add helper methods for event origin detection, enforce proper menu hierarchy, and update documentation and logging for better maintainability and debugging.
Member
Author
|
@tznind this is pretty ready. Would love your eyes on it please. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Refactored ArrangementEditor and NavigationEditor: swapped their responsibilities and names for clarity, updated constructors, fields, and event handlers. ArrangementEditor now edits arrangement-related properties; NavigationEditor edits TabStop.
Added a Null glyph ('␀') to Glyphs with configuration support. Standardized [ConfigurationProperty] attribute formatting in Glyphs.cs.
Fixed Key.cs != operator to handle nulls correctly. Improved ToString() for KeyBinding and MouseBinding to show Data values. WeakReferenceExtensions now uses the Null glyph for dead references.
Fixed trace logging typo in CommandBridge. Corrected ValueChangedUntyped argument order in ScrollBar. Removed redundant OnAccepted in FileDialog and debug log in CheckBox.
…/Terminal.Gui into copilot/fix-command-propagation-issue-clean
The private static string field _null was removed from the Glyphs class in the Terminal.Gui.Drawing namespace as it was unused. No other changes were made.
Accept no longer triggers Action or TargetView commands directly. Now, Accept is translated to Activate only for key bindings (e.g., Enter). Moved OnAccepting override to Shortcut; MenuItem's is commented out. Updated tests to verify Accept does not execute Action or commands. PopoverMenu Enter key handling removed; MenuBar/Menus updated. Clarifies distinction between Accept (confirmation) and Activate (action).
- Use null-conditional operators (`?.`) for safer access to `MenuBar` and related properties/methods in `Menus.cs`. - Fix help text typo and remove redundant `CommandsToBubbleUp` assignment in `UICatalogRunnable.cs`. - Enhance logging in `View.Hierarchy.cs` by using `ToIdentifyingString()` and clarify `SuperView` checks. - Comment out `MouseBindings.Clear()` in `SelectorBase.cs` to preserve mouse bindings. - Refactor `Shortcut.cs`: - Use a switch expression for concise `HelpView` margin logic. - Rewrite `ShowHide()` to avoid redundant add/remove operations and maintain correct subview order. - Remove obsolete comments for clarity. - These changes improve code safety, readability, and maintainability, and address minor UI and logging issues.
Enhanced OptionSelector focus for keyboard navigation. Added Ctrl+hotkeys to trace toggles in UICatalogRunnable and clarified help text. Expanded OptionSelector cycling logic for better keyboard interaction. Uncommented MouseBindings.Clear() in SelectorBase to reset mouse bindings. Commented out TransparentMouse viewport setting in Shortcut views to adjust mouse event handling.
Member
Author
|
I will merge this in the morning.... |
Introduced Lifecycle trace category for Application/Driver events. Updated Trace class to support five categories (Lifecycle, Command, Mouse, Keyboard, Navigation), each independently configurable. Added Trace.LifecycleEnabled property and calls throughout ApplicationImpl and MainLoopCoordinator for detailed lifecycle tracing. Renamed TraceEntry.ViewId to Id for generality. Simplified LoggingBackend formatting and added support for new categories. Updated config.json to enable lifecycle tracing by default. UI catalog trace menu now includes lifecycle toggle; other labels simplified. Refactored methods for clarity and brevity. Updated documentation and tests to use new Id field. Minor bug fixes and improved event handling.
Command system to support bubbling etc...Command system and Fix Menus
Resolved 5 conflicts: - ApplicationImpl.Driver.cs: kept both using statements - ApplicationImpl.Lifecycle.cs: took v2_develop guard clause fix - MainLoopCoordinator.cs: took v2_develop guard clause refactor - ColorPicker.16.cs: kept HEAD's OnActivated override (new CWP pattern) - View.md: took v2_develop's updated scrolling docs from PR gui-cs#4748 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes
Menu,Shortcut, etc... are broken - IntroduceCommandBubbling #4473Loggingto test output #3972Overview
Re-engineers the Terminal.Gui v2 command system for correctness, clarity, and composability. See
docfx/docs/command.mdfor the complete deep dive.What Changed
Core infrastructure (
View.Command.cs):CommandRoutingenum (Direct,BubblingUp,DispatchingDown,Bridged) replaces ad-hoc boolean flagsCommandContext(readonly record struct) withWithCommand/WithRoutingCommandOutcomeenum withbool?conversion shims (migration deferred — see below)GetDispatchTarget/ConsumeDispatchvirtuals for declarative composite-view dispatchCommandBridgefor cross-boundary routing (weak refs, one-way)Trace.CommandEnabled(zero overhead in Release builds)_lastDispatchOccurredreset at handler entry to prevent stale-flag bugsView-specific:
ConsumeDispatch=false) with deferred completion viaCommandView_ActivatedConsumeDispatch=true), context-dependent targetsOnActivatingtoggle logic for activation/deactivationCommandBridge.Connectfor PopoverMenu,Bridgedguard,IsInitializedguardOnActivatingoverride dispatches to focused MenuItemIAcceptTarget, Space/Enter →Command.Accept, does NOT raise ActivatingDesign
See
plans/finalizing-command-system.mdfor:See
plans/menubar-reengineer.mdfor MenuBar bug fixes and test migration.Tests
Old non-parallelizable
MenuBarTests.csdeleted; ~30 modern parallelizable tests replace it.Porting Guide: Migrating from v2_develop
This PR changes how
Activating/Acceptingevents work. Code written againstv2_developwill need updates.The big win: No more
e.Handled = truePreviously, every
Accepting/Activatinghandler had to sete.Handled = trueor the command system would misbehave (double-firing, unexpected bubbling, or the event being silently swallowed). This was a constant source of bugs. Now,Handledis only for cancellation — set it totrueonly when you want to prevent the action from proceeding.Use
Accepted/Activatedinstead ofAccepting/ActivatingPreviously,
Accepteddidn't really work — the post-events were unreliable or missing. All real work had to go in the pre-events (Accepting/Activating). Now the two-phase model works correctly:Accepting/Activating(pre-events) — Use only for cancellation or validation. Sete.Handled = trueto prevent the action.Accepted/Activated(post-events) — Use for reacting to completed actions. NoHandledproperty — these are non-cancellable notifications.Quick migration checklist
view.Accepting += (s, e) => { DoWork(); e.Handled = true; };view.Accepted += (_, _) => { DoWork(); };view.Activating += (s, e) => { DoWork(); e.Handled = true; };view.Activated += (_, _) => { DoWork(); };view.Accepting += (s, e) => { if (invalid) e.Handled = true; };view.Accepting += (_, e) => { if (invalid) e.Handled = true; };(unchanged — cancellation still uses pre-event)override OnAccepting(args) { ...; return true; }override OnAccepted(ctx) { ...; }(move work to post-event unless cancelling)override OnActivating(args) { ...; return true; }override OnActivated(ctx) { ...; }(move work to post-event unless cancelling)Button no longer raises Activating
Buttonnow maps all interactions (Space, Enter, mouse) toCommand.Accept. It does not raiseActivating/Activated. If you were subscribing tobutton.Activating, switch tobutton.Accepted.EventArgs changes
Accepting/ActivatinguseCommandEventArgs(hasHandledandContext)AcceptedusesCommandEventArgs(hasContext, noHandled)ActivatedusesEventArgs<ICommandContext?>(hasValue, noHandled)ICommandContextprovidesCommand,Source,Binding, andRoutingfor advanced scenariosRemaining Work
plans/menubar-reengineer.md→ Remaining Work.AddCommandcall sites needbool?→CommandOutcomemigration. Purely mechanical; conversion shims exist.View.Command.cs(1,043 lines, 6 responsibilities) is an SRP candidate. Deferred — route tracing provides sufficient debugging visibility for now.