Leith.Term.Kernel 431.0.0
Leith.Term.Engine
Git: github.com/buchmiet/Leith.Term.Engine — clone as
Leith.Term.Engine/ (sibling of Leith.Term.Presentation, Leith.Text, …).
Standalone VT/xterm-class terminal engine extracted from Leith.Term.Presentation.
The main library ships as Leith.Term (NuGet id, assembly, and root namespace).
Contents
src/Term/— publicTerminalfacade over the kernelsrc/Kernel/— terminal kernel (grid, modes, graphics, journal, effects)src/VtParser/— standalone VT parser the kernel consumes- sibling
Leith.Imaging— owns the dependency-free PNG, GIF and SIXEL codecs consumed by the engine src/Tests/Tests.Engine/— engine test suite and corporasrc/Tests/Tests.Scenarios/— scenario runner and acceptance corpus shared by the test projectsBenchmarks/Engine.*— decode/parser/SIMD benchmarkstools/kitty-oracle,tools/kitty-keyboard-oracle— Kitty corpus tooling
Build
dotnet build Term.Engine.slnx -c Release
dotnet test --solution Term.Engine.slnx -c Release
The test suites are xunit.v3 4.x, which are self-hosting Microsoft.Testing.Platform applications rather
than VSTest assemblies, and global.json opts dotnet test into that runner. Two consequences worth
knowing before the first confusing result: the project or solution has to be named with --project /
--solution, because a bare positional path is accepted and then quietly runs nothing ("Zero tests ran");
and the reporting switches differ — --report-xunit-trx in place of --logger trx. Each test project is
also directly executable, which is the quickest way to run one suite.
Kitty corpus tests may require LEITH_KGP_CORPUS / homelab checkout — see tools/kitty-oracle/README.md.
IIP codecs
Leith.Term decodes OSC 1337 PNG through Leith.Imaging.Png and GIF through Leith.Imaging.Gif.
Other IIP formats remain opt-in via TerminalGraphicsOptions.ImageDecoder. JPEG, WebP, TIFF and
similar are host business; the engine does not reference ImageSharp.
SIXEL and Jexer gallery tests still use SixLabors.ImageSharp 3.1.x as a test-only PNG reader.
That package is not referenced by shipping code and does not gate Leith.Term.slnx on a Six Labors
license.
Minimal 0.1.0 host wiring (public API only)
raw PTY bytes
↓
Terminal.Process(ReadOnlySpan<byte>)
↓
committed terminal state (Screen, modes, Title, …)
↓
TerminalMutationResult.EffectRange
↓
Terminal.DrainEffects(range) → PtyBytes / HostQuery / WindowOp / Bell
Terminal is not thread-safe: serialize Process, input APIs, DrainEffects, and reads on one lock.
using System.Text;
using Leith.Term;
using Leith.Term.Events;
using Leith.Term.Input;
var options = new TerminalOptions
{
Columns = 120,
Rows = 40,
ScrollbackLines = 10_000,
WindowPermissions = TerminalWindowPermissions.GetGeometryPixels
| TerminalWindowPermissions.ManipulateWindow,
};
using var terminal = new Terminal(options);
long renderWatermark = terminal.Screen.GetViewportChangeSet().ChangeSequence;
void OnPtyBytes(ReadOnlySpan<byte> data)
{
var remaining = data;
while (remaining.Length > 0)
{
var result = terminal.Process(remaining);
foreach (var effect in terminal.DrainEffects(result.EffectRange).Effects)
{
switch (effect.Kind)
{
case TerminalEffectKind.PtyBytes:
pty.Write(effect.Bytes.Span);
break;
case TerminalEffectKind.HostQuery when effect.HostQuery is { } query:
if (TerminalHostQueryReplies.TryEncode(
query,
new WindowCharDimensionsInfo(host.VisibleRows, host.VisibleColumns),
out var wire))
{
OnPtyBytes(wire.Span);
}
break;
case TerminalEffectKind.WindowOp:
host.ApplyWindowOp(effect.WindowOp);
break;
case TerminalEffectKind.Bell:
host.RingBell();
break;
}
}
if (result.Status == ProcessStatus.OutputFull)
{
remaining = remaining[result.Consumed..];
continue;
}
if (terminal.Screen.IsFullDamageSince(renderWatermark))
renderer.InvalidateFull();
else
renderer.InvalidateRows(terminal.Screen, renderWatermark);
renderWatermark = result.ChangeSequence;
remaining = remaining[result.Consumed..];
}
}
var key = terminal.SendKey(new TerminalKeyEvent(TerminalKey.FromRune(new Rune('a')))
{
Modifiers = TerminalKeyModifiers.Control,
});
DrainInputEffects(key);
terminal.SendText("日本語");
terminal.Paste(clipboardText);
terminal.SendMouse(new TerminalMouseEvent(
TerminalMouseEventType.Down,
TerminalMouseButton.Left,
column,
row));
terminal.SendFocus(true);
var line = terminal.Screen.GetViewportLine(0);
if (line is not null)
{
var cell = line.GetCell(0);
Draw(cell);
}
void DrainInputEffects(TerminalMutationResult result)
{
foreach (var effect in terminal.DrainEffects(result.EffectRange).Effects)
{
if (effect.Kind == TerminalEffectKind.PtyBytes)
{
pty.Write(effect.Bytes.Span);
}
}
}
Accidental public API growth is guarded by PublicApiBaselineTests and the checked-in
Leith.Term.PublicApi.baseline.txt snapshot. The public API baseline is enforced
(BaselineTestPolicy.Enabled = true). Kitty/sixel oracle snapshots remain research-only;
see Docs/BASELINE_TESTS_SUSPENDED.md.
Regenerate the tracked public API baseline with
UPDATE_PUBLIC_API_BASELINE=1 dotnet test --project src/Tests/Tests.Engine/Tests.Engine.csproj --filter PublicApi_MatchesCheckedInBaseline.
Headless architecture
Docs/HEADLESS_ARCHITECTURE.md is the authoritative model for
headless use: Terminal as the engine, Screen vs Terminal.Graphics, explicit time, and the
removal of TerminalEngine. Superseded draft: Docs/HEADLESS_ENGINE_API.md.
CLI dependency policy (sibling repo): Docs/Leith.Cli_DEPENDENCY_POLICY.md.
History
Git history was extracted from Leith.Term.Presentation with git filter-repo (engine-related paths only). Terminal remains the integration repo for Session, hosts, transport, and rendering.
License
MIT — see LICENSE and THIRD-PARTY-NOTICES.md.
Showing the top 20 packages that depend on Leith.Term.Kernel.
| Packages | Downloads |
|---|---|
|
Leith.Term
Leith VT/xterm-class terminal engine (.NET 10). See https://github.com/buchmiet/Leith.Term.Engine.
|
34 |
|
Leith.Term
Leith VT/xterm-class terminal engine (.NET 10). See https://github.com/buchmiet/Leith.Term.Engine.
|
3 |
|
Leith.Term
Leith VT/xterm-class terminal engine (.NET 10). See https://github.com/buchmiet/Leith.Term.Engine.
|
0 |
.NET 10.0
- Leith.Term.VtParser (>= 431.0.0)
- Leith.Imaging.Gif (>= 286.0.0)
- Leith.Imaging.Kitty (>= 286.0.0)
- Leith.Imaging.Model (>= 286.0.0)
- Leith.Imaging.Png (>= 286.0.0)
- Leith.Imaging.Sixel (>= 286.0.0)
- Leith.Text (>= 59.0.0)