This commit is contained in:
Tig
2025-12-01 17:24:57 -07:00
parent f2a47367a5
commit 215d76645b
7 changed files with 61 additions and 36 deletions

View File

@@ -12,7 +12,7 @@ using Terminal.Gui.Views;
[assembly: ExampleMetadata ("Simple Example", "A basic login form demonstrating Terminal.Gui fundamentals")]
[assembly: ExampleCategory ("Getting Started")]
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["a", "d", "m", "i", "n", "Tab", "p", "a", "s", "s", "w", "o", "r", "d", "Enter"], Order = 1)]
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["a", "d", "m", "i", "n", "Tab", "p", "a", "s", "s", "w", "o", "r", "d", "Enter"], DelayMs = 500, Order = 1)]
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["Enter"], DelayMs = 500, Order = 2)]
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["Esc"], DelayMs = 100, Order = 3)]
@@ -20,9 +20,6 @@ using Terminal.Gui.Views;
ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
ConfigurationManager.Enable (ConfigLocations.All);
// Setup automatic key injection for testing
ExampleContextInjector.SetupAutomaticInjection ();
// Check for test context to determine driver
string? contextJson = Environment.GetEnvironmentVariable (ExampleContext.ENVIRONMENT_VARIABLE_NAME);
string? driverName = null;
@@ -33,8 +30,12 @@ if (!string.IsNullOrEmpty (contextJson))
driverName = context?.DriverName;
}
IApplication app = Application.Create ().Init (driverName);
IApplication app = Application.Create ();
// Setup automatic key injection for testing
ExampleContextInjector.SetupAutomaticInjection (app);
app.Init (driverName);
app.Run<ExampleWindow> ();
// Dispose the app to clean up and enable Console.WriteLine below

View File

@@ -65,10 +65,11 @@ foreach (ExampleInfo example in examples)
// Create context for running the example
ExampleContext context = new ()
{
DriverName = "FakeDriver",
KeysToInject = ["Esc"], // Just press Esc to quit each example
KeysToInject = example.DemoKeyStrokes.OrderBy (ks => ks.Order)
.SelectMany (ks => ks.KeyStrokes)
.ToList (),
TimeoutMs = 5000,
Mode = ExecutionMode.OutOfProcess
Mode = ExecutionMode.InProcess
};
try

View File

@@ -13,8 +13,6 @@ using Terminal.Gui.Views;
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["CursorDown", "CursorDown", "CursorRight", "Enter"], Order = 1)]
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["Esc"], DelayMs = 100, Order = 2)]
// Setup automatic key injection for testing
ExampleContextInjector.SetupAutomaticInjection ();
// Check for test context to determine driver
string? contextJson = Environment.GetEnvironmentVariable (ExampleContext.ENVIRONMENT_VARIABLE_NAME);
@@ -30,6 +28,9 @@ IApplication? app = Application.Create ()
.Init (driverName)
.Run<ColorPickerView> ();
// Setup automatic key injection for testing
ExampleContextInjector.SetupAutomaticInjection (app);
// Run the application with fluent API - automatically creates, runs, and disposes the runnable
Color? result = app.GetResult () as Color?;

View File

@@ -16,9 +16,6 @@ using Terminal.Gui.Views;
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["Enter", "Esc"], DelayMs = 100, Order = 4)]
[assembly: ExampleDemoKeyStrokes (KeyStrokes = ["Enter", "Esc"], DelayMs = 100, Order = 5)]
// Setup automatic key injection for testing
ExampleContextInjector.SetupAutomaticInjection ();
// Check for test context to determine driver
string? contextJson = Environment.GetEnvironmentVariable (ExampleContext.ENVIRONMENT_VARIABLE_NAME);
string? driverName = null;
@@ -30,6 +27,10 @@ if (!string.IsNullOrEmpty (contextJson))
}
IApplication app = Application.Create ();
// Setup automatic key injection for testing
ExampleContextInjector.SetupAutomaticInjection (app);
app.Init (driverName);
// Example 1: Use extension method with result extraction

View File

@@ -13,12 +13,13 @@ public static class ExampleContextInjector
/// Sets up automatic key injection if a test context is present in the environment.
/// Call this method before calling <see cref="Application.Init"/> or <see cref="IApplication.Init"/>.
/// </summary>
/// <param name="app"></param>
/// <remarks>
/// This method is safe to call multiple times - it will only set up injection once.
/// The actual key injection happens after the application is initialized, via the
/// <see cref="Application.InitializedChanged"/> event.
/// </remarks>
public static void SetupAutomaticInjection ()
public static void SetupAutomaticInjection (IApplication? app)
{
if (_initialized)
{
@@ -43,19 +44,15 @@ public static class ExampleContextInjector
}
// Subscribe to InitializedChanged to inject keys after initialization
Application.InitializedChanged += OnInitializedChanged;
app.SessionBegun += AppOnSessionBegun;
return;
void OnInitializedChanged (object? sender, EventArgs<bool> e)
void AppOnSessionBegun (object? sender, SessionTokenEventArgs e)
{
if (!e.Value)
{
return;
}
// Application has been initialized, inject the keys
if (Application.Driver is null)
if (app.Driver is null)
{
return;
}
@@ -64,12 +61,12 @@ public static class ExampleContextInjector
{
if (Input.Key.TryParse (keyStr, out Input.Key? key) && key is { })
{
Application.Driver.EnqueueKeyEvent (key);
app.Keyboard.RaiseKeyDownEvent (key);
}
}
// Unsubscribe after injecting keys once
Application.InitializedChanged -= OnInitializedChanged;
app.SessionBegun -= AppOnSessionBegun;
}
}
}

View File

@@ -69,29 +69,47 @@ public static class ExampleRunner
}
ParameterInfo [] parameters = entryPoint.GetParameters ();
object? result = null;
if (parameters.Length == 0)
Task executionTask = Task.Run (() =>
{
result = entryPoint.Invoke (null, null);
}
else if (parameters.Length == 1 && parameters [0].ParameterType == typeof (string []))
{
result = entryPoint.Invoke (null, [Array.Empty<string> ()]);
}
else
object? result = null;
if (parameters.Length == 0)
{
result = entryPoint.Invoke (null, null);
}
else if (parameters.Length == 1 && parameters [0].ParameterType == typeof (string []))
{
result = entryPoint.Invoke (null, [Array.Empty<string> ()]);
}
else
{
throw new InvalidOperationException ("Entry point has unsupported signature");
}
// If entry point returns Task, wait for it
if (result is Task task)
{
task.GetAwaiter ().GetResult ();
}
});
bool completed = executionTask.Wait (context.TimeoutMs);
if (!completed)
{
// reset terminal
Console.Clear ();
return new ()
{
Success = false,
ErrorMessage = "Entry point has unsupported signature"
TimedOut = true
};
}
// If entry point returns Task, wait for it
if (result is Task task)
if (executionTask.Exception is { })
{
task.GetAwaiter ().GetResult ();
throw executionTask.Exception.GetBaseException ();
}
return new ()

View File

@@ -127,6 +127,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentExample", "Examples\F
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RunnableWrapperExample", "Examples\RunnableWrapperExample\RunnableWrapperExample.csproj", "{26FDEE3C-9D1F-79A6-F48F-D0944C7F09F8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleRunner", "Examples\ExampleRunner\ExampleRunner.csproj", "{2CB35142-AAD4-D424-61D3-88F9C94AD62A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -209,6 +211,10 @@ Global
{26FDEE3C-9D1F-79A6-F48F-D0944C7F09F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26FDEE3C-9D1F-79A6-F48F-D0944C7F09F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26FDEE3C-9D1F-79A6-F48F-D0944C7F09F8}.Release|Any CPU.Build.0 = Release|Any CPU
{2CB35142-AAD4-D424-61D3-88F9C94AD62A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2CB35142-AAD4-D424-61D3-88F9C94AD62A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CB35142-AAD4-D424-61D3-88F9C94AD62A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CB35142-AAD4-D424-61D3-88F9C94AD62A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE