| Index: runtime/observatory/lib/src/elements/debugger.dart
|
| diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
|
| index 8c1a2ed69da5ed4dcca2e9db5328103174002aad..472335858137e2108a680ab5cf4988d9e86e1b85 100644
|
| --- a/runtime/observatory/lib/src/elements/debugger.dart
|
| +++ b/runtime/observatory/lib/src/elements/debugger.dart
|
| @@ -1087,6 +1087,51 @@ class RefreshCommand extends DebuggerCommand {
|
| 'Syntax: refresh <subcommand>\n';
|
| }
|
|
|
| +class VmRestartCommand extends DebuggerCommand {
|
| + VmRestartCommand(Debugger debugger) : super(debugger, 'restart', []);
|
| +
|
| + Future handleModalInput(String line) async {
|
| + if (line == 'yes') {
|
| + debugger.console.printRed('Restarting VM...');
|
| + await debugger.vm.restart();
|
| + debugger.input.exitMode();
|
| + } else if (line == 'no') {
|
| + debugger.console.printRed('VM restart canceled.');
|
| + debugger.input.exitMode();
|
| + } else {
|
| + debugger.console.printRed("Please type 'yes' or 'no'");
|
| + }
|
| + }
|
| +
|
| + Future run(List<String> args) async {
|
| + debugger.input.enterMode('Restart vm? (yes/no)', handleModalInput);
|
| + }
|
| +
|
| + String helpShort = 'Restart a Dart virtual machine';
|
| +
|
| + String helpLong =
|
| + 'Restart a Dart virtual machine.\n'
|
| + '\n'
|
| + 'Syntax: vm restart\n';
|
| +}
|
| +
|
| +class VmCommand extends DebuggerCommand {
|
| + VmCommand(Debugger debugger) : super(debugger, 'vm', [
|
| + new VmRestartCommand(debugger),
|
| + ]);
|
| +
|
| + Future run(List<String> args) async {
|
| + debugger.console.print("'vm' expects a subcommand (see 'help vm')");
|
| + }
|
| +
|
| + String helpShort = 'Manage a Dart virtual machine';
|
| +
|
| + String helpLong =
|
| + 'Manage a Dart virtual machine.\n'
|
| + '\n'
|
| + 'Syntax: vm <subcommand>\n';
|
| +}
|
| +
|
| class _ConsoleStreamPrinter {
|
| ObservatoryDebugger _debugger;
|
|
|
| @@ -1234,6 +1279,7 @@ class ObservatoryDebugger extends Debugger {
|
| new StepCommand(this),
|
| new SyncNextCommand(this),
|
| new UpCommand(this),
|
| + new VmCommand(this),
|
| ]);
|
| _consolePrinter = new _ConsoleStreamPrinter(this);
|
| }
|
| @@ -1254,23 +1300,24 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
|
|
| _isolate.reload().then((response) {
|
| + if (response.isSentinel) {
|
| + // The isolate has gone away. The IsolateExit event will
|
| + // clear the isolate for the debugger page.
|
| + return;
|
| + }
|
| // TODO(turnidge): Currently the debugger relies on all libs
|
| // being loaded. Fix this.
|
| var pending = [];
|
| - for (var lib in _isolate.libraries) {
|
| + for (var lib in response.libraries) {
|
| if (!lib.loaded) {
|
| pending.add(lib.load());
|
| }
|
| }
|
| Future.wait(pending).then((_) {
|
| - _refreshStack(isolate.pauseEvent).then((_) {
|
| - reportStatus();
|
| - });
|
| - }).catchError((_) {
|
| - // Error loading libraries, try and display stack.
|
| - _refreshStack(isolate.pauseEvent).then((_) {
|
| - reportStatus();
|
| - });
|
| + refreshStack();
|
| + }).catchError((e) {
|
| + print("UNEXPECTED ERROR $e");
|
| + reportStatus();
|
| });
|
| });
|
| } else {
|
| @@ -1300,10 +1347,16 @@ class ObservatoryDebugger extends Debugger {
|
| });
|
| }
|
|
|
| - Future refreshStack() {
|
| - return _refreshStack(isolate.pauseEvent).then((_) {
|
| + Future refreshStack() async {
|
| + try {
|
| + if (_isolate != null) {
|
| + await _refreshStack(_isolate.pauseEvent);
|
| + }
|
| + flushStdio();
|
| reportStatus();
|
| - });
|
| + } catch (e, st) {
|
| + console.printRed("Unexpected error in refreshStack: $e\n$st");
|
| + }
|
| }
|
|
|
| bool isolatePaused() {
|
| @@ -1326,9 +1379,12 @@ class ObservatoryDebugger extends Debugger {
|
|
|
| Future<ServiceMap> _refreshStack(ServiceEvent pauseEvent) {
|
| return isolate.getStack().then((result) {
|
| + if (result.isSentinel) {
|
| + // The isolate has gone away. The IsolateExit event will
|
| + // clear the isolate for the debugger page.
|
| + return;
|
| + }
|
| stack = result;
|
| - // TODO(turnidge): Replace only the changed part of the stack to
|
| - // reduce flicker.
|
| stackElement.updateStack(stack, pauseEvent);
|
| if (stack['frames'].length > 0) {
|
| currentFrame = 0;
|
| @@ -1364,8 +1420,7 @@ class ObservatoryDebugger extends Debugger {
|
| console.print(
|
| "Paused at isolate exit "
|
| "(type 'continue' or [F7] to exit the isolate')");
|
| - }
|
| - if (stack['frames'].length > 0) {
|
| + } else if (stack['frames'].length > 0) {
|
| Frame frame = stack['frames'][0];
|
| var script = frame.location.script;
|
| script.load().then((_) {
|
| @@ -1429,6 +1484,10 @@ class ObservatoryDebugger extends Debugger {
|
| var iso = event.owner;
|
| console.print(
|
| "Isolate ${iso.number} '${iso.name}' has been created");
|
| + if (isolate == null) {
|
| + console.print("Switching to isolate ${iso.number} '${iso.name}'");
|
| + isolate = iso;
|
| + }
|
| }
|
| break;
|
|
|
| @@ -1436,7 +1495,17 @@ class ObservatoryDebugger extends Debugger {
|
| {
|
| var iso = event.owner;
|
| if (iso == isolate) {
|
| - console.print("The current isolate has exited");
|
| + console.print("The current isolate ${iso.number} '${iso.name}' "
|
| + "has exited");
|
| + var isolates = vm.isolates;
|
| + if (isolates.length > 0) {
|
| + var newIsolate = isolates.first;
|
| + console.print("Switching to isolate "
|
| + "${newIsolate.number} '${newIsolate.name}'");
|
| + isolate = newIsolate;
|
| + } else {
|
| + isolate = null;
|
| + }
|
| } else {
|
| console.print(
|
| "Isolate ${iso.number} '${iso.name}' has exited");
|
| @@ -1693,9 +1762,7 @@ class DebuggerPageElement extends ObservatoryElement {
|
| @published Isolate isolate;
|
|
|
| isolateChanged(oldValue) {
|
| - if (isolate != null) {
|
| - debugger.updateIsolate(isolate);
|
| - }
|
| + debugger.updateIsolate(isolate);
|
| }
|
| ObservatoryDebugger debugger = new ObservatoryDebugger();
|
|
|
| @@ -2250,6 +2317,20 @@ class DebuggerInputElement extends ObservatoryElement {
|
| @published String text = '';
|
| @observable ObservatoryDebugger debugger;
|
| @observable bool busy = false;
|
| + @observable String modalPrompt = null;
|
| + var modalCallback = null;
|
| +
|
| + void enterMode(String prompt, callback) {
|
| + assert(prompt == null);
|
| + modalPrompt = prompt;
|
| + modalCallback = callback;
|
| + }
|
| +
|
| + void exitMode() {
|
| + assert(prompt != null);
|
| + modalPrompt = null;
|
| + modalCallback = null;
|
| + }
|
|
|
| @override
|
| void ready() {
|
| @@ -2262,7 +2343,19 @@ class DebuggerInputElement extends ObservatoryElement {
|
| return;
|
| }
|
| busy = true;
|
| - switch (e.keyCode) {
|
| + if (modalCallback != null) {
|
| + if (e.keyCode == KeyCode.ENTER) {
|
| + var response = text;
|
| + modalCallback(response).whenComplete(() {
|
| + text = '';
|
| + busy = false;
|
| + });
|
| + } else {
|
| + busy = false;
|
| + }
|
| + return;
|
| + }
|
| + switch (e.keyCode) {
|
| case KeyCode.TAB:
|
| e.preventDefault();
|
| int cursorPos = textBox.selectionStart;
|
| @@ -2358,7 +2451,7 @@ class DebuggerInputElement extends ObservatoryElement {
|
| default:
|
| busy = false;
|
| break;
|
| - }
|
| + }
|
| });
|
| }
|
|
|
|
|