Embeddable Terminal Power
KetraTerm is a fully decoupled, modular JVM terminal engine. Choose only what you need—from low-level ANSI parsers to high-performance Swing widgets and split-pane workspace managers.
Integrate Module-by-Module
Select the level of abstraction that fits your architecture. Each layer remains strictly isolated.
Parser Only
ketraterm-parser
A table-driven ANSI state machine and UTF-8 stream decoder. Resolves escapes, combining marks, and dispatches semantic commands. Consumes zero UI or grid models.
Headless State Engine
ketraterm-core
Owns circular scrollback histories, vertical/horizontal margin calculations, tab stops, and grid mutations. Ideal for SSH agents, test assertions, or headless automation.
Swing UI Widget
ketraterm-ui-swing
An optimized Swing terminal canvas component. Handles font measurement, color palettes, double-click smart selection, and AWT focus/repaint triggers. Ready for tool windows and splits.
Tab & Split Workspace
ketraterm-workspace
Manages multi-tab lifecycles, split panes, profile settings, and persistent command histories. Ideal for builders of comprehensive terminal desktop clients.
PTY Process Host
ketraterm-pty
Leverages Pty4J for cross-platform local process management. Handles background process threads, size adjustments, and default shell discovery.
Custom Graphics Pipeline
ketraterm-render-cache
Bypass Swing entirely. Consume raw render frames from our triple-buffered caches to draw terminal state on Compose Multiplatform, JavaFX, OpenGL, or native views.
Strict Unidirectional Pipeline
Traditional terminal components often share mutable state, leading to race conditions or split-escape character corruption. KetraTerm serializes all bytes and mutations into a strict, unidirectional event-driven flow.
Three-Tier Concurrency Lock Guard
- inboundLock: Serializes raw bytes entering the parser. Blocks concurrent PTY read buffers to protect the UTF-8 decoder state machine from corrupted escape splits.
- mutationLock: Guards core state mutations and render-cache copies. Background parser updates are suspended while the UI thread takes snapshots of the screen rows, preventing visual tearing.
- outboundWriteLock: Synchronizes process stdin write calls. Guarantees keystrokes, pastes, and device query responses (CPR/DSR) are written atomically without interleaved bytes.
Zero-Allocation Hot Loops
High throughput logs shouldn't trigger JVM garbage collection spikes. Every execution loop is optimized for allocations safety.
Flat Primitive Storage
Rather than allocating an object per cell, KetraTerm rows use parallel primitive arrays: IntArray for Unicode codepoints, and LongArray for packed styling, SGR attributes, and hyperlink indices. This maximizes CPU cache-line locality.
Autoboxing Prevention
Custom primitive-keyed LRU caches (like IntFontLru for codepoint fallback matches and LongTextLayoutLru for styled SGR text segments) bypass standard Java Map allocations during active log rendering ticks.
Triple-Buffered Rendering
The render publisher manages Back, Front, and Spare frames in a lock-free, allocation-conscious layout. Enables steady 60+ FPS paint loops on AWT/Swing without allocating memory in the draw loop.
Zero External Dependencies
The core terminal layers are built from the ground up on standard Kotlin Standard Library and JDK Swing classes. No bloated JSON libraries, no heavy dependencies. The local process transport uses pty4j as its single native executor.
Declare coordinates in your Gradle build, instantiate a session configuration, and bind the widget on any background thread.
Browse Dokka API Referencedependencies {
implementation("io.github.ketraterm:ketraterm-ui-swing:0.1.0")
implementation("io.github.ketraterm:ketraterm-pty:0.1.0")
}
import io.github.ketraterm.ui.swing.api.SwingTerminal
import io.github.ketraterm.pty.TerminalSessions
import io.github.ketraterm.pty.PtyOptions
fun main() {
// 1. Configure local process options
val options = PtyOptions(columns = 100, rows = 30)
// 2. Start a local PTY-backed session
val session = TerminalSessions.localPty(options)
// 3. Create the Swing terminal canvas component
val terminal = SwingTerminal()
// 4. Bind the session (observations and inputs map automatically)
terminal.bind(session)
// 5. Add to standard Swing panels
panel.add(terminal, BorderLayout.CENTER)
}