Rand Stats

Terminal::LineEditor

zef:japhb

Actions Status

NAME

Terminal::LineEditor - Generalized terminal line editing

SYNOPSIS

### PREP

use Terminal::LineEditor;
use Terminal::LineEditor::RawTerminalInput;

# Create a basic CLI text input object
my $cli = Terminal::LineEditor::CLIInput.new;


### BASICS

# Preload some input history
$cli.load-history($history-file);
$cli.add-history('synthetic input', 'more synthetic input');

# Prompt for input, supporting common edit commands,
# scrolling the field to stay on one line
my $input = $cli.prompt('Please enter your thoughts: ');

# Prompt for a password, masking with asterisks (suppresses history)
my $pass  = $cli.prompt('Password: ', mask => '*');

# Prompt defaults to empty
my $stuff = $cli.prompt;

# Review and save history
.say for $cli.history;
$cli.save-history($history-file);


### TYPICAL USE

loop {
    # Get user's input
    my $in = $cli.prompt("My prompt >");

    # Exit loop if user indicated finished
    last without $in;

    # Add line to history if it is non-empty
    $cli.add-history($in) if $in.trim;

    # Do something with the input line; here we just echo it
    say $in;
}

DESCRIPTION

Terminal::LineEditor is a terminal line editing package similar to Linenoise or Readline, but not a drop-in replacement for either of them. Terminal::LineEditor has a few key design differences:

Use with Rakudo REPL

A PR for Rakudo has been created to allow Terminal::LineEditor to be used as the REPL line editor when Rakudo is used in interactive mode. If your Rakudo build includes this PR, you can set the following in your environment to use Terminal::LineEditor by default:

export RAKUDO_LINE_EDITOR=LineEditor

If the environment variable is not specified, but Terminal::LineEditor is the only line editing module installed, Rakudo will auto-detect and enable it.

Default Keymap

The latest version of the default keymap is specified in Terminal::LineEditor::KeyMappable.default-keymap(), but the below represents the currently implemented, commonly used keys:

Commonly Used Keys
KEYFUNCTIONNOTES
Ctrl-Amove-to-start
Ctrl-Bmove-char-back
Ctrl-Cabort-input
Ctrl-Dabort-or-deleteAbort if empty, or delete-char-forward
Ctrl-Emove-to-end
Ctrl-Fmove-char-forward
Ctrl-Hdelete-char-back
Ctrl-JfinishLF (Line Feed)
Ctrl-Kdelete-to-end
Ctrl-Lrefresh-all
Ctrl-MfinishCR (Carriage Return)
Ctrl-Nhistory-next
Ctrl-Phistory-prev
Ctrl-Tswap-chars
Ctrl-Udelete-to-start
Ctrl-Vliteral-next
Ctrl-Wdelete-word-back
Ctrl-Yyank
Ctrl-Zsuspend
Ctrl-_undoCtrl-Shift-<hyphen> on some keyboards
Backspacedelete-char-back
CursorLeftmove-char-back
CursorRightmove-char-forward
CursorHomemove-to-start
CursorEndmove-to-end
CursorUphistory-prev
CursorDownhistory-next
Alt-bmove-word-back
Alt-ctclc-wordReadline treats this as Capitalize
Alt-ddelete-word-forward
Alt-fmove-word-forward
Alt-llowercase-word
Alt-tswap-words
Alt-uuppercase-word
Alt-<history-startAlt-Shift-<comma> on some keyboards
Alt->history-endAlt-Shift-<period> on some keyboards

All bindable edit functions are defined in the Terminal::LineEditor::SingleLineTextInput role (in each corresponding method beginning with edit-) or is one of the following special actions:

Special Actions
ACTIONMEANING
abort-inputThrow away input so far and return an undefined Str
abort-or-deleteabort-input if empty, otherwise delete-char-forward
finishAccept and return current input line
literal-nextInsert a literal control character into the buffer
suspendSuspend the program with SIGTSTP, wait for SIGCONT
history-startSwitch input to first line in history
history-prevSwitch input to previous line in history
history-nextSwitch input to next line in history
history-endSwitch input to last line in history (the partial input)

Architecture

Terminal::LineEditor is built up in layers, starting from the most abstract:

Edge Cases

There are a few edge cases for which Terminal::LineEditor chose one of several possible behaviors. Here's the reasoning for each of these otherwise arbitrary decisions:

Unmapped Functionality

Some of the functionality supported by lower layers of Terminal::LineEditor is not exposed in the default keymap of Terminal::LineEditor::KeyMappable. This is generally because no commonly-agreed shell keys map to this functionality.

For example, Terminal::LineEditor::SingleLineTextBuffer can treat replace as an atomic operation, but basic POSIX shells generally don't; they instead expect the user to delete and insert as separate operations.

That said, if I've missed a commonly-supported key sequence for any of the unmapped functionality, please open an issue for this repository with a link to the relevant docs so I can expand the default keymap.

AUTHOR

Geoffrey Broadwell gjb@sonic.net

COPYRIGHT AND LICENSE

Copyright 2021 Geoffrey Broadwell

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.