Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
4b5e800
Initial plan
Copilot Oct 5, 2025
7510449
Remove legacy drivers and reorganize v2 architecture
Copilot Oct 5, 2025
39c5f07
Extract Windows key helper utilities and fix build
Copilot Oct 5, 2025
f619aa3
Fix all test references to legacy drivers
Copilot Oct 5, 2025
fb9430a
Update documentation to reflect new driver architecture
Copilot Oct 5, 2025
a1314f2
Remove V2.cd diagram file
Copilot Oct 5, 2025
c111028
Fix test failures: support legacy drivers and update exception handling
Copilot Oct 5, 2025
c3f9780
updated driver names
tig Oct 5, 2025
7d11fc8
Move V2 tests from ConsoleDrivers/V2 to proper locations
Copilot Oct 5, 2025
dd2246d
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 5, 2025
f7b25da
Rename ApplicationV2 to ModernApplicationImpl to remove v2 terminology
Copilot Oct 6, 2025
2a87f66
Remove V2 terminology from test drivers and FakeDriver classes
Copilot Oct 6, 2025
12b6a1f
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 6, 2025
c993810
Merge ModernApplicationImpl into ApplicationImpl and move to App folder
Copilot Oct 6, 2025
dafc8b8
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 6, 2025
bb2a0ba
Create modern FakeDriver with component factory architecture in Termi…
Copilot Oct 6, 2025
c5ee3e1
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 6, 2025
b833c63
Refactor: Move non-platform-dependent code from /Drivers to /App
Copilot Oct 6, 2025
9dc92ee
Code cleanup and org
tig Oct 6, 2025
70d37ae
Unit test reorg
tig Oct 6, 2025
4d203ce
Refactor MainLoop architecture: rename classes and enhance documentat…
Copilot Oct 6, 2025
c6597a9
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 6, 2025
08fd6e2
Add comprehensive FakeDriver tests (WIP - some tests need fixes)
Copilot Oct 6, 2025
82af5c5
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 6, 2025
ae06831
Fixed FakeDriver build failures
tig Oct 6, 2025
0cb64b3
Fix all FakeDriver test failures - Application.Top creation and clipb…
Copilot Oct 6, 2025
d100179
Fixed FakeDriver build failures2
tig Oct 6, 2025
e562c44
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 6, 2025
483b458
Remove hanging legacy FakeDriver tests that use Console.MockKeyPresses
Copilot Oct 6, 2025
313b1f4
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 6, 2025
04ae514
Fixed some tests
tig Oct 6, 2025
f93cdbd
Fixed more tests
tig Oct 6, 2025
1df66e6
Fixed more tests
tig Oct 6, 2025
5b3dd59
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 7, 2025
abbaa41
Fix bad copilot (#4277)
tznind Oct 11, 2025
28e4ed8
Update Terminal.Gui/Drivers/FakeDriver/FakeConsoleOutput.cs
tig Oct 11, 2025
1c1744b
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 11, 2025
245ddb8
Merge branch 'v2_develop' into copilot/fix-b6590cf0-cec4-462a-98d6-a1…
tig Oct 11, 2025
93a698a
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 11, 2025
7e7ac24
Refactor Application Init and Update Tests
tig Oct 11, 2025
af737a2
Warp fix copilot (#4278)
tznind Oct 12, 2025
f47dde5
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 12, 2025
55c5f6a
More fixes (#4279)
tznind Oct 12, 2025
6d440d0
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 13, 2025
ca6c804
Fixes/works around test failures and temporarily disable failing test
tig Oct 14, 2025
ea610fc
Allow all tests to run despite failures in UnitTests
tig Oct 14, 2025
8a96c4b
Refactor ApplicationScreenTests for cleaner setup/teardown
tig Oct 14, 2025
bb4eed2
Attempt to fix intermittent local test failures.
tig Oct 14, 2025
15b7c4d
Code cleanup to cause Action to re-run.
tig Oct 14, 2025
77b7afb
Stop tests on first failure in UnitTestsParallelizable
tig Oct 14, 2025
a7d0feb
Allow all tests to run despite failures in CI
tig Oct 14, 2025
c7980be
Merge branch 'v2_develop' into copilot/fix-b6590cf0-cec4-462a-98d6-a1…
tig Oct 15, 2025
173a115
Enhance RuneExtensions docs and update user dictionary
tig Oct 15, 2025
99a09a0
Merge branch 'copilot/fix-b6590cf0-cec4-462a-98d6-a1f9b6313715' of ti…
tig Oct 15, 2025
faa08cf
Improve XML doc formatting in RuneExtensions.cs
tig Oct 15, 2025
b414094
Refactor drivers and improve clipboard handling
tig Oct 15, 2025
54cc788
Remove `PlatformColor` from `Attribute` struct
tig Oct 15, 2025
cf91d58
Refactor Terminal.Gui driver architecture for v2
tig Oct 15, 2025
e64fe14
Moved files around
tig Oct 15, 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
21 changes: 20 additions & 1 deletion Examples/Example/Example.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
using Attribute = Terminal.Gui.Drawing.Attribute;

// Override the default configuration for the application to use the Light theme
ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
//ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
ConfigurationManager.Enable(ConfigLocations.All);



Application.Run<ExampleWindow> ().Dispose ();

// Before the application exits, reset Terminal.Gui for clean shutdown
Expand Down Expand Up @@ -89,5 +91,22 @@ public ExampleWindow ()

// Add the views to the Window
Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin);

ListView lv = new ListView ()
{
Y = Pos.AnchorEnd(),
Height= Dim.Auto(),
Width = Dim.Auto()
};
lv.SetSource (["One", "Two", "Three", "Four"]);
Add (lv);
}

public override void EndInit ()
{
base.EndInit ();
// Set the theme to "Anders" if it exists, otherwise use "Default"
ThemeManager.Theme = ThemeManager.GetThemeNames ().FirstOrDefault (x => x == "Anders") ?? "Default";
}
}

90 changes: 22 additions & 68 deletions Examples/UICatalog/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,30 @@
"commandName": "Project",
"commandLineArgs": "--debug-log-level Debug"
},
"UICatalog --driver NetDriver": {
"UICatalog --driver windows": {
"commandName": "Project",
"commandLineArgs": "--driver NetDriver"
"commandLineArgs": "--driver windows -dl Trace"
},
"UICatalog --driver WindowsDriver": {
"UICatalog --driver dotnet": {
"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"
},
"UICatalog --driver v2net": {
"commandName": "Project",
"commandLineArgs": "--driver v2net -dl Trace"
"commandLineArgs": "--driver dotnet -dl Trace"
},
"WSL: UICatalog": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll",
"distributionName": ""
},
"WSL: UICatalog --driver NetDriver": {
"commandName": "Executable",
"executablePath": "wsl",
"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 v2unix": {
"WSL: UICatalog --driver dotnet": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver v2unix",
"commandLineArgs": "dotnet UICatalog.dll --driver dotnet",
"distributionName": ""
},
"WSL: UICatalog --driver v2net": {
"WSL: UICatalog --driver unix": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver v2net",
"commandLineArgs": "dotnet UICatalog.dll --driver unix",
"distributionName": ""
},
"WSL-Gnome: UICatalog": {
Expand All @@ -60,68 +36,46 @@
"commandLineArgs": "bash -c 'while [ ! -e \"$XDG_RUNTIME_DIR/bus\" ]; do sleep 0.1; done; gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll; exec bash\"'",
"distributionName": ""
},
"WSL-Gnome: UICatalog --driver NetDriver": {
"WSL-Gnome: UICatalog --driver dotnet": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "bash -c 'while [ ! -e \"$XDG_RUNTIME_DIR/bus\" ]; do sleep 0.1; done; gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver NetDriver; exec bash\"'",
"commandLineArgs": "bash -c 'while [ ! -e \"$XDG_RUNTIME_DIR/bus\" ]; do sleep 0.1; done; gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver dotnet; exec bash\"'",
"distributionName": ""
},
"WSL-Gnome: UICatalog --driver v2": {
"WSL-Gnome: UICatalog --driver unix": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "bash -c 'dbus-run-session -- gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver v2; exec bash\"'",
"distributionName": ""
},
"WSL-Gnome: UICatalog --driver v2unix": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "bash -c 'dbus-run-session -- gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver v2unix; exec bash\"'",
"distributionName": ""
},
"WSL-Gnome: UICatalog --driver v2net": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "bash -c 'dbus-run-session -- gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver v2net; exec bash\"'",
"commandLineArgs": "bash -c 'dbus-run-session -- gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver unix; exec bash\"'",
"distributionName": ""
},
"Benchmark All": {
"commandName": "Project",
"commandLineArgs": "--benchmark"
},
"Benchmark All --driver NetDriver": {
"commandName": "Project",
"commandLineArgs": "--driver NetDriver --benchmark"
},
"Benchmark All --driver v2win": {
"Benchmark All --driver dotnet": {
"commandName": "Project",
"commandLineArgs": "--driver v2win --benchmark"
"commandLineArgs": "--driver dotnet --benchmark"
},
"Benchmark All --driver v2net": {
"Benchmark All --driver windows": {
"commandName": "Project",
"commandLineArgs": "--driver v2net --benchmark"
"commandLineArgs": "--driver windows --benchmark"
},
"WSL: Benchmark All": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --benchmark",
"distributionName": ""
},
"WSL: Benchmark All --driver v2": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver v2 --benchmark",
"distributionName": ""
},
"WSL: Benchmark All --driver v2unix": {
"WSL: Benchmark All --driver unix": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver v2unix --benchmark",
"commandLineArgs": "dotnet UICatalog.dll --driver unix --benchmark",
"distributionName": ""
},
"WSL: Benchmark All --driver v2net": {
"WSL: Benchmark All --driver dotnet": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver v2net --benchmark",
"commandLineArgs": "dotnet UICatalog.dll --driver dotnet --benchmark",
"distributionName": ""
},
"Docker": {
Expand All @@ -135,9 +89,9 @@
"commandName": "Project",
"commandLineArgs": "--disable-cm\r\n"
},
"UICatalog --disable-cm --driver v2win": {
"UICatalog --disable-cm --driver windows": {
"commandName": "Project",
"commandLineArgs": "--disable-cm --driver v2win"
"commandLineArgs": "--disable-cm --driver windows"
},
"Themes": {
"commandName": "Project",
Expand Down
51 changes: 38 additions & 13 deletions Examples/UICatalog/UICatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -76,12 +77,25 @@ private static int Main (string [] args)
// Process command line 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 ().Item2.ToArray ()!
);
// Get allowed driver names
string? [] allowedDrivers = Application.GetDriverTypes ().Item2.ToArray ();

Option<string> driverOption = new Option<string> ("--driver", "The IConsoleDriver to use.")
.FromAmong (allowedDrivers!);
driverOption.SetDefaultValue (string.Empty);
driverOption.AddAlias ("-d");
driverOption.AddAlias ("--d");

// Add validator separately (not chained)
driverOption.AddValidator (result =>
{
var value = result.GetValueOrDefault<string> ();
if (result.Tokens.Count > 0 && !allowedDrivers.Contains (value))
{
result.ErrorMessage = $"Invalid driver name '{value}'. Allowed values: {string.Join (", ", allowedDrivers)}";
}
});

// Configuration Management
Option<bool> disableConfigManagement = new (
"--disable-cm",
Expand Down Expand Up @@ -163,6 +177,17 @@ private static int Main (string [] args)
return 0;
}

var parseResult = parser.Parse (args);

if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine (error.Message);
}
return 1; // Non-zero exit code for error
}

Scenario.BenchmarkTimeout = Options.BenchmarkTimeout;

Logging.Logger = CreateLogger ();
Expand All @@ -175,16 +200,16 @@ private static int Main (string [] args)
public static LogEventLevel LogLevelToLogEventLevel (LogLevel logLevel)
{
return logLevel switch
{
LogLevel.Trace => LogEventLevel.Verbose,
LogLevel.Debug => LogEventLevel.Debug,
LogLevel.Information => LogEventLevel.Information,
LogLevel.Warning => LogEventLevel.Warning,
LogLevel.Error => LogEventLevel.Error,
LogLevel.Critical => LogEventLevel.Fatal,
LogLevel.None => LogEventLevel.Fatal, // Default to Fatal if None is specified
_ => LogEventLevel.Fatal // Default to Information for any unspecified LogLevel
};
{
LogLevel.Trace => LogEventLevel.Verbose,
LogLevel.Debug => LogEventLevel.Debug,
LogLevel.Information => LogEventLevel.Information,
LogLevel.Warning => LogEventLevel.Warning,
LogLevel.Error => LogEventLevel.Error,
LogLevel.Critical => LogEventLevel.Fatal,
LogLevel.None => LogEventLevel.Fatal, // Default to Fatal if None is specified
_ => LogEventLevel.Fatal // Default to Information for any unspecified LogLevel
};
}

private static ILogger CreateLogger ()
Expand Down
2 changes: 1 addition & 1 deletion Terminal.Gui/App/Application.Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static partial class Application // Driver abstractions

// BUGBUG: ForceDriver should be nullable.
/// <summary>
/// Forces the use of the specified driver (one of "fake", "ansi", "curses", "net", or "windows"). If not
/// Forces the use of the specified driver (one of "fake", "dotnet", "windows", or "unix"). If not
/// specified, the driver is selected based on the platform.
/// </summary>
/// <remarks>
Expand Down
81 changes: 44 additions & 37 deletions Terminal.Gui/App/Application.Initialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,34 @@ public static partial class Application // Initialization (Init/Shutdown)
/// <paramref name="driverName"/> are specified the default driver for the platform will be used.
/// </param>
/// <param name="driverName">
/// The short name (e.g. "net", "windows", "ansi", "fake", or "curses") of the
/// The short name (e.g. "dotnet", "windows", "unix", or "fake") of the
/// <see cref="IConsoleDriver"/> to use. If neither <paramref name="driver"/> or <paramref name="driverName"/> are
/// specified the default driver for the platform will be used.
/// </param>
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
public static void Init (IConsoleDriver? driver = null, string? driverName = null)
{
// Check if this is a request for a legacy driver (like FakeDriver)
// that isn't supported by the modern application architecture
if (driver is null)
{
var driverNameToCheck = string.IsNullOrWhiteSpace (driverName) ? ForceDriver : driverName;
if (!string.IsNullOrEmpty (driverNameToCheck))
{
(List<Type?> drivers, List<string?> driverTypeNames) = GetDriverTypes ();
Type? driverType = drivers.FirstOrDefault (t => t!.Name.Equals (driverNameToCheck, StringComparison.InvariantCultureIgnoreCase));

// If it's a legacy IConsoleDriver (not a Facade), use InternalInit which supports legacy drivers
if (driverType is { } && !typeof (IConsoleDriverFacade).IsAssignableFrom (driverType))
{
InternalInit (driver, driverName);
return;
}
}
}

// Otherwise delegate to the ApplicationImpl instance (which uses the modern architecture)
ApplicationImpl.Instance.Init (driver, driverName);
}

Expand Down Expand Up @@ -90,44 +110,31 @@ internal static void InternalInit (
ForceDriver = driverName;
}

// Check if we need to use a legacy driver (like FakeDriver)
// or go through the modern application architecture
if (Driver is null)
{
PlatformID p = Environment.OSVersion.Platform;

if (string.IsNullOrEmpty (ForceDriver))
{
if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
{
Driver = new WindowsDriver ();
}
else
{
Driver = new CursesDriver ();
}
}
else
//// Try to find a legacy IConsoleDriver type that matches the driver name
//bool useLegacyDriver = false;
//if (!string.IsNullOrEmpty (ForceDriver))
//{
// (List<Type?> drivers, List<string?> driverTypeNames) = GetDriverTypes ();
// Type? driverType = drivers.FirstOrDefault (t => t!.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase));

// if (driverType is { } && !typeof (IConsoleDriverFacade).IsAssignableFrom (driverType))
// {
// // This is a legacy driver (not a ConsoleDriverFacade)
// Driver = (IConsoleDriver)Activator.CreateInstance (driverType)!;
// useLegacyDriver = true;
// }
//}

//// Use the modern application architecture
//if (!useLegacyDriver)
{
(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 (
$"Invalid driver name: {ForceDriver}. Valid names are {string.Join (", ", drivers.Select (t => t!.Name))}"
);
}
ApplicationImpl.Instance.Init (driver, driverName);
Debug.Assert (Driver is { });
return;
}
}

Expand Down Expand Up @@ -217,7 +224,7 @@ public static (List<Type?>, List<string?>) GetDriverTypes ()
List<string?> driverTypeNames = driverTypes
.Where (d => !typeof (IConsoleDriverFacade).IsAssignableFrom (d))
.Select (d => d!.Name)
.Union (["v2", "v2win", "v2net", "v2unix"])
.Union (["dotnet", "windows", "unix", "fake"])
.ToList ()!;

return (driverTypes, driverTypeNames);
Expand Down
Loading
Loading