Files
Terminal.Gui/docs/analysis/cwp_analysis_report.md
2025-10-02 15:44:11 +00:00

14 KiB

Cancellable Work Pattern (CWP) Analysis Report

Executive Summary

This report analyzes all instances of the Cancellable Work Pattern (CWP) in the Terminal.Gui codebase to assess the potential impact of reversing the calling order from:

  • Current: Virtual method first → Event second
  • Proposed: Event first → Virtual method second

Background

The CWP pattern currently calls the virtual method (OnXxx) before invoking the event (Xxx). This gives inherited code (via override) priority over external code (via event subscription). Issue #3714 raises concerns about this order, particularly for mouse events where external code cannot prevent events from reaching overridden methods in views.

Analysis Methodology

  1. Identified all protected virtual bool OnXxx methods in Terminal.Gui
  2. Located their corresponding event invocations
  3. Analyzed the calling context and dependencies
  4. Assessed impact of order reversal

Detailed Analysis

1. Mouse Events

1.1 OnMouseEvent / MouseEvent

File: Terminal.Gui/ViewBase/View.Mouse.cs:348 Calling Context:

public bool RaiseMouseEvent (MouseEventArgs mouseEvent)
{
    if (OnMouseEvent (mouseEvent) || mouseEvent.Handled)
    {
        return true;
    }
    MouseEvent?.Invoke (this, mouseEvent);
    return mouseEvent.Handled;
}

Current Order: OnMouseEventMouseEvent

Impact Analysis:

  • HIGH IMPACT: This is the primary mouse event handler
  • Problem: Views like Slider that override OnMouseEvent cannot be prevented from handling mouse events by external code
  • Dependencies: Many views override OnMouseEvent expecting priority
  • Reversing Order Would:
    • Allow external code to cancel before view's override processes
    • Break existing assumptions in views that expect first access
    • Require review of all OnMouseEvent overrides

1.2 OnMouseClick / MouseClick

File: Terminal.Gui/ViewBase/View.Mouse.cs:515 Calling Context:

protected bool RaiseMouseClickEvent (MouseEventArgs args)
{
    if (OnMouseClick (args) || args.Handled)
    {
        return args.Handled;
    }
    MouseClick?.Invoke (this, args);
    // ...
}

Current Order: OnMouseClickMouseClick

Impact Analysis:

  • HIGH IMPACT: Same issue as OnMouseEvent
  • Problem: External code cannot prevent clicks from reaching view's override
  • Reversing Order Would:
    • Enable external mouse click prevention
    • Consistent with OnMouseEvent changes
    • Requires coordination with all click handlers

1.3 OnMouseEnter / MouseEnter

File: Terminal.Gui/ViewBase/View.Mouse.cs:125 Calling Context:

internal bool? NewMouseEnterEvent (CancelEventArgs eventArgs)
{
    if (OnMouseEnter (eventArgs))
    {
        return true;
    }
    MouseEnter?.Invoke (this, eventArgs);
    // ...
}

Current Order: OnMouseEnterMouseEnter

Impact Analysis:

  • MEDIUM IMPACT: Less commonly overridden
  • Reversing Order Would:
    • Allow external code to prevent enter notifications
    • Minimal breaking changes expected

1.4 OnMouseWheel / MouseWheel

File: Terminal.Gui/ViewBase/View.Mouse.cs:610 Calling Context:

protected bool RaiseMouseWheelEvent (MouseEventArgs args)
{
    if (OnMouseWheel (args) || args.Handled)
    {
        return args.Handled;
    }
    MouseWheel?.Invoke (this, args);
    // ...
}

Current Order: OnMouseWheelMouseWheel

Impact Analysis:

  • MEDIUM IMPACT: Wheel handling is specific
  • Reversing Order Would:
    • Enable external scroll prevention
    • Useful for modal dialogs or locked views

2. Keyboard Events

2.1 OnKeyDown / KeyDown

File: Terminal.Gui/ViewBase/View.Keyboard.cs:367 Calling Context:

public bool NewKeyDownEvent (Key k)
{
    if (OnKeyDown (k) || k.Handled)
    {
        return true;
    }
    KeyDown?.Invoke (this, k);
    return k.Handled;
}

Current Order: OnKeyDownKeyDown

Impact Analysis:

  • HIGH IMPACT: Core keyboard input handling
  • Dependencies: Many views override for input processing
  • Reversing Order Would:
    • Allow external key interception before view processing
    • Could break views expecting first access to keys
    • Major behavioral change for input handling

2.2 OnKeyDownNotHandled / KeyDownNotHandled

File: Terminal.Gui/ViewBase/View.Keyboard.cs:399 Current Order: OnKeyDownNotHandledKeyDownNotHandled

Impact Analysis:

  • LOW IMPACT: Secondary handler for unhandled keys
  • Reversing Order Would:
    • Minor change, already handles unhandled keys
    • Low risk

2.3 OnKeyUp / KeyUp

File: Terminal.Gui/ViewBase/View.Keyboard.cs (implementation in NewKeyUpEvent) Current Order: OnKeyUpKeyUp

Impact Analysis:

  • LOW-MEDIUM IMPACT: Less commonly used than KeyDown
  • Reversing Order Would:
    • Enable external key-up prevention
    • Lower risk than KeyDown

3. Command Events

3.1 OnAccepting / Accepting

File: Terminal.Gui/ViewBase/View.Command.cs:190 Impact Analysis:

  • MEDIUM-HIGH IMPACT: Core command pattern
  • Used by: CheckBox, RadioGroup, Button, etc.
  • Reversing Order Would:
    • Allow external cancellation before view logic
    • May break views expecting to set state first

3.2 OnSelecting / Selecting

File: Terminal.Gui/ViewBase/View.Command.cs:245 Impact Analysis:

  • MEDIUM IMPACT: Selection behavior
  • Reversing Order Would:
    • Enable external selection control
    • Useful for validation scenarios

3.3 OnHandlingHotKey / HandlingHotKey

File: Terminal.Gui/ViewBase/View.Command.cs:291 Impact Analysis:

  • LOW-MEDIUM IMPACT: HotKey processing
  • Reversing Order Would:
    • Allow hotkey override by external code
    • Could be useful for dynamic hotkey management

3.4 OnCommandNotBound / CommandNotBound

File: Terminal.Gui/ViewBase/View.Command.cs:93 Impact Analysis:

  • LOW IMPACT: Fallback for unmapped commands
  • Reversing Order Would:
    • Minor impact, handles unbound commands

4. Drawing Events

4.1 Drawing Pipeline Events

Files: Terminal.Gui/ViewBase/View.Drawing.cs

  • OnDrawingAdornments / DrawingAdornments
  • OnClearingViewport / ClearingViewport
  • OnDrawingText / DrawingText
  • OnDrawingContent / DrawingContent
  • OnDrawingSubViews / DrawingSubViews
  • OnRenderingLineCanvas / RenderingLineCanvas

Impact Analysis:

  • LOW-MEDIUM IMPACT: Rendering customization
  • Reversing Order Would:
    • Allow external drawing interception
    • Useful for debugging/tracing
    • Lower risk as drawing is less state-dependent

5. Navigation Events

5.1 OnAdvancingFocus / AdvancingFocus

File: Terminal.Gui/ViewBase/View.Navigation.cs:208 Impact Analysis:

  • MEDIUM-HIGH IMPACT: Focus management
  • Reversing Order Would:
    • Allow external focus control
    • Could break focus flow expectations

5.2 OnHasFocusChanging / HasFocusChanging

File: Terminal.Gui/ViewBase/View.Navigation.cs:717 Impact Analysis:

  • MEDIUM-HIGH IMPACT: Focus state management
  • Reversing Order Would:
    • Enable external focus validation
    • Useful for preventing focus changes

6. Property Change Events

6.1 OnSchemeNameChanging / SchemeNameChanging

File: Terminal.Gui/ViewBase/View.Drawing.Scheme.cs:51 Impact Analysis:

  • LOW-MEDIUM IMPACT: Scheme change validation
  • Uses: CWPPropertyHelper
  • Reversing Order Would:
    • Allow external scheme validation
    • Low risk

6.2 OnGettingScheme / GettingScheme

File: Terminal.Gui/ViewBase/View.Drawing.Scheme.cs:170 Impact Analysis:

  • LOW-MEDIUM IMPACT: Scheme resolution
  • Reversing Order Would:
    • Allow external scheme override
    • Useful for theming

6.3 OnSettingScheme / SettingScheme

File: Terminal.Gui/ViewBase/View.Drawing.Scheme.cs:241 Impact Analysis:

  • LOW-MEDIUM IMPACT: Scheme application
  • Reversing Order Would:
    • Enable external scheme interception
    • Low risk

6.4 OnVisibleChanging / VisibleChanging

File: Terminal.Gui/ViewBase/View.cs:382 Impact Analysis:

  • MEDIUM IMPACT: Visibility state management
  • Reversing Order Would:
    • Allow external visibility control
    • Could affect layout calculations

6.5 OnOrientationChanging (commented out)

File: Terminal.Gui/ViewBase/Orientation/OrientationHelper.cs:166 Impact Analysis:

  • N/A: Currently commented out
  • Note: OrientationHelper uses callback pattern

7. View-Specific Events

7.1 OnCellActivated (TableView)

File: Terminal.Gui/Views/TableView/TableView.cs:1277 Impact Analysis:

  • LOW IMPACT: TableView-specific
  • Reversing Order Would:
    • Allow external cell activation control
    • Isolated to TableView

7.2 OnPositionChanging (ScrollBar, ScrollSlider)

Files:

  • Terminal.Gui/Views/ScrollBar/ScrollBar.cs:375
  • Terminal.Gui/Views/ScrollBar/ScrollSlider.cs:245 Impact Analysis:
  • LOW-MEDIUM IMPACT: Scrollbar-specific
  • Reversing Order Would:
    • Enable external scroll validation
    • Useful for scroll constraints

7.3 OnCheckedStateChanging (CheckBox)

File: Terminal.Gui/Views/CheckBox.cs:187 Impact Analysis:

  • LOW-MEDIUM IMPACT: CheckBox state management
  • Reversing Order Would:
    • Allow external state validation
    • Useful for validation logic

8. Other Events

8.1 OnBorderStyleChanged

File: Terminal.Gui/ViewBase/View.Adornments.cs:162 Impact Analysis:

  • LOW IMPACT: Border styling
  • Reversing Order Would:
    • Enable external border control
    • Minimal risk

8.2 OnMouseIsHeldDownTick (MouseHeldDown)

File: Terminal.Gui/ViewBase/MouseHeldDown.cs:71 Impact Analysis:

  • LOW IMPACT: Continuous mouse press
  • Reversing Order Would:
    • Allow external hold-down control
    • Minimal risk

8.3 OnGettingAttributeForRole

File: Terminal.Gui/ViewBase/View.Drawing.Attribute.cs:78 Impact Analysis:

  • LOW IMPACT: Attribute resolution
  • Reversing Order Would:
    • Enable external attribute override
    • Useful for accessibility

Summary Statistics

Total CWP Implementations Found: 33

By Impact Level:

  • HIGH IMPACT: 3 (Mouse/Keyboard core events)
  • MEDIUM-HIGH IMPACT: 4 (Commands, Navigation)
  • MEDIUM IMPACT: 8 (Various UI events)
  • LOW-MEDIUM IMPACT: 10 (Property changes, view-specific)
  • LOW IMPACT: 8 (Specialized/rare events)

Code Dependencies on Current Order

Tests That Validate Order

Located in Tests/UnitTestsParallelizable/View/Orientation/OrientationTests.cs:

[Fact]
public void OrientationChanging_VirtualMethodCalledBeforeEvent()
{
    // Test explicitly validates virtual method is called before event
}

[Fact]
public void OrientationChanged_VirtualMethodCalledBeforeEvent()
{
    // Test explicitly validates virtual method is called before event
}

Impact: These tests will FAIL if order is reversed - they explicitly test current behavior.

Views With Override Dependencies

Based on code search, many views override these methods and may depend on being called first:

  • Slider.OnMouseEvent - Core issue from #3714
  • Various views override OnKeyDown for input handling
  • Command handlers in Button, CheckBox, RadioGroup
  • Custom drawing in various views

Recommendations

Option 1: Reverse Order Globally

Pros:

  • Solves #3714 completely
  • Consistent pattern across all events
  • External code gets priority (looser coupling)

Cons:

  • MAJOR BREAKING CHANGE
  • Requires updating all views that override CWP methods
  • Extensive testing required
  • May break user code

Effort: HIGH (4-6 weeks) Risk: HIGH

Option 2: Add "Before" Events

Pros:

  • Non-breaking
  • Explicit control for when needed
  • Gradual migration path

Cons:

  • More API surface
  • Complexity in naming/documentation
  • Two patterns coexist

Effort: MEDIUM (2-3 weeks) Risk: LOW

Option 3: Add IgnoreMouse Property

Pros:

  • Minimal change
  • Solves immediate #3714 issue
  • No breaking changes

Cons:

  • Band-aid solution
  • Doesn't address root cause
  • Only solves mouse issue

Effort: LOW (1 week) Risk: VERY LOW

Option 4: Reverse Order for Mouse Events Only

Pros:

  • Solves #3714
  • Limited scope reduces risk
  • Mouse is primary concern

Cons:

  • Inconsistent pattern
  • Still breaking for mouse overrides
  • Confusion with different orders

Effort: MEDIUM (2 weeks) Risk: MEDIUM

Conclusion

The analysis reveals that reversing CWP order globally would be a significant breaking change affecting 33+ event pairs across the codebase. The highest impact would be on:

  1. Mouse events (OnMouseEvent, OnMouseClick) - direct issue #3714
  2. Keyboard events (OnKeyDown) - core input handling
  3. Command events (OnAccepting, OnSelecting) - state management
  4. Navigation events (OnAdvancingFocus, OnHasFocusChanging) - focus flow

Recommended Approach:

  • Short-term: Option 3 (IgnoreMouse property) or Option 2 (Before events for mouse only)
  • Long-term: Consider Option 2 with gradual migration, or accept current design as intentional

The current design prioritizes inheritance over composition, which may be appropriate for a UI framework where tight coupling through inheritance is common. However, it limits external control, which is the root cause of #3714.

Next Steps

  1. Review this analysis with maintainers
  2. Decide on approach based on project priorities
  3. If proceeding with order reversal:
    • Create comprehensive test plan
    • Update all affected views
    • Update documentation
    • Provide migration guide
  4. If proceeding with alternative:
    • Implement chosen solution
    • Update documentation with rationale
    • Add examples for working around current limitation