Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
30b798b
Fixes #4274. Using Windows Host Console v2win is rendering window siz…
BDisp Oct 6, 2025
595b30f
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Oct 7, 2025
0954330
Merge branch 'v2_develop' into v2_4274_v2win-window-size-vsdebugconso…
tig Oct 11, 2025
122e828
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Oct 15, 2025
fe848d2
Fixes #4259. Our wcwidth library is out of date (#4281)
tig Oct 15, 2025
731b721
Remove legacy drivers, simplify architecture, and reorganize codebase…
Copilot Oct 15, 2025
897d63b
Merge branch 'v2_develop' into v2_4274_v2win-window-size-vsdebugconso…
BDisp Oct 15, 2025
5990582
Fix nit test.
BDisp Oct 15, 2025
9341aaf
Change ClearScreenNextIteration to internal and trying to fix unit te…
BDisp Oct 15, 2025
85582b9
Reuse method and fix text field color to normal, probably due some ch…
BDisp Oct 16, 2025
218e8f0
Fix scenario Shortcut not restoring Application.Quit
BDisp Oct 16, 2025
f8fdffd
Giving more time to load Scrolling scenario and display failing scenario
BDisp Oct 16, 2025
34271e8
Revert changes and add more assertions
BDisp Oct 16, 2025
6c080d4
Forcing CI tests again and I suspect that is causing by UpdateFromJso…
BDisp Oct 16, 2025
ceaee09
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Oct 16, 2025
7a5d15a
Merge branch 'v2_4274_v2win-window-size-vsdebugconsole-fix' of github…
tig Oct 16, 2025
f250558
Changed test to force fake driver
tig Oct 16, 2025
00af070
Merge pull request #212 from tig/BDisp-v2_4274_v2win-window-size-vsde…
BDisp Oct 16, 2025
ba29c72
Ensure restore the original colors
BDisp Oct 16, 2025
c4f805a
Update test runner behavior in unit-tests.yml
tig Oct 16, 2025
6a69d3f
Merge branch 'v2_develop' into v2_4274-vsdebugconsole-and-unittests
tig Oct 16, 2025
6285ef6
Merge branch 'v2_develop' into v2_4274-vsdebugconsole-and-unittests
tig Oct 16, 2025
090b58a
Merge branch 'v2_4274-vsdebugconsole-and-unittests' of tig:tig/Termin…
tig Oct 16, 2025
69fae08
Found cause of #4288 and provided a workaround
tig Oct 17, 2025
1164ae4
Reverted unneeded change to ComboBoxTests
tig Oct 17, 2025
06f98d7
Fixed test that wasn't actually testing anything
tig Oct 17, 2025
7838b3e
Added more precise unit test showing issue
tig Oct 17, 2025
debfa70
Added more precise unit test showing issue2
tig Oct 17, 2025
f4992f3
Made test even more precise
tig Oct 17, 2025
05527f1
Potential fix for underlying issue
tig Oct 18, 2025
b1cf133
Fixed test that broke with last change
tig Oct 18, 2025
dda564a
Reverted`ConfigurationManager` to return `_hardCodedConfigPropertyCac…
tig Oct 18, 2025
3822e8f
Updated the `Disable` method calls across test classes to use
tig Oct 18, 2025
20b7183
Refactor and fix configuration and theme management
tig Oct 18, 2025
3cbc501
Fix hard-coded defaults corruption in ThemeScope
tig Oct 19, 2025
6be258d
Clarify comments and add theme reset functionality
tig Oct 19, 2025
3329897
Removed special handling for the "Schemes" key in `hardCodedThemeProp…
tig Oct 19, 2025
10bb56d
Code cleanup
tig Oct 19, 2025
52d1244
Refactor and remove redundant validation methods
tig Oct 19, 2025
412498e
Refactor ConfigurationManager for clarity and safety
tig Oct 19, 2025
18f1719
Code cleanup
tig Oct 19, 2025
ea9aee9
Code Cleanup - Refactor ThemeManager and improve nullability handling
tig Oct 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Examples/UICatalog/Scenarios/CombiningMarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public override void Main ()
top.DrawComplete += (s, e) =>
{
// Forces reset _lineColsOffset because we're dealing with direct draw
Application.ClearScreenNextIteration = true;
Application.Top!.SetNeedsDraw ();

var i = -1;
top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616.");
Expand Down
2 changes: 2 additions & 0 deletions Examples/UICatalog/Scenarios/Shortcuts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ public class Shortcuts : Scenario
public override void Main ()
{
Application.Init ();
var quitKey = Application.QuitKey;
Window app = new ();

app.Loaded += App_Loaded;

Application.Run (app);
app.Dispose ();
Application.Shutdown ();
Application.QuitKey = quitKey;
}

// Setting everything up in Loaded handler because we change the
Expand Down
2 changes: 1 addition & 1 deletion Examples/UICatalog/Scenarios/Themes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public override void Main ()
else
{
appWindow.Remove (allViewsView);
allViewsView.Dispose ();
allViewsView!.Dispose ();
allViewsView = null;

appWindow.Add (viewFrame);
Expand Down
4 changes: 2 additions & 2 deletions Terminal.Gui/App/Application.Screen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ public static bool OnSizeChanging (SizeChangedEventArgs args)
/// Gets or sets whether the screen will be cleared, and all Views redrawn, during the next Application iteration.
/// </summary>
/// <remarks>
/// This is typicall set to true when a View's <see cref="View.Frame"/> changes and that view has no
/// This is typical set to true when a View's <see cref="View.Frame"/> changes and that view has no
/// SuperView (e.g. when <see cref="Application.Top"/> is moved or resized.
/// </remarks>
public static bool ClearScreenNextIteration { get; set; }
internal static bool ClearScreenNextIteration { get; set; }
}
3 changes: 3 additions & 0 deletions Terminal.Gui/Configuration/ConfigProperty.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json;
Expand Down Expand Up @@ -74,6 +75,8 @@ public bool Apply ()
{
// Use DeepCloner to create a deep copy of PropertyValue
object? val = DeepCloner.DeepClone (PropertyValue);

Debug.Assert (!Immutable);
PropertyInfo.SetValue (null, val);

}
Expand Down
50 changes: 30 additions & 20 deletions Terminal.Gui/Configuration/ConfigurationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static class ConfigurationManager
{
/// <summary>The backing property for <see cref="Settings"/> (config settings of <see cref="SettingsScope"/>).</summary>
/// <remarks>
/// Is <see langword="null"/> until <see cref="ResetToCurrentValues"/> is called. Gets set to a new instance by
/// Is <see langword="null"/> until <see cref="UpdateToCurrentValues"/> is called. Gets set to a new instance by
/// deserialization
/// (see <see cref="Load"/>).
/// </remarks>
Expand Down Expand Up @@ -117,15 +117,19 @@ internal static bool IsInitialized ()
}
}

// TODO: Find a way to make this cache truly read-only at the leaf node level.
// TODO: Right now, the dictionary is frozen, but the ConfigProperty instances can still be modified
// TODO: if the PropertyValue is a reference type.
// TODO: See https://github.com/gui-cs/Terminal.Gui/issues/4288
/// <summary>
/// A cache of all<see cref="ConfigurationPropertyAttribute"/> properties and their hard coded values.
/// </summary>
/// <remarks>Is <see langword="null"/> until <see cref="Initialize"/> is called.</remarks>
#pragma warning disable IDE1006 // Naming Styles
internal static FrozenDictionary<string, ConfigProperty>? _hardCodedConfigPropertyCache;

private static readonly object _hardCodedConfigPropertyCacheLock = new ();
#pragma warning restore IDE1006 // Naming Styles

internal static FrozenDictionary<string, ConfigProperty>? GetHardCodedConfigPropertyCache ()
{
lock (_hardCodedConfigPropertyCacheLock)
Expand Down Expand Up @@ -183,7 +187,7 @@ internal static void Initialize ()
lock (_uninitializedConfigPropertiesCacheCacheLock)
{
// _allConfigProperties: for ordered, iterable access (LINQ-friendly)
// _frozenConfigPropertyCache: for high-speed key lookup (frozen)
// _hardCodedConfigPropertyCache: for high-speed key lookup (frozen)

// Note GetAllConfigProperties returns a new instance and all the properties !HasValue and Immutable.
_uninitializedConfigPropertiesCache = ConfigProperty.GetAllConfigProperties ();
Expand All @@ -209,6 +213,11 @@ internal static void Initialize ()
}

LoadHardCodedDefaults ();

// BUGBUG: ThemeScope is broken and needs to be fixed to not have the hard coded schemes get overwritten.
// BUGBUG: This a partial workaround.
// BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/4288
ThemeManager.Themes? [ThemeManager.Theme]?.Apply ();
}

#endregion Initialization
Expand Down Expand Up @@ -291,6 +300,7 @@ public static void Disable (bool resetToHardCodedDefaults = false)

if (resetToHardCodedDefaults)
{
// Calls Apply
ResetToHardCodedDefaults ();
}
}
Expand All @@ -299,16 +309,17 @@ public static void Disable (bool resetToHardCodedDefaults = false)

#region Reset

// `Reset` - Reset the configuration to either the current values or the hard-coded defaults.
// Resetting does not load the configuration; it only resets the configuration to the default values.
// `Update` - Updates the configuration from either the current values or the hard-coded defaults.
// Updating does not load the configuration; it only updates the configuration to the values currently
// in the static ConfigProperties.

/// <summary>
/// INTERNAL: Resets <see cref="ConfigurationManager"/>. Loads settings from the current
/// INTERNAL: Updates <see cref="ConfigurationManager"/> to the settings from the current
/// values of the static <see cref="ConfigurationPropertyAttribute"/> properties.
/// </summary>
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
internal static void ResetToCurrentValues ()
internal static void UpdateToCurrentValues ()
{
if (!IsInitialized ())
{
Expand All @@ -327,13 +338,13 @@ internal static void ResetToCurrentValues ()
_settingsLockSlim.ExitWriteLock ();
}

Settings!.LoadCurrentValues ();
Settings!.UpdateToCurrentValues ();
ThemeManager.UpdateToCurrentValues ();
AppSettings!.LoadCurrentValues ();
AppSettings!.UpdateToCurrentValues ();
}

/// <summary>
/// INTERNAL: Resets <see cref="ConfigurationManager"/>. Loads the hard-coded values of the
/// INTERNAL: Loads the hard-coded values of the
/// <see cref="ConfigurationPropertyAttribute"/> properties and applies them.
/// </summary>
[RequiresUnreferencedCode ("AOT")]
Expand Down Expand Up @@ -374,7 +385,7 @@ internal static void LoadHardCodedDefaults ()

Settings = new ();
Settings!.LoadHardCodedDefaults ();
ThemeManager.ResetToHardCodedDefaults ();
ThemeManager.LoadHardCodedDefaults ();
AppSettings!.LoadHardCodedDefaults ();
}

Expand Down Expand Up @@ -447,10 +458,6 @@ public static void Load (ConfigLocations locations)
{
SourcesManager?.Load (Settings, $"~/.tui/{AppName}.{_configFilename}", ConfigLocations.AppHome);
}

Settings!.Validate ();
ThemeManager.Validate ();
AppSettings!.Validate ();
}

// TODO: Rename to Loaded?
Expand Down Expand Up @@ -566,7 +573,7 @@ private static void OnApplied ()

[SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
internal static readonly SourceGenerationContext SerializerContext = new (
new JsonSerializerOptions
new()
{
// Be relaxed
ReadCommentHandling = JsonCommentHandling.Skip,
Expand Down Expand Up @@ -638,7 +645,7 @@ public static AppSettingsScope? AppSettings
if (!appSettingsConfigProperty.HasValue)
{
var appSettings = new AppSettingsScope ();
appSettings.LoadCurrentValues ();
appSettings.UpdateToCurrentValues ();

return appSettings;
}
Expand Down Expand Up @@ -710,8 +717,9 @@ public static void PrintJsonErrors ()
{
if (_jsonErrors.Length > 0)
{
Console.WriteLine (@"Terminal.Gui ConfigurationManager encountered these errors while reading configuration files" +
@"(set ThrowOnJsonErrors to have these caught during execution):");
Console.WriteLine (
@"Terminal.Gui ConfigurationManager encountered these errors while reading configuration files"
+ @"(set ThrowOnJsonErrors to have these caught during execution):");
Console.WriteLine (_jsonErrors.ToString ());
}
}
Expand Down Expand Up @@ -783,8 +791,10 @@ public static string GetHardCodedConfig ()

Debug.Assert (filtered is { });

IEnumerable<KeyValuePair<string, ConfigProperty>> configPropertiesByScope = filtered as KeyValuePair<string, ConfigProperty> [] ?? filtered.ToArray ();
IEnumerable<KeyValuePair<string, ConfigProperty>> configPropertiesByScope =
filtered as KeyValuePair<string, ConfigProperty> [] ?? filtered.ToArray ();
Debug.Assert (configPropertiesByScope.All (v => !v.Value.HasValue));

return configPropertiesByScope;
}
}
Expand Down
40 changes: 25 additions & 15 deletions Terminal.Gui/Configuration/SchemeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,29 @@
namespace Terminal.Gui.Configuration;

/// <summary>
/// Holds the <see cref="Drawing.Scheme"/>s that define the <see cref="System.Attribute"/>s that are used by views to render
/// themselves. A Scheme is a mapping from <see cref="Drawing.VisualRole"/>s (such as <see cref="Drawing.VisualRole.Focus"/>) to <see cref="System.Attribute"/>s.
/// Holds the <see cref="Drawing.Scheme"/>s that define the <see cref="System.Attribute"/>s that are used by views to
/// render
/// themselves. A Scheme is a mapping from <see cref="Drawing.VisualRole"/>s (such as
/// <see cref="Drawing.VisualRole.Focus"/>) to <see cref="System.Attribute"/>s.
/// A Scheme defines how a `View` should look based on its purpose (e.g. Menu or Dialog).
/// </summary>
public sealed class SchemeManager// : INotifyCollectionChanged, IDictionary<string, Scheme?>
public sealed class SchemeManager // : INotifyCollectionChanged, IDictionary<string, Scheme?>
{
#pragma warning disable IDE1006 // Naming Styles
private static readonly object _schemesLock = new ();
#pragma warning restore IDE1006 // Naming Styles

/// <summary>
/// INTERNAL: Gets the hard-coded schemes defined by <see cref="View"/>. These are not loaded from the configuration files,
/// INTERNAL: Gets the hard-coded schemes defined by <see cref="View"/>. These are not loaded from the configuration
/// files,
/// but are hard-coded in the source code. Used for unit testing when ConfigurationManager is not initialized.
/// </summary>
/// <returns></returns>
internal static ImmutableSortedDictionary<string, Scheme?>? GetHardCodedSchemes () { return Scheme.GetHardCodedSchemes ()!; }

/// <summary>
/// Use <see cref="AddScheme"/>, <see cref="GetScheme(Drawing.Schemes)"/>, <see cref="GetSchemeNames"/>, <see cref="GetSchemesForCurrentTheme"/>, etc... instead.
/// Use <see cref="AddScheme"/>, <see cref="GetScheme(Drawing.Schemes)"/>, <see cref="GetSchemeNames"/>,
/// <see cref="GetSchemesForCurrentTheme"/>, etc... instead.
/// </summary>
[ConfigurationProperty (Scope = typeof (ThemeScope), OmitClassName = true)]
[JsonConverter (typeof (DictionaryJsonConverter<Scheme?>))]
Expand Down Expand Up @@ -54,7 +58,7 @@ public sealed class SchemeManager// : INotifyCollectionChanged, IDictionary<stri
/// <summary>INTERNAL: The set method for <see cref="Schemes"/>.</summary>
[RequiresUnreferencedCode ("Calls Terminal.Gui.ConfigProperty.UpdateFrom(Object)")]
[RequiresDynamicCode ("Calls Terminal.Gui.ConfigProperty.UpdateFrom(Object)")]
private static void SetSchemes (Dictionary<string, Scheme?>? value)
internal static void SetSchemes (Dictionary<string, Scheme?>? value)
{
lock (_schemesLock)
{
Expand Down Expand Up @@ -117,6 +121,7 @@ public static Scheme GetScheme (Schemes schemeName)
{
// Convert schemeName to string via Enum api
string? schemeNameString = SchemesToSchemeName (schemeName);

if (schemeNameString is null)
{
throw new ArgumentException ($"Invalid scheme name: {schemeName}");
Expand All @@ -131,21 +136,15 @@ public static Scheme GetScheme (Schemes schemeName)
/// <param name="schemeName"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static Scheme GetScheme (string schemeName)
{
return GetSchemesForCurrentTheme ()! [schemeName]!;
}
public static Scheme GetScheme (string schemeName) { return GetSchemesForCurrentTheme ()! [schemeName]!; }

/// <summary>
/// Gets the name of the specified <see cref="Schemes"/>. Will throw an exception if <paramref name="schemeName"/>
/// is not a built-in Scheme.
/// </summary>
/// <param name="schemeName"></param>
/// <returns>The name of scheme.</returns>
public static string? SchemesToSchemeName (Schemes schemeName)
{
return Enum.GetName (typeof (Schemes), schemeName);
}
public static string? SchemesToSchemeName (Schemes schemeName) { return Enum.GetName (typeof (Schemes), schemeName); }

/// <summary>
/// Converts a string to a <see cref="Schemes"/> enum value.
Expand All @@ -158,11 +157,12 @@ public static Scheme GetScheme (string schemeName)
{
return value?.ToString ();
}

return null;
}

/// <summary>
/// Get the dictionary schemes from the selected theme loaded from configuration.
/// Get the dictionary of schemes from the current theme. Current means active.
/// </summary>
/// <returns></returns>
public static Dictionary<string, Scheme?> GetSchemesForCurrentTheme ()
Expand Down Expand Up @@ -195,4 +195,14 @@ public static ImmutableList<string> GetSchemeNames ()
return GetSchemes ()!.Keys.ToImmutableList ();
}
}

[RequiresUnreferencedCode ("Calls SetSchemes")]
[RequiresDynamicCode ("Calls SetSchemes")]
internal static void LoadToHardCodedDefaults ()
{
// BUGBUG: SchemeManager is broken and needs to be fixed to not have the hard coded schemes get overwritten.
// BUGBUG: This is a partial workaround
// BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/4288
SetSchemes (GetHardCodedSchemes ()!.ToDictionary ());
}
}
Loading
Loading