Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1415)

Unified Diff: runtime/observatory/lib/src/elements/debugger.dart

Issue 918003002: Add 'break' and 'clear' commands to Observatory debugger. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: fixups Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 9c18f941245e7b0657c7354a6ae4eea5ce9ff922..d1feb86f6821f6044d1272a87d16c5be881d4c39 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -8,12 +8,13 @@ import 'dart:async';
import 'dart:html';
import 'observatory_element.dart';
import 'package:observatory/cli.dart';
+import 'package:observatory/debugger.dart';
import 'package:observatory/service.dart';
import 'package:polymer/polymer.dart';
-// TODO(turnidge): Move Debugger, DebuggerCommand to their own lib.
+// TODO(turnidge): Move Debugger, DebuggerCommand to debugger library.
abstract class DebuggerCommand extends Command {
- Debugger debugger;
+ ObservatoryDebugger debugger;
DebuggerCommand(this.debugger, name, children)
: super(name, children);
@@ -28,16 +29,15 @@ class HelpCommand extends DebuggerCommand {
con.newline();
// TODO(turnidge): Build a real help system.
- List completions = debugger.cmd.completeCommand('');
- completions = completions.map((s )=> s.trimRight()).toList();
- completions.sort();
- con.printLine(completions.toString());
- con.newline();
- con.printLine("Command prefixes are accepted (e.g. 'h' for 'help')");
- con.printLine("Hit [TAB] to complete a command (try 'i[TAB][TAB]')");
- con.printLine("Hit [ENTER] to repeat the last command");
-
- return new Future.value(null);
+ return debugger.cmd.completeCommand('').then((completions) {
+ completions = completions.map((s) => s.trimRight()).toList();
+ completions.sort();
+ con.printLine(completions.toString());
+ con.newline();
+ con.printLine("Command prefixes are accepted (e.g. 'h' for 'help')");
+ con.printLine("Hit [TAB] to complete a command (try 'i[TAB][TAB]')");
+ con.printLine("Hit [ENTER] to repeat the last command");
+ });
}
}
@@ -126,6 +126,131 @@ class FinishCommand extends DebuggerCommand {
}
}
+class BreakCommand extends DebuggerCommand {
+ BreakCommand(Debugger debugger) : super(debugger, 'break', []);
+
+ Future run(List<String> args) {
+ if (args.length > 1) {
+ debugger.console.printLine('not implemented');
+ return new Future.value(null);
+ }
+ var arg = (args.length == 0 ? '' : args[0]);
+ return SourceLocation.parse(debugger, arg).then((loc) {
+ if (loc.valid) {
+ if (loc.function != null) {
+ debugger.console.printLine(
+ 'Ignoring breakpoint at $loc: '
+ 'Function entry breakpoints not yet implemented');
+ return null;
+ }
+ if (loc.col != null) {
+ // TODO(turnidge): Add tokenPos breakpoint support.
+ debugger.console.printLine(
+ 'Ignoring column: '
+ 'adding breakpoint at a specific column not yet implemented');
+ }
+ return debugger.isolate.addBreakpoint(loc.script, loc.line).then((result) {
+ if (result is DartError) {
+ debugger.console.printLine('Unable to set breakpoint at ${loc}');
+ } else {
+ // TODO(turnidge): Adding a duplicate breakpoint is
+ // currently ignored. May want to change the protocol to
+ // inform us when this happens.
+
+ // The BreakpointResolved event prints resolved
+ // breakpoints already. Just print the unresolved ones here.
+ ServiceMap bpt = result;
+ if (!bpt['resolved']) {
+ var script = bpt['location']['script'];
+ var bpId = bpt['breakpointNumber'];
+ var tokenPos = bpt['location']['tokenPos'];
+ return script.load().then((_) {
+ var line = script.tokenToLine(tokenPos);
+ var col = script.tokenToCol(tokenPos);
+ debugger.console.printLine(
+ 'Future breakpoint ${bpId} added at '
+ '${script.name}:${line}:${col}');
+ });
+ }
+ }
+ });
+ } else {
+ debugger.console.printLine(loc.errorMessage);
+ }
+ });
+ }
+
+ Future<List<String>> complete(List<String> args) {
+ if (args.length != 1) {
+ return new Future.value([]);
+ }
+ // TODO - fix SourceLocation complete
+ return new Future.value(SourceLocation.complete(debugger, args[0]));
+ }
+}
+
+class ClearCommand extends DebuggerCommand {
+ ClearCommand(Debugger debugger) : super(debugger, 'clear', []);
+
+ Future run(List<String> args) {
+ if (args.length > 1) {
+ debugger.console.printLine('not implemented');
+ return new Future.value(null);
+ }
+ var arg = (args.length == 0 ? '' : args[0]);
+ return SourceLocation.parse(debugger, arg).then((loc) {
+ if (loc.valid) {
+ if (loc.function != null) {
+ debugger.console.printLine(
+ 'Ignoring breakpoint at $loc: '
+ 'Function entry breakpoints not yet implemented');
+ return null;
+ }
+ if (loc.col != null) {
+ // TODO(turnidge): Add tokenPos clear support.
+ debugger.console.printLine(
+ 'Ignoring column: '
+ 'clearing breakpoint at a specific column not yet implemented');
+ }
+
+ for (var bpt in debugger.isolate.breakpoints) {
+ var script = bpt['location']['script'];
+ if (script.id == loc.script.id) {
+ assert(script.loaded);
+ var line = script.tokenToLine(bpt['location']['tokenPos']);
+ if (line == loc.line) {
+ return debugger.isolate.removeBreakpoint(bpt).then((result) {
+ if (result is DartError) {
+ debugger.console.printLine(
+ 'Unable to clear breakpoint at ${loc}: ${result.message}');
+ return;
+ } else {
+ // TODO(turnidge): Add a BreakpointRemoved event to
+ // the service instead of printing here.
+ var bpId = bpt['breakpointNumber'];
+ debugger.console.printLine(
+ 'Breakpoint ${bpId} removed at ${loc}');
+ return;
+ }
+ });
+ }
+ }
+ }
+ debugger.console.printLine('No breakpoint found at ${loc}');
+ } else {
+ debugger.console.printLine(loc.errorMessage);
+ }
+ });
+ }
+
+ Future<List<String>> complete(List<String> args) {
+ if (args.length != 1) {
+ return new Future.value([]);
+ }
+ return new Future.value(SourceLocation.complete(debugger, args[0]));
+ }
+}
+
// TODO(turnidge): Add argument completion.
class DeleteCommand extends DebuggerCommand {
DeleteCommand(Debugger debugger) : super(debugger, 'delete', []);
@@ -177,8 +302,15 @@ class InfoBreakpointsCommand extends DebuggerCommand {
var tokenPos = bpt['location']['tokenPos'];
var line = script.tokenToLine(tokenPos);
var col = script.tokenToCol(tokenPos);
+ var extras = new StringBuffer();
+ if (!bpt['resolved']) {
+ extras.write(' unresolved');
+ }
+ if (!bpt['enabled']) {
+ extras.write(' disabled');
+ }
debugger.console.printLine(
- 'Breakpoint ${bpId} at ${script.name}:${line}:${col}');
+ 'Breakpoint ${bpId} at ${script.name}:${line}:${col}${extras}');
}
});
}
@@ -234,13 +366,14 @@ class RefreshCommand extends DebuggerCommand {
}
// Tracks the state for an isolate debugging session.
-class Debugger {
+class ObservatoryDebugger extends Debugger {
RootCommand cmd;
DebuggerConsoleElement console;
DebuggerStackElement stackElement;
ServiceMap stack;
+ int currentFrame = 0;
- Debugger() {
+ ObservatoryDebugger() {
cmd = new RootCommand([
new HelpCommand(this),
new PauseCommand(this),
@@ -248,6 +381,8 @@ class Debugger {
new NextCommand(this),
new StepCommand(this),
new FinishCommand(this),
+ new BreakCommand(this),
+ new ClearCommand(this),
new DeleteCommand(this),
new InfoCommand(this),
new RefreshCommand(this),
@@ -258,9 +393,19 @@ class Debugger {
_isolate = iso;
if (_isolate != null) {
_isolate.reload().then((_) {
- _isolate.vm.events.stream.listen(_onEvent);
- _refreshStack(isolate.pauseEvent).then((_) {
- reportStatus();
+ // TODO(turnidge): Currently the debugger relies on all libs
+ // being loaded. Fix this.
+ var pending = [];
+ for (var lib in _isolate.libraries) {
+ if (!lib.loaded) {
+ pending.add(lib.load());
+ }
+ }
+ Future.wait(pending).then((_) {
+ _isolate.vm.events.stream.listen(_onEvent);
+ _refreshStack(isolate.pauseEvent).then((_) {
+ reportStatus();
+ });
});
});
}
@@ -300,7 +445,6 @@ class Debugger {
stack = result;
// TODO(turnidge): Replace only the changed part of the stack to
// reduce flicker.
- // stackElement.stack = stack;
stackElement.updateStack(stack, pauseEvent);
});
}
@@ -367,8 +511,17 @@ class Debugger {
console.printLine('Continuing...');
break;
- case '_Graph':
case 'BreakpointResolved':
+ var bpId = event.breakpoint['breakpointNumber'];
+ var script = event.breakpoint['location']['script'];
+ var tokenPos = event.breakpoint['location']['tokenPos'];
+ var line = script.tokenToLine(tokenPos);
+ var col = script.tokenToCol(tokenPos);
+ console.printLine(
+ 'Breakpoint ${bpId} added at ${script.name}:${line}:${col}');
+ break;
+
+ case '_Graph':
case 'IsolateCreated':
case 'GC':
// Ignore these events for now.
@@ -380,39 +533,55 @@ class Debugger {
}
}
- String complete(String line) {
- List<String> completions = cmd.completeCommand(line);
- if (completions.length == 0) {
- // No completions. Leave the line alone.
- return line;
- } else if (completions.length == 1) {
- // Unambiguous completion.
- return completions[0];
- } else {
- // Ambigous completion.
- completions = completions.map((s )=> s.trimRight()).toList();
- completions.sort();
- console.printBold(completions.toString());
+ static String _commonPrefix(String a, String b) {
+ int pos = 0;
+ while (pos < a.length && pos < b.length) {
+ if (a.codeUnitAt(pos) != b.codeUnitAt(pos)) {
+ break;
+ }
+ pos++;
+ }
+ return a.substring(0, pos);
+ }
- // TODO(turnidge): Complete to common prefix of all completions.
- return line;
+ static String _foldCompletions(List<String> values) {
+ if (values.length == 0) {
+ return '';
+ }
+ var prefix = values[0];
+ for (int i = 1; i < values.length; i++) {
+ prefix = _commonPrefix(prefix, values[i]);
}
+ return prefix;
+ }
+
+ Future<String> complete(String line) {
+ return cmd.completeCommand(line).then((completions) {
+ if (completions.length == 0) {
+ // No completions. Leave the line alone.
+ return line;
+ } else if (completions.length == 1) {
+ // Unambiguous completion.
+ return completions[0];
+ } else {
+ // Ambigous completion.
+ completions = completions.map((s )=> s.trimRight()).toList();
+ console.printBold(completions.toString());
+ return _foldCompletions(completions);
+ }
+ });
}
// TODO(turnidge): Implement real command line history.
String lastCommand;
- bool busy = false;
Future run(String command) {
- assert(!busy);
- busy = true;
- if (command == '') {
+ if (command == '' && lastCommand != null) {
command = lastCommand;
}
- lastCommand = command;
console.printBold('\$ $command');
return cmd.runCommand(command).then((_) {
- busy = false;
+ lastCommand = command;
}).catchError((e) {
console.printLine('ERROR $e');
});
@@ -428,7 +597,7 @@ class DebuggerPageElement extends ObservatoryElement {
debugger.isolate = isolate;
}
}
- Debugger debugger = new Debugger();
+ ObservatoryDebugger debugger = new ObservatoryDebugger();
DebuggerPageElement.created() : super.created();
@@ -468,7 +637,7 @@ class DebuggerStackElement extends ObservatoryElement {
@published Isolate isolate;
@observable bool hasStack = false;
@observable bool isSampled = false;
- Debugger debugger = null;
+ ObservatoryDebugger debugger;
_addFrame(List frameList, ObservableMap frameInfo, bool expand) {
DebuggerFrameElement frameElement = new Element.tag('debugger-frame');
@@ -652,7 +821,12 @@ class DebuggerConsoleElement extends ObservatoryElement {
class DebuggerInputElement extends ObservatoryElement {
@published Isolate isolate;
@published String text = '';
- @observable Debugger debugger;
+ @observable ObservatoryDebugger debugger;
+ @observable bool busy = false;
+
+ void _notBusy() {
+ busy = false;
+ }
@override
void ready() {
@@ -660,19 +834,26 @@ class DebuggerInputElement extends ObservatoryElement {
var textBox = $['textBox'];
textBox.select();
textBox.onKeyDown.listen((KeyboardEvent e) {
+ // TODO(turnidge): Ignore *all* key events while busy.
switch (e.keyCode) {
case KeyCode.TAB:
e.preventDefault();
- int cursorPos = textBox.selectionStart;
- var completion = debugger.complete(text.substring(0, cursorPos));
- text = completion + text.substring(cursorPos);
- // TODO(turnidge): Move the cursor to the end of the
- // completion, rather than the end of the string.
+ if (!busy) {
+ busy = true;
+ int cursorPos = textBox.selectionStart;
+ debugger.complete(text.substring(0, cursorPos)).then((completion) {
+ text = completion + text.substring(cursorPos);
+ // TODO(turnidge): Move the cursor to the end of the
+ // completion, rather than the end of the string.
+ }).whenComplete(_notBusy);
+ }
break;
case KeyCode.ENTER:
- if (!debugger.busy) {
- debugger.run(text);
+ if (!busy) {
+ busy = true;
+ var command = text;
text = '';
+ debugger.run(command).whenComplete(_notBusy);
}
break;
}

Powered by Google App Engine
This is Rietveld 408576698