Overview
readline wraps GNU Readline — the interactive line-editing library that powers the bash shell, the Python REPL, PostgreSQL's psql, MySQL's mysql client, and hundreds of other CLI tools. It gives users the editing experience they already know from their shell, for free.
Key features: cursor movement within a line (not just backspace), searchable history (Ctrl+R), programmable Tab completion, persistent history files, and switchable vi/emacs key binding modes. All of this with a handful of function calls.
Requires libreadline-dev. Ubuntu/Debian: sudo apt install libreadline-dev
Quick Start
Simple REPL
uses readline;
LoadHistory('/home/user/.myapp_history');
while True do
begin
var line := ReadLineHistory('myapp> ');
if line = '' then Break; { Ctrl+D = EOF }
{ Process command... }
WriteLn('You entered: ' + line);
end;
SaveHistory('/home/user/.myapp_history', 1000);
Custom Tab completion
uses readline;
SetWordList(['help', 'quit', 'load', 'save', 'list', 'show', 'delete']);
while True do
begin
var cmd := ReadLineHistory('cmd> ');
if cmd = 'quit' then Break;
{ Tab completes from the word list }
end;
Reading Input API
The core input functions. ReadLineHistory is the most common — it reads a line, adds it to history automatically, and lets the user edit with full cursor movement.
| Function | Description |
|---|---|
| ReadLine(prompt) | Display prompt and read a line. No history integration. Returns empty string on EOF (Ctrl+D). |
| ReadLineHistory(prompt) | Like ReadLine but automatically adds non-empty lines to the in-memory history. The most common function. |
| ReadLineNoEcho(prompt) | Read a line without echoing characters — use for passwords. History is not recorded. |
| ReadLineDefault(prompt, defaultText) | Pre-fill the input buffer with defaultText; user can edit or accept with Enter |
| IsEOF | Returns True if the last ReadLine call received EOF (Ctrl+D) |
uses readline;
{ Pre-fill with a default value the user can edit }
var name := ReadLineDefault('Your name: ', 'Alice');
{ Password prompt — no echo }
var pass := ReadLineNoEcho('Password: ');
{ Loop until clean EOF }
var line := ReadLineHistory('> ');
while not IsEOF do
begin
WriteLn('Got: ' + line);
line := ReadLineHistory('> ');
end;
History API
Readline maintains an in-memory list of previous inputs. Users navigate it with the Up/Down arrow keys or Ctrl+R (reverse search). Persist it across sessions with LoadHistory / SaveHistory.
| Function | Description |
|---|---|
| AddHistory(line) | Manually add a line to the in-memory history list |
| LoadHistory(path) | Load history from a file into memory (call at startup) |
| SaveHistory(path, maxLines) | Write the current in-memory history to a file, keeping at most maxLines entries |
| AppendHistory(path, count) | Append only the count most recent entries to an existing history file (efficient for long sessions) |
| ClearHistory | Remove all entries from the in-memory history list |
| HistoryLength | Return the number of entries currently in memory |
| GetHistoryEntry(index) | Return the history line at position index (0-based, oldest first) |
| RemoveHistoryEntry(index) | Delete a specific entry from the history list |
| SetHistoryMaxLength(n) | Limit the in-memory list to n entries; older entries are dropped automatically |
uses readline;
LoadHistory('/home/user/.myapp_history');
SetHistoryMaxLength(500);
{ Run REPL... }
{ At exit: append new entries only }
AppendHistory('/home/user/.myapp_history', 50);
WriteLn('Session history: ' + IntToStr(HistoryLength) + ' entries');
Completion API
Tab completion is one of readline's most valuable features. The simplest approach is providing a static word list; the library handles prefix matching automatically.
| Function | Description |
|---|---|
| SetWordList(words) | Provide a static list of completion candidates. Tab cycles through words that match what the user has typed so far. |
| AddCompletionWord(word) | Add a single word to the current completion list |
| ClearCompletionWords | Remove all completion words (e.g. to swap context-sensitive lists) |
| SetFilenameCompletion | Switch to readline's built-in filename/path completion (the default bash behavior) |
| DisableCompletion | Turn off Tab completion entirely |
uses readline;
{ Static word list }
SetWordList(['connect', 'disconnect', 'status',
'list-topics', 'subscribe', 'publish', 'exit']);
{ Switch to filename completion when user types "load " }
var cmd := ReadLineHistory('broker> ');
if cmd = 'load' then
begin
SetFilenameCompletion;
var path := ReadLineHistory('file> ');
SetWordList(['connect', 'disconnect', 'status']); { restore }
end;
Configuration API
Configure readline behavior at startup. Settings persist for the process lifetime unless changed.
| Function | Description |
|---|---|
| SetEditMode(mode) | Key binding mode: 'emacs' (default) or 'vi' |
| SetBellStyle(style) | Bell on ambiguous completion: 'audible', 'visible', or 'none' |
| SetCompleteOnTab(enable) | If False, Tab lists completions instead of cycling through them (default: True) |
| SetHorizontalScroll(enable) | Scroll long lines horizontally instead of wrapping (default: False) |
| SetColoredCompletion(enable) | Colorize completion matches (requires a terminal with ANSI support) |
| ReadInitFile(path) | Load a readline init file (.inputrc format) for user-specific customization |
Key Bindings API
Bind custom key sequences to named readline functions, or query what is currently bound. This is an advanced feature; most apps do not need it.
| Function | Description |
|---|---|
| BindKey(keySeq, func) | Bind a key sequence (e.g. '\\C-t') to a named readline function (e.g. 'transpose-chars') |
| UnbindKey(keySeq) | Remove the binding for a key sequence |
| GetKeyBinding(keySeq) | Return the function name currently bound to a key sequence, or empty string if unbound |
| ListBindings | Return all current bindings as a newline-delimited string of key: function pairs |
Utilities API
| Function | Description |
|---|---|
| RLVersion | Return the readline library version string (e.g. '8.2') |
| GetTerminalWidth | Current terminal column width (refreshed on SIGWINCH) |
| SetPromptColor(color) | Wrap the prompt in ANSI color escape codes. Pass one of: 'red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'white', 'reset' |
| ResetTerminal | Restore terminal settings if your program is interrupted while readline is active |
| RedisplayPrompt | Redraw the current prompt and input buffer (useful after asynchronous output) |
uses readline;
SetPromptColor('cyan');
WriteLn('readline v' + RLVersion + ', terminal width: '
+ IntToStr(GetTerminalWidth) + ' cols');
var line := ReadLineHistory('> ');
{ If background thread prints output during input, redraw the prompt }
RedisplayPrompt;
Key Bindings Reference
Default emacs mode bindings (active by default). All standard shell shortcuts work out of the box.
| Key | Action |
|---|---|
| Ctrl+A | Move cursor to beginning of line |
| Ctrl+E | Move cursor to end of line |
| Ctrl+W | Delete word before cursor |
| Ctrl+K | Delete from cursor to end of line (kill) |
| Ctrl+U | Delete from cursor to beginning of line |
| Ctrl+R | Reverse incremental history search |
| Ctrl+S | Forward incremental history search |
| Ctrl+Y | Yank (paste) last killed text |
| Ctrl+L | Clear screen and redisplay prompt |
| Ctrl+D | EOF / delete character under cursor (EOF if line is empty) |
| Ctrl+C | Interrupt (raises SIGINT) |
| Up / Down | Navigate history (previous / next entry) |
| Left / Right | Move cursor one character left / right |
| Alt+B / Alt+F | Move cursor one word backward / forward |
| Tab | Complete current word (cycles or lists depending on SetCompleteOnTab) |
vi mode commands
Enable with SetEditMode('vi'). Input starts in insert mode; press Esc to enter command mode.
| Key (command mode) | Action |
|---|---|
| h / l | Move cursor left / right |
| w / b | Move forward / backward one word |
| 0 / $ | Move to beginning / end of line |
| x | Delete character under cursor |
| dw / db | Delete word forward / backward |
| dd | Delete entire line |
| i / a | Return to insert mode (before / after cursor) |
| k / j | Previous / next history entry |
| / | Search history forward |
| ? | Search history backward |
If your program writes output to stdout while readline is waiting for input (e.g. from a background goroutine or agent), call RedisplayPrompt after the write to keep the prompt and partial input visible and correctly positioned.
Package Info
System Requirements
libreadline-devUbuntu/Debian:
sudo apt install libreadline-dev
Used by
psql • mysql • gdb
irb (Ruby) • node REPL
Functions
- ReadLine
- ReadLineHistory
- ReadLineNoEcho
- ReadLineDefault
- IsEOF
- AddHistory
- LoadHistory / SaveHistory
- AppendHistory
- ClearHistory
- HistoryLength
- GetHistoryEntry
- RemoveHistoryEntry
- SetHistoryMaxLength
- SetWordList
- AddCompletionWord
- ClearCompletionWords
- SetFilenameCompletion
- DisableCompletion
- SetEditMode
- SetBellStyle
- SetCompleteOnTab
- SetHorizontalScroll
- SetColoredCompletion
- ReadInitFile
- BindKey / UnbindKey
- GetKeyBinding
- ListBindings
- RLVersion
- GetTerminalWidth
- SetPromptColor
- ResetTerminal
- RedisplayPrompt
See Also
- cli-parser
- colors (ANSI colors)
- progress-bar
- table (ASCII tables)