Crate Reference - D0n9X1n/SonicTerm GitHub Wiki
This is the canonical map of the 23 Rust crates in the Cargo workspace. The root
Cargo.toml supplies their version, edition, Rust version, authors, license, and
repository metadata. sonicterm-app is the default workspace member. The
shipping binaries are sonicterm-mac, sonicterm-windows, and
sonicterm-linux; the Linux executable is named sonicterm.
flowchart BT
types["sonicterm-types"]
resource["sonicterm-resource"]
grid["sonicterm-grid"]
vt["sonicterm-vt"]
io["sonicterm-io"]
logging["sonicterm-logging"]
cfg["sonicterm-cfg"]
text["sonicterm-text"]
ui["sonicterm-ui"]
model["sonicterm-render-model"]
fontparts["font-config · fontconfig · freetype · harfbuzz"]
font["sonicterm-font"]
engine["sonicterm-engine"]
block["sonicterm-block-glyph"]
gpu["sonicterm-gpu"]
core["sonicterm-app-core"]
app["sonicterm-app"]
platforms["mac · windows · linux"]
resource --> types
grid --> types
vt --> grid
vt --> types
io --> types
logging --> types
cfg --> logging
cfg --> types
text --> types
ui --> cfg
ui --> grid
model --> cfg
model --> grid
model --> ui
font --> fontparts
engine --> font
engine --> text
gpu --> block
gpu --> model
gpu --> engine
gpu --> text
core --> types
app --> core
app --> vt
app --> io
app --> cfg
app --> ui
app --> model
app --> gpu
app --> resource
app --> logging
platforms --> app
platforms --> core
The diagram shows the main architecture edges. Each entry below gives the exact
first-party Cargo dependencies. Unless an entry says otherwise, these are normal
Cargo dependencies, not build or test dependencies. sonicterm-logging additionally
uses sonicterm-resource with test-util as a dev dependency.
sonicterm-font's fontconfig alias is target-gated to Android and non-macOS Unix;
config, freetype, and harfbuzz are library aliases, not extra crates.
The workspace has no first-party build-dependency edge. External build tools and
native link requirements still belong to the FFI and platform crates.
Use this table for state owners and public interfaces; use the entries below for exact dependencies and source paths. Paths are crate-relative unless stated. Compatibility traits need not drive production, and this is not an unsafe-call audit.
| Crate | Mutable state and lifecycle owner | Public interface and named boundary exceptions |
|---|---|---|
sonicterm-types |
Values belong to their callers; no window, PTY, or renderer lifecycle. |
Cell, GlyphKey, ResourceAmount, WindowKey, and backend-free traits in src/traits/; the Painter trait is a dormant compatibility seam. |
sonicterm-resource |
ResourceGovernor shares Arc<Ledger>; reservation tokens own charges, and ReaperSupervisor owns admitted cleanup tasks. UnresolvedSink retains type-erased native payloads together with their accounting. |
try_reserve, Reservation, CommittedReservation, snapshot, ReaperSupervisor, and UnresolvedSink; snapshots are observational and GUI process/window limits remain tracking-only. |
sonicterm-grid |
Each Grid owns visible/history/saved-primary rows, revisions, and dirty bits; HyperlinkRegistry separately owns link metadata. The production parser owns the grid. |
Grid::resize, revision, retained_amount_by_region, row access, and Line; no native handles, PTY transport, or presentation. |
sonicterm-vt |
Parser owns its Grid, parser state, capture buffers, and reply/event state; a pane worker advances it under the pane's parser lock. |
Parser::advance, grid, grid_mut, and VtEvent in src/vt.rs; callbacks produce data, not native-window calls. |
sonicterm-io |
PtyHandle owns child-process and bounded input/output transport state, cancellation, and reader/writer lifetimes. Drop starts bounded teardown. |
spawn_default_shell, send_input_nonblocking, PtyInputSender, resize, out_rx, and optional SshHandle; GUI callers do not own native PTY internals. |
sonicterm-cfg |
Callers own loaded Config, Theme, and Keymap values and decide when to replace them. |
TOML/asset/URI APIs in src/{config,theme,keymap,assets,url_scan,url_open}.rs; LoggingConfig is re-exported from logging, and filesystem targets do not enter the URI opener. |
sonicterm-logging |
Process subscriber, panic/exit hooks, ring, and artifact workers are logging-owned; the binary retains LoggingGuard to keep the appender alive. |
init, init_in, LoggingConfig, install_panic_hook, and breadcrumb/session APIs; initialization is process-wide, not one subscriber per window. See Logging for persistence scope. |
sonicterm-ui |
App and WindowState hold UI controllers; CommandPalette owns its cached text and filtered selection, TabBar owns tab identities and each tab's measured title width, and the active tab-width limits are process scalars, while each TabBar records the limits it was last laid out with. |
CommandPalette, PaletteLayout, TabBarLayout, PaneTree, Selection, and I18n; these compute state/layout without owning native windows or executing actions. |
sonicterm-render-model |
Caller-owned frame records borrow live grid state; InlineImage shares decoded bytes with Arc. No renderer or native lifecycle is owned here. |
PaneRender<'a>, PixelRect, and HoveredUrlCells; production lends parser guards to one releasing call and releases them before presentation; FrameSource, BorrowedSource and the metadata AckReceipt live here. boundary::{grid,cfg,ui} re-exports concrete types unchanged; RenderInputs and the dormant Painter do not replace the production entrypoint. |
sonicterm-text |
CPU GlyphAtlas and RowGlyphCache own pixels, metadata, and cached instances; their containing renderer controls lifetime and invalidation. |
Rasterizer, RasterTile, GlyphInstance, ShapedGlyph, and atlas/cache methods; native discovery/shaping/raster objects live in font/engine, not this crate. |
sonicterm-font-config |
ConfigHandle shares immutable Arc<Config> snapshots; a process mutex stores the current handle and generations distinguish replacements. |
configuration, use_this_configuration, TextStyle, font attributes, and rasterizer policy; library alias config is distinct from sonicterm-cfg, and owns no native face. |
sonicterm-fontconfig |
Raw Fontconfig ABI exposes native objects; matching wrappers in sonicterm-font::fcwrap own references and destruction. |
Fc* types/functions in src/lib.rs; system linking is build-time and the font consumer is target-gated, not a Windows/macOS discovery path. |
sonicterm-freetype |
Generated ABI owns no Rust wrapper lifecycle; sonicterm-font::ftwrap owns library/face lifetimes and keeps backing sources alive. |
FT_* bindings and fixed-point helpers; build.rs compiles embedded native sources, while callers of raw ABI retain its unsafe obligations. |
sonicterm-harfbuzz |
Generated ABI exposes native references; sonicterm-font::hbwrap manages buffers, blobs, font references, and their release callbacks. |
hb_* bindings; the freetype dependency aliases sonicterm-freetype, and native amalgamation/link setup stays in build.rs. |
sonicterm-font |
FontConfiguration shares thread-confined Rc state; LoadedFont owns RefCell shaping/raster/fallback caches and native wrappers own handle lifetimes. |
FontConfiguration, LoadedFont, locator/shaper/rasterizer traits, FontMetrics, and RasterizedGlyph; raw ftwrap re-exports remain an explicit low-level surface, not a blanket safe-API claim. |
sonicterm-engine |
FontStack shares Rc<FontConfiguration> and owns per-stack size/weight/metric state; the renderer retains the stack. |
FontStack, CellMetricsPx, shaping and atlas-tile conversion; the direct text dependency carries CPU data, not another terminal state owner. |
sonicterm-block-glyph |
Callers own returned CPU bitmap tiles; block geometry uses transient raster state, not a shared renderer or font-face owner. |
BlockKey, SizedBlockKey, block_sprite_with_cell_metrics, and glue::BlockRasterTile; no first-party dependency, with preserved WezTerm attribution. |
sonicterm-gpu |
GpuRenderer owns per-window surfaces, retained frame, pipelines, atlases, caches, software frame, and font stacks. GpuSharedContext shares wgpu-refcounted device/queue handles, not a second device. |
GpuRenderer::new, new_with_shared_context, render, render_releasing, render_with_outcome, try_resize, retained_amounts, and live_renderer_count; UI/grid types cross render-model. The retained report describes this instance, while the live count tracks lifecycle. CPU success is observable; wgpu success here is submit/present invocation. |
sonicterm-app-core |
AppStateMachine owns backend-free transition/effect values, not live WindowState, parser locks, or PTYs. |
AppState, AppIntent, AppEffect, handle, and effect ordering; production topology remains in App rather than being inferred from this model. |
sonicterm-app |
App owns live WindowState objects, warm renderers, routing, and resource coordination. Each window owns tabs/panes; each pane owns parser/PTY/image state. |
App, WindowState, PaneState, run_action_for_window, and platform Shell wrappers; redraw collects visible parser guards with try_lock and moves them into a frame source that is held only through assembly; the source and its guards drop before presentation, and a presented frame's receipts are acknowledged at the next collection. Native workers do not resolve UI windows. |
sonicterm-mac |
Binary startup retains logging/session guards, installs AppKit hooks, and hands event-loop ownership to MacShell. |
src/main.rs and menu/open-document/drag modules; AppKit calls remain on the main thread, terminal behavior stays in shared app/IO crates. |
sonicterm-windows |
Binary startup retains logging/session guards, installs Win32 menu/backdrop/OLE hooks, and runs WindowsShell. |
src/main.rs, CLI and native GUI modules, and WiX assets; PTY/ConPTY process ownership remains in sonicterm-io. |
sonicterm-linux |
Binary startup owns Linux capability normalization and packaged-font preflight, retains logging/session guards, then runs LinuxShell. |
src/main.rs and package resources; the direct engine dependency serves font preflight, while X11/Wayland windows and terminal state remain app-owned. |
Role: dependency-light contracts shared across the workspace: cells, geometry, colors, actions, modifier keys, glyph/window/hyperlink identifiers, shell quoting, paste encoding, resource types, and backend traits.
First-party dependencies: none.
Read: src/{cell,action,glyph_key,geom,resource}.rs, src/traits/.
Role: process-local resource governor with owner hierarchy, sharded ledger, RAII reservations, cancellation tokens, and a bounded reaper supervisor.
Supervisor shutdown wakes capacity waiters to ShuttingDown, including when a
reservation deadline races shutdown. Settled task destruction runs after the
counter lock is released, so native-handle permit destructors may return their
counts. Slot notification follows destruction even if it unwinds.
shutdown_handle() returns a cloneable ReapShutdownHandle; its
close_admission(drain_by) lowers the shared deadline without running another
poll loop or setting the cancellation token. Running calls and deferred waits
observe the earlier of their own deadline and that shared deadline.
try_reserve_unit(ReapUnitDemand) atomically reserves a task and individual
ReapHandlePermit values; BelowMinimumCapacity distinguishes fixed ceilings
that cannot fit the unit from occupied capacity reported as QueueFull. Sink
entries retain capacity until process exit, so QueueFull need not be temporary.
Callers bound their retries and then use synchronous fallback without abandoning
unresolved ownership. Helpers are claimed only when work starts. Ordinary tasks keep per-call helper admission; opt-in tasks
receive one whole HelperGrant after the counter lock is released and use
Held on retries. Each worker keeps a grant clone and occupies one grant slot;
failed spawn returns that slot, not the task's entire grant. The helper count is
reserved capacity, including retained grants with no running workers.
Opt-in tasks retain abandoned helper handles and expose whole-task completion to
collect_settled_retained. The collector runs before pending retries, joins only
finished handles outside supervisor locks, and releases the collected task's
permit and unresolved owner record. This opt-in requires a unique transport owner
per task; shared-owner tasks remain non-collectable. requeue_unstarted preserves
eligible work across a normal cutoff. Before querying has_startable_work, the
caller must collect completed retained tasks and check control after every wake,
recheck and run return. The query does not collect on its own; it parks carried
units until their whole grant fits. Closing admission disables that normal retry path.
UnresolvedSink keeps an incomplete native payload and its accounting in a
separate owned list. Its entries consume task admission, and shutdown reports
both entries and open slotless cancellation duplicates. Terminal sink disposal
forgets unresolved entries instead of executing their unsafe-to-finish native
destructors or releasing charges. The ledger permits retired PtyTransport
owners directly below a GUI process, not below its window, pane, or local PTY.
First-party dependencies: sonicterm-types.
Read: src/{ledger,owner,reservation,reaper,cancel}.rs.
Role: primary and alternate screens, visible rows, bounded scrollback, cursor state, wide and combining cells, hyperlinks, prompt regions, dirty rows, and line storage.
First-party dependencies: sonicterm-types.
Read: src/{grid,line,hyperlink}.rs.
Role: vte-based ANSI/VT parser and performer. It turns control sequences into grid changes, terminal replies, and typed events. OSC 7 retains authority and decoded path separately for host-aware working-directory use.
First-party dependencies: sonicterm-grid, sonicterm-types.
Read: src/vt.rs, tests/autowrap/main.rs,
tests/control_sequences/main.rs.
Role: local PTY and process transport, resize and child cleanup, shell
selection, and foreground-process discovery. PtyHandle::into_teardown transfers
owned native cleanup without waiting. PtyTeardown retains native values,
per-handle permits, phase state and worker handles through retry; the backend-free
NativeWorkerSpawner contract lets App supply a whole helper grant without an IO
dependency on the resource governor. PtyCompletion separates successful phases
from actual worker exit and joins.
First-party dependencies: sonicterm-types.
Read: src/{pty,proc_info,foreground_proc}.rs.
Role: tracing sinks, log retention, panic artifacts, fatal-exit markers, session markers, bounded breadcrumbs, postmortem discovery, and process-memory sampling.
First-party dependencies: sonicterm-types; tests additionally use
sonicterm-resource with test-util.
Read: src/{lib,config,cleanup,crash,exit_trace,breadcrumbs,postmortem,session_state}.rs.
Detailed fields and procedures belong on Logging.
Role: the only parser for sonicterm.toml, theme and keymap TOML, dimensions,
asset lookup, typed URI/path detection, and safe URI-open policy.
First-party dependencies: sonicterm-logging, sonicterm-types.
Read: src/{config,theme,keymap,assets,url_scan,url_open,dimension}.rs.
Role: renderer-independent UI state and layout for tabs, panes, command palette, search, selection, READONLY/copy mode, scrollbar, IME, broadcast, notifications, and localization.
First-party dependencies: sonicterm-cfg, sonicterm-grid,
sonicterm-types.
On macOS, text editing uses AppKit's string-only attributed-string word-boundary
API for Option deletion, with checked UTF-16/UTF-8 conversion. The target-specific
objc2-app-kit and objc2-foundation dependencies create no native view or window.
Canonical decomposition uses unicode-normalization; terminal encoding stays in
the app rather than in these field-editing operations.
Tab layout reads each tab's stored title width. The renderer measures it in the
tab font right before it draws the bar (TabBar::refresh_content_widths), and
every TabBarLayout::compute* sizes the tabs from it, so drawing, hit-testing,
drag and tear-out slots, and the overflow selector share one layout without a
font. Each width is clamped between the tab_min_width and tab_max_width the
bar was last laid out with (tab_width_limits_of): config sets the process-wide
limits at startup and on reload, and each measurement pass records them on the
bar. Crowding and the overflow threshold use only the font/scale-derived readable
width. While a tab
is pressed or dragged, or the pointer rests on the bar, a changed title, badge
or privilege marker is measured but laid out only once no tab is pressed or
dragged and the pointer leaves the bar; a font, scale or width-limit change
lays the bar out at once. Whether the pointer rests on the bar comes from the
window's own pointer, which the dispatcher records on every move and leave
before an overlay, a modal or a handler can consume the event. A redraw whose
frame does not present restores the widths and limits still on screen
(TabBar::restore_laid_out_widths), so clicks and drops resolve against the
bar the user sees. fit_title_to_width cuts a title that does not fit at a
grapheme boundary.
The renderer keeps the tab-title font in a device-free type (TabTitleFont)
that holds the title stack, its raster size and the key stored widths are
measured under. GpuRenderer::set_font, the scale-factor rebuild and
GpuRenderer::measure_tab_widths all go through it, so a font or scale change
reaches the next measurement, which runs on the CPU.
Pointer input on the tab bar is routed by WindowState::route_tab_press,
route_tab_motion and route_tab_release, which take the drawn bar layout, the
pointer position and the window's gesture state and return the action;
App::apply_tab_press, apply_tab_motion and apply_tab_release carry it out.
The main and child pointer handlers supply only the native inputs: the bar
layout, from the native window size for the main window and from the renderer
for a child, and the event loop a tear-out needs.
The palette separates metadata, presentation, and execution:
-
command_label::descriptordefines variant identity, category, localization key, English aliases, target requirements, and READONLY allowance. App supplies window-localCommandContext;disabled_reasonhas no native handles, terminal payload, or execution authority. English fallback preserves literal arguments. -
CommandPalettecaches labels, search text, first-binding hints, and chrome withI18nat refresh. Locale refresh rebuilds every mode's text; only Commands refilters indices.PaletteLayoutuses cached identity in the frame key, without per-frame translation. Fluent count/title phrases split around one internal value slot to preserve word order; titles are not interpreted, and the caret is appended separately. -
highlightedpreserves row identity;currentexcludes disabled entries.PaletteEntrydistinguishes commands fromTabIdtargets. App resolves a live target's current index in the attached window; closure never selects a replacement. - App refreshes context before input and from the already-held rendering grid.
Input selection validation uses
try_lock, never re-locking a render guard. Overflow and native/local drop snapshots keep absolute indices. Tab-only mode uses the same palette; one modal pointer capture revalidates identity/availability on release without stealing an earlier terminal or chrome gesture.
Read: src/{tabs,pane,command_palette,command_label,search,selection,copy_mode,ime,overlays,i18n}.rs.
Role: renderer-neutral pane, geometry, overlay, and input bundles. It
re-exports grid/config/UI type identities through boundary::{grid,cfg,ui} so
the GPU crate has one declared model boundary.
First-party dependencies: sonicterm-cfg, sonicterm-grid,
sonicterm-types, sonicterm-ui.
Read: src/{pane_render,inputs,geometry,lib}.rs.
Role: CPU glyph atlas, row glyph cache, shaping records, and the
GlyphInstance data consumed by the renderer.
First-party dependencies: sonicterm-types.
Read: src/{glyph_atlas,row_glyph_cache,shape,lib}.rs.
Role: font configuration value model: text styles, attributes, weights,
stretches, rasterizer selection, and policy. Its Rust library name is config.
First-party dependencies: none.
Read: src/lib.rs.
Role: hand-written Fontconfig ABI declarations plus the build/link shim used for Android and
non-macOS Unix font discovery. build.rs probes system Fontconfig through
pkg-config.
First-party dependencies: none.
Read: build.rs, hand-written src/lib.rs.
Role: generated FreeType ABI and fixed-point helpers. build.rs compiles the
embedded zlib, libpng, and FreeType sources and exports their build paths.
First-party dependencies: none.
Read: build.rs, bindings.h, src/{lib,types,fixed_point}.rs.
Role: generated HarfBuzz ABI. build.rs compiles the embedded HarfBuzz C++
amalgamation against the FreeType build. Native atomics, mutexes, and thread-safe
static initialization stay enabled: independent font objects on different threads
still share HarfBuzz callback tables. The font wrapper tests exercise concurrent
creation and teardown without sharing mutable font objects.
First-party dependencies: sonicterm-freetype under the dependency alias
freetype.
Read: build.rs, bindings.h, generated src/lib.rs.
Role: safe font discovery and matching, HarfBuzz shaping, fallback, FreeType/DirectWrite/HarfBuzz rasterization, COLR glyphs, and native-handle wrappers.
First-party dependencies: sonicterm-font-config as config,
sonicterm-freetype as freetype, and sonicterm-harfbuzz as harfbuzz;
Android and non-macOS Unix builds also use sonicterm-fontconfig as
fontconfig.
Read: src/db.rs, src/locator/, src/shaper/, src/rasterizer/,
src/{ftwrap,hbwrap,fcwrap,parser}.rs.
Role: small font-facing engine seam. FontStack turns shaping and raster
results into cell metrics and atlas RasterTiles.
First-party dependencies: sonicterm-font-config as config,
sonicterm-font, sonicterm-text, sonicterm-types.
Read: src/fontstack.rs.
Role: geometry and rasterization for box drawing, block elements, Powerline, Braille, sextants, octants, and synthetic terminal symbols.
First-party dependencies: none.
Read: src/{lib,glue,customglyph}.rs; attribution is in
LICENSE-WEZTERM.
Role: wgpu device and surface owner, frame assembly, dirty-row damage, quad and glyph emission, atlas upload, retained frames, software-adapter detection, and Windows CPU presentation data.
First-party dependencies: sonicterm-block-glyph, sonicterm-engine,
sonicterm-render-model, sonicterm-text, sonicterm-types.
The private FramePlan composes frame identity, mode, damage, pane clips,
viewport slots, and expected revisions from metadata. Production consumes it
during assembly, while the borrowed grids and parser guards are held, with stateful
atlas/cache work; presentation runs after they are released. It is not a snapshot or
threaded renderer boundary.
present.rs holds the presentation seam: the wgpu and Windows GDI presenters
behind one hand-off, and the typed PresentOutcome that render_releasing
returns in its FrameOutcome, with a presented frame's receipts. The
render_with_outcome compatibility wrapper returns the outcome alone, and render
maps it back to its Result<()>.
Read: src/{core,present,frame_plan,atlas_upload,row_quad_cache,chrome_text,cursor,color,software_frame,software_windows}.rs.
Role: backend-free AppIntent, AppEffect, AppState, reducer, stable
effect ordering, and state machine. Live window/tab/pane topology remains in
sonicterm-app.
First-party dependencies: sonicterm-types.
Read: src/{app_state,intent,effect,reducer,state_machine}.rs.
Role: cross-platform winit orchestration for windows, renderers, tabs,
panes, PTYs/parsers, input, config reload, redraw, overlays, tab transfer,
bounded target probes, and native direct-open dispatch. One ReaperDriver owns
all PTY reaper runs. retire_pane moves native custody to a unique process-root
PtyTransport charged with one ReaperWork item, then releases pane accounting.
A live transfer preserves its reservation. finish_session retires every pane
before shutdown and caches whether teardown settled; ShellRunResult keeps that
answer separate from the original application result.
First-party dependencies: sonicterm-app-core, sonicterm-cfg,
sonicterm-gpu, sonicterm-grid, sonicterm-io, sonicterm-logging,
sonicterm-render-model, sonicterm-resource, sonicterm-text,
sonicterm-types, sonicterm-ui, sonicterm-vt.
macOS dependencies: objc2, objc2-foundation, objc2-app-kit and
objc2-quartz-core, already in the lockfile through other crates, for the
per-window NSView.displayLink and its tick target (src/app/display_link.rs).
Read: src/app/{mod,window_state,window_registry,session,input_dispatch,effects}.rs,
src/app/{event_loop,window_event,window_keyboard,window_pointer,spawn_pane,reaper_driver,keymap_dispatch,path_target,tear_out}.rs,
src/shell.rs.
Role: macOS binary and AppKit glue: startup, NSMenu, open-document events, NSPasteboard tab handoff, NSWindow setup, and bundle entry point.
First-party dependencies: sonicterm-app, sonicterm-app-core,
sonicterm-cfg, sonicterm-logging.
Read: src/{main,menubar,open_documents,os_drag_mac,tab_drag_os}.rs.
Native details belong on Platform Integration.
Role: Windows binary and Win32 GUI glue: DPI setup, CLI, muda menu, DWM
backdrop, OLE tab drag/drop, software presentation support, Win32 resources, and
WiX metadata. ConPTY remains behind sonicterm-io.
First-party dependencies: sonicterm-app, sonicterm-app-core,
sonicterm-cfg, sonicterm-logging, sonicterm-types.
Read: src/{main,cli,startup,backdrop,menubar,os_drag_win,software_presenter}.rs,
build.rs, wix/main.wxs.
Role: shipping Linux sonicterm binary: X11/Wayland identity, capability
normalization, diagnostics, packaged-font preflight, and desktop/AppStream
metadata.
First-party dependencies: sonicterm-app, sonicterm-app-core,
sonicterm-cfg, sonicterm-engine, sonicterm-logging.
Read: src/main.rs, resources/.
Every crate has a local CLAUDE.md with its guardrails and local gate. Package
layouts belong on Packaging; CI behavior belongs on
CI and Coverage, and release behavior on
Release Process.