feat(repl): interactive line editor — history, cursor editing, tab completion (#392)#456
Merged
Merged
Conversation
…mpletion (#392) Port the EigenOS console editor (EigenOS src/hal.c) to the CLI REPL as a zero-dependency raw-termios line editor in the new CLI-only src/repl.c: - history: in-memory ring + EIGS_HISTORY file (default ~/.eigenscript_history, created 0600), draft parking on up-arrow, consecutive dedupe, persistence across sessions - editing: arrows, Home/End/Delete, Ctrl-A/E/U/K/W/L, Ctrl-C cancels the line AND an open ':' block, Ctrl-D is EOF on an empty line - tab completion over builtins + session bindings (both are env bindings, so one env-chain walk covers them) - observer touch: interactive sessions arm g_trace_hist/g_trace_obs_hist from the start, so 'prev of x' works on session bindings (per-line compilation otherwise records no history to answer from) Piped/non-tty stdin keeps the old fgets loop byte-for-byte (verified against a pre-change binary across 9 transcript+rc scenarios); EIGS_REPL_PLAIN=1 forces it on a tty. TCSADRAIN (not TCSAFLUSH) around eval so pasted type-ahead survives. The parse-error path now frees the partial AST (cf. #214) — the old inline loop leaked it. repl.c is CLI-only like main.c (Makefile CLI_ONLY filter for LSP/embed/fuzz; amalgamate.sh drops it) so termios never reaches the embed/freestanding profiles. Suite section [42c]: 3 byte-exact piped-transcript goldens + 13 pty-driven editor tests (tests/test_repl.py). Release and ASan (detect_leaks=1) suites both 2552/2552; make lsp / embed-smoke / freestanding-check green. Closes #392 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
build.sh's hardcoded SOURCES didn't know about the new CLI-only repl.c — undefined reference to eigenscript_repl on every CI job that builds via build.sh (linux/macos matrix, bench, install.sh). The lsp branch strips repl.c alongside main.c. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
openpty()+subprocess left the child with no controlling tty; the raw-termios calls sat in undefined job-control territory — Linux tolerated it, macOS wedged the child and all 13 editor tests hung. pty.fork() gives the child the pty as its controlling terminal, which is what a real terminal session is anyway. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| if r: | ||
| try: | ||
| self.buf += os.read(self.master, 4096) | ||
| except OSError: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The last item in the #419 "Now" tier: the CLI REPL on a tty gets a zero-dependency raw-termios line editor, ported from the EigenOS console editor (the downstream-gap-surfaces-upstream rule applied to our own port). Pressing up-arrow now recalls history instead of printing
^[[A.EIGS_HISTORYfile (default~/.eigenscript_history, created 0600), draft parking on up-arrow, consecutive dedupe, persists across sessions.:block; Ctrl-D is EOF on an empty line.prev of xworks on session bindings; per-line compilation otherwise records nothing to answer from.Invariants held
EIGS_REPL_PLAIN=1forces it on a tty.repl.cis CLI-only likemain.c(MakefileCLI_ONLYfilter for LSP/embed/fuzz builds;amalgamate.shdrops it), so termios never reaches the embed/freestanding profiles.TCSADRAIN, notTCSAFLUSH, around eval — flush discarded pasted type-ahead (found by the pty tests).Acceptance (from #392)
tests/test_repl.py)makeoutput has zero new link dependenciesGates
detect_leaks=1suite 2552/2552 ([42c] re-run standalone against the ASan binary: 16/16)make lsp/make embed-smoke/make freestanding-checkgreenCloses #392
🤖 Generated with Claude Code