blob: a7904def1393171f46e9f9be9e0039e1002e8d66 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
enum Output {
// Rewrite the prompt line, including text entered by the user.
prompt,
// Tell the user they did something illegal.
bell,
// Evaluate a Dart expression and print the result.
evaluate,
}
// Interact with the user on the command line, by converting input strings
// into output events.
Stream<List<dynamic>> interact(Stream<String> inputs) async* {
var history = <String>[];
var historyAt = 0;
var line = '';
var cursorAt = 0;
List<dynamic> getPrompt() {
return [Output.prompt, line, cursorAt];
}
await for (var input in inputs) {
if (input == '\u{7f}') {
// Delete
if (cursorAt == 0) {
yield [Output.bell];
} else {
line = line.substring(0, cursorAt - 1) + line.substring(cursorAt);
cursorAt--;
yield getPrompt();
}
} else if (input == '\u{1b}[A') {
// Up
if (historyAt == 0) {
yield [Output.bell];
} else {
historyAt--;
line = history[historyAt];
cursorAt = line.length;
yield getPrompt();
}
} else if (input == '\u{1b}[B') {
// Down
if (historyAt >= history.length - 1) {
yield [Output.bell];
} else {
historyAt++;
line = history[historyAt];
cursorAt = line.length;
yield getPrompt();
}
} else if (input == '\u{1b}[C') {
// Forward
if (cursorAt == line.length) {
yield [Output.bell];
} else {
cursorAt++;
yield getPrompt();
}
} else if (input == '\u{1b}[D') {
// Back
if (cursorAt == 0) {
yield [Output.bell];
} else {
cursorAt--;
yield getPrompt();
}
} else {
var buffer = StringBuffer();
for (var rune in input.runes) {
if (rune > 127) {
// Substitute unicode literals in ASCII, so that we don't have to
// figure out characters' display width when moving the cursor.
var hex = rune.toRadixString(16);
buffer.write('\\u{$hex}');
} else if (rune == 10) {
// New line
line += buffer.toString();
buffer.clear();
yield [Output.evaluate, line];
history.add(line);
historyAt = history.length;
line = '';
cursorAt = 0;
} else {
buffer.writeCharCode(rune);
}
}
if (buffer.isNotEmpty) {
line =
line.substring(0, cursorAt) +
buffer.toString() +
line.substring(cursorAt);
cursorAt += buffer.length;
yield getPrompt();
}
}
}
}