Skip to content

Latest commit

 

History

2,314 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Icod.Terminal

Icod TUI Toolchain

PR Staging build Main Release validation

Icod.Terminal is a managed, cross-platform live-terminal session and terminal-control library for .NET. It combines immutable terminal capability data from Icod.TermInfo with live endpoint observation, input, queries, semantic output, screen-operation planning, and terminal-state ownership for higher-level consumers such as TUI libraries, command-line tools, monitors, editors, pagers, and REPLs.

Status

Current stable release: Icod.Terminal 1.20.0.

Version 1.20 adds immutable screen-advertisement facts, fixes generation and late-response ownership in existing support verification, and expands the capability guide and runnable sample. Static advertisement, concrete plans, live support evidence, and endpoint availability remain separate decisions.

Version 1.18 adds TerminalScreenPlanner.PlanRenditionBaseline(), allowing a Terminal-only renderer to establish the normalized default rendition safely when the physical starting state is unknown. The operation returns no plan when any profile-exposed rendition axis cannot be restored unconditionally.

Version 1.17 adds Terminal-owned dimensions, an immutable semantic terminal profile, side-effect-free screen-operation planning, and bounded session-bound output transactions. These contracts provide the Terminal-side boundary used by the decoupled Icod.DCurses 2.x renderer.

The stable 1.0.0 compatibility floor remains unchanged. Version 1.20 retains every 1.19 public signature and enum value, adding nine read-only advertisement properties and three kind-based queries. Existing screen planning, transactions, rendition, raster, input, and lifecycle contracts remain available.

See the 1.20.0 release notes and changelog for release-specific details.

Support the Project

Icod.Terminal and its ecosystem packages (Icod.TermInfo and Icod.DCurses) are built and maintained by a solo developer. If these packages save you or your team time, please consider supporting their continued development and maintenance.

GitHub Sponsors Ko-fi PayPal

Architecture

Icod.Terminal is the live-session layer of the Icod terminal stack. The Icod.DCurses 2.x dependency direction is:

higher-level terminal applications
             |
        Icod.DCurses
             |
        Icod.Terminal
             |
        Icod.TermInfo
             |
       terminal / console
  • Icod.TermInfo owns immutable terminal capability data, compiled terminfo acquisition, and capability expansion.
  • Icod.Terminal owns the live terminal conversation: endpoint observation, native modes, input decoding, lifecycle, active queries, semantic events, capability evidence/planning, semantic output, raster execution, persistent raster resource/placement/placeholder/animation ownership, and reversible/scoped terminal state.
  • Icod.DCurses owns higher-level cells, windows, pads, retained presentation state, layout, clipping, scrolling, refresh/diff policy, damage, and curses-style interaction abstractions.
  • PTY/process hosting remains orthogonal to the Icod.Terminal runtime contract.

Published Icod.DCurses 1.6.0 remains the compatibility baseline and directly references both Icod.Terminal and Icod.TermInfo. Published Icod.DCurses 2.2.0 is also qualified and depends directly only on Icod.Terminal; Terminal continues to use TermInfo internally.

The direct production dependency graph is intentionally small:

Icod.Terminal
├── Icod.TermInfo 1.16.0
└── Icod.Timing   1.0.0

Icod.TermInfo.Inspection 1.16.0 is used only by optional integration tests and samples. It is not a production dependency of Icod.Terminal. Its raster-backend planner remains caller-side advisory policy rather than part of Terminal's production router.

See docs/Architecture.md for the permanent architecture contract.

Quick Start

Install this version:

dotnet add package Icod.Terminal --version 1.20.0

Open a managed terminal session, write application text, and read through the authoritative event path:

using Icod.Terminal;

await using TerminalSession session = await TerminalSession.OpenAsync(
	new TerminalSessionOptions {
		InputMode = TerminalInputMode.CBreak,
		EchoInput = false
	}
);

await session.WriteTextAsync( "Terminal session ready.\r\n" );

TerminalEvent terminalEvent = await session.ReadEventAsync(
	TimeSpan.FromSeconds( 1 )
);

A live TerminalSession owns the authoritative input reader for its transport. Use ReadEventAsync(...) and the typed query APIs rather than introducing a competing Console.Read* or stream reader on the same terminal conversation.

For curses-style cells, windows, layout, clipping, scrolling, and refresh/damage policy, prefer Icod.DCurses rather than rebuilding those responsibilities directly over TerminalSession.

For a screen frame, establish a safe rendition baseline and plan the cursor position before creating one session-bound transaction:

TerminalScreenOperationPlan? baseline = session.Screen.PlanRenditionBaseline();
TerminalScreenOperationPlan? cursor = session.Screen.PlanCursorMove(
	null,
	new TerminalScreenPosition( 0, 0 )
);

if ( !baseline.HasValue || !cursor.HasValue ) {
	// Report that this rendering mode is unavailable, or select a fallback.
	return;
}

TerminalScreenOutputTransaction frame = session.CreateScreenOutputTransaction();
frame.Add( baseline.Value );
frame.Add( cursor.Value );
frame.WriteText( "Ready" );
await frame.CommitAsync();

A null baseline means at least one rendition axis exposed by the selected profile cannot be restored unconditionally from unknown state; callers must not substitute a claimed known default. A null cursor plan means the requested movement is unavailable. A valid zero-byte plan is still usable.

Each transaction is single-use, and intervening output can invalidate it before commitment. After a committed failure, output may be partial: discard physical-state assumptions and let the application choose recovery. See the screen-output guide and interactive sample for the complete flow, presentation cleanup, and an executable stale-transaction recovery example.

Profile contains immutable selected-profile facts, while GetDimensions() reports the current Terminal-owned size result. A plan is opaque and session-bound; creating it emits nothing, and the transaction preserves ordering under one output gate and flush boundary. Retained cells, layout, Unicode width, clipping, damage, and repaint policy remain caller-owned.

Choosing a capability API

Question API Terminal traffic
What representations does the selected description contain? session.Profile.Screen None; immutable static facts.
Can this session plan the operation with these arguments? session.Screen.Plan...(...) None; returns a concrete plan or no plan, or reports invalid input/expansion.
What support and endpoint availability are currently known? session.InspectCapability(...) None; returns an immutable snapshot.
Can an existing live query establish stronger support knowledge? session.VerifyCapabilityAsync(...) May send queries for keyboard reporting, raster graphics, or persistent raster graphics. The other nine capabilities return inspection results.

For example, inspect advertisement and request a plan independently:

bool advertised = session.Profile.Screen.AdvertisesErase(
	TerminalScreenEraseKind.ToEndOfLine
);
TerminalScreenOperationPlan? erase = session.Screen.PlanErase(
	TerminalScreenEraseKind.ToEndOfLine
);
// 'advertised' is a diagnostic fact; 'erase' describes this concrete request.
if ( erase.HasValue ) {
	TerminalScreenOutputTransaction output = session.CreateScreenOutputTransaction();
	output.Add( erase.Value );
	await output.CommitAsync();
}

Advertisement includes present empty or malformed representations. A valid zero-byte plan is usable; malformed expansion can fail. Ask for cursor plans even when absolute addressing is absent because alternative routes may exist. Planning emits nothing; committing the transaction performs output and can fail independently of support knowledge.

IsUsable combines current support knowledge with endpoint availability. Silence can leave support Unknown, and an unavailable endpoint does not mean Unsupported. Verification does not enable keyboard reporting or create raster resources. Re-inspect after lifecycle invalidation because earlier snapshots do not update themselves. The capability sample walkthrough includes annotated output, lifecycle re-inspection, and verification commands.

Feature Inventory

The root README describes the current product by capability rather than by the release in which each feature first appeared.

  • Live terminal session and lifecycle — terminal endpoint observation; native terminal-mode capture/mutation; deterministic session disposal; lifecycle invalidation; scoped/reversible state where exact restoration is supportable.
  • Unified input and events — one authoritative reader for text, keys, bracketed paste, focus, mouse, lifecycle observations, active query responses, and unsolicited protocol-neutral semantic events.
  • Typed terminal queries — bounded cursor, status, style, color, clipboard, notification, pointer, and related observations integrated with the same input/query authority.
  • Static screen advertisement — immutable Profile.Screen.Advertises... facts, separate from parameter-specific planning and live evidence; the capability sample demonstrates all three.
  • Semantic capability planning — side-effect-free InspectCapability(...), explicit bounded VerifyCapabilityAsync(...), separate support/evidence/endpoint-availability state, and no terminal-brand heuristics as capability truth.
  • Semantic terminal output — application text, titles, current location, hyperlinks, clipboard operations, notifications, cursor style, synchronized output, progress, pointer shape, prompt/shell metadata, and terminal color operations.
  • Semantic screen planning — Terminal-owned dimensions/profile facts plus opaque costed cursor, rendition, ACS, erase, shift, scroll, and region plans; retained-screen comparison and layout remain caller-owned.
  • Session-bound screen transactions — bounded ordered composition of screen plans, application text, strict hyperlinks, and raster-placeholder cells under one output gate and flush boundary, with optional synchronized framing.
  • Reversible presentation state — scoped ownership for terminal features whose prior state can be observed truthfully and restored deterministically.
  • Backend-neutral ephemeral raster display — bounded TerminalRasterImage data with verified Sixel and Kitty Graphics routing behind one semantic DisplayRasterAsync(...) surface.
  • Persistent raster ownership — opaque terminal-resident resources and placements; source-pixel cropping; signed z-order; immutable-parent relative placement; generation-scoped ownership; deterministic descendant-first cleanup; no hidden raster replay.
  • Persistent ownership observation — atomic Current, Stale, Released, and Disposed snapshots with semantic loss/release reasons and no passive terminal-side existence fiction.
  • Unicode raster placeholders — opaque virtual placements, semantic row/column cell tokens, self-contained current-cursor output, and physical placement relative to a virtual parent without exposing Kitty numeric identities or placeholder encoding.
  • Persistent raster animation — one resource-owned controller, opaque root/appended frame tokens, exact positive timing, selection, loading-mode streaming, finite/indefinite playback, bounded sequence tracking, and no hidden source-frame replay.
  • Optional TermInfo planning integration — consumer-owned lifecycle, placement, runtime-evidence, and raster-backend planning through Icod.TermInfo.Inspection without widening the production dependency graph or transferring live routing authority away from Terminal.

Raster Ownership at a Glance

The current persistent-raster ownership model is:

TerminalRasterResource
    |
    +-- TerminalRasterPlacement
    |       ordinary or relative physical placement
    |
    +-- TerminalRasterPlaceholder
    |       virtual placement
    |       |
    |       +-- TerminalRasterPlaceholderCell
    |               semantic text-grid token
    |
    +-- TerminalRasterAnimation
            resource-owned frame sequence
            |
            +-- TerminalRasterAnimationFrame
                    opaque known-frame token

Portable ownership bounds are explicit:

live persistent resources                    256
physical + virtual placements               4096
relative-placement depth                       8
placeholder rows                            1..256
placeholder columns                         1..256
session-wide known animation frames, roots      4096

Placeholder cell output is current-cursor text output. Animation changes the current pixels of the same resource without creating another placement graph. Terminal owns protocol-private image/placement/frame identity and encoding; the caller owns screen coordinates, clipping, scrolling, redraw order, damage, layout, and higher-level animation policy.

See docs/Persistent-Raster-Ownership.md for lifecycle, capacity, failure, cleanup, relative-placement, and placeholder guarantees.

Platforms and Targets

The package targets:

net8.0
net9.0
net10.0

The repository uses C# 13. Release qualification covers Windows, Linux, and macOS.

Icod.Terminal is a managed library but intentionally uses native platform facilities where terminal modes or console behavior require them. Protocol and feature availability still depends on the terminal endpoint attached to the process; operating-system identity or terminal brand is not treated as sufficient support proof.

Design Boundaries and Guarantees

  • One live session owns one authoritative terminal input/query/event conversation; features do not install competing readers.
  • Static terminal-description evidence and generation-scoped live evidence remain distinct. Timeout or silence does not automatically become Unsupported truth.
  • Public APIs describe semantic operations rather than exposing generic raw CSI/DCS/OSC/APC vendor dispatch or caller-manufactured graphics identities.
  • Capability routing is evidence-driven rather than terminal-brand driven. Ordinary raster, persistent raster, Unicode-placeholder, and persistent-animation capabilities remain distinct.
  • Persistent resources, physical placements, virtual placeholders, animations, and frame tokens are generation-scoped terminal-resident ownership, not exactly restorable state. The library does not retain hidden source images or frames for automatic replay/re-upload.
  • Committed graphics operations do not intentionally truncate after commitment. Transport/protocol failure is surfaced without blind replay or speculative backend switching.
  • Terminal-controlled responses and unsolicited reports are external input. Correlation grants routing ownership, not authenticity or trust.
  • Graphics, parser, query, event, registry, placeholder, and protocol work is explicitly bounded.
  • File, temporary-file, and shared-memory Kitty transfers are not silently selected for persistent ownership; the reviewed persistent path uses direct terminal transfer.
  • Icod.Terminal does not own higher-level cells, windows, virtual-screen state, scene composition, clipping, damage, scrolling, or layout. Those concerns belong above the live-session layer, normally in Icod.DCurses.
  • PTY/ConPTY child-process hosting, terminal emulation, image-file decoding/transcoding, and process ownership remain separate concerns.

Security and privacy details are maintained in docs/Security-and-Privacy.md.

Samples and Documentation

The samples directory contains focused examples for session construction, semantic screen frames and explicit recovery, rich input, bounded queries, semantic capability planning, terminal colors and reversible state, notifications and metadata, backend-neutral raster display, persistent raster ownership, Unicode raster placeholders, persistent raster animation, and optional TermInfo planning integration.

Recommended documentation entry points:

Release notes, public-API baselines, tranche records, implementation plans, and historical roadmaps remain in the repository as engineering evidence. They are intentionally not repeated in this README.

Compatibility and Versioning

Stable 1.0.0 remains the compatibility floor. The package supports net8.0, net9.0, and net10.0; compatible 1.x releases add semantic capabilities and public members without silently repurposing established signatures, enum values, lifecycle guarantees, or protocol-neutral behavior.

The frozen 1.20 public API fingerprint is:

d308fb6ead5bd24c564d159297e6d08793c08eb4db21418eca6a5563aa5c4cbf

Public API, package, target-framework, release-qualification, and compatibility policy is maintained in docs/Compatibility-and-Versioning.md. Consumers upgrading from the pre-1.0 line should also review docs/Migration-to-1.0.md.

This README is maintained as a current product and contributor entry point. Release-by-release chronology belongs in CHANGELOG.md, curated release notes, versioned roadmaps, public-API baselines, and release audits rather than accumulating here.

Authors

Inspired by original work from Bill Joy, author of the original termcap; Ken Arnold, for his work on termcap and curses; Mary Ann (born Mark) Horton, author of terminfo; Pavel Curtis, author of pcurses; and Zeyd Ben-Halim, Eric S. Raymond, and Thomas Dickey, whose work developed and maintained libtinfo and ncurses.

Managed .NET implementation by Timothy J. Bruce uniblab@hotmail.com.

Copyright

Copyright (c) 2026 Timothy J. Bruce

License

Icod.Terminal is licensed under the GNU Lesser General Public License, version 3 or later. Sample applications are licensed under the GNU General Public License, version 3 or later, as stated in their source headers.

See LICENSE and the per-project/source declarations for the applicable terms.

About

Managed, cross-platform live-terminal session, input, lifecycle, mode, and terminal-control library for .NET.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages