mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:39:49 +00:00
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:
parent
a7a91aff59
commit
ae1efb2e73
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue