Leith.Term.Presentation.Gui.Definitions 435.0.0

Leith.Term.Presentation

Leith — pronounced /liːθ/; in Scottish English, like leaf.

Terminal hosting for .NET: open local PTY or SSH sessions, drive input and process APIs, and render the visible terminal grid with framework-neutral presentation contracts or SkiaSharp.

Status: 0.1.0 pre-publication, not yet published — a private prototype under active development. There is no compatibility promise yet: the public API baselines are a drift detector, not a freeze, and the surface is expected to be reshaped before the first release. During the current Leith.Term refactor, baseline snapshot tests are suspended — see Docs/BASELINE_TESTS_SUSPENDED.md. Read ../Leith.Workspace/PRE_PUBLICATION.md for which constraints in this documentation are live and which describe the state at publication; see the 0.1.0 shipping record before publishing.

Packages

NuGet IDs match assembly names (Leith.Term.Presentation.*). The IDs below describe the current release candidate.

Package ID Role
Leith.Term.Presentation.Abstractions Host/session contracts, snapshots, transports, and features
Leith.Term.Presentation.Integration Semantic input contracts and the framework-neutral session input router
Leith.Term.Presentation.Session Host factory and session host over the Leith.Term engine
Leith.Term.Presentation.Transport.Local Cross-platform local PTY through sibling Leith.Pty
Leith.Term.Presentation.Transport.Ssh SSH PTY through sibling Tmds.Ssh
Leith.Term.Presentation.Host.Platform A ready-to-open request for the current OS shell
Leith.Term.Presentation.Host.Avalonia Avalonia composition root for hosts and transports
Leith.Term.Presentation.Host.ProGpu ProGPU composition root for hosts and transports
Leith.Term.Presentation.Gui.Definitions Framework-neutral frames, geometry, presentation, and themes
Leith.Term.Presentation.Rendering.Skia Font metrics and a canvas presenter for SkiaSharp
Leith.Term.Presentation.Control.Avalonia Avalonia terminal control

All packages target .NET 10.

Engine (Leith.Term)

The VT emulator engine lives in the sibling repo Leith.Term.Engine (../Leith.Term.Engine/ next to this checkout). Leith.Term.Presentation.Session references the Leith.Term package from that repo via ProjectReference. Engine tests and benchmarks run in Leith.Term.Engine, not here.

Current product path: Session owns Leith.Term.Terminal directly. Local transport is sibling Leith.Pty Dedicated. Performance status: Benchmarks/results/PERFORMANCE_STATUS.md.

Avalonia quick start

Install the UI package, plus Leith.Term.Presentation.Host.Avalonia for the local shell request:

<PackageReference Include="Leith.Term.Presentation.Control.Avalonia" Version="0.1.0" />
<PackageReference Include="Leith.Term.Presentation.Host.Avalonia" Version="0.1.0" />

Control.Avalonia deliberately does not depend on Host.Avalonia: which shell to launch is an application decision, and an SSH-only consumer has no use for it. Take Host.Avalonia when you want the ready-made local shell request below.

Apply the styles once during application initialization, then open and display a session:

using Leith.Term.Presentation.Abstractions;
using Leith.Term.Presentation.Control.Avalonia.Controls;
using Leith.Term.Presentation.Control.Avalonia.Styling;
using Leith.Term.Presentation.Host;
using Leith.Term.Presentation.Host.Avalonia;

TerminalControlStyles.Apply(application);

var host = AvaloniaTerminalHost.CreateLocal();
var open = await host.OpenAsync(LocalTerminalRequestFactory.CreateDefault());
if (open.Status == TerminalOperationStatus.Succeeded && open.Session is { } session)
{
    Content = SessionTerminalControlFactory.CreateWithSkiaMetrics(session);
}

// Keep the host for the lifetime of the UI. During application shutdown:
// await host.DisposeAsync();

The complete runnable version is in src/samples/AvaloniaHelloTerminal. For a full capability gallery, see AvaloniaFeatureGallery.

Custom Skia canvas quick start

Other Skia hosts use the same public presenter:

using SkiaSharp;
using Leith.Term.Presentation.Rendering.Skia;

using var presenter = new TerminalSkiaCanvasPresenter(session);
presenter.Invalidated += (_, _) => InvalidateCanvas();

// In the framework's size callback:
await presenter.ResizeAsync(width, height, renderScale);

// In the framework's paint callback:
presenter.Render(canvas, SKRect.Create(width, height), renderScale);

The terminal host must receive a real UI dispatcher. ImmediateGuiDispatcher is intended for tests and headless tools, not for a live UI session.

Composition and lifetime

Leith.Term.Presentation uses Pure DI by default. The composition root lives in the application (or a platform package such as Leith.Term.Presentation.Host.Avalonia), not inside GUI controls.

Component Lifetime Notes
ITerminalHost Singleton per app Owns open sessions; dispose on shutdown
ITerminalSession Per open Created by OpenAsync; dispose with host or CloseAsync
ITerminalTransportProvider Singleton Registered in the composition root
IGuiDispatcher Singleton Must match the UI thread
ITerminalFontMetricsProvider Singleton or transient Injected into controls via SessionTerminalControlFactory

TerminalHostFactory.Create is the canonical Pure DI entry point. If you already use a container, every package registers the piece it owns:

using Leith.Term.Presentation.Host.Avalonia;   // AddAvaloniaTerminalHost
using Leith.Term.Presentation.Transport.Local; // AddLocalPtyTransport

services.AddAvaloniaTerminalHost()    // Avalonia dispatcher + ITerminalHost
        .AddLocalPtyTransport();      // the "local" transport

// Shut down asynchronously - the host owns child processes and PTYs:
await serviceProvider.DisposeAsync();

Host.ProGpu exposes the same shape. Add AddSshTransport() for SSH; transports accumulate rather than replace each other.

Call Add…TerminalHost from the UI thread — the dispatcher is built there — and dispose the container with DisposeAsync, not Dispose.

GUI packages (Control.Avalonia) depend only on abstractions and rendering contracts — they do not reference Session or Transport.*. Use Host.Avalonia to wire dispatcher, transports, and host together.

Headless or custom composition

Packages: Leith.Term.Presentation.Session, Leith.Term.Presentation.Transport.Local, Leith.Term.Presentation.Host.Platform.

using Leith.Term.Presentation.Abstractions;
using Leith.Term.Presentation.Host;
using Leith.Term.Presentation.Session;
using Leith.Term.Presentation.Transport.Local;

ITerminalHost host = TerminalHostFactory.Create(
    dispatcher,
    [new LocalPtyTerminalTransportProvider()]);

var open = await host.OpenAsync(LocalTerminalRequestFactory.CreateDefault());
if (open.Session is { } session)
{
    await session.Input.SendLineAsync("dotnet --info");
    var snapshot = session.Screen.GetSnapshot();
}

Runnable samples

Sample What it demonstrates Requirement
AvaloniaHelloTerminal Full Avalonia terminal control Windows, macOS, or Linux

The canvas samples deliberately use a command box instead of pretending to be complete terminal controls. A production control must additionally handle key chords, IME, paste, selection, mouse protocols, focus, and accessibility.

In-tree backends

Alongside the shipped Avalonia package the repository contains the ProGPU control under src/Gui/Gui.Control/. It is not packable and is not published; build it from source. Whether it ships is an open decision — see 0.1.0 shipping record.

To write a backend for another framework, see Docs/BACKEND_AUTHOR_GUIDE.md.

Consumer API

The canonical boundary is ITerminalHost / ITerminalSession:

  • Screen — read-only size, title, and neutral snapshots
  • Features — optional features discovered through TryGet<T>()
  • Input — bytes, text, or complete lines
  • Process — commands, working directory, reconnect, and stop
  • ResizeAsync — grid resize propagated to the transport

Shipping assemblies expose no engine types. Expected operational failures return TerminalOperationResult or TerminalOpenResult; programmer errors throw. Cancellation cancels the current operation, not the lifetime of the child process.

Build, test, and pack

The repository pins the stable .NET 10 SDK in global.json.

dotnet build Term.Presentation.slnx -c Release
dotnet test Term.Presentation.slnx -c Release --no-build
dotnet pack Term.Presentation.slnx -c Release -o artifacts/nupkg

The normal suite is hermetic. The SSH live smoke is opt-in through TERMINAL_SHARP_SSH_LIVE=1 and TERMINAL_SHARP_SSH_LIVE_ALIAS=<ssh-config-alias>.

Repository layout

Path Role
src/Abstractions Public contracts
src/Session Host and internal engine session
src/Transport/Transport.Local, Transport.Ssh Local PTY and SSH transports
src/Host/Host.Platform OS shell resolvers and the default local-shell request
src/Host/Host.* Per-framework composition roots (dispatcher + transports + host)
src/Gui/Gui.Definitions Framework-neutral presentation, framing, and input decisions
src/Gui/Gui.Rendering/Rendering.Skia Skia glyph shaping and canvas presenter
src/Gui/Gui.Control/Control.* UI backends; only Control.Avalonia ships as a package
src/samples Runnable integration examples
src/Tests Contract, session, architecture, and backend tests
Docs Architecture, adapter, and release notes

License

Leith.Term.Presentation is MIT-licensed; see LICENSE.

The embedded Symbols Nerd Font Mono carries its own license in THIRD-PARTY. Builtin box-drawing tables follow Windows Terminal's MIT-licensed BuiltinGlyphs.cpp; source provenance is recorded in the relevant files. NuGet dependencies retain their own licenses.

Governance: ../Leith.Workspace/. Build/test: product Docs/ and this README.

Avalonia is a registered trademark of AvaloniaUI OÜ. Leith.Term.Presentation is an independent project and is not affiliated with or endorsed by AvaloniaUI OÜ.

Showing the top 20 packages that depend on Leith.Term.Presentation.Gui.Definitions.

Packages Downloads
Leith.Term.Presentation.Control.Avalonia
Avalonia terminal control for Leith.Term.Presentation.
0
Leith.Term.Presentation.Rendering.Skia
Skia rendering and font-metrics backend for Leith.Term.Presentation.
0
Leith.Term.Presentation.Session
Leith.Term.Presentation session host over the Leith.Term engine.
0

Version Downloads Last updated
435.0.0 0 10/01/2026
432.0.0 0 10/01/2026
430.0.0 0 10/01/2026
428.0.0 0 10/01/2026
422.0.0 0 09/30/2026
420.0.0 0 09/30/2026
418.0.0 0 09/30/2026
416.0.0 0 09/30/2026
414.0.0 0 09/30/2026
412.0.0 0 09/30/2026
410.0.0 0 09/30/2026
409.0.0 0 09/30/2026
407.0.0 0 09/30/2026
405.0.0 0 09/30/2026
403.0.0 0 09/30/2026
401.0.0 0 09/30/2026
399.0.0 0 09/30/2026
387.0.0 0 09/29/2026
386.0.0 0 09/29/2026
382.0.0 0 09/28/2026
381.0.0 0 09/28/2026
380.0.0 0 09/28/2026
379.0.0 0 09/28/2026
378.0.0 0 09/28/2026
377.0.0 0 09/28/2026
376.0.0 0 09/28/2026
375.0.0 0 09/28/2026
374.0.0 0 09/28/2026
373.0.0 0 09/28/2026