Skip to content

Interactive readline

Justin Hileman edited this page Mar 23, 2026 · 2 revisions

🧪 Interactive Readline

PsySH's interactive readline is a pure-PHP readline replacement that gives PsySH full control over input, editing, completion, and rendering. Instead of delegating to ext-readline or ext-libedit, it handles everything directly... which means better completions, multi-line editing, and a bunch of features that weren't possible before.

This is opt-in and experimental. Default behavior is completely unchanged.

Enabling it

// In your PsySH config file
'useExperimentalReadline' => true,
// 'useSuggestions' => true,
// 'useBracketedPaste' => true,
// 'useSyntaxHighlighting' => false,
# Or from the command line
psysh --experimental-readline

Requires an interactive terminal (TTY). Falls back to the standard readline stack automatically in non-interactive contexts.

Smart completions

The old tab completion system matches strings against lists of known symbol names. The new completion engine is fundamentally different:

  • Syntax-aware: Parses your input with php-parser to understand context. It knows $foo-> needs instance methods, Foo:: needs static members, and a bare arra needs global functions or classes.
  • Type-aware: Resolves types through assignments, return types, and doc annotations. $repo->find(1)-> completes with methods on the return type.
  • Runtime-value-aware: Inspects actual live objects in scope. If $user is a User instance, $user-> shows User's real methods and properties, not every symbol name PHP knows about.

Fuzzy matching

Type asum to find array_sum, or stl to find strtolower. No need to remember exact prefixes.

Navigable completion menu

Completions display in a multi-column menu. Use arrow keys to browse, keep typing to filter. Enter to accept, Escape to dismiss.

Custom matchers still work

Existing custom tab completion matchers (via the matchers config option) are automatically bridged into the new completion system via MatcherAdapterSource.

Syntax highlighting

Interactive readline highlights PHP syntax and PsySH commands as you type.

'useSyntaxHighlighting' => true,

This is enabled by default when interactive readline is active. If you run into terminal rendering issues, disable it with 'useSyntaxHighlighting' => false or config set useSyntaxHighlighting off.

Multi-line editing

Press Enter with unclosed brackets or an incomplete statement and the input continues on the next line, with proper indentation. Closing brackets auto-dedent. Shift+Enter always inserts a newline.

No more fighting the shell to write a multi-line closure or a long match expression.

History

Reverse search (Ctrl+R)

Start a reverse history search with Ctrl+R. An overlay shows matching results with highlighting, smart-case filtering, and deduplication. Navigate with Up/Down or Ctrl+R/Ctrl+S, press Enter or Right to accept.

Filtered history navigation

Type the beginning of a previous command, then press Up/Down to cycle through matching history entries. This works like Fish and Zsh: the text you've already typed acts as a filter.

Inline autosuggestions

Fish-style ghost text suggestions from your command history, shown as you type. Press Right or Ctrl+F to accept the full suggestion, Alt+Right to accept word-by-word.

Note

Autosuggestions are behind a separate feature flag because they're still a bit rough around the edges. Enable them with 'useSuggestions' => true in your config.

Auto-pairing

Opening brackets and quotes auto-insert their closing counterpart:

  • Type ( → inserts () with cursor between them
  • Type ) when cursor is before ) → skips over it instead of doubling
  • Backspace between () → deletes both

Works for (), [], {}, "", and ''.

Bracketed paste

Enable bracketed paste with 'useBracketedPaste' => true to have multi-line code inserted verbatim as a single block, without line-by-line execution or auto-indentation interference.

Keyboard shortcuts

Navigation

Key Action
Ctrl+A / Home Move to start of line (toggles between first non-whitespace and column 0)
Ctrl+E / End Move to end of line
Ctrl+B / Left Move cursor left
Ctrl+F / Right Move cursor right (or accept suggestion)
Alt+B / Alt+Left Move word backward
Alt+F / Alt+Right Move word forward (or accept suggestion word)
Up / Down Move within multiline input, then navigate history

Editing

Key Action
Ctrl+W Delete word backward
Ctrl+K Delete to end of line
Ctrl+U Delete to start of line
Delete Delete character forward
Ctrl+D Delete forward (or exit on empty input)

History & completion

Key Action
Tab Complete / indent
Ctrl+R Reverse history search
Up / Down (with text) Filtered history navigation

Control

Key Action
Enter Submit (or continue on next line if incomplete)
Shift+Enter Always insert newline
Ctrl+C Clear current input
Ctrl+L Clear screen
Ctrl+D (empty) Exit

Requirements

  • Interactive terminal (TTY)
  • Symfony Console 5.1+ (for Cursor support)
  • ext-readline and ext-libedit are not required

Feedback

This is experimental and we want your feedback! If you run into issues, rough edges, or have ideas for improvements, please open an issue and let us know. The goal is to make this the default readline implementation.

Clone this wiki locally