>_EXECUTIVE SUMMARY
Large-scale C-to-Rust port of upstream zsh: strict-port code under src/ported/ plus non-port extensions. The core file table below is regenerated from the same indexer as port_report.html (regex C top-level defs + Rust fn names + port-doc mining). Those counts are a mechanical index, not proof that every path is behavior-complete.
Codebase split (NEW): the runtime crate now physically isolates ported code from non-port code so drift is mechanically detectable.
src/ported/ is the strict-port directory — every .rs mirrors a real src/zsh/Src/<x>.c file, every top-level fn carries a /// Port of <cname>() from Src/<file>.c:NNNN doc-comment, and the file set is FROZEN (no new files).
src/extensions/ is the non-port directory — features zsh C does not have (AOT, daemon coordination, plugin/script/autoload caches, fish-style autosuggest/abbrev/highlight, persistent worker pools, ZWC byte-code helpers).
src/recorder/ is feature-gated; deleted by rustc in the default build.
Both invariants are enforced by tests/port_purity.rs — a regression of either rule fails CI.
Scope note: this report covers the C-to-Rust port (i.e. src/ported/ only) — what was translated from upstream zsh.
It does not cover the new Rust infrastructure layered on top
(zshrs-daemon singleton, zshrs-recorder AOP intercept, IPC + HTTP + OpenAPI surface,
canonical-state rkyv shards, the z* builtin family, session-persistent supervised jobs with
bidirectional ptmx attach, the parser surface in src/ported/parse.rs). That work has no C ancestor and is reported separately in
daemon-report.html. See “BEYOND THE C PORT” section
below for the cross-link.
#FILE-BY-FILE COVERAGE
Per-file columns: C Fns = symbols whose primary C definition is that file (unique name, heuristic indexer). Same-name Rust fn = a Rust definition with the identical identifier. Other rows = the remainder (doc-only pointers, different Rust names, or not yet indexed). Port-index % = ported / total from gen_port_report.py (ported = any Rust hit or port-doc mention). Rust targets: src/ported/<stem>.rs.
| C Source | Rust Target | C Lines | Rust Lines | Ratio | C Fns | Same-name Rust fn | Other rows | Port-index % | |
|---|---|---|---|---|---|---|---|---|---|
| lex.c | ported/lex.rs | 2,294 | 7,739 | 337.4% | 25 | 25 | 0 | ✅ | |
| parse.c | ported/parse.rs | 4,080 | 12,808 | 313.9% | 75 | 75 | 0 | ⚠️ | |
| subst.c | src/ported/subst.rs | 4,952 | 34,354 | 693.7% | 24 | 24 | 0 | ✅ | |
| math.c | src/ported/math.rs | 1,685 | 7,752 | 460.1% | 20 | 20 | 0 | ✅ | |
| exec.c | src/ported/exec.rs | 6,578 | 15,029 | 228.5% | 76 | 74 | 2 | ⚠️ | |
| params.c | src/ported/params.rs | 6,501 | 23,620 | 363.3% | 171 | 168 | 3 | ⚠️ | |
| pattern.c | src/ported/pattern.rs | 4,384 | 11,279 | 257.3% | 40 | 40 | 0 | ⚠️ | |
| glob.c | src/ported/glob.rs | 3,986 | 9,934 | 249.2% | 52 | 52 | 0 | ⚠️ | |
| jobs.c | src/ported/jobs.rs | 3,320 | 7,803 | 235.0% | 57 | 57 | 0 | ⚠️ | |
| hist.c | src/ported/hist.rs | 3,970 | 9,186 | 231.4% | 76 | 76 | 0 | ⚠️ | |
| utils.c | src/ported/utils.rs | 7,792 | 17,967 | 230.6% | 172 | 172 | 0 | ⚠️ | |
| prompt.c | src/ported/prompt.rs | 2,562 | 7,230 | 282.2% | 32 | 32 | 0 | ✅ | |
| init.c | src/ported/init.rs | 2,001 | 3,614 | 180.6% | 23 | 23 | 0 | ✅ | |
| signals.c | src/ported/signals.rs | 1,339 | 3,871 | 289.1% | 27 | 27 | 0 | ⚠️ | |
| TOTAL (core) | 55,444 | 172,186 | 310.6% | 870 | 865 | 5 | ℹ️ | ||
&RENAMING PATTERNS
C uses free functions with global state. Rust uses struct methods, enum variants, and pattern matching. Every “renamed” C function maps to a Rust equivalent under an idiomatic name. This section explains the mapping patterns.
params.c → ParamTable
60+ GSU callback pointers (randomgetfn, uidsetfn, ifsgetfn, homegetfn, termsetfn, etc.) become match arms in ParamTable::get_special_value() and handle_special_set(). Internal helpers (getparamnode, assigngetset, scanparamvals, paramvalarr, getvaluearr) become get_param(), set_scalar(), scan_match(). Env functions (zputenv, addenv, mkenvstr, delenv, copyenvstr) use std::env::set_var/remove_var. Nameref (resolve_nameref_rec, setscope, upscope) becomes resolve_nameref_name(). Uniq array (simple_arrayuniq, newuniqtable, arrayuniq) becomes uniq_array().
parse.c → ShellParser + AST
C’s recursive-descent functions (par_for, par_case, par_if, par_while, par_repeat, par_subsh, par_funcdef, par_time, par_dinbrack, par_simple, par_redir, par_wordlist, par_cond*) become parse_for(), parse_case(), parse_if(), etc. Bytecode system (ecadd, ecdel, ecstrcode, bld_eprog, ecgetstr, ecgetlist, ecgetredirs, init_eprog) replaced by typed AST: ShellCommand enum with Simple, Pipeline, Compound, FunctionDef. ZWC dump/load (dump_find_func, bin_zcompile, load_dump_header, write_dump, build_dump, try_dump_file) moves to zwc.rs.
exec.c → ShellExecutor
execlist→execute_list(), execpline→execute_pipeline(), execsimple→execute_simple(), execode→execute_command(). Function: execshfunc/runshfunc→call_function(), execautofn→autoload_function(). Pipes: spawnpipes/getpipe inline in pipeline execution. Fd: fixfds/closemn/closemnodes inline.
glob.c → Qualifier enum
15 qualifier test functions (qualdev, qualnlink, qualuid, qualgid, qualisdev, qualisblk, qualischr, qualisdir, qualisfifo, qualislnk, qualisreg, qualissock, qualflags, qualmodeflags, qualnonemptydir) become enum variants + GlobMatch::from_path(). Match internals (igetmatch, matchpat, parsecomplist, parsepat, insert_glob_match) in getmatch(), pattern_match(), GlobEngine::glob().
init.c → init_main()
zsh_main→init_main(). Subsystem inits (init_signals, init_misc, init_bltinmods, init_shout, setupshin) fold into ShellExecutor::new() and init_main(). Stubs (noop_function, noop_function_int, zleentry, fallback_compctlread) not needed. parseopts_insert/printhelp/getmypath/tccap_get_name handled inline.
lex.c → Lexer struct
lexinit/initlextabs→Lexer::new(). lex_context_save/restore→save_state()/restore_state(). checkalias/exalias inline in next_token(). skipcomm→lex_comment(). Raw buffer ops (zshlex_raw_add/back/mark/back_to_mark) unnecessary — Rust String handles buffer ops natively.
math.c → MathEvaluator
lexconstant part of number parser. callmathfunc→call_math_func(). setmathvar→set_variable(). getmathparam→get_variable(). mathevall→evaluate(). checkunary/notzero/getcvar inline in eval loop.
jobs.c builtins
bin_fg, bin_kill and bin_suspend keep their C names in src/ported/jobs.rs, the same file as the job internals, as in C, and are registered in BUILTINS (src/ported/builtin.rs).
subst.c
wcpadwidth/subst_parse_str inline in SubstState methods. All 22 other functions matched by name.
$KEY FEATURES PORTED
params.c — Full Parameter System
All 80+ special params with dynamic get/set:
$?,$$,$!,$#,$*,$@,$0,$_,$-RANDOM(LCG PRNG, seedable),SECONDS(int + float modes)ERRNO,UID/EUID/GID/EGID(with setuid on assign)COLUMNS/LINES(ioctl),SHLVL,FUNCNEST,OPTIND/OPTARGIFS,HOME,TERM,WORDCHARS,HISTCHARSPS1-PS4,RPS1/2,RPROMPT/2,SPROMPT,POSTEDITPATH/path,CDPATH/cdpath,FPATH/fpathtied pairspipestatus,argv,HISTSIZE/SAVEHIST- Namerefs with loop detection, scope push/pop with save/restore
typeset -pre-executable output,+=augmented assignment
pattern.c — Complete Pattern Engine
Bytecode-compiled pattern matcher:
- Wildcards:
*,?,[...],[!...],[^...] - Extended glob:
#(0+),##(1+),^(negation),~(exclusion) - KSH globs:
?(pat),*(pat),+(pat),!(pat),@(pat) - Numeric ranges:
<n-m>,<n->,<-m> - Backreferences with
()capture groups (9 max) - Case-insensitive:
(#i), lowercase-match-upper:(#l) - POSIX classes:
[:alpha:],[:digit:],[:space:], etc. - Glob flags:
(#b)backrefs,(#m)match refs,(#s)/(#e)anchors - Pattern scope management for completion system
Builtins — Ported + Extensions
Every ported zsh builtin (BUILTINS, src/ported/builtin.rs), plus the extension builtins, including the in-process coreutils:
- Variables:
typeset/local/declare/export/readonly/integer/float - I/O:
print/printf/echo/read/getln/pushln - History:
fc/history/r - Control:
eval/source/exec/command/builtin/noglob - Jobs:
bg/fg/jobs/kill/wait/disown/suspend - Dir:
cd/pushd/popd/dirs/pwd - Options:
set/setopt/unsetopt/emulate - Traps:
trap/kill - Completion:
compgen/complete/compdef/compadd/compset - ZLE:
bindkey/zle/vared - Modules:
zmodload/autoload/functions - Files:
mkdir/rmdir/rm/cp/mv/ln/chmod/chown - Coreutils (anti-fork):
cat/head/tail/wc/sort/find/uniq/cut/tr/seq/rev/tee/sleep/date/mktemp/hostname/uname/whoami/id/basename/dirname/touch/realpath - Misc:
getopts/zparseopts/zstyle/sched/zformat/coproc
glob.c — Full Globbing
Complete file globbing engine:
- Recursive scanning with
**/support - Brace expansion:
{a,b,c},{1..10},{a..z} - 20+ glob qualifiers:
(.)regular,(/)dir,(@)symlink,(=)socket,(p)fifo,(%b)block,(%c)char - Permission qualifiers:
(r)/(w)/(x),(R)/(W)/(X),(s)setuid - Ownership:
(u:name:),(U)owned by EUID - Size/time/links:
(L+n),(m-n),(l+n) - Sorting:
(on)name,(oL)size,(om)mtime - Match/replace:
${var/pat/repl},${var//pat/repl} - Tokenization:
tokenize(),shtokenize(),zshtokenize()
hist.c — Full History
Complete history expansion and management:
- Event designators:
!!,!n,!-n,!string,!?string? - Word designators:
!:0,!:^,!:$,!:*,!:n-m - Quick substitution:
^old^new - Modifiers:
:hhead,:ttail,:rroot,:eext,:l/:ucase,:s/o/n/subst,:&repeat,:q/:Qquote,:xwords,:aabs path - File I/O with locking, extended format timestamps
- Deduplication, blank reduction, word splitting
- History stack for nested parsing contexts
- Search: prefix (
hcomsearch) and substring (hconsearch)
jobs.c — Full Job Control
Complete job lifecycle management:
- Job table with add/remove/reap/expand/shrink
- Process tracking:
update_process,update_job,update_bg_job - Wait:
waitforpid,waitjob,waitjobs,waitonejob - Control:
fg_job,bg_job,disown_job,killjob - Process groups:
acquire_pgrp,release_pgrp - Pipestats tracking with
PIPEFAILsupport - Background status:
addbgstatus/getbgstatus - Superjob/subjob hierarchy
- Time reporting:
format_timewith%E/%U/%S/%P/%J - Signal name/number conversion: all 31 standard signals
utils.c — utility surface
Complete utility library:
- Error/warning:
zerr,zerrnam,zwarn,zerrmsg - Quoting:
quotestring(7 modes),quotedzputs,dquotedztrdup - String ops:
sepsplit,spacesplit,sepjoin,zjoin,colonsplit - Path ops:
expand_tilde,findpwd,lchdir,xsymlink,slashsplit - Named dirs:
finddir,adduserdir,getnameddir,substnamedir - Terminal:
get_term_width/height,adjustwinsize,gettyinfo/settyinfo - Fd:
movefd,redup,zclose,read_loop/write_loop - Escape parsing:
getkeystring(\n\t\xNN\uNNNN\UNNNNNNNN\0NNN\cX) - Spelling correction:
spdist,spckword,spname,mindist - Time:
ztrftime,monotonic_time_ns,zsleep
prompt.c + signals.c + init.c
Complete prompt, signal, and init systems:
- All
%escapes: dir (%~/%//%c), user (%n/%m/%M), status (%?/%#), time (%D/%T/%*), history (%h), jobs (%j), psvar (%v) - Formatting:
%B/%U/%Sbold/underline/standout,%F{color}/%K{color} - Conditionals:
%(?.true.false), truncation, right prompt - True color detection, named colors, highlight parsing
- 28 signal handlers: block/unblock, queue, trap scope management
- Startup sequence:
zshenv,zprofile,zshrc,zlogin,zlogout - Emulation modes: zsh, sh, ksh, csh
@PER-SYMBOL PORT INDEX
Hand-maintained per-function tables previously claimed a fixed “859” row total and drifted (wrong Rust paths, inflated coverage). Those rows are removed. The port_report.html file produced by python3 scripts/gen_port_report.py lists every C symbol the indexer extracts from src/zsh/Src/**/*.c (heuristic: top-level ident( with a following {) together with Rust placement and port-doc pointers — regenerate after upstream or port changes.
The core file table above (between PORT_REPORT:CORETABLE markers) is rewritten by the same script from live tree counts; it is not manually curated.
!TEST RESULTS
Pass/fail counts are intentionally not pinned in this HTML snapshot (they drift with feature flags and cargo version). The static surface is the #[test] hook total in the engineering overview below. For a local matrix run cargo test with the same features you ship; when triaging ordering-sensitive cases, --test-threads=1 remains the tie-breaker.
~ARCHITECTURE: WHY RUST IS DIFFERENT
C wordcode vs Rust AST port
C zsh lowers shell to wordcode (ecadd, ecstrcode, bld_eprog) executed from Src/exec.c. The zshrs parser port surfaces a typed AST instead (ShellCommand::Pipeline(Vec<ShellCommand>, bool), etc.), so many wordcode helpers disappear behind enum variants and structured lowering.
Methods Instead of Function Pointers
C’s parameter system uses GSU (get/set/unset) function pointer structs — 60+ callback functions like randomgetfn, uidsetfn, ifsgetfn. Rust dispatches by parameter name in two central match expressions: get_special_value() and handle_special_set(). Same functionality, ~130 fewer function definitions.
Native UTF-8 vs Meta Encoding
C’s zsh uses a custom “meta” encoding for strings containing special characters (20+ functions: metafy, unmetafy, metalen, unmeta, metacharinc, mb_metacharlenconv, etc.). Rust’s String is natively UTF-8. Most meta functions become identity operations or char iteration.
RAII vs Manual Memory
C requires explicit freearray(), freeparamnode(), freeeprog(), freerepldata(), freestr(), deleteparamtable(). Rust’s ownership system handles all of these automatically via Drop. These functions are provided as no-ops for API completeness.
%ENGINEERING OVERVIEW
Workspace-wide cargo workspace layout (zshrs root crate — compsys folded in — plus zshrs-daemon, znative, and vendored crates). Size figures are not typed here; regenerate them with git ls-files '*.rs' | xargs wc -l when needed.
ΔMAY 2026 — RECENT PORT WORK
Three themes closed out across May 2026: (1) every // Deferred / // FAKE / // stub marker in builtin.rs turned into a real C-faithful body, (2) the try_with_executor dispatch path — a Rust-only abstraction that bypassed paramtab — was removed from src/ported/ in May (40 → 0 call sites; later work reintroduced calls, see below), and (3) all 30 module files (clone/cap/example/datetime/socket/tcp/stat/zftp/zprof/zselect/watch/zpty/termcap/terminfo/attr/system/zutil/ksh93/db_gdbm/pcre/param_private/mathfunc/langinfo/hlgroup/mapfile/parameter/nearcolor/random/regex/files) were migrated from per-module featuresarray/handlefeatures/getfeatureenables/setfeatureenables stub copies to the canonical crate::ported::module::* impls — 4 stubs × 30 modules = 120 duplicate fake fns deleted, replaced with slice-based module::Features { bn_list, cd_list, mf_list, pd_list } arrays populated with the real BUILTIN/CONDDEF/MATHFUNC/PARAMDEF entries.
Other major de-faking in May: fake structs in hashtable.rs deleted (CmdName / Alias / Reswd / DirCache / SuffixAliasTable / ReswdToken / ShFunc impl block — all replaced with canonical lowercase C-named structs from zsh_h.rs), jobs.rs deleted (JobEntry / BgStatus / PipeStats / CommandTimer / JobPointers fake aggregates; JobState/JobInfo/JobTable moved out to exec_jobs.rs), input.rs deleted (StringInput convenience wrapper, InputBuffer aggregate, INP_* drift constants), glob.rs deleted (GlobOptions / GlobSort / SortOrder / SortSpec / TimeUnit / SizeUnit / RangeOp / impl GlobMatch), cond.rs deleted (CondType / CondResult / CondEval fake enums), module.rs deleted (Wrapper struct + addwrapper/deletewrapper), options.rs deleted (ShellOption enum, with opt_state_get("name") globally swapped to isset(OPT_CONST)).
| Area | What landed | C source | Rust location |
|---|---|---|---|
| builtin.rs | loadautofn — real $fpath walk + file read + PM_UNDEFINED clear (was return-0 stub) | exec.c:5050 | ported/builtin.rs:883 |
| builtin.rs | bin_functions -c autoload-trampoline now invokes loadautofn | builtin.c:3414 | ported/builtin.rs:1593 |
| builtin.rs | scanmatchshfunc wired (replaces stale “funcs.rs” comment that referenced a non-existent file) | builtin.c:3682 | ported/hashtable.rs |
| builtin.rs | bin_functions -M / +M / -m+M — full add/list/remove/match paths into the new MATHFUNCS global | builtin.c:3478–3611 | ported/module.rs:31 |
| builtin.rs | bin_return POSIX-trap promotion to TRAP_STATE_FORCE_RETURN | builtin.c:5845–5854 | exec.rs::TRAP_STATE/TRAP_RETURN |
| builtin.rs | bin_enable toggles for Builtin / Shfunc / Reswd via real disable/enable; new BUILTINS_DISABLED set | builtin.c:541–547 | ported/builtin.rs |
| builtin.rs | init_builtins — real reswdtab.disable("repeat") when not EMULATE_ZSH | builtin.c:212 | ported/builtin.rs:361 |
| signals.rs | SIGPIPE / SIGHUP / SIGINT / SIGWINCH / SIGALRM real bodies (zexit, errflag, stopmsg, adjustwinsize, TMOUT) | signals.c:429–498 | ported/signals.rs:670 |
| signals.rs | POSIXTRAPS option lookup for SIGEXIT sticky-tag bypass | signals.c:746 | ported/signals.rs |
| jobs.rs | kill %jobspec dispatch: real getjob + killjb + SIGCONT-after-stop loop | jobs.c:2989–3010 | ported/jobs.rs:2635 |
| params.rs | getsparam/getiparam/getnparam rewritten to C-faithful single-arg paramtab read (was a drift wrapper around HashMap) | params.c:3076 | ported/params.rs:1726 |
| params.rs | numeric-prefix detection (blanks / minus / 0x / base#) for PM_RIGHT_Z padding | params.c:2446–2466 | ported/params.rs:975 |
| params.rs | fetchvalue real bracket-subscript dispatch into getindex + KSHARRAYS implicit [0] | params.c:2289–2296 | ported/params.rs |
| params.rs | new DELUNSET atomic file-global; deleteparamtable save/restore; freeparamnode unsetfn dispatch | params.c:610 / 5986 | ported/params.rs |
| module.rs | new HOOKTAB global (mirror of Hookdef hooktab) + addhookfunc/deletehookfunc wrappers | module.c:843 | ported/module.rs |
| module.rs | new MATHFUNCS global — user math fn chain for functions -M | module.c:1258 | ported/module.rs:31 |
| zle/zle_main.rs | new WATCH_FDS global — bin_zle -F registration store | zle_main.c:204 | ported/zle/zle_main.rs |
| zle/zle_refresh.rs | new TCOUT_FUNC_NAME global — bin_zle -T tc redisplay transform | zle_refresh.c:246 | ported/zle/zle_refresh.rs |
| zle/zle_vi.rs | VIRANGEFLAG / WORDFLAG / VILINERANGE / VICHGFLAG / VIINREPEAT / VIINSBEGIN atomic file-globals (replaces ViState aggregate) | zle_vi.c:36–78 | ported/zle/zle_vi.rs |
| prompt.rs | sync_from_executor → sync_from_globals: reads paramtab / LASTVAL / curhist / JOBTAB / scriptname directly | prompt.c:56 | ported/prompt.rs |
| utils.rs | printprompt4 reads isset(XTRACE) + getsparam("PS4") + opt_state save/restore | utils.c:1720–1730 | ported/utils.rs:5025 |
| utils.rs | callhookfunc walks shfunctab + paramtab <name>_functions array | utils.c:1494–1514 | ported/utils.rs |
try_with_executor in src/ported/: the May 2026 migration took it from 40 call sites to 0; live calls have since returned in exec.rs, builtin.rs and subst.rs (list them with grep -rn 'try_with_executor(' src/ported | grep -v //).
*MODULE BREAKDOWN BY SUBSYSTEM
Every tracked .rs file under src/ported/ assigned to exactly one subsystem; lines from git ls-files 'src/ported/*.rs' | xargs wc -l (106 files), 2026-10-18.
| Subsystem | Modules | Lines | % | Coverage Bar | Description |
|---|---|---|---|---|---|
| Core Engine | lex, parse, exec, subst, loop, cond, builtin, builtins/* | 103,466 | 23.0% | Lexer, parser, executor (pipelines, redirects), substitution, loops and conditionals, the builtin table | |
| ZLE Line Editor | zle/* (28 files) | 125,185 | 27.8% | Keymaps, widgets, vi mode, completion, refresh, history navigation, text objects, complete/complist/compctl/compmatch/compcore | |
| Loadable Modules | modules/* (33 modules + mod.rs, tcp_h.rs) | 69,562 | 15.4% | 33 module ports: networking, files, PCRE, curses, profiling, pseudo-tty, parameter introspection, math functions, db_gdbm, etc. | |
| Utilities | utils, compat, sort, string, input, linklist, mem | 28,508 | 6.3% | String ops, quoting, escape parsing, path resolution, spelling correction | |
| Parameters | params | 23,620 | 5.2% | Special params, namerefs, scoping, tied pairs, typeset, GSU dispatch (param_private and parameter are counted under Loadable Modules) | |
| Pattern / Glob | pattern, glob | 21,213 | 4.7% | Compiled pattern engine, glob qualifiers, brace expansion, match/replace | |
| Jobs / Signals | jobs, signals, signals_h | 13,132 | 2.9% | Process lifecycle, pipestats, trap scopes, signal queuing, fg/bg/disown | |
| Math | math | 7,752 | 1.7% | Arithmetic evaluator (mathfunc is counted under Loadable Modules) | |
| Prompt / Text | prompt, text | 9,685 | 2.1% | % escape expansion, colors, truncation, right prompt, AST deparsing | |
| History | hist | 9,186 | 2.0% | Expansion (!!/!$/^old^new), modifiers (:h:t:r:e:s), file I/O, word splitting | |
| Options / Init | options, init, context | 8,083 | 1.8% | Shell options, startup files, emulation modes (sh/ksh/csh/zsh) | |
| Other | hashtable, hashtable_h, hashnameddir, module, modentry, zsh_h, zsh_system_h, ztype_h, config_h, prototypes_h, patchlevel, openssh_bsd_setres_id, mod | 31,288 | 6.9% | Hash tables, module loader, header ports (zsh.h, system.h, ztype.h, config.h, prototypes.h) | |
| TOTAL (src/ported/) | 450,680 | 100% | |||
+33 LOADABLE MODULE PORTS
Each C module from src/zsh/Src/Modules/ has a corresponding strict-port Rust implementation in src/ported/modules/. Module file set is included in the file freeze on src/ported/; every module now routes its features_ / enables_ / cleanup_ hooks through the canonical module::featuresarray / handlefeatures / setfeatureenables impls instead of per-module Rust-only stub copies.
zsh/attr
zgetattr, zsetattr, zdelattr, zlistattr — extended attributes (xattr)
zsh/cap
cap, getcap, setcap — POSIX capabilities (gated on Linux and a libcap cargo feature that Cargo.toml does not declare, so absent from current builds)
zsh/clone
clone builtin — fork shell to new tty
zsh/curses
zcurses — ncurses windows, colors, attributes, input
zsh/datetime
strftime builtin, $EPOCHSECONDS/$EPOCHREALTIME/$epochtime
zsh/db/gdbm
ztie, zuntie, zgdbmpath — GDBM tied associative arrays
zsh/example
Demonstration module — builtins / conddefs / mathfuncs / paramdefs
zsh/files
chgrp, chmod, chown, ln, mkdir, mv, rm, rmdir, sync + zf_ aliases (18 entries)
zsh/hlgroup
$.zle.esc, $.zle.sgr — highlighting group helper
zsh/ksh93
nameref + .sh.* param family (edchar, edmode, file, lineno, match, name, subscript, subshell, version)
zsh/langinfo
$langinfo — nl_langinfo(3) queries (CODESET, D_FMT, etc.)
zsh/mapfile
$mapfile assoc array — memory-mapped file access
zsh/mathfunc
48 math functions (sin/cos/log/sqrt/atan/copysign/hypot/ilogb/nextafter/scalb/...)
zsh/nearcolor
Hook into get_color_attr for nearest-truecolor remap
zsh/newuser
First-login wizard hook (~/.zshrc seeding)
zsh/param/private
private builtin — local-only param scope override
zsh/parameter
33 magic assoc params: $parameters, $functions, $aliases, $commands, $options, $history, $modules, etc.
zsh/pcre
pcre_compile, pcre_match, pcre_study, =~ condition — Perl-compatible regex
zsh/random
$SRANDOM, zrand_float, zrand_int — /dev/urandom backed
zsh/random/real
Real-valued random number generation (extras for math expressions)
zsh/regex
POSIX regex-match condition — [[ x =~ pat ]]
zsh/net/socket
zsocket builtin — Unix domain sockets
zsh/stat
zstat, stat builtins — stat fields, formatting, array output
zsh/system
syserror, sysread, syswrite, sysopen, sysseek, zsystem flock, systell math fn, $errnos/$sysparams
zsh/net/tcp
ztcp builtin — TCP client/server connections
zsh/termcap
echotc + $termcap assoc — termcap capability database
zsh/terminfo
echoti + $terminfo assoc — terminfo capability database
zsh/watch
log builtin, $WATCH/$watch arrays — login/logout watching, utmp parsing
zsh/zftp
zftp builtin — full FTP client (open / get / put / ls / cd / mkdir / ...)
zsh/zprof
zprof builtin — function profiler (gprof-style call/arc graph)
zsh/zpty
zpty builtin — pseudo-terminal process management
zsh/zselect
zselect builtin — poll/select on file descriptors
zsh/zutil
zformat, zparseopts, zregexparse, zstyle — completion-system utilities
^ZLE LINE EDITOR — 28 FILES, 125,185 LINES
The Zsh Line Editor (ZLE) is a complete terminal-based input system with vi and emacs keybinding modes, programmable widgets, and inline completion. Ported from src/zsh/Src/Zle/*.c. Files mirror the C source 1:1 with the canonical zsh prefix (zle_* / comp* / termquery / deltochar).
| File | Lines | Responsibility |
|---|---|---|
| computil.rs | 11,626 | Completion utility functions used by _arguments etc. |
| zle_refresh.rs | 10,025 | Screen refresh, cursor positioning, line wrapping, TCOUT_FUNC_NAME |
| compcore.rs | 9,598 | Completion core: shared matcher state, group ordering |
| complist.rs | 9,093 | Menu selection (Tab cycling, arrow nav, mouse) |
| compctl.rs | 8,606 | Legacy compctl system (pre-compsys, kept for back-compat) |
| compmatch.rs | 7,566 | Match patterns, anchor matching, case-insensitive matchers |
| zle_tricky.rs | 7,103 | Completion: prefix matching, menu selection, listing |
| compresult.rs | 6,212 | Match result presentation, prefix/suffix sharing |
| zle_main.rs | 5,594 | ZLE main loop, key reading, widget dispatch, initialization, WATCH_FDS |
| complete.rs | 5,039 | Completion engine: compadd, compset, _arguments dispatch |
| zle_keymap.rs | 4,911 | Keymap management, key binding, bindkey builtin |
| zle_misc.rs | 4,874 | Miscellaneous widgets: transpose, case change, undo, named-cmd lookup |
| zle_hist.rs | 4,168 | History widgets: up/down, search, accept-line |
| zle_utils.rs | 3,769 | ZLE utility functions, character classification, prompt expansion |
| zle_thingy.rs | 3,365 | Thingy (widget reference) management, zle -A / zle -N |
| zle_params.rs | 3,049 | ZLE special parameters: $BUFFER, $CURSOR, $LBUFFER, $RBUFFER, $REGION_ACTIVE, etc. |
| zle_vi.rs | 2,903 | Vi mode: motions, operators, text objects, registers; VIRANGEFLAG / WORDFLAG / VILINERANGE / VICHGFLAG / VIINREPEAT / VIINSBEGIN atomics |
| termquery.rs | 2,616 | Terminal capability queries (tigetstr / tparm) |
| zle_word.rs | 2,574 | Word detection, WORDCHARS handling, shell-word vs vi-word |
| zle_move.rs | 2,466 | Cursor movement: word, line, char, matching bracket |
| zle_h.rs | 2,003 | Header port — keymap / widget / keystruct types |
| comp_h.rs | 1,971 | Header port — Cmatcher / Cmgroup / Cmlist types |
| zle_bindings.rs | 1,802 | Default emacs/vi keymap tables |
| zleparameter.rs | 1,450 | $widgets, $keymaps, $builtins intro params for zle/parameter module |
| compctl_h.rs | 1,305 | Header port for compctl |
| textobjects.rs | 1,040 | Vi text objects: iw, aw, i", a(, i{, etc. |
| deltochar.rs | 353 | Delete-to-char widget (Vi f/t/F/T family) |
| mod.rs | 104 | Module declarations and re-exports |
| TOTAL ZLE | 125,185 |
;PORTED SHELL BUILTINS
The ported builtin table is BUILTINS in src/ported/builtin.rs; each BUILTIN(...) row names its bin_* handler, defined in src/ported/builtin.rs or in the port file that owns it (src/ported/modules/*.rs, src/ported/zle/*.rs, jobs.rs, options.rs, builtins/rlimits.rs, …). The table holds BUILTIN( rows (fg, kill and suspend are each registered twice) and BIN_PREFIX( precommand modifiers; every distinct BUILTIN name is listed below. compat_builtin_names() (src/extensions/ext_builtins.rs), which feeds the reference’s Compat Builtin Index and zbanner, dedups the table. The zshrs extension builtins (EXT_BUILTIN_NAMES: coreutils, parallel primitives, compgen/complete, …) are a separate table and are not listed here.
Variable Declaration (12)
typeset local declare export readonly integer float set unset shift private nameref
I/O (6)
echo print printf read getln pushln
Flow Control & Exit (9)
. source eval break continue return exit bye logout
Job Control & Traps (8)
bg fg jobs kill wait disown suspend trap
Directory (6)
cd chdir pushd popd dirs pwd
History (3)
fc history r
Options & Emulation (5)
setopt unsetopt emulate enable disable
Alias, Function & Hash (8)
alias unalias functions autoload unfunction hash unhash rehash
Lookup (4)
type whence where which
Test & Arithmetic (6)
test [ let true false :
Modules, Compilation & Option Parsing (4)
zmodload zcompile getopts zparseopts
Completion (compctl / computil / complete) (12)
compadd comparguments compcall compctl compdescribe compfiles compgroups compquote compset comptags comptry compvalues
ZLE (3)
bindkey zle vared
File Operations (zsh/files) (18)
chgrp chmod chown ln mkdir mv rm rmdir sync zf_chgrp zf_chmod zf_chown zf_ln zf_mkdir zf_mv zf_rm zf_rmdir zf_sync
stat & xattr (zsh/stat, zsh/attr) (6)
stat zstat zgetattr zsetattr zdelattr zlistattr
System (zsh/system) (6)
syserror sysopen sysread sysseek syswrite zsystem
Limits, Timing & Scheduling (6)
ulimit limit unlimit umask times sched
Networking (3)
ztcp zsocket zftp
Terminal (6)
echotc echoti ttyctl zcurses zpty zselect
zsh/zutil (3)
zformat zstyle zregexparse
Other Modules (14)
strftime clone log cap getcap setcap example zprof ztie zuntie zgdbmpath pcre_compile pcre_match pcre_study
Debug-Build Builtins (zsh: ZSH_HASH_DEBUG / ZSH_MEM_DEBUG / ZSH_PAT_DEBUG) (3)
hashinfo mem patdebug
zshrs-native (no C counterpart) (1)
__rust_compile
Precommand modifiers (BIN_PREFIX, not counted above) (5)
- builtin command exec noglob
&DEPENDENCY ARCHITECTURE
Line counts are wc -l on the named files under src/ported/ (directories: sum of their tracked .rs files), 2026-10-18.
┌─────────────────────────────────────┐
│ exec.rs (15,029) │
│ builtin.rs (25,612) │
└──────────────────┬──────────────────┘
│
┌───────────────────────────┼───────────────────────────┐
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ parse.rs │ │ lex.rs │ │ subst.rs │
│ (12,808) │ │ (7,739) │ │ (34,354) │
└─────┬─────┘ └───────────┘ └─────┬─────┘
│ │
├─────────────┬─────────────┬─────────────┬─────────────┼─────────────┐
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ params │ │ pattern │ │ glob │ │ hist │ │ math │ │ text │
│ (23,620) │ │ (11,279) │ │ (9,934) │ │ (9,186) │ │ (7,752) │ │ (2,455) │
└─────┬─────┘ └───────────┘ └───────────┘ └─────┬─────┘ └───────────┘ └───────────┘
│ │
┌─────▼─────┐ ┌───────────┐ ┌───────────┐ ┌─────▼─────┐ ┌───────────┐ ┌───────────┐
│ utils │ │ jobs │ │ signals │ │ prompt │ │ init │ │ options │
│ (17,967) │ │ (7,803) │ │ (3,871) │ │ (7,230) │ │ (3,614) │ │ (3,630) │
└───────────┘ └─────┬─────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘
│
┌─────────────┼─────────────┬─────────────┐
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ zle/ │ │ cond │ │ loop │ │ modules/ │
│ (125,185) │ │ (2,220) │ │ (1,300) │ │ (69,562) │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
◆COMPSYS — ZSH COMPLETION SYSTEM IN RUST
zsh’s compsys — the programmable completion system — inside the runtime crate under src/compsys/ (the former standalone crate was folded in). Runtime files plus engine ports under src/compsys/ported/, which sit beside the upstream Completion/ files copied verbatim.
| Module | Lines | Description |
|---|---|---|
| ported/ (250 files) | 76,916 | Engine functions ported to Rust, one .rs per upstream function, each citing its shell source; per-directory breakdown below. |
| cache.rs | 2,149 | SQLite mirror tables for compsys. Mirror only — the authoritative completion cache is the rkyv-mmap’d shard set (zero-copy hot path); this file backs dbview / SQL inspection. |
| router.rs | 1,012 | Backend router between the Rust ports under ported/ and the upstream shell functions. |
| in_editor.rs | 837 | In-editor entry point: drives _main_complete outside an interactive shell so the LSP gets the match list a Tab press would produce. |
| zpwr_colors.rs | 804 | ZPWR zstyle color configuration parser. |
| mod.rs | 342 | Module root. |
| TOTAL COMPSYS | 82,060 | 255 files |
// 250 ENGINE PORTS BY UPSTREAM DIRECTORY
| Directory | Files | Lines |
|---|---|---|
| Unix/Type | 70 | 19,130 |
| Base/Utility | 26 | 11,268 |
| (top level: compinit, compdump, compaudit, shared, mod) | 5 | 9,546 |
| Base/Core | 11 | 6,564 |
| Zsh/Type | 28 | 6,050 |
| Base/Completer | 16 | 5,188 |
| X/Type | 19 | 3,423 |
| Zsh/Context | 16 | 3,297 |
| Base/Widget | 12 | 2,685 |
| BSD/Type | 11 | 1,934 |
| Linux/Type | 8 | 1,557 |
| Debian/Type | 5 | 1,322 |
| Zsh/Function | 7 | 1,278 |
| Darwin/Type | 3 | 1,129 |
| Zsh/Command | 3 | 781 |
| Solaris/Type | 3 | 760 |
| AIX/Type | 4 | 504 |
| X/Utility | 2 | 469 |
| Unix/Command | 1 | 31 |
| TOTAL PORTED | 250 | 76,916 |
⬢FUSEVM + LEX / PARSE (src/ported/)
Runtime bytecode targets the crates.io fusevm crate (pinned in workspace Cargo.toml). Lexing and parsing live in src/ported/lex.rs and src/ported/parse.rs in the runtime crate (the standalone parse package was absorbed back). Stryke / strykelang is a separate repository — it is not part of this workspace; the former Perl-interpreter block here was erroneous pasted content.
// LEX + PARSER (IN-CRATE PORTS)
| File | Lines | Role |
|---|---|---|
src/ported/lex.rs | 7,739 | Lexer port of Src/lex.c — tokens, contexts, alias fusion |
src/ported/parse.rs | 12,808 | Parser port of Src/parse.c — lists, compounds, redirections |
| LEX + PARSE | 20,547 | two files in src/ported/ (no separate parse crate) |
// EXECUTION PIPELINE (ZSHRS)
Source / REPL input (zsh script)
│
▼
┌─────────────────┐ ┌──────────────────┐
│ Lexer │────▶│ Parser │
│ (lex.rs) │ │ (parse.rs) │
│ token stream │ │ AST / commands │
└────────┬────────┘ └────────┬─────────┘
│ │
└───────────┬───────────┘
▼
┌────────────────────┐
│ compile_zsh (+AOT) │ ──▶ fusevm bytecode (workspace crate)
│ extensions/ │
└─────────┬──────────┘
▼
┌────────────────────┐
│ ShellExecutor / VM │ ──▶ builtins, jobs, redirects, zle
└────────────────────┘
●BEYOND THE C PORT — RUNTIME INFRASTRUCTURE
The C-to-Rust port covered above lives under src/ported/ against upstream src/zsh/Src/**/*.c. The numbers below count what zshrs adds — new Rust code with no C ancestor. This is the layer that takes zshrs from “zsh in Rust” to “the first JIT-compiled Unix shell with a session-persistent daemon, AOP-intercept recorder, and bidirectional ptmx-attach job supervisor.” Non-port runtime code lives in src/extensions/ — mechanically isolated from src/ported/ by tests/port_purity.rs.
| Crate / Layer | Files | Lines | Pub Fns | Tests | Purpose |
|---|---|---|---|---|---|
src/extensions/ |
135 | 148,648 | 945 | 1,417 | The non-port directory. Features zsh C demonstrably does not have: AOT compile (aot.rs, compile_zsh.rs), autoload / plugin / script caches (autoload_cache.rs, plugin_cache.rs, script_cache.rs), fish-style features (fish_features.rs), persistent worker pool (worker.rs), arith JIT compiler (arith_compiler.rs), AST s-exp dump (ast_sexp.rs), ZWC byte-code helpers (zwc.rs, zwc_decode.rs), recorder hooks (recorder.rs), daemon presence (daemon_presence.rs), structured logging (log.rs), ext builtins (ext_builtins.rs), regex module (regex_mod.rs), config (config.rs), overlay snapshot + canonical apply (overlay_snapshot.rs, canonical_apply.rs), fds / hist (fds.rs, history.rs), stringsort (stringsort.rs), completion shim (completion.rs). Mounted at the crate root by #[path = "extensions/…"] module declarations in src/lib.rs, so call sites resolve to crate::aot::*, etc. |
daemon/ |
43 | 29,687 | 239 | 142 | Singleton daemon: IPC server, HTTP listener (auto-derived OpenAPI 3.1), canonical-state engine, fsnotify, schedule, supervisor (jobs + bidirectional ptmx attach), pub/sub bus, named locks, ask-inbox, snapshots, artifacts, cache. Hosts every z* builtin. |
src/recorder/ (feature-gated) |
1 | 2,134 | 56 | 2 | AOP intercept: every state-mutating dispatcher fires a record event with (kind, name, value, file, line, fn_chain). #[cfg(feature = "recorder")]-gated — deleted by rustc in the default zshrs build, compiled into the separate zshrs-recorder binary. Replaces the static-walker approach every other shell uses for completion/fpath scanning. |
vendor/fish/ |
157 | 88,088 | 1,244 | 175 | Fish-style reader, syntax highlighter, autosuggestions, abbreviations, env dispatch, history backend, process control, event system. Largest non-port surface in the workspace. |
src/compsys/ |
255 | 82,060 | 501 | 1,032 | Completion system inside the runtime crate: SQL mirror, backend router, in-editor entry point, and 250 engine ports of upstream Completion/ shell functions. No C ancestor (zsh's compsys is shell-script, not C). |
| NEW INFRASTRUCTURE (rows above) | 591 | 350,617 | 2,985 | 2,768 | |
Sums cover the five layers in this table only. Workspace-wide Rust LOC additionally includes src/ported/, the top-level src/*.rs glue, tests/, examples/, bins/, build.rs, znative/ and runtime/. | |||||
Architectural moves with no zsh equivalent: the 90/10 daemon/shell work split (singleton daemon owns every mutation; thin shell clients are stateless and forkable);
the recorder-owns-rebuild stance (no in-daemon walker; zshrs-recorder is the sole producer of recorder-managed canonical subsystems);
the single ~/.zshrs/ directory rule (every config + log + sqlite + rkyv shard + socket under one root, configurable via $ZSHRS_HOME);
the z* builtin family (zcache / zls / zsend / znotify / zsubscribe / zjob / zsync / zask / zlock / zpublish / zwhere / zd);
session-persistent supervised jobs with bidirectional ptmx attach (replaces nohup + screen + pueue + disown);
the auto-derived OpenAPI 3.1 surface at GET /openapi from the daemon op registry;
the flat zsh-extended-history text file + sibling FTS5 sqlite index;
zsh grammar introspection to stdout (lexer token stream, Eprog wordcode layout, parser AST S-expression) via zshrs --dump-* and zshrs_dump (dumptokens, dumpwordcode) in formats byte-diffable against parity harnesses — not shipped as a trio by stock zsh.
Op-by-op detail in
daemon-report.html.
≡GRAND TOTAL — FULL WORKSPACE
Four Rust packages in one Cargo workspace (zshrs + zshrs-daemon + znative + zshrs-runtime, the 16-line crate that emits the zsh staticlib for AOT linking; compsys was folded into zshrs). Size figures are not typed here; regenerate them with git ls-files '*.rs' | xargs wc -l.
| Crate | Description |
|---|---|
zshrs (root, lib zsh) |
Runtime: src/ (ported + extensions + compsys + exec bridge), bins/, tests/, examples/, build.rs. Lines/tests include integration suites. |
vendor/ (vendored crates) |
Vendored third-party crates carried in-tree so a clone builds offline — includes vendor/fish/. (compsys is no longer a separate package — it was folded into the root crate.) |
zshrs-daemon |
Singleton daemon: IPC + HTTP/OpenAPI, canonical shards, jobs, fsnotify, pub/sub. |
znative |
Published plugin ABI SDK: third parties cargo add znative, ship a cdylib, load it via zmodload -R. |
zshrs-runtime |
Emits libzsh.a for AOT linking so cargo install zshrs does not build it (runtime/src/lib.rs). |