Skip to content

Commit 155c717

Browse files
committed
UICatalog scenario to open another scenario process and return some result
1 parent e199063 commit 155c717

File tree

4 files changed

+173
-2
lines changed

4 files changed

+173
-2
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#nullable enable
2+
3+
using System.Diagnostics;
4+
using System.IO.Pipes;
5+
using System.Text.Json;
6+
7+
namespace UICatalog.Scenarios;
8+
9+
[ScenarioMetadata ("OpenChildInAnotherProcess", "Open Child In Another Process")]
10+
[ScenarioCategory ("Application")]
11+
public sealed class OpenChildInAnotherProcess : Scenario
12+
{
13+
public override void Main ()
14+
{
15+
IApplication app = Application.Create ();
16+
17+
app.Init ();
18+
19+
// Setup - Create a top-level application window and configure it.
20+
Window appWindow = new ()
21+
{
22+
Title = GetQuitKeyAndName (),
23+
BorderStyle = LineStyle.None
24+
};
25+
26+
var label = new Label { X = Pos.Center (), Y = 3 };
27+
28+
var button = new Button ()
29+
{
30+
X = Pos.Center (),
31+
Y = 1,
32+
Title = "_Open Child In Another Process",
33+
};
34+
35+
button.Accepting += async (_, e) =>
36+
{
37+
// When Accepting is handled, set e.Handled to true to prevent further processing.
38+
button.Enabled = false;
39+
e.Handled = true;
40+
label.Text = await OpenNewTerminalWindowAsync<string> ("EditName");
41+
button.Enabled = true;
42+
};
43+
44+
appWindow.Add (button, label);
45+
46+
app.Run (appWindow);
47+
appWindow.Dispose ();
48+
49+
app.Shutdown ();
50+
}
51+
52+
public async Task<T> OpenNewTerminalWindowAsync<T> (string action)
53+
{
54+
string pipeName = "RunChildProcess";
55+
56+
// Start named pipe server before launching child
57+
var server = new NamedPipeServerStream (pipeName, PipeDirection.In);
58+
59+
// Launch external console process running UICatalog app again
60+
var p = new Process ();
61+
p.StartInfo.FileName = Environment.ProcessPath!;
62+
p.StartInfo.Arguments = $"{pipeName} --child --action \"{action}\"";
63+
p.StartInfo.UseShellExecute = true; // Needed so it opens a new terminal window
64+
p.Start ();
65+
66+
// Wait for connection from child
67+
await server.WaitForConnectionAsync ();
68+
69+
using var reader = new StreamReader (server);
70+
string json = await reader.ReadToEndAsync ();
71+
72+
return JsonSerializer.Deserialize<T> (json)!;
73+
}
74+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#nullable enable
2+
3+
using System.IO.Pipes;
4+
using System.Text.Json;
5+
6+
namespace UICatalog.Scenarios;
7+
8+
[ScenarioMetadata ("RunChildProcess", "Run Child Process from Open Child In Another Process")]
9+
[ScenarioCategory ("Application")]
10+
public sealed class RunChildProcess : Scenario
11+
{
12+
public static async Task RunChildAsync (string pipeName, string action)
13+
{
14+
// Run your Terminal.Gui UI
15+
object result = await RunMyDialogAsync (action);
16+
17+
// Send result back
18+
await using var client = new NamedPipeClientStream (".", pipeName, PipeDirection.Out);
19+
await client.ConnectAsync ();
20+
21+
string json = JsonSerializer.Serialize (result);
22+
await using var writer = new StreamWriter (client);
23+
await writer.WriteAsync (json);
24+
await writer.FlushAsync ();
25+
}
26+
27+
public static Task<string> RunMyDialogAsync (string action)
28+
{
29+
TaskCompletionSource<string> tcs = new ();
30+
string? result = null;
31+
32+
IApplication app = Application.Create ();
33+
34+
app.Init ();
35+
36+
var win = new Window ()
37+
{
38+
Width = Dim.Fill (),
39+
Height = Dim.Fill (),
40+
Title = $"Child Window: {action}"
41+
};
42+
43+
var input = new TextField
44+
{
45+
X = 1,
46+
Y = 1,
47+
Width = 30
48+
};
49+
50+
var ok = new Button
51+
{
52+
X = 1,
53+
Y = 3,
54+
Text = "Ok",
55+
IsDefault = true
56+
};
57+
ok.Accepting += (_, e) =>
58+
{
59+
result = input.Text;
60+
app.RequestStop ();
61+
e.Handled = true;
62+
};
63+
64+
win.Add (input, ok);
65+
66+
app.Run (win);
67+
win.Dispose ();
68+
app.Shutdown ();
69+
70+
tcs.SetResult (result ?? string.Empty);
71+
72+
return tcs.Task;
73+
}
74+
}

Examples/UICatalog/UICatalog.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using Serilog;
2626
using Serilog.Core;
2727
using Serilog.Events;
28+
using UICatalog.Scenarios;
2829
using Command = Terminal.Gui.Input.Command;
2930
using ILogger = Microsoft.Extensions.Logging.ILogger;
3031

@@ -141,9 +142,18 @@ private static int Main (string [] args)
141142
.ToArray ()
142143
);
143144

145+
Option<bool> childOption = new ("--child", "Run in child mode");
146+
147+
Option<string> actionOption = new (
148+
name: "--action",
149+
description: "Optional action for child window",
150+
getDefaultValue: () => string.Empty
151+
);
152+
144153
var rootCommand = new RootCommand ("A comprehensive sample library and test app for Terminal.Gui")
145154
{
146-
scenarioArgument, debugLogLevel, benchmarkFlag, benchmarkTimeout, resultsFile, driverOption, disableConfigManagement
155+
scenarioArgument, debugLogLevel, benchmarkFlag, benchmarkTimeout, resultsFile, driverOption, disableConfigManagement,
156+
childOption, actionOption
147157
};
148158

149159
rootCommand.SetHandler (
@@ -157,7 +167,9 @@ private static int Main (string [] args)
157167
Benchmark = context.ParseResult.GetValueForOption (benchmarkFlag),
158168
BenchmarkTimeout = context.ParseResult.GetValueForOption (benchmarkTimeout),
159169
ResultsFile = context.ParseResult.GetValueForOption (resultsFile) ?? string.Empty,
160-
DebugLogLevel = context.ParseResult.GetValueForOption (debugLogLevel) ?? "Warning"
170+
DebugLogLevel = context.ParseResult.GetValueForOption (debugLogLevel) ?? "Warning",
171+
IsChild = context.ParseResult.GetValueForOption (childOption),
172+
Action = context.ParseResult.GetValueForOption (actionOption) ?? string.Empty
161173
/* etc. */
162174
};
163175

@@ -380,6 +392,13 @@ private static void UICatalogMain (UICatalogCommandLineOptions options)
380392
)!);
381393
UICatalogTop.CachedSelectedScenario = (Scenario)Activator.CreateInstance (UICatalogTop.CachedScenarios [item].GetType ())!;
382394

395+
if (options.IsChild)
396+
{
397+
Task.Run (async () => await RunChildProcess.RunChildAsync (UICatalogTop.CachedSelectedScenario.GetName (), options.Action)).Wait ();
398+
399+
return;
400+
}
401+
383402
BenchmarkResults? results = RunScenario (UICatalogTop.CachedSelectedScenario, options.Benchmark);
384403

385404
if (results is { })

Examples/UICatalog/UICatalogCommandLineOptions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,9 @@ public struct UICatalogCommandLineOptions
1616
public string ResultsFile { get; set; }
1717

1818
public string DebugLogLevel { get; set; }
19+
20+
public bool IsChild { get; set; }
21+
22+
public string Action { get; set; }
1923
/* etc. */
2024
}

0 commit comments

Comments
 (0)