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

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

Issue 1393523002: Support tab completion of line:col in the debugger. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix warnings and other issues Created 5 years, 2 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
« no previous file with comments | « no previous file | runtime/observatory/lib/src/elements/debugger.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/observatory/lib/src/debugger/debugger_location.dart
diff --git a/runtime/observatory/lib/src/debugger/debugger_location.dart b/runtime/observatory/lib/src/debugger/debugger_location.dart
index a517cd28ab3fada3c2508bc650be83517ad6461e..b6114d24320d36df96c3996bc8963c2917b854f0 100644
--- a/runtime/observatory/lib/src/debugger/debugger_location.dart
+++ b/runtime/observatory/lib/src/debugger/debugger_location.dart
@@ -42,23 +42,29 @@ class DebuggerLocation {
"Invalid source location '${locDesc}'"));
}
- static Future<DebuggerLocation> _currentLocation(Debugger debugger) {
+ static Future<Frame> _currentFrame(Debugger debugger) async {
ServiceMap stack = debugger.stack;
if (stack == null || stack['frames'].length == 0) {
- return new Future.value(new DebuggerLocation.error(
- 'A script must be provided when the stack is empty'));
+ return null;
+ }
+ return stack['frames'][debugger.currentFrame];
+ }
+
+ static Future<DebuggerLocation> _currentLocation(Debugger debugger) async {
+ var frame = await _currentFrame(debugger);
+ if (frame == null) {
+ return new DebuggerLocation.error(
+ 'A script must be provided when the stack is empty');
}
- var frame = stack['frames'][debugger.currentFrame];
Script script = frame.location.script;
- return script.load().then((_) {
- var line = script.tokenToLine(frame.location.tokenPos);
- var col = script.tokenToCol(frame.location.tokenPos);
- return new Future.value(new DebuggerLocation.file(script, line, col));
- });
+ await script.load();
+ var line = script.tokenToLine(frame.location.tokenPos);
+ var col = script.tokenToCol(frame.location.tokenPos);
+ return new DebuggerLocation.file(script, line, col);
}
static Future<DebuggerLocation> _parseScriptLine(Debugger debugger,
- Match match) {
+ Match match) async {
var scriptName = match.group(1);
if (scriptName != null) {
scriptName = scriptName.substring(0, scriptName.length - 1);
@@ -84,28 +90,25 @@ class DebuggerLocation {
if (scriptName != null) {
// Resolve the script.
- return _lookupScript(debugger.isolate, scriptName).then((scripts) {
- if (scripts.length == 0) {
- return new DebuggerLocation.error("Script '${scriptName}' not found");
- } else if (scripts.length == 1) {
- return new DebuggerLocation.file(scripts[0], line, col);
- } else {
- // TODO(turnidge): Allow the user to disambiguate.
- return new DebuggerLocation.error("Script '${scriptName}' is ambigous");
- }
- });
+ var scripts = await _lookupScript(debugger.isolate, scriptName);
+ if (scripts.length == 0) {
+ return new DebuggerLocation.error("Script '${scriptName}' not found");
+ } else if (scripts.length == 1) {
+ return new DebuggerLocation.file(scripts[0], line, col);
+ } else {
+ // TODO(turnidge): Allow the user to disambiguate.
+ return new DebuggerLocation.error("Script '${scriptName}' is ambigous");
+ }
} else {
// No script provided. Default to top of stack for now.
- ServiceMap stack = debugger.stack;
- if (stack == null || stack['frames'].length == 0) {
+ var frame = await _currentFrame(debugger);
+ if (frame == null) {
return new Future.value(new DebuggerLocation.error(
'A script must be provided when the stack is empty'));
}
- var frame = stack['frames'][debugger.currentFrame];
Script script = frame.location.script;
- return script.load().then((_) {
- return new Future.value(new DebuggerLocation.file(script, line, col));
- });
+ await script.load();
+ return new DebuggerLocation.file(script, line, col);
}
}
@@ -160,7 +163,10 @@ class DebuggerLocation {
static Future<List<Class>> _lookupClass(Isolate isolate,
String name,
- { bool allowPrefix: false }) {
+ { bool allowPrefix: false }) async {
+ if (isolate == null) {
+ return [];
+ }
var pending = [];
for (var lib in isolate.libraries) {
assert(lib.loaded);
@@ -170,23 +176,22 @@ class DebuggerLocation {
}
}
}
- return Future.wait(pending).then((_) {
- var matches = [];
- for (var lib in isolate.libraries) {
- for (var cls in lib.classes) {
- if (allowPrefix) {
- if (cls.name.startsWith(name)) {
- matches.add(cls);
- }
- } else {
- if (name == cls.name) {
- matches.add(cls);
- }
+ await Future.wait(pending);
+ var matches = [];
+ for (var lib in isolate.libraries) {
+ for (var cls in lib.classes) {
+ if (allowPrefix) {
+ if (cls.name.startsWith(name)) {
+ matches.add(cls);
+ }
+ } else {
+ if (name == cls.name) {
+ matches.add(cls);
}
}
}
- return matches;
- });
+ }
+ return matches;
}
static ServiceFunction _getConstructor(Class cls, String name) {
@@ -255,7 +260,7 @@ class DebuggerLocation {
}
static RegExp partialSourceLocMatcher =
- new RegExp(r'^([^\d:]?[^:]+[:]?)?(\d+)?([:]\d+)?');
+ new RegExp(r'^([^\d:]?[^:]+[:]?)?(\d+)?([:]\d*)?');
static RegExp partialFunctionMatcher = new RegExp(r'^([^.]*)([.][^.]*)?');
/// Completes a partial source location description.
@@ -326,25 +331,105 @@ class DebuggerLocation {
}
}
- static Future<List<String>> _completeFile(Debugger debugger, Match match) {
- var scriptName = match.group(1);
- var lineStr = match.group(2);
- var colStr = match.group(3);
- if (lineStr != null || colStr != null) {
- // TODO(turnidge): Complete valid line and column numbers.
- return new Future.value([]);
+ static bool _startsWithDigit(String s) {
+ return '0'.compareTo(s[0]) <= 0 && '9'.compareTo(s[0]) >= 0;
+ }
+
+ static Future<List<String>> _completeFile(
+ Debugger debugger, Match match) async {
+ var scriptName;
+ var scriptNameComplete = false;
+ var lineStr;
+ var lineStrComplete = false;
+ var colStr;
+ if (_startsWithDigit(match.group(1))) {
+ // CASE 1: We have matched a prefix of (lineStr:)(colStr)
+ var frame = await _currentFrame(debugger);
+ if (frame == null) {
+ return [];
+ }
+ scriptName = frame.location.script.name;
+ scriptNameComplete = true;
+ lineStr = match.group(1);
+ lineStr = (lineStr == null ? '' : lineStr);
+ if (lineStr.endsWith(':')) {
+ lineStr = lineStr.substring(0, lineStr.length - 1);
+ lineStrComplete = true;
+ }
+ colStr = match.group(2);
+ colStr = (colStr == null ? '' : colStr);
+ } else {
+ // CASE 2: We have matched a prefix of (scriptName:)(lineStr)(:colStr)
+ scriptName = match.group(1);
+ scriptName = (scriptName == null ? '' : scriptName);
+ if (scriptName.endsWith(':')) {
+ scriptName = scriptName.substring(0, scriptName.length - 1);
+ scriptNameComplete = true;
+ }
+ lineStr = match.group(2);
+ lineStr = (lineStr == null ? '' : lineStr);
+ colStr = match.group(3);
+ colStr = (colStr == null ? '' : colStr);
+ if (colStr.startsWith(':')) {
+ lineStrComplete = true;
+ colStr = colStr.substring(1);
+ }
}
- scriptName = (scriptName == null ? '' : scriptName);
- return _lookupScript(debugger.isolate, scriptName, allowPrefix:true)
- .then((scripts) {
+ if (!scriptNameComplete) {
+ // The script name is incomplete. Complete it.
+ var scripts =
+ await _lookupScript(debugger.isolate, scriptName, allowPrefix:true);
+ List completions = [];
+ for (var script in scripts) {
+ completions.add(script.name + ':');
+ }
+ completions.sort();
+ return completions;
+
+ } else {
+ // The script name is complete. Look it up.
+ var scripts =
+ await _lookupScript(debugger.isolate, scriptName, allowPrefix:false);
+ if (scripts.isEmpty) {
+ return [];
+ }
+ var script = scripts[0];
+ await script.load();
+ if (!lineStrComplete) {
+ // Complete the line.
+ var sharedPrefix = '${script.name}:';
+ List completions = [];
+ for (var line in script.lines) {
+ if (line.possibleBpt) {
+ var currentLineStr = line.line.toString();
+ if (currentLineStr.startsWith(lineStr)) {
+ completions.add('${sharedPrefix}${currentLineStr} ');
+ completions.add('${sharedPrefix}${currentLineStr}:');
+ }
+ }
+ }
+ return completions;
+
+ } else {
+ // Complete the column.
+ int lineNum = int.parse(lineStr);
+ var scriptLine = script.getLine(lineNum);
+ if (!scriptLine.possibleBpt) {
+ return [];
+ }
+ var sharedPrefix = '${script.name}:${lineStr}:';
List completions = [];
- for (var script in scripts) {
- completions.add(script.name + ':');
+ int maxCol = scriptLine.text.runes.length;
rmacnak 2015/10/07 18:03:09 DBC: It would be good to have a test with characte
+ for (int i = 1; i <= maxCol; i++) {
+ var currentColStr = i.toString();
+ if (currentColStr.startsWith(colStr)) {
+ completions.add('${sharedPrefix}${currentColStr} ');
+ }
}
- completions.sort();
return completions;
- });
+ }
+ }
}
String toString() {
« no previous file with comments | « no previous file | runtime/observatory/lib/src/elements/debugger.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698