readText function
Reads a line of free text below header, or null on Esc or Ctrl-C.
Implementation
Future<String?> readText(Console console, {required List<String> header}) async {
final terminal = console.terminal;
if (!terminal.interactive) {
console.print(header);
terminal.write('> ');
return terminal.readLine();
}
final editor = LineEditor();
void render() {
final width = max(20, terminal.columns - 1);
final lines = <String>[...header.expand((line) => wrapText(line, width))];
final layout = layoutText(editor.chars, editor.cursor, width - 2);
final firstRow = lines.length;
for (var index = 0; index < layout.rows.length; index++) {
lines.add('${index == 0 ? Style.accent('❯') : ' '} ${layout.rows[index]}');
}
lines
..add('')
..add(Style.dim('Enter to submit · Esc to cancel'));
console.showLive(lines, cursorRow: firstRow + layout.row, cursorColumn: 2 + layout.column);
}
final result = Completer<String?>();
render();
final stopListening = terminal.listen((event) {
if (result.isCompleted) {
return true;
}
switch (event.key) {
case Key.text || Key.paste:
editor.insert(event.text.replaceAll(RegExp(r'\r\n?'), '\n'));
case Key.newline:
editor.insert('\n');
case Key.enter:
if (editor.text.trim().isNotEmpty) {
result.complete(editor.text.trim());
return true;
}
case Key.escape || Key.ctrlC || Key.ctrlD:
result.complete(null);
return true;
case Key.backspace:
editor.backspace();
case Key.delete:
editor.deleteForward();
case Key.left:
editor.left();
case Key.right:
editor.right();
case Key.home || Key.ctrlA:
editor.home();
case Key.end || Key.ctrlE:
editor.end();
case Key.wordLeft:
editor.wordLeft();
case Key.wordRight:
editor.wordRight();
case Key.ctrlW:
editor.deleteWordBefore();
case Key.ctrlU:
editor.killToStart();
case Key.ctrlK:
editor.killToEnd();
default:
break;
}
render();
return true;
});
final text = await result.future;
stopListening();
console.live.clear();
return text;
}