A very common thing to do when developing interactive CLIs with prompts is to allow code completion of commands typed into the prompt.
The current API of Console.readLine() makes this a little difficult, because it maintains it's own internal buffer of text that was inserted and its own cursor position. The callback parameter that can be supplied cannot modify this internal state of readLine() and therefore not e.g. auto complete.
A simple change that would allow tab-completion is the following
diff --git a/lib/src/console.dart b/lib/src/console.dart
index 9f7a7a0..48a2f58 100644
--- a/lib/src/console.dart
+++ b/lib/src/console.dart
@@ -534,7 +534,7 @@ class Console {
{bool cancelOnBreak = false,
bool cancelOnEscape = false,
bool cancelOnEOF = false,
- void Function(String text, Key lastPressed)? callback}) {
+ String? Function(String text, Key lastPressed)? callback}) {
var buffer = '';
var index = 0; // cursor position relative to buffer, not screen
@@ -650,7 +650,16 @@ class Console {
write(buffer); // allow for backspace condition
cursorPosition = Coordinate(screenRow, screenColOffset + index);
- if (callback != null) callback(buffer, key);
+ if (callback != null) {
+ final left = buffer.substring(0, index);
+ final right = buffer.substring(index);
+
+ final leftReplacement = callback(left, key);
+ if (leftReplacement != null) {
+ index = leftReplacement.length;
+ buffer = leftReplacement + right;
+ }
+ }
}
}
}
Using this change one can get tab-completion e.g. with this example:
import 'package:dart_console/dart_console.dart';
final console = Console.scrolling();
final commands = ['java', 'dart', 'pascal', 'delphi'];
String? completeCommand(String buffer) {
if (buffer.isEmpty) return null;
for (final command in commands) {
if (command.startsWith(buffer) && buffer.length < command.length) {
return command;
}
}
return null;
}
String? suggestedCompletion;
String? completion(String text, Key lastPressed) {
if (lastPressed.isControl) {
final completion = suggestedCompletion;
suggestedCompletion = null;
if (lastPressed.controlChar == ControlCharacter.tab && completion != null) {
// Write remaining characters to the screen.
console.write(completion.substring(text.length));
// Let the `Console.readLine()` API know the replacement text.
return completion;
}
return null;
}
final int prefixStart = text.lastIndexOf(' ');
var completion = completeCommand(text.substring(prefixStart + 1));
if (completion != null) {
if (prefixStart >= 0) {
completion = text.substring(0, prefixStart) + ' ' + completion;
}
suggestedCompletion = completion;
// Write the text that can be tab-completed in different color.
final old = console.cursorPosition;
console.setForegroundColor(ConsoleColor.brightWhite);
console.write(completion.substring(text.length));
console.cursorPosition = old;
// Reset color to what it used to be.
console.setForegroundColor(ConsoleColor.brightGreen);
}
return null;
}
void main() {
while (true) {
console.setForegroundColor(ConsoleColor.brightBlue);
console.write('>>> ');
console.resetColorAttributes();
console.setForegroundColor(ConsoleColor.brightGreen);
final response = console.readLine(cancelOnEOF: true, callback: completion);
if (response == null) break;
print(response.toUpperCase());
}
}
Though maybe a more direct API of the callback to the internal buffer and index would be better.
Would be wonderful have a way to build on package:dart_console and get tab-completion working.
/cc @timsneath
A very common thing to do when developing interactive CLIs with prompts is to allow code completion of commands typed into the prompt.
The current API of
Console.readLine()makes this a little difficult, because it maintains it's own internal buffer of text that was inserted and its own cursor position. Thecallbackparameter that can be supplied cannot modify this internal state ofreadLine()and therefore not e.g. auto complete.A simple change that would allow tab-completion is the following
Using this change one can get tab-completion e.g. with this example:
Though maybe a more direct API of the callback to the internal buffer and index would be better.
Would be wonderful have a way to build on
package:dart_consoleand get tab-completion working./cc @timsneath