Skip to content

Release v2.4.14-beta.1#5557

Merged
tig merged 29 commits into
mainfrom
release/v2.4.14-beta.1
Jun 28, 2026
Merged

Release v2.4.14-beta.1#5557
tig merged 29 commits into
mainfrom
release/v2.4.14-beta.1

Conversation

@tig

@tig tig commented Jun 28, 2026

Copy link
Copy Markdown
Member

Release v2.4.14-beta.1

This is a beta pre-release.

Version: 2.4.14-beta.1
NuGet Package: Terminal.Gui 2.4.14-beta.1

What happens when this PR is merged

  1. ✅ The Finalize Release workflow will automatically create tag v2.4.14-beta.1
  2. ✅ The Publish workflow will build and push to NuGet.org
  3. ✅ A GitHub Release will be created with auto-generated notes
  4. ✅ A back-merge PR from maindevelop will be opened

Checklist

  • CI passes on this PR
  • Version looks correct: 2.4.14-beta.1
  • Release notes reviewed (will be auto-generated on merge)

Copilot AI and others added 29 commits May 25, 2026 01:21
- Replace fabricated Driver.ForceMaxColors with actual Driver.SizeDetection
- Replace FakeDriver/Fake with valid driver name 'ansi'
- Replace fabricated theme names with actual: Default, Dark, Light,
  TurboPascal 5, Anders, Green Phosphor, Amber Phosphor
- Fix Button.DefaultHighlightStyle -> Button.DefaultMouseHighlightStates
- Fix CheckBox.DefaultCheckState -> CheckBox.DefaultMouseHighlightStates
- Fix Dialog defaults: Heavy border (not Single), Transparent shadow (not
  Opaque), replace MinimumWidth/Height with ButtonAlignment/AlignmentModes
- Fix MessageBox: has DefaultButtonAlignment not DefaultShadow, Heavy border
- Fix Window.DefaultShadow: None (not Opaque, config.json overrides)
- Remove fabricated MenuBar.UseKeysUpDownAsKeysLeftRight, add MenuBar.DefaultKey
- Add missing properties: View.ViewKeyBindings, Color.Colors16, NerdFonts.Enable
- Update attribute count from ~195 to ~188
- Record D-01 decision (Option 2: static facade) with rationale
- Record D-02 decision (Option 3: support both formats, flat deprecated)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the Microsoft.Extensions.Configuration infrastructure alongside the
existing ConfigurationManager (no removals, no breaking changes).

New NuGet dependencies:
- Microsoft.Extensions.Configuration
- Microsoft.Extensions.Configuration.Binder
- Microsoft.Extensions.Configuration.Json
- Microsoft.Extensions.Options

New Settings POCOs (Terminal.Gui/Configuration/Settings/):
- ApplicationSettings (AppModel, ForceDriver, IsMouseDisabled)
- DriverSettings (Force16Colors, SizeDetection)
- ButtonSettings (DefaultShadow, DefaultMouseHighlightStates)
- CheckBoxSettings (DefaultMouseHighlightStates)
- DialogSettings (DefaultShadow, DefaultBorderStyle, DefaultButtonAlignment, DefaultButtonAlignmentModes)
- MessageBoxSettings (DefaultBorderStyle, DefaultButtonAlignment)
- WindowSettings (DefaultShadow, DefaultBorderStyle)
- ViewBorderSettings (shared POCO for FrameView, HexView, Menu, etc.)

Each POCO has a static Defaults facade (D-01 decision: Option 2) so that
Views can be constructed before Application.Create() without DI.

New infrastructure:
- TuiConfigurationExtensions: AddTuiLibraryDefaults(), AddTuiAppDefaults(),
  AddTuiUserFiles(), AddTuiEnvironmentVariable(), AddTuiRuntimeConfig()
- TuiConfigurationBuilder: Convenience class that builds the full MEC
  provider chain and applies config to static facades.

Tests: 14 new tests in Tests/UnitTestsParallelizable covering POCOs,
builder, extension methods, precedence, and static facade updates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create individual Settings POCO files for each view/component that
needs configurable defaults via the MEC binding pattern:
- MenuBarSettings, MenuSettings, PopoverMenuSettings
- StatusBarSettings, FrameViewSettings, HexViewSettings
- TextFieldSettings, TextViewSettings, SelectorBaseSettings
- FileDialogStyleSettings, FileDialogSettings
- LinearRangeSettings, CharMapSettings
- NerdFontsSettings, KeySettings, TraceSettings, GlyphSettings

Delete ViewBorderSettings.cs which combined multiple views in one class.

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

All View/Driver/App static properties now delegate to their corresponding
Settings POCO Defaults. The [ConfigurationProperty] attributes are preserved
for CM backward compatibility during the transition.

- 144 Glyph properties delegate to GlyphSettings.Defaults
- 23 View/App properties delegate to their respective POCOs
- TuiConfigurationBuilder.ApplyToStaticFacades() binds all 24 sections
- Complex types (ThemeManager, SchemeManager, key bindings, Color.Colors16)
  deferred to Phase 3/4

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

- IThemeManager interface with SwitchTheme(), CurrentThemeName, ThemeNames
- ISchemeManager interface with GetScheme(), AddScheme(), SchemeNames
- MecThemeManager delegates to existing ThemeManager during transition
- MecSchemeManager delegates to existing SchemeManager during transition
- ThemeSettings POCO tracks active theme name
- TuiConfigurationBuilder exposes ThemeManager/SchemeManager properties
- 9 new tests covering interface implementations

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…wire MEC startup

- Removed [ConfigurationProperty] from ~174 properties now backed by MEC POCOs
- Kept [ConfigurationProperty] on 8 complex properties still managed by CM
  (ThemeManager.Themes/Theme, SchemeManager.Schemes, key bindings, Color.Colors16,
  ConfigurationManager.AppSettings/ThrowOnJsonErrors)
- Wired MEC into application startup via ModuleInitializers.cs
- Cleaned ConfigPropertyHostTypes to only list types still using CM
- Updated ScopeJsonConverter to skip unknown properties gracefully
- All 17,110 tests pass (0 failures)

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

- Mark AppSettingsScope as [Obsolete] with migration guidance
- Add BindAppSettings<T>() method to TuiConfigurationBuilder for app POCOs
- Comprehensive XML doc examples on TuiConfigurationBuilder
- 4 new tests demonstrating the app-developer workflow

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ConfigurationManager marked [Obsolete] with migration guidance
- ConfigProperty, ConfigPropertyHostTypes, SettingsScope, ThemeScope marked [Obsolete]
- ConfigurationPropertyAttribute marked [Obsolete]
- Targeted #pragma warning disable CS0618 in 27 internal files that still
  reference obsolete types during transition
- Public MEC APIs remain clean (no obsolete markers)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Re-adds [ConfigurationProperty (Scope = typeof (ThemeScope))] and
[ConfigurationProperty (Scope = typeof (SettingsScope))] attributes to
static properties that delegate to POCO settings. These attributes are
needed for backward compatibility with existing ConfigurationManager
tests and theme/settings serialization discovery.

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

- Restore full ConfigPropertyHostTypes (29 types) for CM reflection scan
- Restore [ConfigurationProperty] on all 144 Glyphs.cs properties
- Revert ScopeJsonConverter to throw on unknown properties (fixes test cascade)
- Add [UnconditionalSuppressMessage] for IL2026/IL3050 on MEC binder methods
- Add IL3050 to NoWarn in csproj alongside IL2026
- Restore removed InlineData test cases in ScopeJsonConverterTests

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

In NativeAOT, Activator.CreateInstance fails for dictionary types whose
constructors are trimmed. The JSON serialization path (which uses source-generated
code) is AOT-safe but was guarded by 'comparer is null', preventing it from being
used when dictionaries have default comparers. Remove the guard so the JSON path
is always attempted first, plus add explicit typed paths for Dictionary<Command,
PlatformKeyBinding> and Dictionary<string, Dictionary<Command, PlatformKeyBinding>>.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Mark spec status as implementation-in-progress with #5411 focus
- Add Phase 3A detailing remaining complex-type migration scope
- Define #5411 done criteria for themes, schemes, key bindings, Colors16
- Clarify #5416 as follow-up for CM cleanup/removal phases

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…facade, TuiSerializerContext extraction

Pulled forward from #5416 to make the MEC story in #5411 coherent without expanding scope to JSON-shape changes or CM deletion.

A1: IThemeManager gains a ThemeChanged event. MecThemeManager subscribes to legacy ThemeManager.ThemeChanged in its ctor and forwards. Runtime theme/scheme data still lives in legacy CM; A2 (Mec owning theme data) remains in #5416 because it requires the config.json shape decision.

B: New static facade Terminal.Gui.Configuration.ThemeChanges bridges both ConfigurationManager.Applied and ThemeManager.ThemeChanged into a single ThemeChanged event. Menu, MenuBar, StatusBar, and LineCanvas now subscribe to ThemeChanges.ThemeChanged instead of ConfigurationManager.Applied. ConfigurationManager.Applied stays public+obsolete for external consumers.

C: Extracted the configured SourceGenerationContext instance to a non-obsolete internal class TuiSerializerContext (Instance). The obsolete ConfigurationManager.SerializerContext delegates to it for back-compat. Updated all 7 internal JSON-converter consumers to use TuiSerializerContext.Instance, removing CS0618 pragmas from AttributeJsonConverter, SchemeJsonConverter, DictionaryJsonConverter, and ConcurrentDictionaryJsonConverter. DeepCloner, ScopeJsonConverter, and SourcesManager retain their pragmas for other obsolete CM uses.

Spec updated with a new Phase 3A.x section documenting what landed in #5411 and why A2/D/E/PrintJsonErrors are deferred to #5416.

All 17283 UnitTestsParallelizable tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… refs to TuiSerializerContext.Instance

Mechanical rename of remaining CS0618-bound references on the obsolete
ConfigurationManager.SerializerContext field (= TuiSerializerContext.Instance,
same readonly field) to the non-obsolete home directly.

- DeepCloner.cs: remove now-stale '#pragma warning disable CS0618' (no
  SerializerContext references remain; all migrated in Phase C-extract).
- 4 test files (Key/Rune/Scheme/ScopeJsonConverterTests): mechanical
  ConfigurationManager.SerializerContext.{Options,SettingsScope} ->
  TuiSerializerContext.Instance.{Options,SettingsScope}.

Behavior-neutral: ConfigurationManager.SerializerContext is literally
'= TuiSerializerContext.Instance' (ConfigurationManager.cs:720). Both
references resolve to the same readonly static field.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previous commit re-encoded 4 test files via PowerShell Set-Content -NoNewline
which stripped UTF-8 BOM and mangled Unicode literals in [InlineData] strings.
This broke RuneJsonConverterTests.RoundTripConversion_Positive on CI runners
where the input emoji codepoints were corrupted into invalid sequences.

Re-applied the SerializerContext rename preserving the original UTF-8 BOM
encoding via [System.Text.UTF8Encoding]::new(true) and File.WriteAllText.

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

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

# Conflicts:
#	Terminal.Gui/App/Application.cs
#	Terminal.Gui/Configuration/ConcurrentDictionaryJsonConverter.cs
#	Terminal.Gui/Drawing/Glyphs.cs
Adds specs/breaking-changes-cm-mec.md analyzing the real consumer-facing
impact of the CM->MEC migration:
- #5411 removes/renames no public API; only marks 6 public CM types
  [Obsolete] (CS0618) and adds 4 Microsoft.Extensions.* dependencies.
- In-repo builds hide CS0618 via .editorconfig; external NuGet consumers
  will see the deprecation warnings.
- All hard, compile-breaking removals are deferred to #5416.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Back-merge v2.4.13 from main into develop
Reassigning a copied explicit role to the same value must not make it implicit.

Fixes #5555
Two issues surfaced by code review on #5411:

1. MEC binding was inert against the shipped config.json format. The real
   config uses flat dotted keys (e.g. "Driver.Force16Colors", "Key.Separator")
   and a scalar "Theme" key, but ApplyToStaticFacades bound nested sections via
   GetSection(name).Bind(), which reads nothing because the MEC JSON provider
   stores dotted keys literally (only ':' is a section separator).

   - BindSection now falls back to BindFlatDottedKeys when the nested section
     does not exist, mapping flat "Section.Property" keys onto the POCO.
   - BindThemeScalar binds the scalar "Theme" key to ThemeSettings.Theme.
   - Nested-section format still binds, so existing config keeps working.
   - SwitchTheme records the switched theme after ApplyToStaticFacades so the
     config re-apply (which can now read "Theme") cannot reset the selection.

2. MecThemeManager leaked a static-event subscription. The ctor did
   ThemeManager.ThemeChanged += OnLegacyThemeChanged with no unsubscribe, so
   every instance was pinned alive by the static event and fired once per live
   instance. Forwarding is now wired up lazily via custom event accessors only
   while the instance has subscribers, and torn down when the last detaches.

Test-first: adds MecDottedKeyTests (flat/scalar/nested binding) and
MecThemeManagerLeakTests (no leak, subscribe/unsubscribe, forwarding). Gates
the pre-existing MEC tests that mutate static Defaults into the shared
"StaticSettingsTests" collection to keep them race-free.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #5411 marks ConfigurationManager [Obsolete], and the Validate Doc
Snippets CI job elevates CS0618 to an error. Update the "set theme at
startup" snippet to the MEC replacement (TuiConfigurationBuilder +
RuntimeConfig + ApplyToStaticFacades), which the flat/scalar binding fix
now makes functional for the "Theme" scalar key.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prepares for Fixing #4943 - Refactors `ConfigurationManager` to be based on `MEC`

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12aca25f1e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

public static TraceCategory EnabledCategories
{
get => _asyncLocalEnabledCategories.Value;
get => TraceSettings.Defaults.EnabledCategories;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve async-local trace categories

Trace.EnabledCategories is documented as per async flow and TraceScope saves/restores it for scoped tracing, but this getter now reads the process-wide TraceSettings.Defaults instead of _asyncLocalEnabledCategories. In parallel tests or any two async contexts, one context setting Trace.EnabledCategories changes what every other context reads, and PushScope restores the wrong previous value, so tracing leaks across scopes.

Useful? React with 👍 / 👎.

// During transition, delegate to existing ThemeManager
try
{
return ThemeManager.GetThemeNames ();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use MEC configuration when listing themes

In normal MEC usage (new TuiConfigurationBuilder() without the obsolete ConfigurationManager.Enable(...)), the builder loads the embedded config.json containing themes like Dark and Green Phosphor, but this delegates ThemeNames to the legacy ThemeManager, whose state only contains the hard-coded Default until legacy configuration is enabled. As a result, builder.ThemeManager.SwitchTheme("Dark") returns false even though the theme exists in the configuration the builder just loaded.

Useful? React with 👍 / 👎.


// Re-apply all ThemeScope POCOs from configuration. This may rebind the scalar "Theme" key
// from config, so the switched theme is recorded afterwards to ensure the selection persists.
_builder.ApplyToStaticFacades ();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply selected theme overrides during switch

When legacy configuration has been loaded so a non-default theme is available, SwitchTheme can return true, but this re-apply only binds root-level settings; the shipped theme overrides are nested under Themes[...], and ThemeManager.Theme = themeName only changes the name and raises an event. For example, switching to Green Phosphor leaves Button.DefaultShadow at the hard-coded Opaque instead of applying the theme's None, so the new API reports a theme switch without updating the ThemeScope defaults.

Useful? React with 👍 / 👎.

@tig tig merged commit 7f04ed8 into main Jun 28, 2026
17 checks passed
@tig tig deleted the release/v2.4.14-beta.1 branch June 28, 2026 16:23
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.

3 participants