ddbg_service changes.

Make a CommandList class and move command matching and completion
logic into it.  Rework command completion to begin to allow for
recursive completion of subcommands.

BUG=
R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org//562273005

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@40564 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
turnidge@google.com 2014-09-22 20:10:07 +00:00
parent a7a91aff59
commit ae1efb2e73
2 changed files with 130 additions and 91 deletions

View file

@ -143,9 +143,7 @@ class Commando {
break;
case runeTAB:
if (_complete(_tabCount > 1)) {
_tabCount = 0;
}
_complete(_tabCount > 1);
break;
case runeNewline:
@ -327,57 +325,57 @@ class Commando {
return shared;
}
bool _complete(bool showCompletions) {
void _complete(bool showCompletions) {
if (completer == null) {
return false;
return;
}
var linePrefix = _currentLine.take(_cursorPos).toList();
List<String> commandParts =
_trimLeadingSpaces(new String.fromCharCodes(linePrefix)).split(' ');
var lineAsString = new String.fromCharCodes(linePrefix);
var commandParts = new List.from(lineAsString.split(' ').where((line) {
return line != ' ' && line != '';
}));
if (lineAsString.endsWith(' ')) {
// If the current line ends with a space, they are hoping to
// complete the next word in the command. Add an empty string
// to the commandParts to signal this to the completer.
commandParts.add('');
}
List<String> completionList = completer(commandParts);
var completion = '';
var completion = null;
if (completionList.length == 0) {
// The current line admits no possible completion.
return false;
return;
} else if (completionList.length == 1) {
// There is a single, non-ambiguous completion for the current line.
completion = completionList[0];
// If we are at the end of the line, add a space to signal that
// the completion is unambiguous.
if (_currentLine.length == _cursorPos) {
completion = completion + ' ';
}
} else {
// There are ambiguous completions. Find the longest common
// shared prefix of all of the completions.
completion = completionList.fold(completionList[0], _sharedPrefix);
}
var lastWord = commandParts.last;
if (completion == lastWord) {
// The completion does not add anything.
if (showCompletions) {
// User hit double-TAB. Show them all possible completions.
_move(_cursorPos, _currentLine.length);
_stdout.writeln();
_stdout.writeln(completionList);
_writePromptAndLine();
}
return false;
if (showCompletions) {
// User hit double-TAB. Show them all possible completions.
completionList.sort((a,b) => a.compareTo(b));
_move(_cursorPos, _currentLine.length);
_stdout.writeln();
_stdout.writeln(completionList);
_writePromptAndLine();
return;
} else {
// Apply the current completion.
var completionRunes = completion.runes.toList();
var newLine = [];
newLine..addAll(linePrefix)
..addAll(completionRunes.skip(lastWord.length))
newLine..addAll(completionRunes)
..addAll(_currentLine.skip(_cursorPos));
_update(newLine, _cursorPos + completionRunes.length - lastWord.length);
return true;
_update(newLine, completionRunes.length);
return;
}
}

View file

@ -14,6 +14,8 @@ class Debugger {
Commando cmdo;
var _cmdoSubscription;
CommandList _commands;
VM _vm;
VM get vm => _vm;
set vm(VM vm) {
@ -91,10 +93,16 @@ class Debugger {
}
Debugger() {
cmdo = new Commando(completer: completeCommand);
cmdo = new Commando(completer: _completeCommand);
_cmdoSubscription = cmdo.commands.listen(_processCommand,
onError: _cmdoError,
onDone: _cmdoDone);
_commands = new CommandList();
_commands.register(new AttachCommand());
_commands.register(new DetachCommand());
_commands.register(new HelpCommand(_commands));
_commands.register(new IsolateCommand());
_commands.register(new QuitCommand());
}
Future _closeCmdo() {
@ -116,7 +124,7 @@ class Debugger {
});
}
void _cmdoError(self, parent, zone, error, StackTrace trace) {
void _cmdoError(error, StackTrace trace) {
cmdo.print('\n--------\nExiting due to unexpected error:\n'
' $error\n$trace\n');
quit();
@ -126,6 +134,10 @@ class Debugger {
quit();
}
List<String> _completeCommand(List<String> commandParts) {
return _commands.complete(commandParts);
}
void _processCommand(String cmdLine) {
void huh() {
cmdo.print("'$cmdLine' not understood, try 'help' for help.");
@ -138,7 +150,7 @@ class Debugger {
return;
}
var command = args[0];
var matches = matchCommand(command, true);
var matches = _commands.match(command, true);
if (matches.length == 0) {
huh();
cmdo.show();
@ -161,6 +173,10 @@ abstract class Command {
String get helpShort;
void printHelp(Debugger debugger, List<String> args);
Future run(Debugger debugger, List<String> args);
List<String> complete(List<String> commandParts) {
return ["$name ${commandParts.join(' ')}"];
}
}
class AttachCommand extends Command {
@ -203,11 +219,70 @@ Usage:
}
}
class CommandList {
List _commands = new List<Command>();
void register(Command cmd) {
_commands.add(cmd);
}
List<Command> match(String commandName, bool exactMatchWins) {
var matches = [];
for (var command in _commands) {
if (command.name.startsWith(commandName)) {
if (exactMatchWins && command.name == commandName) {
// Exact match
return [command];
} else {
matches.add(command);
}
}
}
return matches;
}
List<String> complete(List<String> commandParts) {
var completions = new List<String>();
String prefix = commandParts[0];
for (var command in _commands) {
if (command.name.startsWith(prefix)) {
completions.addAll(command.complete(commandParts.sublist(1)));
}
}
return completions;
}
void printHelp(Debugger debugger, List<String> args) {
var cmdo = debugger.cmdo;
if (args.length <= 1) {
cmdo.print("\nDebugger commands:\n");
for (var command in _commands) {
cmdo.print(' ${command.name.padRight(11)} ${command.helpShort}');
}
cmdo.print("For more information about a particular command, type:\n\n"
" help <command>\n");
cmdo.print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
} else {
var commandName = args[1];
var matches =match(commandName, true);
if (matches.length == 0) {
cmdo.print("Command '$commandName' not recognized. "
"Try 'help' for a list of commands.");
} else {
for (var command in matches) {
command.printHelp(debugger, args);
}
}
}
}
}
class DetachCommand extends Command {
final name = 'detach';
final helpShort = 'Detach from a running Dart VM';
void printHelp(Debugger debugger, List<String> args) {
cmdo.print('''
debugger.cmdo.print('''
----- detach -----
Detach from the Dart VM.
@ -233,6 +308,9 @@ Usage:
}
class HelpCommand extends Command {
HelpCommand(this._commands);
final CommandList _commands;
final name = 'help';
final helpShort = 'Show a list of debugger commands';
void printHelp(Debugger debugger, List<String> args) {
@ -249,31 +327,18 @@ Usage:
}
Future run(Debugger debugger, List<String> args) {
var cmdo = debugger.cmdo;
if (args.length <= 1) {
cmdo.print("\nDebugger commands:\n");
for (var command in commandList) {
cmdo.print(' ${command.name.padRight(11)} ${command.helpShort}');
}
cmdo.print("For more information about a particular command, type:\n\n"
" help <command>\n");
cmdo.print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
} else {
var commandName = args[1];
var matches = matchCommand(commandName, true);
if (matches.length == 0) {
cmdo.print("Command '$commandName' not recognized. "
"Try 'help' for a list of commands.");
} else {
for (var command in matches) {
command.printHelp(debugger, args);
}
}
}
_commands.printHelp(debugger, args);
return new Future.value();
}
List<String> complete(List<String> commandParts) {
if (commandParts.isEmpty) {
return ['$name '];
}
return _commands.complete(commandParts).map((value) {
return '$name $value';
});
}
}
class IsolateCommand extends Command {
@ -375,6 +440,17 @@ Usage:
});
return new Future.value();
}
List<String> complete(List<String> commandParts) {
if (commandParts.isEmpty) {
return ['$name ${commandParts.join(" ")}'];
} else {
var completions = _commands.complete(commandParts);
return completions.map((completion) {
return '$name $completion';
});
}
}
}
class QuitCommand extends Command {
@ -400,38 +476,3 @@ Usage:
return debugger.quit();
}
}
List<Command> commandList =
[ new AttachCommand(),
new DetachCommand(),
new HelpCommand(),
new IsolateCommand(),
new QuitCommand() ];
List<Command> matchCommand(String commandName, bool exactMatchWins) {
var matches = [];
for (var command in commandList) {
if (command.name.startsWith(commandName)) {
if (exactMatchWins && command.name == commandName) {
// Exact match
return [command];
} else {
matches.add(command);
}
}
}
return matches;
}
List<String> completeCommand(List<String> commandParts) {
var completions = new List<String>();
if (commandParts.length == 1) {
String prefix = commandParts[0];
for (var command in commandList) {
if (command.name.startsWith(prefix)) {
completions.add(command.name);
}
}
}
return completions;
}