Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6ab8f35
feat: help TUI viewer, markdown rendering, rename ExampleApp to greet
tig May 24, 2026
4ab71d8
Fix terminal encoding for ANSI rendering and add multiple help topics
tig May 24, 2026
f353898
Add default command support, help link navigation, and fix positional…
tig May 24, 2026
54fb655
Port clet's BrowseBar with back/forward nav and syntax highlighting
tig May 24, 2026
dd6d7d7
Add visual help browser tests and greet example execution tests
tig May 24, 2026
0315803
Escape markdown table cells in MetadataHelpProvider
tig May 24, 2026
ddd82e3
fix: use explicit type in collection expression for ReSharper compliance
tig May 24, 2026
d54b075
Merge pull request #7 from gui-cs/tig/help-tui-viewer-and-rename-exam…
tig May 24, 2026
adb8e35
Merge pull request #10 from gui-cs/tig/readme-and-hero-gif
tig May 26, 2026
cbec53d
Add SourceLink and symbol package support (#11)
tig May 26, 2026
e666545
Back-merge main into develop (#13)
tig May 26, 2026
e8e61bc
Fix MarkdownRenderer global state leaks (#14)
tig May 27, 2026
31199e0
fix: set IApplication.AppModel and defer Init() for inline input comm…
tig May 28, 2026
f4398a8
fix: centralize Terminal.Gui lifecycle for headless markdown renderin…
tig Jun 11, 2026
8464565
Library improvements extracted from survey example work (#23)
tig Jun 11, 2026
6ccf07d
chore: bump version to 0.2.0-develop for upcoming release
tig Jun 11, 2026
fa1e9b3
Back-merge v0.2.0 from main into develop (#25)
tig Jun 11, 2026
c964cab
fix: restore Application.AppModel after dispatch and lock in init con…
tig Jun 11, 2026
709bd1d
chore: bump version to 0.2.1-develop for upcoming release
tig Jun 11, 2026
f1ef14b
Merge remote-tracking branch 'origin/main' into release/v0.2.1
tig Jun 11, 2026
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 Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<Company>gui-cs</Company>
<Copyright>Copyright (c) gui-cs and contributors</Copyright>

<Version>0.2.0-develop</Version>
<Version>0.2.1-develop</Version>
<PackageProjectUrl>https://github.com/gui-cs/cli</PackageProjectUrl>
<RepositoryUrl>https://github.com/gui-cs/cli</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand Down
18 changes: 15 additions & 3 deletions src/Terminal.Gui.Cli/CliHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,24 @@ private async Task<CommandResult> RunWithTerminalGuiAsync (ICliCommand command,
CancellationToken cancellationToken)
{
var useInline = command.Kind == CommandKind.Input && !runOptions.Fullscreen;

// Application.AppModel is process-wide state; restore it after dispatch so later
// Terminal.Gui sessions in the same process (embedding, headless rendering) do not
// inherit this command's app model.
AppModel previousAppModel = Application.AppModel;
Application.AppModel = useInline ? AppModel.Inline : AppModel.FullScreen;

using IApplication app = Application.Create ();
app.Init ();
try
{
using IApplication app = Application.Create ();
app.Init ();

return await command.RunAsync (app, runOptions.Initial, runOptions, cancellationToken);
return await command.RunAsync (app, runOptions.Initial, runOptions, cancellationToken);
}
finally
{
Application.AppModel = previousAppModel;
}
}

private void WriteRootFlag (ArgParser.RootFlag rootFlag, TextWriter stdout)
Expand Down
77 changes: 76 additions & 1 deletion tests/Terminal.Gui.Cli.IntegrationTests/AppModelDispatchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,85 @@ namespace Terminal.Gui.Cli.IntegrationTests;

/// <summary>
/// Verifies that CliHost.RunWithTerminalGuiAsync sets IApplication.AppModel
/// correctly based on CommandKind and the --fullscreen option.
/// correctly based on CommandKind and the --fullscreen option, initializes the
/// application before dispatching (issue #18), and restores the process-wide
/// Application.AppModel after dispatch (issue #26).
/// </summary>
public sealed class AppModelDispatchTests
{
[Fact]
public async Task InputCommand_Inline_ReceivesInitializedApplication ()
{
// ICliCommand.RunAsync contract: commands run after the host has initialized
// Terminal.Gui, including on the inline input path (issue #18).
bool? initialized = null;
SpyInputCommand spy = new (app => initialized = app.Initialized);

CliHost host = new ();
host.Registry.Register (spy);
using StringWriter stdout = new ();
using StringWriter stderr = new ();

await host.RunAsync (["spy-input"], TestContext.Current.CancellationToken, stdout, stderr);

Assert.True (initialized);
}

[Fact]
public async Task InputCommand_Inline_RestoresAppModelAfterDispatch ()
{
// Application.AppModel is process-wide; leaving it set to Inline after dispatch
// makes later Terminal.Gui sessions in the same process inherit it (issue #26).
AppModel before = Application.AppModel;

try
{
Application.AppModel = AppModel.FullScreen;
SpyInputCommand spy = new (_ => { });

CliHost host = new ();
host.Registry.Register (spy);
using StringWriter stdout = new ();
using StringWriter stderr = new ();

await host.RunAsync (["spy-input"], TestContext.Current.CancellationToken, stdout, stderr);

Assert.Equal (AppModel.FullScreen, Application.AppModel);
}
finally
{
Application.AppModel = before;
}
}

[Fact]
public async Task InputCommand_ThrowsCancellation_RestoresAppModel ()
{
// The restore must also happen when the command throws (issue #26).
AppModel before = Application.AppModel;

try
{
Application.AppModel = AppModel.FullScreen;
SpyInputCommand spy = new (_ => throw new OperationCanceledException ());

CliHost host = new ();
host.Registry.Register (spy);
using StringWriter stdout = new ();
using StringWriter stderr = new ();

var exitCode = await host.RunAsync (["spy-input"], TestContext.Current.CancellationToken, stdout,
stderr);

Assert.Equal (ExitCodes.Cancelled, exitCode);
Assert.Equal (AppModel.FullScreen, Application.AppModel);
}
finally
{
Application.AppModel = before;
}
}

[Fact]
public async Task InputCommand_WithoutFullscreen_SetsInlineAppModel ()
{
Expand Down
Loading