Skip to content

Fixes #4885. View.GetScheme() falls back gracefully instead of throwing when SchemeName is not found#4886

Merged
tig merged 7 commits intogui-cs:developfrom
YourRobotOverlord:feat/theme-fallback-chain
Apr 8, 2026
Merged

Fixes #4885. View.GetScheme() falls back gracefully instead of throwing when SchemeName is not found#4886
tig merged 7 commits intogui-cs:developfrom
YourRobotOverlord:feat/theme-fallback-chain

Conversation

@YourRobotOverlord
Copy link
Copy Markdown
Collaborator

Fixes #4885.

Summary

When View.SchemeName is set to a name that doesn't exist in the active theme, View.GetScheme() previously threw a KeyNotFoundException. This PR implements a graceful fallback chain so the view degrades silently instead of crashing.

Fallback Chain

If the named scheme is not found, resolution continues through:

  1. Named scheme — if found in the active theme, use it
  2. SuperView.GetScheme() — inherit from the parent view (recursive)
  3. "Base" scheme from the active theme
  4. Hard-coded "Base" — always available regardless of config state

A Logging.Warning is emitted when a fallback occurs so developers can diagnose misconfigured SchemeName values.

Changes

SchemeManager — new TryGetScheme method

csharp public static bool TryGetScheme(string schemeName, [NotNullWhen(true)] out Scheme? scheme)

Fully exception-safe: handles an uninitialised ConfigurationManager and a theme with no Schemes property, returning false in both cases. GetScheme(string) is left unchanged (backward compat — it still throws).

View.GetScheme() — use fallback chain

Replaced the direct SchemeManager.GetScheme(SchemeName) call (which throws) with TryGetScheme + ResolveFallbackScheme().

UICatalog scenario — Theme Fallback

New demo scenario (Examples/UICatalog/Scenarios/ThemeFallback.cs) showing:

  • A view with SchemeName = "CustomHighlight" (exists on Default, blinking yellow/blue)
  • A view with SchemeName = "NonExistentScheme" (never exists, always falls back)
  • A theme selector so you can watch the fallback chain activate live when switching themes

Tests

7 new tests across two files — all in UnitTestsParallelizable:

File Tests added
SchemeManagerTests.cs TryGetScheme happy path, missing scheme, CM-not-initialised
SchemeTests.cs Fallback to SuperView, fallback to Base, no regression, deep chain

All 15,163 existing tests pass; no new warnings.

YourRobotOverlord and others added 2 commits April 3, 2026 21:51
…etScheme()

Add SchemeManager.TryGetScheme() — a non-throwing scheme lookup that safely
handles uninitialized ConfigurationManager and missing Schemes in the current
theme (both cases that GetSchemesForCurrentTheme() throws for).

Refactor View.GetScheme() DefaultAction to use the full fallback chain in all
cases, removing the asymmetry where a SchemeName pointing to a missing scheme
threw KeyNotFoundException while no SchemeName gracefully fell back:

  HasScheme (_scheme)
    -> Named scheme via TryGetScheme(SchemeName)
      -> SuperView.GetScheme()
        -> 'Base' scheme
          -> Hard-coded 'Base' (guaranteed last resort)

Add Logging.Warning() when SchemeName is set but not found, to aid debugging.

Add tests covering: TryGetScheme happy/sad paths, fallback to SuperView,
fallback to Base, and full chain traversal with missing scheme at every level.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k chain

- Registers a custom 'CustomHighlight' scheme with TextStyle.Blink on the
  Default theme, making it visually distinct from built-in schemes
- Shows a view with SchemeName = 'CustomHighlight' (found on Default, blinks)
- Shows a view with SchemeName = 'NonExistentScheme' (never found, falls back)
- Includes a theme selector: switching to a non-Default theme causes
  'CustomHighlight' to also fall back, demonstrating both fallback cases live
- The warning written to the debug log for missing scheme names is mentioned
  in the UI

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@YourRobotOverlord YourRobotOverlord requested a review from tig as a code owner April 5, 2026 04:31
@YourRobotOverlord
Copy link
Copy Markdown
Collaborator Author

WindowsTerminal_VwyqmNRxk2

Copy link
Copy Markdown
Collaborator

@tig tig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent!

I effed up on an earlier merge to develop and introduced a bug to UICatalog. I pulled your branch down to review and noticed that. So I fixed it in your branch and pushed that and some code cleanup changes too.

…d didn't test...

Refactor style, naming, and shortcut logic for consistency

Refactored constant naming and string interpolation in ThemeFallback for clarity and consistency. Improved XML documentation formatting. Updated UICatalogRunnable shortcut key assignment to avoid conflicts and accept ignored keys. Fixed GetScheme logic in View to handle empty SchemeName correctly. Replaced var with explicit types and used collection expressions in tests. Improved lambda formatting and simplified event handler assignments. Applied project code style conventions throughout.
@tig tig requested a review from Copilot April 8, 2026 14:28
@tig tig merged commit 6006bcf into gui-cs:develop Apr 8, 2026
13 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a non-throwing scheme resolution path so View.GetScheme() gracefully falls back when SchemeName is missing from the active theme (Fixes #4885), while preserving existing throwing APIs for backwards compatibility.

Changes:

  • Added SchemeManager.TryGetScheme(string, out Scheme?) to safely resolve schemes without exceptions.
  • Updated View.GetScheme() to use TryGetScheme plus a fallback chain (SuperView → theme “Base” → hard-coded “Base”) and emit a warning when falling back.
  • Added/updated tests and introduced a new UICatalog scenario to demonstrate the fallback behavior live.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
Tests/UnitTestsParallelizable/ViewBase/Draw/SchemeTests.cs Adds fallback-chain tests and refactors some locals/types.
Tests/UnitTestsParallelizable/Configuration/SourcesManagerTests.cs Minor test refactors/cleanup unrelated to schemes.
Tests/UnitTestsParallelizable/Configuration/SchemeManagerTests.cs Adds tests for TryGetScheme behavior.
Terminal.Gui/ViewBase/View.Drawing.Scheme.cs Implements GetScheme() fallback chain + warning logging.
Terminal.Gui/Configuration/SchemeManager.cs Adds TryGetScheme API and updates exception docs for GetScheme(string).
Examples/UICatalog/UICatalogRunnable.cs Adjusts unbound F-key selection logic for StatusBar/menu usage.
Examples/UICatalog/Scenarios/ThemeFallback.cs New scenario demonstrating missing-scheme fallback behavior across theme changes.

Comment thread Terminal.Gui/ViewBase/View.Drawing.Scheme.cs
Comment thread Terminal.Gui/Configuration/SchemeManager.cs
Comment thread Examples/UICatalog/UICatalogRunnable.cs
Comment thread Examples/UICatalog/UICatalogRunnable.cs
Comment thread Examples/UICatalog/UICatalogRunnable.cs
Comment thread Tests/UnitTestsParallelizable/ViewBase/Draw/SchemeTests.cs
Comment thread Tests/UnitTestsParallelizable/ViewBase/Draw/SchemeTests.cs
Comment thread Tests/UnitTestsParallelizable/Configuration/SourcesManagerTests.cs
@YourRobotOverlord YourRobotOverlord deleted the feat/theme-fallback-chain branch April 10, 2026 03:06
YourRobotOverlord added a commit to YourRobotOverlord/Terminal.Gui that referenced this pull request Apr 10, 2026
…g.md

Document PR gui-cs#4886 functionality in config.md:

- Add 'Custom Schemes for Individual Views' section showing View.SchemeName,
  SchemeManager.AddScheme(), and JSON config definition of custom schemes
- Add 'Scheme Resolution Order' section with Mermaid flowchart of the
  View.GetScheme() fallback chain (HasScheme -> SchemeName -> SuperView ->
  Base theme -> hard-coded Base) and priority table
- Note SchemeManager.TryGetScheme() as the safe consumer API

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: View.GetScheme() should fall back gracefully instead of throwing when SchemeName is not found

3 participants