Skip to content

Fixes #4139. Application.Run<T> isn't initializing properly by setting the Application.ForceDriver property #4142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 12, 2025
Merged
16 changes: 16 additions & 0 deletions Examples/UICatalog/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"commandName": "Project",
"commandLineArgs": "--driver WindowsDriver"
},
"UICatalog --driver v2": {
"commandName": "Project",
"commandLineArgs": "--driver v2 -dl Trace"
},
"UICatalog --driver v2win": {
"commandName": "Project",
"commandLineArgs": "--driver v2win -dl Trace"
Expand All @@ -32,6 +36,18 @@
"commandLineArgs": "dotnet UICatalog.dll --driver NetDriver",
"distributionName": ""
},
"WSL: UICatalog --driver v2": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver v2",
"distributionName": ""
},
"WSL: UICatalog --driver v2net": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver v2net",
"distributionName": ""
},
"Benchmark All": {
"commandName": "Project",
"commandLineArgs": "--benchmark"
Expand Down
8 changes: 2 additions & 6 deletions Examples/UICatalog/UICatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ namespace UICatalog;
/// </remarks>
public class UICatalog
{
private static string _forceDriver = string.Empty;
private static string? _forceDriver = null;

public static string LogFilePath { get; set; } = string.Empty;
public static LoggingLevelSwitch LogLevelSwitch { get; } = new ();
Expand All @@ -77,11 +77,7 @@ private static int Main (string [] args)

// If no driver is provided, the default driver is used.
Option<string> driverOption = new Option<string> ("--driver", "The IConsoleDriver to use.").FromAmong (
Application.GetDriverTypes ()
.Where (d => !typeof (IConsoleDriverFacade).IsAssignableFrom (d))
.Select (d => d!.Name)
.Union (["v2", "v2win", "v2net"])
.ToArray ()
Application.GetDriverTypes ().Item2.ToArray ()!
);
driverOption.AddAlias ("-d");
driverOption.AddAlias ("--d");
Expand Down
43 changes: 26 additions & 17 deletions Terminal.Gui/App/Application.Initialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ public static partial class Application // Initialization (Init/Shutdown)
[RequiresDynamicCode ("AOT")]
public static void Init (IConsoleDriver? driver = null, string? driverName = null)
{
if (driverName?.StartsWith ("v2") ?? false)
{
ApplicationImpl.ChangeInstance (new ApplicationV2 ());
}

ApplicationImpl.Instance.Init (driver, driverName);
}

Expand Down Expand Up @@ -83,12 +78,6 @@ internal static void InternalInit (
ResetState (ignoreDisposed: true);
}

Debug.Assert (Navigation is null);
Navigation = new ();

Debug.Assert(Popover is null);
Popover = new ();

// For UnitTests
if (driver is { })
{
Expand All @@ -105,8 +94,6 @@ internal static void InternalInit (
}
}

AddKeyBindings ();

// Ignore Configuration for ForceDriver if driverName is specified
if (!string.IsNullOrEmpty (driverName))
{
Expand All @@ -130,13 +117,21 @@ internal static void InternalInit (
}
else
{
List<Type?> drivers = GetDriverTypes ();
(List<Type?> drivers, List<string?> driverTypeNames) = GetDriverTypes ();
Type? driverType = drivers.FirstOrDefault (t => t!.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase));

if (driverType is { })
{
Driver = (IConsoleDriver)Activator.CreateInstance (driverType)!;
}
else if (ForceDriver?.StartsWith ("v2") ?? false)
{
ApplicationImpl.ChangeInstance (new ApplicationV2 ());
ApplicationImpl.Instance.Init (driver, ForceDriver);
Debug.Assert (Driver is { });

return;
}
else
{
throw new ArgumentException (
Expand All @@ -146,6 +141,14 @@ internal static void InternalInit (
}
}

Debug.Assert (Navigation is null);
Navigation = new ();

Debug.Assert (Popover is null);
Popover = new ();

AddKeyBindings ();

try
{
MainLoop = Driver!.Init ();
Expand Down Expand Up @@ -201,10 +204,10 @@ internal static void UnsubscribeDriverEvents ()
private static void Driver_KeyUp (object? sender, Key e) { RaiseKeyUpEvent (e); }
private static void Driver_MouseEvent (object? sender, MouseEventArgs e) { RaiseMouseEvent (e); }

/// <summary>Gets of list of <see cref="IConsoleDriver"/> types that are available.</summary>
/// <summary>Gets of list of <see cref="IConsoleDriver"/> types and type names that are available.</summary>
/// <returns></returns>
[RequiresUnreferencedCode ("AOT")]
public static List<Type?> GetDriverTypes ()
public static (List<Type?>, List<string?>) GetDriverTypes ()
{
// use reflection to get the list of drivers
List<Type?> driverTypes = new ();
Expand All @@ -220,7 +223,13 @@ internal static void UnsubscribeDriverEvents ()
}
}

return driverTypes;
List<string?> driverTypeNames = driverTypes
.Where (d => !typeof (IConsoleDriverFacade).IsAssignableFrom (d))
.Select (d => d!.Name)
.Union (["v2", "v2win", "v2net"])
.ToList ()!;

return (driverTypes, driverTypeNames);
}

/// <summary>Shutdown an application initialized with <see cref="Init"/>.</summary>
Expand Down
11 changes: 9 additions & 2 deletions Terminal.Gui/App/ApplicationImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static void ChangeInstance (IApplication newApplication)
[RequiresDynamicCode ("AOT")]
public virtual void Init (IConsoleDriver? driver = null, string? driverName = null)
{
Application.InternalInit (driver, driverName);
Application.InternalInit (driver, string.IsNullOrWhiteSpace (driverName) ? Application.ForceDriver : driverName);
}

/// <summary>
Expand Down Expand Up @@ -85,7 +85,12 @@ public virtual T Run<T> (Func<Exception, bool>? errorHandler = null, IConsoleDri
if (!Application.Initialized)
{
// Init() has NOT been called.
Application.InternalInit (driver, null, true);
Application.InternalInit (driver, Application.ForceDriver, true);
}

if (Instance is ApplicationV2)
{
return Instance.Run<T> (errorHandler, driver);
}

var top = new T ();
Expand Down Expand Up @@ -227,6 +232,8 @@ public virtual void Shutdown ()

Application.OnInitializedChanged (this, new (in init));
}

_lazyInstance = new (() => new ApplicationImpl ());
}

/// <inheritdoc />
Expand Down
8 changes: 7 additions & 1 deletion Terminal.Gui/Drivers/NetDriver/NetEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public NetEvents (IConsoleDriver consoleDriver)
{
_consoleDriver = consoleDriver ?? throw new ArgumentNullException (nameof (consoleDriver));

if (ConsoleDriver.RunningUnitTests)
{
return;
}

Task.Run (() =>
{
try
Expand All @@ -29,7 +34,8 @@ public NetEvents (IConsoleDriver consoleDriver)
{ }
}, _netEventsDisposed.Token);

Task.Run (() => {
Task.Run (() =>
{
try
{
CheckWindowSizeChange ();
Expand Down
14 changes: 13 additions & 1 deletion Terminal.Gui/Drivers/V2/ConsoleDriverFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,19 @@ private void CreateClipboard ()
}

/// <summary>Gets the location and size of the terminal screen.</summary>
public Rectangle Screen => new (new (0, 0), _output.GetWindowSize ());
public Rectangle Screen
{
get
{
if (ConsoleDriver.RunningUnitTests)
{
// In unit tests, we don't have a real output, so we return an empty rectangle.
return Rectangle.Empty;
}

return new (new (0, 0), _output.GetWindowSize ());
}
}

/// <summary>
/// Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject
Expand Down
16 changes: 15 additions & 1 deletion Terminal.Gui/Drivers/V2/NetInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public class NetInput : ConsoleInput<ConsoleKeyInfo>, INetInput
public NetInput ()
{
Logging.Logger.LogInformation ($"Creating {nameof (NetInput)}");

if (ConsoleDriver.RunningUnitTests)
{
return;
}

PlatformID p = Environment.OSVersion.Platform;

if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
Expand All @@ -39,7 +45,15 @@ public NetInput ()
}

/// <inheritdoc/>
protected override bool Peek () { return Console.KeyAvailable; }
protected override bool Peek ()
{
if (ConsoleDriver.RunningUnitTests)
{
return false;
}

return Console.KeyAvailable;
}

/// <inheritdoc/>
protected override IEnumerable<ConsoleKeyInfo> Read ()
Expand Down
16 changes: 15 additions & 1 deletion Terminal.Gui/Drivers/V2/NetOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public void Write (ReadOnlySpan<char> text)
/// <inheritdoc/>
public void Write (IOutputBuffer buffer)
{
if (ConsoleDriver.RunningUnitTests)
{
return;
}

if (Console.WindowHeight < 1
|| buffer.Contents.Length != buffer.Rows * buffer.Cols
|| buffer.Rows != Console.WindowHeight)
Expand Down Expand Up @@ -197,7 +202,16 @@ public void Write (IOutputBuffer buffer)
}

/// <inheritdoc/>
public Size GetWindowSize () { return new (Console.WindowWidth, Console.WindowHeight); }
public Size GetWindowSize ()
{
if (ConsoleDriver.RunningUnitTests)
{
// For unit tests, we return a default size.
return Size.Empty;
}

return new (Console.WindowWidth, Console.WindowHeight);
}

private void WriteToConsole (StringBuilder output, ref int lastCol, int row, ref int outputWidth)
{
Expand Down
5 changes: 5 additions & 0 deletions Terminal.Gui/Drivers/V2/WindowSizeMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public WindowSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer outputBuffer)
/// <inheritdoc/>
public bool Poll ()
{
if (ConsoleDriver.RunningUnitTests)
{
return false;
}

Size size = _consoleOut.GetWindowSize ();

if (size != _lastSize)
Expand Down
16 changes: 15 additions & 1 deletion Terminal.Gui/Drivers/V2/WindowsInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ out uint lpNumberOfEventsRead
public WindowsInput ()
{
Logging.Logger.LogInformation ($"Creating {nameof (WindowsInput)}");

if (ConsoleDriver.RunningUnitTests)
{
return;
}

_inputHandle = GetStdHandle (STD_INPUT_HANDLE);

GetConsoleMode (_inputHandle, out uint v);
Expand Down Expand Up @@ -110,5 +116,13 @@ protected override bool Peek ()
}
}

public override void Dispose () { SetConsoleMode (_inputHandle, _originalConsoleMode); }
public override void Dispose ()
{
if (ConsoleDriver.RunningUnitTests)
{
return;
}

SetConsoleMode (_inputHandle, _originalConsoleMode);
}
}
23 changes: 17 additions & 6 deletions Terminal.Gui/Drivers/V2/WindowsOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ public WindowsOutput ()
{
Logging.Logger.LogInformation ($"Creating {nameof (WindowsOutput)}");

if (ConsoleDriver.RunningUnitTests)
{
return;
}

_screenBuffer = CreateConsoleScreenBuffer (
DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
ShareMode.FileShareRead | ShareMode.FileShareWrite,
Expand Down Expand Up @@ -171,12 +176,13 @@ public void Write (IOutputBuffer buffer)
};

//size, ExtendedCharInfo [] charInfoBuffer, Coord , SmallRect window,
if (!WriteToConsole (
new (buffer.Cols, buffer.Rows),
outputBuffer,
bufferCoords,
damageRegion,
Application.Driver!.Force16Colors))
if (!ConsoleDriver.RunningUnitTests
&& !WriteToConsole (
new (buffer.Cols, buffer.Rows),
outputBuffer,
bufferCoords,
damageRegion,
Application.Driver!.Force16Colors))
{
int err = Marshal.GetLastWin32Error ();

Expand Down Expand Up @@ -312,6 +318,11 @@ public Size GetWindowSize ()
/// <inheritdoc/>
public void SetCursorVisibility (CursorVisibility visibility)
{
if (ConsoleDriver.RunningUnitTests)
{
return;
}

if (Application.Driver!.Force16Colors)
{
var info = new WindowsConsole.ConsoleCursorInfo
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO.Abstractions;
using System.Globalization;
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;
using System.Runtime.InteropServices;
using TerminalGuiFluentTesting;
Expand All @@ -12,6 +13,7 @@ public class FileDialogFluentTests

public FileDialogFluentTests (ITestOutputHelper outputHelper)
{
CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
_out = new TestOutputWriter (outputHelper);
}

Expand Down
2 changes: 2 additions & 0 deletions Tests/IntegrationTests/FluentTests/MenuBarv2Tests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using System.Reflection;
using TerminalGuiFluentTesting;
using Xunit.Abstractions;
Expand All @@ -13,6 +14,7 @@ public class MenuBarv2Tests

public MenuBarv2Tests (ITestOutputHelper outputHelper)
{
CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
_out = new TestOutputWriter (outputHelper);
}

Expand Down
Loading
Loading