Skip to content

Integrated Terminals

Use the terminal chapter for a guided shell/tool session, or the task guide for placement, copy and shutdown procedures. This reference defines the exact interactive terminal commands and limits. One-shot shell commands receive finite stdin and collect plain text for a checked edit; interactive sessions run a shell or tool under a PTY and retain terminal state.

Opening a shell

Use M-x terminal-open, or :terminal-open from modal source editing, to open the instance's default shell in a lower panel. Repeating the command selects the same live session. Creation uses the selected directory context, then the current file's parent or launch directory. Startup [terminal] preferences select the executable and literal argument array; no shell starts automatically.

Live input and mouse

The live panel owns printable keys and ordinary child input in either profile. C-g returns focus to the editor. M-x opens host commands while the panel is focused; a prompt's C-g cancels that prompt before returning editor focus. Printable colon and Escape belong to the live child. C-x retains the host prefix. C-q, or terminal-send-next-key, forwards exactly one following normalized key to the child, including C-g, M-x or C-x. Key releases do not consume that request. Return, Tab, deletion, arrows, Home/End, paging and F1-F20 use classic VT encodings; modified movement uses native modifier parameters. Child application-cursor, reported application-keypad and newline modes are respected. C-c C-t enters a frozen copy view of retained output. C-c C-c sends one child interrupt, and C-q C-c sends it literally; C-c C-g cancels the prefix. An unclaimed second key sends the deferred C-c and that key together.

The child cursor uses its requested block, bar or underline shape and blink state; host prompts and source editing restore their own cursor presentation.

Child-enabled pointer reporting uses classic, UTF-8 or SGR coordinates with button, drag, wheel and requested motion events. Shift retains local cell selection and bounded history scrolling. Without child reporting, pointer selection and wheel scrolling are local to that attachment; retained-history views also keep local control. Releasing outside a captured terminal clips to its admitted cells. Source drags retain their original source owner. Visible terminal surfaces acquire native mouse reports even when source mouse mode is disabled; only a focused child requesting motion acquires all-motion tracking. Hiding or leaving the terminal restores native tracking ownership.

Links and child effects

Control-click activates an OSC 8 hyperlink only after URI validation. Admitted schemes are HTTP, HTTPS, mailto and local file URIs; remote file authorities and executable schemes are rejected. Links require explicit org.tools.viewer argv, using the existing {target} substitution or one appended target. The viewer receives the URI as literal data in the terminal's creation directory, with the existing viewer time/output limits. One activation can be owned at a time. Missing configuration and viewer failure remain visible. Child clipboard requests, host commands, title effects and unsupported graphics remain inert.

Retained output and paste

terminal-copy-mode captures a private read-only projection for the selected attachment. Native point, region, search and selection copying inspect that snapshot while the child continues producing output. Copying retains the view and selection. Return or terminal-copy-mode-done resumes live input without sending a child Return. C-g cancels a search first, then clears a selection, then leaves copy mode; stronger host prompts retain their cancellation owner.

Each projection preserves physical terminal rows, cell spacing, wide characters and combining text, with a 1 MiB UTF-8 text cap. At most 32 projections are retained under an 8 MiB editor storage charge, separately from emulator history. Admission failure keeps existing views and the live child. Local pointer inspection also freezes output; returning its wheel position to the tail, or accepted live input, resumes following. Explicit copy mode retains keyboard ownership until exited.

terminal-yank (C-y in live terminal input) pastes the shared kill ring's newest entry; terminal-yank-pop (M-y) rotates it only while that exact paste remains wholly queued. Any write, later input, protocol reply, unrelated command or changed kill ring ends replacement authority. Rev never guesses how to erase text a child has consumed. Literal-next still sends these keys to the child. Explicit frontend paste uses the same atomic queue and active bracketed-paste mode. Text exceeding the configured input limit, including framing, is rejected before queue mutation. Escape and control characters other than line breaks and tabs are rejected. Child clipboard requests remain denied.

terminal-clear sends C-l to the child; terminal-clear-scrollback removes retained emulator history and copy projections for that session, preserves the live screen and sends no child input. Copy line start/end operate on the frozen text. terminal-reset-cursor-point aligns with the live cursor only while its current text is still represented by that copy; otherwise it reports the need to refresh. terminal-send-return, tab, escape, backspace, delete, up/down, left/right, prior/next (paging), and space use the same mode-aware live VT key encoder. terminal-undo sends C-_ to the child without changing source history. Input commands, including literal-next, require exiting explicit copy mode.

Reported prompts and error locations

terminal-previous-prompt and terminal-next-prompt navigate actual retained OSC 133 A reports in a copy projection. Prompt-looking text supplies no evidence. The engine retains at most 1024 reports, follows ordinary full-screen scrolling and drops unproven positions after resizing or complex grid transformations. Each copy keeps its captured reports while live output continues. terminal-next-error recognizes retained path:line[:column]: error: locations with positive decimal positions. It opens an existing regular file using the terminal's creation directory for relative paths. Missing files, malformed or out-of-range locations and unavailable evidence retain the current source. It does not infer a shell's later working directory. terminal-open-link activates the validated URI at the live cursor or frozen copy point through the configured viewer. Copy snapshots retain at most 1024 link spans charged within 64 KiB; absent evidence never falls back to new live output. Control-click also uses captured evidence during copy inspection.

Placement and selection

Use terminal-toggle to hide or restore the panel without restarting its shell. The panel remembers its height and clamps it to preserve a usable source pane.

list-buffers and switch-to-buffer include the terminal's stable buffer name. C-x b displays a filterable candidate list immediately, including panel sessions. Selecting it restores its current placement. Use terminal-new for an independent panel session or terminal-new-buffer for direct main-area entry. Move the same process with terminal-move-to-buffer and terminal-move-to-panel; a rejected geometry keeps the old attachment. terminal-list shows retained sessions, and terminal-rename accepts a unique 1-256 byte name without control characters. Names start with terminal, then terminal-2 under ordinary buffer name conflict handling.

terminal-open-here uses the current source file's containing directory. For a terminal resource, it uses the admitted creation directory; it does not guess a shell's later working-directory changes. terminal-open-other-pane selects the terminal in the next pane, preparing a right split when there is only one. Splitting a terminal buffer presents the same child in another view; focused live input owns resize, and each attachment retains its own viewport state. Small screens suspend presentation until geometry becomes usable again.

Terminal buffers hold emulator state rather than editable source text, so file saves, text edits, undo, bookmarks, completion, LSP, Org and AI source actions require returning to a source buffer. Killing a live terminal buffer asks before terminating its owned process group.

Command inventory

Every name below is available through M-x and the shared command catalog. Modal colon entry requires a compatible source or copy context: a colon typed in live terminal input belongs to the child.

Command Effect
terminal-open Open or select the instance default interactive terminal in the lower panel.
terminal-toggle Hide or restore the lower terminal panel without restarting the child.
terminal-new-buffer Create an independent terminal directly in the selected editing pane.
terminal-move-to-buffer Move the current terminal into the selected editing pane.
terminal-move-to-panel Dock the same session in the lower panel.
terminal-new Create an independent lower-panel session.
terminal-list Select or inspect retained terminal sessions.
terminal-rename Give the selected terminal buffer a unique name without changing its identity.
terminal-open-here Create a session from the current resource's directory context.
terminal-open-other-pane Select a terminal in the next pane, creating a right split when needed.
terminal-send-next-key Send one following normalized key literally to the child, bypassing host recovery.
terminal-copy-mode Freeze retained output for native navigation, selection and search.
terminal-copy-mode-done Resume live input without sending Return to the child.
terminal-yank Paste the newest retained text using active bracket framing.
terminal-yank-pop Rotate only while the preceding paste remains wholly queued.
terminal-clear Send C-l through ordinary child input.
terminal-clear-scrollback Clear retained history and copy projections, preserving live screen/input.
terminal-beginning-of-line Move to the frozen copy line start.
terminal-end-of-line Move to the frozen copy line end.
terminal-reset-cursor-point Align copy point with a still-represented live cursor.
terminal-undo Send C-_ to the child without source undo.
terminal-send-return Send Return with the live mode-aware VT encoder.
terminal-send-tab Send Tab with the live mode-aware VT encoder.
terminal-send-escape Send Escape with the live mode-aware VT encoder.
terminal-send-backspace Send Backspace with the live mode-aware VT encoder.
terminal-send-delete Send Delete with the live mode-aware VT encoder.
terminal-send-up Send Up with the live mode-aware VT encoder.
terminal-send-down Send Down with the live mode-aware VT encoder.
terminal-send-left Send Left with the live mode-aware VT encoder.
terminal-send-right Send Right with the live mode-aware VT encoder.
terminal-send-prior Send PageUp with the live mode-aware VT encoder.
terminal-send-next Send PageDown with the live mode-aware VT encoder.
terminal-send-space Send Space with the live mode-aware VT encoder.
terminal-next-prompt Navigate the next captured OSC 133 prompt.
terminal-previous-prompt Navigate the previous captured OSC 133 prompt.
terminal-next-error Visit an actually recognized retained error location.
terminal-open-link Explicitly activate the validated link at live or frozen point.

Startup settings

The following seven settings belong to [terminal]. They are read at editor startup and do not start a shell by themselves. terminal.args is literal argv; no -c or login flag is added implicitly. The child inherits the editor's process environment. These preferences are separate from [shell] text-filter preferences. Invalid configuration follows the ordinary all-or-default policy.

Setting Type/range Default Contract
terminal.program String "" Empty selects the nonempty startup SHELL value, then /bin/sh. Otherwise one executable, at most 4096 UTF-8 bytes without NUL.
terminal.args Array of strings [] Whole-array replacement, including an empty array; at most 32 strings and 16384 combined UTF-8 bytes without NUL.
terminal.panel_height Integer 3..=200 10 Preferred terminal content rows, clamped to valid geometry that preserves usable source panes.
terminal.max_sessions Integer 1..=32 8 Owned live and exited sessions; explicit closure releases capacity. Cell admission can reject a session before this count is reached.
terminal.scrollback_lines Integer 0..=20000 2000 Requested retained rows, additionally constrained by cell and extra-storage admission.
terminal.max_pending_input_bytes Integer 4096..=1048576 262144 Complete input sequences are accepted atomically into this bound.
terminal.max_pending_output_bytes Integer 4096..=1048576 262144 Maximum pre-parser output; direct bounded reads apply PTY backpressure without an accumulating output queue.

For example, select an interactive Bash explicitly:

[terminal]
program = "/bin/bash"
args = ["--noprofile", "--norc", "-i"]
panel_height = 15

The complete sample remains the packaged default configuration. No terminal session, process, scrollback or current tool state is restored after restarting rev.

Lifecycle and ownership

State Meaning
Running The editor owns the live child; hidden views do not change this state.
Draining Leader exit was observed; final output and owned cleanup are still pending.
Exited Final output has drained and the actual exit status is known; automatic buffer closure follows.
Closing Cleanup after shell exit or approved termination is running; the buffer and capacity remain owned.
Failed A diagnostic is retained; failure does not count as successful cleanup.
Closed Cleanup completed and the registry can release this session.

Closing a live terminal with kill-buffer asks whether to terminate it. Declining or cancelling retains the session. When the shell exits, with any exit code, rev automatically closes its terminal buffer after draining and successful owned cleanup. A main-area terminal restores source editing; a selected panel terminal is removed from the panel. Background completion preserves unrelated prompts and buffers. Merely hiding the panel, changing buffers or removing a view does not terminate a child. Opening the default after its exit creates a fresh shell. Exited terminal buffers disappear from buffer selection after cleanup.

Quitting first resolves source saves/discards, then asks once about live terminal sessions. Declining keeps the editor and sessions. Approved cleanup runs off the UI: owned session groups receive hangup, a 500 ms grace period, then kill if needed, within the two-second cleanup deadline. This includes owned background groups; unrelated processes are never targeted. Pending or failed cleanup remains visible and cannot be reported as completed. A changed source cancels exit; cancelling exit after cleanup was approved does not undo signals already authorized. A host I/O failure still attempts owned cleanup and terminal restoration. Live commands and loops have no runtime timeout.

Resource limits and rendering

Admission is bounded by 1048576 reserved cells per session and 2097152 across the editor, including both screens, retained rows and row caches. Each session has a separate 8 MiB extras bound; control strings stop at 4096 bytes and combining text at 64 scalars per cell. One service turn handles at most 65536 bytes across sessions with fair rotation. Reads use bounded scratch storage and PTY backpressure; accepted arbitrary bytes are not dropped to meet a limit. A rejected creation, resize, move or paste preserves its previously admitted state and reports the failure.

The host terminal owns fonts, glyph appearance and ligatures. rev renders admitted terminal cells/styles within its own panes. Unsupported child effects do not become host commands or source edits. Physical keys depend on distinguishable terminal reports; in live mode a separately decoded Escape goes to the child, while an explicit reported Alt-x opens host commands. The source editor's Escape/Meta deadline is not a live child prefix.

See the terminal acceptance procedure for the bounded real-shell/lazygit and resource observations.