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

Side by Side Diff: runtime/observatory/lib/src/elements/debugger.dart

Issue 2312553002: Converted Observatory debugger elements (Closed)
Patch Set: Sharing command history and console Created 4 years, 3 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library debugger_page_element; 5 library debugger_page_element;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:svg';
8 import 'dart:html'; 9 import 'dart:html';
9 import 'dart:math'; 10 import 'dart:math';
10 import 'observatory_element.dart';
11 import 'package:observatory/event.dart'; 11 import 'package:observatory/event.dart';
12 import 'package:observatory/models.dart' as M; 12 import 'package:observatory/models.dart' as M;
13 import 'package:observatory/app.dart'; 13 import 'package:observatory/app.dart';
14 import 'package:observatory/cli.dart'; 14 import 'package:observatory/cli.dart';
15 import 'package:observatory/debugger.dart'; 15 import 'package:observatory/debugger.dart';
16 import 'package:observatory/service.dart'; 16 import 'package:observatory/src/elements/function_ref.dart';
17 import 'package:observatory/src/elements/helpers/any_ref.dart';
18 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
19 import 'package:observatory/src/elements/helpers/tag.dart';
20 import 'package:observatory/src/elements/helpers/uris.dart';
21 import 'package:observatory/src/elements/instance_ref.dart';
22 import 'package:observatory/src/elements/nav/bar.dart';
23 import 'package:observatory/src/elements/nav/isolate_menu.dart';
24 import 'package:observatory/src/elements/nav/menu.dart';
25 import 'package:observatory/src/elements/nav/notify.dart';
26 import 'package:observatory/src/elements/nav/top_menu.dart';
27 import 'package:observatory/src/elements/nav/vm_menu.dart';
28 import 'package:observatory/src/elements/source_inset.dart';
29 import 'package:observatory/src/elements/source_link.dart';
30 import 'package:observatory/service.dart' as S;
17 import 'package:logging/logging.dart'; 31 import 'package:logging/logging.dart';
18 import 'package:polymer/polymer.dart';
19 32
20 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library. 33 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library.
21 abstract class DebuggerCommand extends Command { 34 abstract class DebuggerCommand extends Command {
22 ObservatoryDebugger debugger; 35 ObservatoryDebugger debugger;
23 36
24 DebuggerCommand(this.debugger, name, children) 37 DebuggerCommand(this.debugger, name, children)
25 : super(name, children); 38 : super(name, children);
26 39
27 String get helpShort; 40 String get helpShort;
28 String get helpLong; 41 String get helpLong;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 debugger.console.print('print expects arguments'); 167 debugger.console.print('print expects arguments');
155 return; 168 return;
156 } 169 }
157 if (debugger.currentFrame == null) { 170 if (debugger.currentFrame == null) {
158 debugger.console.print('No stack'); 171 debugger.console.print('No stack');
159 return; 172 return;
160 } 173 }
161 var expression = args.join(''); 174 var expression = args.join('');
162 var response = await debugger.isolate.evalFrame(debugger.currentFrame, 175 var response = await debugger.isolate.evalFrame(debugger.currentFrame,
163 expression); 176 expression);
164 if (response is DartError) { 177 if (response is S.DartError) {
165 debugger.console.print(response.message); 178 debugger.console.print(response.message);
166 } else { 179 } else {
167 debugger.console.print('= ', newline:false); 180 debugger.console.print('= ', newline:false);
168 debugger.console.printRef(response); 181 debugger.console.printRef(debugger.isolate, response, debugger.instances);
169 } 182 }
170 } 183 }
171 184
172 String helpShort = 'Evaluate and print an expression in the current frame'; 185 String helpShort = 'Evaluate and print an expression in the current frame';
173 186
174 String helpLong = 187 String helpLong =
175 'Evaluate and print an expression in the current frame.\n' 188 'Evaluate and print an expression in the current frame.\n'
176 '\n' 189 '\n'
177 'Syntax: print <expression>\n' 190 'Syntax: print <expression>\n'
178 ' p <expression>\n'; 191 ' p <expression>\n';
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 if (args.length > 1) { 654 if (args.length > 1) {
642 debugger.console.print('not implemented'); 655 debugger.console.print('not implemented');
643 return; 656 return;
644 } 657 }
645 var arg = (args.length == 0 ? '' : args[0]); 658 var arg = (args.length == 0 ? '' : args[0]);
646 var loc = await DebuggerLocation.parse(debugger, arg); 659 var loc = await DebuggerLocation.parse(debugger, arg);
647 if (loc.valid) { 660 if (loc.valid) {
648 if (loc.function != null) { 661 if (loc.function != null) {
649 try { 662 try {
650 await debugger.isolate.addBreakpointAtEntry(loc.function); 663 await debugger.isolate.addBreakpointAtEntry(loc.function);
651 } on ServerRpcException catch(e) { 664 } on S.ServerRpcException catch(e) {
652 if (e.code == ServerRpcException.kCannotAddBreakpoint) { 665 if (e.code == S.ServerRpcException.kCannotAddBreakpoint) {
653 debugger.console.print('Unable to set breakpoint at ${loc}'); 666 debugger.console.print('Unable to set breakpoint at ${loc}');
654 } else { 667 } else {
655 rethrow; 668 rethrow;
656 } 669 }
657 } 670 }
658 } else { 671 } else {
659 assert(loc.script != null); 672 assert(loc.script != null);
660 var script = loc.script; 673 var script = loc.script;
661 await script.load(); 674 await script.load();
662 if (loc.line < 1 || loc.line > script.lines.length) { 675 if (loc.line < 1 || loc.line > script.lines.length) {
663 debugger.console.print( 676 debugger.console.print(
664 'line number must be in range [1,${script.lines.length}]'); 677 'line number must be in range [1,${script.lines.length}]');
665 return; 678 return;
666 } 679 }
667 try { 680 try {
668 await debugger.isolate.addBreakpoint(script, loc.line, loc.col); 681 await debugger.isolate.addBreakpoint(script, loc.line, loc.col);
669 } on ServerRpcException catch(e) { 682 } on S.ServerRpcException catch(e) {
670 if (e.code == ServerRpcException.kCannotAddBreakpoint) { 683 if (e.code == S.ServerRpcException.kCannotAddBreakpoint) {
671 debugger.console.print('Unable to set breakpoint at ${loc}'); 684 debugger.console.print('Unable to set breakpoint at ${loc}');
672 } else { 685 } else {
673 rethrow; 686 rethrow;
674 } 687 }
675 } 688 }
676 } 689 }
677 } else { 690 } else {
678 debugger.console.print(loc.errorMessage); 691 debugger.console.print(loc.errorMessage);
679 } 692 }
680 } 693 }
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 var lineInfo = script.getLine(loc.line); 762 var lineInfo = script.getLine(loc.line);
750 var bpts = lineInfo.breakpoints; 763 var bpts = lineInfo.breakpoints;
751 var foundBreakpoint = false; 764 var foundBreakpoint = false;
752 if (bpts != null) { 765 if (bpts != null) {
753 var bptList = bpts.toList(); 766 var bptList = bpts.toList();
754 for (var bpt in bptList) { 767 for (var bpt in bptList) {
755 if (loc.col == null || 768 if (loc.col == null ||
756 loc.col == script.tokenToCol(bpt.location.tokenPos)) { 769 loc.col == script.tokenToCol(bpt.location.tokenPos)) {
757 foundBreakpoint = true; 770 foundBreakpoint = true;
758 var result = await debugger.isolate.removeBreakpoint(bpt); 771 var result = await debugger.isolate.removeBreakpoint(bpt);
759 if (result is DartError) { 772 if (result is S.DartError) {
760 debugger.console.print( 773 debugger.console.print(
761 'Error clearing breakpoint ${bpt.number}: ${result.message}'); 774 'Error clearing breakpoint ${bpt.number}: ${result.message}');
762 } 775 }
763 } 776 }
764 } 777 }
765 } 778 }
766 if (!foundBreakpoint) { 779 if (!foundBreakpoint) {
767 debugger.console.print('No breakpoint found at ${loc}'); 780 debugger.console.print('No breakpoint found at ${loc}');
768 } 781 }
769 } 782 }
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
931 candidate = isolate; 944 candidate = isolate;
932 } 945 }
933 } 946 }
934 if (candidate == null) { 947 if (candidate == null) {
935 debugger.console.print("Invalid isolate identifier '${arg}'"); 948 debugger.console.print("Invalid isolate identifier '${arg}'");
936 } else { 949 } else {
937 if (candidate == debugger.isolate) { 950 if (candidate == debugger.isolate) {
938 debugger.console.print( 951 debugger.console.print(
939 "Current isolate is already ${candidate.number} '${candidate.name}'" ); 952 "Current isolate is already ${candidate.number} '${candidate.name}'" );
940 } else { 953 } else {
941 debugger.console.print( 954 new AnchorElement(href: Uris.debugger(candidate)).click();
942 "Switching to isolate ${candidate.number} '${candidate.name}'");
943 debugger.isolate = candidate;
944 } 955 }
945 } 956 }
946 return new Future.value(null); 957 return new Future.value(null);
947 } 958 }
948 959
949 Future<List<String>> complete(List<String> args) { 960 Future<List<String>> complete(List<String> args) {
950 if (args.length != 1) { 961 if (args.length != 1) {
951 return new Future.value([args.join('')]); 962 return new Future.value([args.join('')]);
952 } 963 }
953 var result = []; 964 var result = [];
(...skipping 12 matching lines...) Expand all
966 } 977 }
967 String helpShort = 'Switch, list, rename, or reload isolates'; 978 String helpShort = 'Switch, list, rename, or reload isolates';
968 979
969 String helpLong = 980 String helpLong =
970 'Switch the current isolate.\n' 981 'Switch the current isolate.\n'
971 '\n' 982 '\n'
972 'Syntax: isolate <number>\n' 983 'Syntax: isolate <number>\n'
973 ' isolate <name>\n'; 984 ' isolate <name>\n';
974 } 985 }
975 986
976 String _isolateRunState(Isolate isolate) { 987 String _isolateRunState(S.Isolate isolate) {
977 if (isolate.paused) { 988 if (isolate.paused) {
978 return 'paused'; 989 return 'paused';
979 } else if (isolate.running) { 990 } else if (isolate.running) {
980 return 'running'; 991 return 'running';
981 } else if (isolate.idle) { 992 } else if (isolate.idle) {
982 return 'idle'; 993 return 'idle';
983 } else { 994 } else {
984 return 'unknown'; 995 return 'unknown';
985 } 996 }
986 } 997 }
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
1241 class _ConsoleStreamPrinter { 1252 class _ConsoleStreamPrinter {
1242 ObservatoryDebugger _debugger; 1253 ObservatoryDebugger _debugger;
1243 1254
1244 _ConsoleStreamPrinter(this._debugger); 1255 _ConsoleStreamPrinter(this._debugger);
1245 Level _minimumLogLevel = Level.OFF; 1256 Level _minimumLogLevel = Level.OFF;
1246 String _savedStream; 1257 String _savedStream;
1247 String _savedIsolate; 1258 String _savedIsolate;
1248 String _savedLine; 1259 String _savedLine;
1249 List<String> _buffer = []; 1260 List<String> _buffer = [];
1250 1261
1251 void onEvent(String streamName, ServiceEvent event) { 1262 void onEvent(String streamName, S.ServiceEvent event) {
1252 if (event.kind == ServiceEvent.kLogging) { 1263 if (event.kind == S.ServiceEvent.kLogging) {
1253 // Check if we should print this log message. 1264 // Check if we should print this log message.
1254 if (event.logRecord['level'].value < _minimumLogLevel.value) { 1265 if (event.logRecord['level'].value < _minimumLogLevel.value) {
1255 return; 1266 return;
1256 } 1267 }
1257 } 1268 }
1258 String isolateName = event.isolate.name; 1269 String isolateName = event.isolate.name;
1259 // If we get a line from a different isolate/stream, flush 1270 // If we get a line from a different isolate/stream, flush
1260 // any pending output, even if it is not newline-terminated. 1271 // any pending output, even if it is not newline-terminated.
1261 if ((_savedIsolate != null && isolateName != _savedIsolate) || 1272 if ((_savedIsolate != null && isolateName != _savedIsolate) ||
1262 (_savedStream != null && streamName != _savedStream)) { 1273 (_savedStream != null && streamName != _savedStream)) {
1263 flush(); 1274 flush();
1264 } 1275 }
1265 String data; 1276 String data;
1266 bool hasNewline; 1277 bool hasNewline;
1267 if (event.kind == ServiceEvent.kLogging) { 1278 if (event.kind == S.ServiceEvent.kLogging) {
1268 data = event.logRecord["message"].valueAsString; 1279 data = event.logRecord["message"].valueAsString;
1269 hasNewline = true; 1280 hasNewline = true;
1270 } else { 1281 } else {
1271 data = event.bytesAsString; 1282 data = event.bytesAsString;
1272 hasNewline = data.endsWith('\n'); 1283 hasNewline = data.endsWith('\n');
1273 } 1284 }
1274 if (_savedLine != null) { 1285 if (_savedLine != null) {
1275 data = _savedLine + data; 1286 data = _savedLine + data;
1276 _savedIsolate = null; 1287 _savedIsolate = null;
1277 _savedStream = null; 1288 _savedStream = null;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1313 } 1324 }
1314 1325
1315 // Tracks the state for an isolate debugging session. 1326 // Tracks the state for an isolate debugging session.
1316 class ObservatoryDebugger extends Debugger { 1327 class ObservatoryDebugger extends Debugger {
1317 final SettingsGroup settings = new SettingsGroup('debugger'); 1328 final SettingsGroup settings = new SettingsGroup('debugger');
1318 RootCommand cmd; 1329 RootCommand cmd;
1319 DebuggerPageElement page; 1330 DebuggerPageElement page;
1320 DebuggerConsoleElement console; 1331 DebuggerConsoleElement console;
1321 DebuggerInputElement input; 1332 DebuggerInputElement input;
1322 DebuggerStackElement stackElement; 1333 DebuggerStackElement stackElement;
1323 ServiceMap stack; 1334 S.ServiceMap stack;
1335 final S.Isolate isolate;
1324 String breakOnException = "none"; // Last known setting. 1336 String breakOnException = "none"; // Last known setting.
1325 1337
1326 int get currentFrame => _currentFrame; 1338 int get currentFrame => _currentFrame;
1327 1339
1328 void set currentFrame(int value) { 1340 void set currentFrame(int value) {
1329 if (value != null && (value < 0 || value >= stackDepth)) { 1341 if (value != null && (value < 0 || value >= stackDepth)) {
1330 throw new RangeError.range(value, 0, stackDepth); 1342 throw new RangeError.range(value, 0, stackDepth);
1331 } 1343 }
1332 _currentFrame = value; 1344 _currentFrame = value;
1333 if (stackElement != null) { 1345 if (stackElement != null) {
(...skipping 20 matching lines...) Expand all
1354 void downFrame(int count) { 1366 void downFrame(int count) {
1355 if (_upIsDown) { 1367 if (_upIsDown) {
1356 currentFrame -= count; 1368 currentFrame -= count;
1357 } else { 1369 } else {
1358 currentFrame += count; 1370 currentFrame += count;
1359 } 1371 }
1360 } 1372 }
1361 1373
1362 int get stackDepth => stack['frames'].length; 1374 int get stackDepth => stack['frames'].length;
1363 1375
1364 ObservatoryDebugger() { 1376 static final _history = [''];
1377
1378 ObservatoryDebugger(this.isolate) {
1365 _loadSettings(); 1379 _loadSettings();
1366 cmd = new RootCommand([ 1380 cmd = new RootCommand([
1367 new AsyncNextCommand(this), 1381 new AsyncNextCommand(this),
1368 new BreakCommand(this), 1382 new BreakCommand(this),
1369 new ClearCommand(this), 1383 new ClearCommand(this),
1370 new ClsCommand(this), 1384 new ClsCommand(this),
1371 new ContinueCommand(this), 1385 new ContinueCommand(this),
1372 new DeleteCommand(this), 1386 new DeleteCommand(this),
1373 new DownCommand(this), 1387 new DownCommand(this),
1374 new FinishCommand(this), 1388 new FinishCommand(this),
1375 new FrameCommand(this), 1389 new FrameCommand(this),
1376 new HelpCommand(this), 1390 new HelpCommand(this),
1377 new InfoCommand(this), 1391 new InfoCommand(this),
1378 new IsolateCommand(this), 1392 new IsolateCommand(this),
1379 new LogCommand(this), 1393 new LogCommand(this),
1380 new PauseCommand(this), 1394 new PauseCommand(this),
1381 new PrintCommand(this), 1395 new PrintCommand(this),
1382 new RefreshCommand(this), 1396 new RefreshCommand(this),
1383 new SetCommand(this), 1397 new SetCommand(this),
1384 new SmartNextCommand(this), 1398 new SmartNextCommand(this),
1385 new StepCommand(this), 1399 new StepCommand(this),
1386 new SyncNextCommand(this), 1400 new SyncNextCommand(this),
1387 new UpCommand(this), 1401 new UpCommand(this),
1388 new VmCommand(this), 1402 new VmCommand(this),
1389 ]); 1403 ], _history);
1390 _consolePrinter = new _ConsoleStreamPrinter(this); 1404 _consolePrinter = new _ConsoleStreamPrinter(this);
1391 } 1405 }
1392 1406
1393 void _loadSettings() { 1407 void _loadSettings() {
1394 _upIsDown = settings.get('up-is-down'); 1408 _upIsDown = settings.get('up-is-down');
1395 } 1409 }
1396 1410
1397 VM get vm => page.app.vm; 1411 S.VM get vm => page.app.vm;
1398
1399 void updateIsolate(Isolate iso) {
1400 _isolate = iso;
1401 if (_isolate != null) {
1402 if ((breakOnException != iso.exceptionsPauseInfo) &&
1403 (iso.exceptionsPauseInfo != null)) {
1404 breakOnException = iso.exceptionsPauseInfo;
1405 }
1406
1407 _isolate.reload().then((response) {
1408 if (response.isSentinel) {
1409 // The isolate has gone away. The IsolateExit event will
1410 // clear the isolate for the debugger page.
1411 return;
1412 }
1413 // TODO(turnidge): Currently the debugger relies on all libs
1414 // being loaded. Fix this.
1415 var pending = [];
1416 for (var lib in response.libraries) {
1417 if (!lib.loaded) {
1418 pending.add(lib.load());
1419 }
1420 }
1421 Future.wait(pending).then((_) {
1422 refreshStack();
1423 }).catchError((e) {
1424 print("UNEXPECTED ERROR $e");
1425 reportStatus();
1426 });
1427 });
1428 } else {
1429 reportStatus();
1430 }
1431 }
1432
1433 set isolate(Isolate iso) {
1434 // Setting the page's isolate will trigger updateIsolate to be called.
1435 //
1436 // TODO(turnidge): Rework ownership of the ObservatoryDebugger in another
1437 // change.
1438 page.isolate = iso;
1439 }
1440 Isolate get isolate => _isolate;
1441 Isolate _isolate;
1442 1412
1443 void init() { 1413 void init() {
1444 console.newline(); 1414 console.printBold('Debugging isolate isolate ${isolate.number} '
1445 console.printBold("Type 'h' for help"); 1415 '\'${isolate.name}\' ');
1416 console.printBold('Type \'h\' for help');
1446 // Wait a bit and if polymer still hasn't set up the isolate, 1417 // Wait a bit and if polymer still hasn't set up the isolate,
1447 // report this to the user. 1418 // report this to the user.
1448 new Timer(const Duration(seconds:1), () { 1419 new Timer(const Duration(seconds:1), () {
1449 if (isolate == null) { 1420 if (isolate == null) {
1450 reportStatus(); 1421 reportStatus();
1451 } 1422 }
1452 }); 1423 });
1424
1425 if ((breakOnException != isolate.exceptionsPauseInfo) &&
1426 (isolate.exceptionsPauseInfo != null)) {
1427 breakOnException = isolate.exceptionsPauseInfo;
1428 }
1429
1430 isolate.reload().then((response) {
1431 if (response.isSentinel) {
1432 // The isolate has gone away. The IsolateExit event will
1433 // clear the isolate for the debugger page.
1434 return;
1435 }
1436 // TODO(turnidge): Currently the debugger relies on all libs
1437 // being loaded. Fix this.
1438 var pending = [];
1439 for (var lib in response.libraries) {
1440 if (!lib.loaded) {
1441 pending.add(lib.load());
1442 }
1443 }
1444 Future.wait(pending).then((_) {
1445 refreshStack();
1446 }).catchError((e) {
1447 print("UNEXPECTED ERROR $e");
1448 reportStatus();
1449 });
1450 });
1453 } 1451 }
1454 1452
1455 Future refreshStack() async { 1453 Future refreshStack() async {
1456 try { 1454 try {
1457 if (_isolate != null) { 1455 if (isolate != null) {
1458 await _refreshStack(_isolate.pauseEvent); 1456 await _refreshStack(isolate.pauseEvent);
1459 } 1457 }
1460 flushStdio(); 1458 flushStdio();
1461 reportStatus(); 1459 reportStatus();
1462 } catch (e, st) { 1460 } catch (e, st) {
1463 console.printRed("Unexpected error in refreshStack: $e\n$st"); 1461 console.printRed("Unexpected error in refreshStack: $e\n$st");
1464 } 1462 }
1465 } 1463 }
1466 1464
1467 bool isolatePaused() { 1465 bool isolatePaused() {
1468 // TODO(turnidge): Stop relying on the isolate to track the last 1466 // TODO(turnidge): Stop relying on the isolate to track the last
1469 // pause event. Since we listen to events directly in the 1467 // pause event. Since we listen to events directly in the
1470 // debugger, this could introduce a race. 1468 // debugger, this could introduce a race.
1471 return (isolate != null && 1469 return isolate.status == M.IsolateStatus.paused;
1472 isolate.pauseEvent != null &&
1473 isolate.pauseEvent is M.ResumeEvent);
1474 } 1470 }
1475 1471
1476 void warnOutOfDate() { 1472 void warnOutOfDate() {
1477 // Wait a bit, then tell the user that the stack may be out of date. 1473 // Wait a bit, then tell the user that the stack may be out of date.
1478 new Timer(const Duration(seconds:2), () { 1474 new Timer(const Duration(seconds:2), () {
1479 if (!isolatePaused()) { 1475 if (!isolatePaused()) {
1480 stackElement.isSampled = true; 1476 stackElement.isSampled = true;
1481 } 1477 }
1482 }); 1478 });
1483 } 1479 }
1484 1480
1485 Future<ServiceMap> _refreshStack(M.DebugEvent pauseEvent) { 1481 Future<S.ServiceMap> _refreshStack(M.DebugEvent pauseEvent) {
1486 return isolate.getStack().then((result) { 1482 return isolate.getStack().then((result) {
1487 if (result.isSentinel) { 1483 if (result.isSentinel) {
1488 // The isolate has gone away. The IsolateExit event will 1484 // The isolate has gone away. The IsolateExit event will
1489 // clear the isolate for the debugger page. 1485 // clear the isolate for the debugger page.
1490 return; 1486 return;
1491 } 1487 }
1492 stack = result; 1488 stack = result;
1493 stackElement.updateStack(stack, pauseEvent); 1489 stackElement.updateStack(stack, pauseEvent);
1494 if (stack['frames'].length > 0) { 1490 if (stack['frames'].length > 0) {
1495 currentFrame = 0; 1491 currentFrame = 0;
1496 } else { 1492 } else {
1497 currentFrame = null; 1493 currentFrame = null;
1498 } 1494 }
1499 input.focus(); 1495 input.focus();
1500 }); 1496 });
1501 } 1497 }
1502 1498
1503 void reportStatus() { 1499 void reportStatus() {
1504 flushStdio(); 1500 flushStdio();
1505 if (_isolate == null) { 1501 if (isolate == null) {
1506 console.print('No current isolate'); 1502 console.print('No current isolate');
1507 } else if (_isolate.idle) { 1503 } else if (isolate.idle) {
1508 console.print('Isolate is idle'); 1504 console.print('Isolate is idle');
1509 } else if (_isolate.running) { 1505 } else if (isolate.running) {
1510 console.print("Isolate is running (type 'pause' to interrupt)"); 1506 console.print("Isolate is running (type 'pause' to interrupt)");
1511 } else if (_isolate.pauseEvent != null) { 1507 } else if (isolate.pauseEvent != null) {
1512 _reportPause(_isolate.pauseEvent); 1508 _reportPause(isolate.pauseEvent);
1513 } else { 1509 } else {
1514 console.print('Isolate is in unknown state'); 1510 console.print('Isolate is in unknown state');
1515 } 1511 }
1516 warnOutOfDate(); 1512 warnOutOfDate();
1517 } 1513 }
1518 1514
1519 void _reportIsolateError(Isolate isolate, M.DebugEvent event) { 1515 void _reportIsolateError(S.Isolate isolate, M.DebugEvent event) {
1520 if (isolate == null) { 1516 if (isolate == null) {
1521 return; 1517 return;
1522 } 1518 }
1523 DartError error = isolate.error; 1519 S.DartError error = isolate.error;
1524 if (error == null) { 1520 if (error == null) {
1525 return; 1521 return;
1526 } 1522 }
1527 console.newline(); 1523 console.newline();
1528 if (event is M.PauseExceptionEvent) { 1524 if (event is M.PauseExceptionEvent) {
1529 console.printBold('Isolate will exit due to an unhandled exception:'); 1525 console.printBold('Isolate will exit due to an unhandled exception:');
1530 } else { 1526 } else {
1531 console.printBold('Isolate has exited due to an unhandled exception:'); 1527 console.printBold('Isolate has exited due to an unhandled exception:');
1532 } 1528 }
1533 console.print(error.message); 1529 console.print(error.message);
(...skipping 24 matching lines...) Expand all
1558 console.print( 1554 console.print(
1559 "Paused at isolate exit " 1555 "Paused at isolate exit "
1560 "(type 'continue' or [F7] to exit the isolate')"); 1556 "(type 'continue' or [F7] to exit the isolate')");
1561 _reportIsolateError(isolate, event); 1557 _reportIsolateError(isolate, event);
1562 } else if (event is M.PauseExceptionEvent) { 1558 } else if (event is M.PauseExceptionEvent) {
1563 console.print( 1559 console.print(
1564 "Paused at an unhandled exception " 1560 "Paused at an unhandled exception "
1565 "(type 'continue' or [F7] to exit the isolate')"); 1561 "(type 'continue' or [F7] to exit the isolate')");
1566 _reportIsolateError(isolate, event); 1562 _reportIsolateError(isolate, event);
1567 } else if (stack['frames'].length > 0) { 1563 } else if (stack['frames'].length > 0) {
1568 Frame frame = stack['frames'][0]; 1564 S.Frame frame = stack['frames'][0];
1569 var script = frame.location.script; 1565 var script = frame.location.script;
1570 script.load().then((_) { 1566 script.load().then((_) {
1571 var line = script.tokenToLine(frame.location.tokenPos); 1567 var line = script.tokenToLine(frame.location.tokenPos);
1572 var col = script.tokenToCol(frame.location.tokenPos); 1568 var col = script.tokenToCol(frame.location.tokenPos);
1573 if ((event is M.PauseBreakpointEvent) && 1569 if ((event is M.PauseBreakpointEvent) &&
1574 (event.breakpoint != null)) { 1570 (event.breakpoint != null)) {
1575 var bpId = event.breakpoint.number; 1571 var bpId = event.breakpoint.number;
1576 console.print('Paused at breakpoint ${bpId} at ' 1572 console.print('Paused at breakpoint ${bpId} at '
1577 '${script.name}:${line}:${col}'); 1573 '${script.name}:${line}:${col}');
1578 } else if ((event is M.PauseExceptionEvent) && 1574 } else if ((event is M.PauseExceptionEvent) &&
1579 (event.exception != null)) { 1575 (event.exception != null)) {
1580 console.print('Paused due to exception at ' 1576 console.print('Paused due to exception at '
1581 '${script.name}:${line}:${col}'); 1577 '${script.name}:${line}:${col}');
1582 // This seems to be missing if we are paused-at-exception after 1578 // This seems to be missing if we are paused-at-exception after
1583 // paused-at-isolate-exit. Maybe we shutdown part of the debugger too 1579 // paused-at-isolate-exit. Maybe we shutdown part of the debugger too
1584 // soon? 1580 // soon?
1585 console.printRef(event.exception); 1581 console.printRef(isolate, event.exception, instances);
1586 } else { 1582 } else {
1587 console.print('Paused at ${script.name}:${line}:${col}'); 1583 console.print('Paused at ${script.name}:${line}:${col}');
1588 } 1584 }
1589 }); 1585 });
1590 } else { 1586 } else {
1591 console.print("Paused in message loop (type 'continue' or [F7] " 1587 console.print("Paused in message loop (type 'continue' or [F7] "
1592 "to resume processing messages)"); 1588 "to resume processing messages)");
1593 } 1589 }
1594 } 1590 }
1595 1591
1596 Future _reportBreakpointEvent(ServiceEvent event) async { 1592 Future _reportBreakpointEvent(S.ServiceEvent event) async {
1597 var bpt = event.breakpoint; 1593 var bpt = event.breakpoint;
1598 var verb = null; 1594 var verb = null;
1599 switch (event.kind) { 1595 switch (event.kind) {
1600 case ServiceEvent.kBreakpointAdded: 1596 case S.ServiceEvent.kBreakpointAdded:
1601 verb = 'added'; 1597 verb = 'added';
1602 break; 1598 break;
1603 case ServiceEvent.kBreakpointResolved: 1599 case S.ServiceEvent.kBreakpointResolved:
1604 verb = 'resolved'; 1600 verb = 'resolved';
1605 break; 1601 break;
1606 case ServiceEvent.kBreakpointRemoved: 1602 case S.ServiceEvent.kBreakpointRemoved:
1607 verb = 'removed'; 1603 verb = 'removed';
1608 break; 1604 break;
1609 default: 1605 default:
1610 break; 1606 break;
1611 } 1607 }
1612 var script = bpt.location.script; 1608 var script = bpt.location.script;
1613 await script.load(); 1609 await script.load();
1614 1610
1615 var bpId = bpt.number; 1611 var bpId = bpt.number;
1616 var locString = await bpt.location.toUserString(); 1612 var locString = await bpt.location.toUserString();
1617 if (bpt.resolved) { 1613 if (bpt.resolved) {
1618 console.print( 1614 console.print(
1619 'Breakpoint ${bpId} ${verb} at ${locString}'); 1615 'Breakpoint ${bpId} ${verb} at ${locString}');
1620 } else { 1616 } else {
1621 console.print( 1617 console.print(
1622 'Future breakpoint ${bpId} ${verb} at ${locString}'); 1618 'Future breakpoint ${bpId} ${verb} at ${locString}');
1623 } 1619 }
1624 } 1620 }
1625 1621
1626 void onEvent(ServiceEvent event) { 1622 void onEvent(S.ServiceEvent event) {
1627 switch(event.kind) { 1623 switch(event.kind) {
1628 case ServiceEvent.kVMUpdate: 1624 case S.ServiceEvent.kVMUpdate:
1629 var vm = event.owner; 1625 var vm = event.owner;
1630 console.print("VM ${vm.target.networkAddress} renamed to '${vm.name}'"); 1626 console.print("VM ${vm.target.networkAddress} renamed to '${vm.name}'");
1631 break; 1627 break;
1632 1628
1633 case ServiceEvent.kIsolateStart: 1629 case S.ServiceEvent.kIsolateStart:
1634 { 1630 {
1635 var iso = event.owner; 1631 var iso = event.owner;
1636 console.print( 1632 console.print(
1637 "Isolate ${iso.number} '${iso.name}' has been created"); 1633 "Isolate ${iso.number} '${iso.name}' has been created");
1638 if (isolate == null) {
1639 console.print("Switching to isolate ${iso.number} '${iso.name}'");
1640 isolate = iso;
1641 }
1642 } 1634 }
1643 break; 1635 break;
1644 1636
1645 case ServiceEvent.kIsolateExit: 1637 case S.ServiceEvent.kIsolateExit:
1646 { 1638 {
1647 var iso = event.owner; 1639 var iso = event.owner;
1648 if (iso == isolate) { 1640 if (iso == isolate) {
1649 console.print("The current isolate ${iso.number} '${iso.name}' " 1641 console.print("The current isolate ${iso.number} '${iso.name}' "
1650 "has exited"); 1642 "has exited");
1651 var isolates = vm.isolates; 1643 var isolates = vm.isolates;
1652 if (isolates.length > 0) { 1644 if (isolates.length > 0) {
1653 var newIsolate = isolates.first; 1645 var newIsolate = isolates.first;
1654 console.print("Switching to isolate " 1646 new AnchorElement(href: Uris.debugger(newIsolate)).click();
1655 "${newIsolate.number} '${newIsolate.name}'");
1656 isolate = newIsolate;
1657 } else { 1647 } else {
1658 isolate = null; 1648 new AnchorElement(href: Uris.vm()).click();
1659 } 1649 }
1660 } else { 1650 } else {
1661 console.print( 1651 console.print(
1662 "Isolate ${iso.number} '${iso.name}' has exited"); 1652 "Isolate ${iso.number} '${iso.name}' has exited");
1663 } 1653 }
1664 } 1654 }
1665 break; 1655 break;
1666 1656
1667 case ServiceEvent.kDebuggerSettingsUpdate: 1657 case S.ServiceEvent.kDebuggerSettingsUpdate:
1668 if (breakOnException != event.exceptions) { 1658 if (breakOnException != event.exceptions) {
1669 breakOnException = event.exceptions; 1659 breakOnException = event.exceptions;
1670 console.print("Now pausing for exceptions: $breakOnException"); 1660 console.print("Now pausing for exceptions: $breakOnException");
1671 } 1661 }
1672 break; 1662 break;
1673 1663
1674 case ServiceEvent.kIsolateUpdate: 1664 case S.ServiceEvent.kIsolateUpdate:
1675 var iso = event.owner; 1665 var iso = event.owner;
1676 console.print("Isolate ${iso.number} renamed to '${iso.name}'"); 1666 console.print("Isolate ${iso.number} renamed to '${iso.name}'");
1677 break; 1667 break;
1678 1668
1679 case ServiceEvent.kIsolateReload: 1669 case S.ServiceEvent.kIsolateReload:
1680 var reloadError = event.reloadError; 1670 var reloadError = event.reloadError;
1681 if (reloadError != null) { 1671 if (reloadError != null) {
1682 console.print('Isolate reload failed: ${event.reloadError}'); 1672 console.print('Isolate reload failed: ${event.reloadError}');
1683 } else { 1673 } else {
1684 console.print('Isolate reloaded.'); 1674 console.print('Isolate reloaded.');
1685 } 1675 }
1686 break; 1676 break;
1687 1677
1688 case ServiceEvent.kPauseStart: 1678 case S.ServiceEvent.kPauseStart:
1689 case ServiceEvent.kPauseExit: 1679 case S.ServiceEvent.kPauseExit:
1690 case ServiceEvent.kPauseBreakpoint: 1680 case S.ServiceEvent.kPauseBreakpoint:
1691 case ServiceEvent.kPauseInterrupted: 1681 case S.ServiceEvent.kPauseInterrupted:
1692 case ServiceEvent.kPauseException: 1682 case S.ServiceEvent.kPauseException:
1693 if (event.owner == isolate) { 1683 if (event.owner == isolate) {
1694 var e = createEventFromServiceEvent(event); 1684 var e = createEventFromServiceEvent(event);
1695 _refreshStack(e).then((_) async { 1685 _refreshStack(e).then((_) async {
1696 flushStdio(); 1686 flushStdio();
1697 if (isolate != null) { 1687 if (isolate != null) {
1698 await isolate.reload(); 1688 await isolate.reload();
1699 } 1689 }
1700 _reportPause(e); 1690 _reportPause(e);
1701 }); 1691 });
1702 } 1692 }
1703 break; 1693 break;
1704 1694
1705 case ServiceEvent.kResume: 1695 case S.ServiceEvent.kResume:
1706 if (event.owner == isolate) { 1696 if (event.owner == isolate) {
1707 flushStdio(); 1697 flushStdio();
1708 console.print('Continuing...'); 1698 console.print('Continuing...');
1709 } 1699 }
1710 break; 1700 break;
1711 1701
1712 case ServiceEvent.kBreakpointAdded: 1702 case S.ServiceEvent.kBreakpointAdded:
1713 case ServiceEvent.kBreakpointResolved: 1703 case S.ServiceEvent.kBreakpointResolved:
1714 case ServiceEvent.kBreakpointRemoved: 1704 case S.ServiceEvent.kBreakpointRemoved:
1715 if (event.owner == isolate) { 1705 if (event.owner == isolate) {
1716 _reportBreakpointEvent(event); 1706 _reportBreakpointEvent(event);
1717 } 1707 }
1718 break; 1708 break;
1719 1709
1720 case ServiceEvent.kIsolateRunnable: 1710 case S.ServiceEvent.kIsolateRunnable:
1721 case ServiceEvent.kGraph: 1711 case S.ServiceEvent.kGraph:
1722 case ServiceEvent.kGC: 1712 case S.ServiceEvent.kGC:
1723 case ServiceEvent.kInspect: 1713 case S.ServiceEvent.kInspect:
1724 // Ignore. 1714 // Ignore.
1725 break; 1715 break;
1726 1716
1727 case ServiceEvent.kLogging: 1717 case S.ServiceEvent.kLogging:
1728 _consolePrinter.onEvent(event.logRecord['level'].name, event); 1718 _consolePrinter.onEvent(event.logRecord['level'].name, event);
1729 break; 1719 break;
1730 1720
1731 default: 1721 default:
1732 console.print('Unrecognized event: $event'); 1722 console.print('Unrecognized event: $event');
1733 break; 1723 break;
1734 } 1724 }
1735 } 1725 }
1736 1726
1737 _ConsoleStreamPrinter _consolePrinter; 1727 _ConsoleStreamPrinter _consolePrinter;
1738 1728
1739 void flushStdio() { 1729 void flushStdio() {
1740 _consolePrinter.flush(); 1730 _consolePrinter.flush();
1741 } 1731 }
1742 1732
1743 void onStdout(ServiceEvent event) { 1733 void onStdout(S.ServiceEvent event) {
1744 _consolePrinter.onEvent('stdout', event); 1734 _consolePrinter.onEvent('stdout', event);
1745 } 1735 }
1746 1736
1747 void onStderr(ServiceEvent event) { 1737 void onStderr(S.ServiceEvent event) {
1748 _consolePrinter.onEvent('stderr', event); 1738 _consolePrinter.onEvent('stderr', event);
1749 } 1739 }
1750 1740
1751 static String _commonPrefix(String a, String b) { 1741 static String _commonPrefix(String a, String b) {
1752 int pos = 0; 1742 int pos = 0;
1753 while (pos < a.length && pos < b.length) { 1743 while (pos < a.length && pos < b.length) {
1754 if (a.codeUnitAt(pos) != b.codeUnitAt(pos)) { 1744 if (a.codeUnitAt(pos) != b.codeUnitAt(pos)) {
1755 break; 1745 break;
1756 } 1746 }
1757 pos++; 1747 pos++;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1791 String lastCommand; 1781 String lastCommand;
1792 1782
1793 Future run(String command) { 1783 Future run(String command) {
1794 if (command == '' && lastCommand != null) { 1784 if (command == '' && lastCommand != null) {
1795 command = lastCommand; 1785 command = lastCommand;
1796 } 1786 }
1797 console.printBold('\$ $command'); 1787 console.printBold('\$ $command');
1798 return cmd.runCommand(command).then((_) { 1788 return cmd.runCommand(command).then((_) {
1799 lastCommand = command; 1789 lastCommand = command;
1800 }).catchError((e, s) { 1790 }).catchError((e, s) {
1801 if (e is NetworkRpcException) { 1791 if (e is S.NetworkRpcException) {
1802 console.printRed('Unable to execute command because the connection ' 1792 console.printRed('Unable to execute command because the connection '
1803 'to the VM has been closed'); 1793 'to the VM has been closed');
1804 } else { 1794 } else {
1805 if (s != null) { 1795 if (s != null) {
1806 console.printRed('Internal error: $e\n$s'); 1796 console.printRed('Internal error: $e\n$s');
1807 } else { 1797 } else {
1808 console.printRed('Internal error: $e\n'); 1798 console.printRed('Internal error: $e\n');
1809 } 1799 }
1810 } 1800 }
1811 }); 1801 });
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1914 return new Future.value(null); 1904 return new Future.value(null);
1915 } 1905 }
1916 return isolate.stepInto(); 1906 return isolate.stepInto();
1917 } else { 1907 } else {
1918 console.print('The program is already running'); 1908 console.print('The program is already running');
1919 return new Future.value(null); 1909 return new Future.value(null);
1920 } 1910 }
1921 } 1911 }
1922 } 1912 }
1923 1913
1924 @CustomTag('debugger-page') 1914 class DebuggerPageElement extends HtmlElement implements Renderable {
1925 class DebuggerPageElement extends ObservatoryElement { 1915 static const tag = const Tag<DebuggerPageElement>('debugger-page',
1926 @published Isolate isolate; 1916 dependencies: const [
1917 NavBarElement.tag,
1918 NavTopMenuElement.tag,
1919 NavVMMenuElement.tag,
1920 NavIsolateMenuElement.tag,
1921 NavMenuElement.tag,
1922 NavNotifyElement.tag,
1923 ]);
1927 1924
1928 isolateChanged(oldValue) { 1925 S.Isolate _isolate;
1929 debugger.updateIsolate(isolate); 1926 ObservatoryDebugger _debugger;
1930 } 1927 M.InstanceRepository _instances;
1931 ObservatoryDebugger debugger = new ObservatoryDebugger(); 1928 M.ScriptRepository _scripts;
1929 M.EventRepository _events;
1932 1930
1933 DebuggerPageElement.created() : super.created() { 1931 factory DebuggerPageElement(S.Isolate isolate,
1934 debugger.page = this; 1932 M.InstanceRepository instances,
1933 M.ScriptRepository scripts,
1934 M.EventRepository events) {
1935 assert(isolate != null);
1936 assert(instances != null);
1937 assert(scripts != null);
1938 assert(events != null);
1939 final e = document.createElement(tag.name);
1940 final debugger = new ObservatoryDebugger(isolate);
1941 debugger.page = e;
1942 e._isolate = isolate;
1943 e._debugger = debugger;
1944 e._instances = instances;
1945 e._scripts = scripts;
1946 e._events = events;
1947 return e;
1935 } 1948 }
1936 1949
1937 StreamSubscription _resizeSubscription; 1950 DebuggerPageElement.created() : super.created();
1951
1938 Future<StreamSubscription> _vmSubscriptionFuture; 1952 Future<StreamSubscription> _vmSubscriptionFuture;
1939 Future<StreamSubscription> _isolateSubscriptionFuture; 1953 Future<StreamSubscription> _isolateSubscriptionFuture;
1940 Future<StreamSubscription> _debugSubscriptionFuture; 1954 Future<StreamSubscription> _debugSubscriptionFuture;
1941 Future<StreamSubscription> _stdoutSubscriptionFuture; 1955 Future<StreamSubscription> _stdoutSubscriptionFuture;
1942 Future<StreamSubscription> _stderrSubscriptionFuture; 1956 Future<StreamSubscription> _stderrSubscriptionFuture;
1943 Future<StreamSubscription> _logSubscriptionFuture; 1957 Future<StreamSubscription> _logSubscriptionFuture;
1944 1958
1959 ObservatoryApplication get app => ObservatoryApplication.app;
1960
1961 Timer _timer;
1962
1963 static final consoleElement = new DebuggerConsoleElement();
1964
1945 @override 1965 @override
1946 void attached() { 1966 void attached() {
1947 super.attached(); 1967 super.attached();
1948 _onResize(null); 1968
1969 final stackDiv = new DivElement()..classes = ['stack'];
1970 final stackElement = new DebuggerStackElement(_isolate, _debugger, stackDiv,
1971 _instances, _scripts,
1972 _events);
1973 stackDiv.children = [stackElement];
1974 final consoleDiv = new DivElement()..classes = ['console']
1975 ..children = [consoleElement];
1976 final commandElement = new DebuggerInputElement(_isolate, _debugger);
1977 final commandDiv = new DivElement()..classes = ['commandline']
1978 ..children = [commandElement];
1979
1980 children = [
1981 new NavBarElement(queue: app.queue)
1982 ..children = [
1983 new NavTopMenuElement(queue: app.queue),
1984 new NavVMMenuElement(app.vm, app.events, queue: app.queue),
1985 new NavIsolateMenuElement(_isolate, app.events, queue: app.queue),
1986 new NavMenuElement('debugger', last: true, queue: app.queue),
1987 new NavNotifyElement(app.notifications, notifyOnPause: false,
1988 queue: app.queue)
1989 ],
1990 new DivElement()..classes = ['variable']
1991 ..children = [
1992 stackDiv,
1993 new DivElement()
1994 ..children = [
1995 new HRElement()..classes = ['splitter']
1996 ],
1997 consoleDiv,
1998 ],
1999 commandDiv
2000 ];
2001
2002 DebuggerConsoleElement._scrollToBottom(consoleDiv);
1949 2003
1950 // Wire the debugger object to the stack, console, and command line. 2004 // Wire the debugger object to the stack, console, and command line.
1951 var stackElement = $['stackElement']; 2005 _debugger.stackElement = stackElement;
1952 debugger.stackElement = stackElement; 2006 _debugger.console = consoleElement;
1953 stackElement.debugger = debugger; 2007 _debugger.input = commandElement;
1954 stackElement.scroller = $['stackDiv']; 2008 _debugger.input._debugger = _debugger;
1955 debugger.console = $['console']; 2009 _debugger.init();
1956 debugger.input = $['commandline'];
1957 debugger.input.debugger = debugger;
1958 debugger.init();
1959 2010
1960 _resizeSubscription = window.onResize.listen(_onResize);
1961 _vmSubscriptionFuture = 2011 _vmSubscriptionFuture =
1962 app.vm.listenEventStream(VM.kVMStream, debugger.onEvent); 2012 app.vm.listenEventStream(S.VM.kVMStream, _debugger.onEvent);
1963 _isolateSubscriptionFuture = 2013 _isolateSubscriptionFuture =
1964 app.vm.listenEventStream(VM.kIsolateStream, debugger.onEvent); 2014 app.vm.listenEventStream(S.VM.kIsolateStream, _debugger.onEvent);
1965 _debugSubscriptionFuture = 2015 _debugSubscriptionFuture =
1966 app.vm.listenEventStream(VM.kDebugStream, debugger.onEvent); 2016 app.vm.listenEventStream(S.VM.kDebugStream, _debugger.onEvent);
1967 _stdoutSubscriptionFuture = 2017 _stdoutSubscriptionFuture =
1968 app.vm.listenEventStream(VM.kStdoutStream, debugger.onStdout); 2018 app.vm.listenEventStream(S.VM.kStdoutStream, _debugger.onStdout);
1969 if (_stdoutSubscriptionFuture != null) { 2019 if (_stdoutSubscriptionFuture != null) {
1970 // TODO(turnidge): How do we want to handle this in general? 2020 // TODO(turnidge): How do we want to handle this in general?
1971 _stdoutSubscriptionFuture.catchError((e, st) { 2021 _stdoutSubscriptionFuture.catchError((e, st) {
1972 Logger.root.info('Failed to subscribe to stdout: $e\n$st\n'); 2022 Logger.root.info('Failed to subscribe to stdout: $e\n$st\n');
1973 _stdoutSubscriptionFuture = null; 2023 _stdoutSubscriptionFuture = null;
1974 }); 2024 });
1975 } 2025 }
1976 _stderrSubscriptionFuture = 2026 _stderrSubscriptionFuture =
1977 app.vm.listenEventStream(VM.kStderrStream, debugger.onStderr); 2027 app.vm.listenEventStream(S.VM.kStderrStream, _debugger.onStderr);
1978 if (_stderrSubscriptionFuture != null) { 2028 if (_stderrSubscriptionFuture != null) {
1979 // TODO(turnidge): How do we want to handle this in general? 2029 // TODO(turnidge): How do we want to handle this in general?
1980 _stderrSubscriptionFuture.catchError((e, st) { 2030 _stderrSubscriptionFuture.catchError((e, st) {
1981 Logger.root.info('Failed to subscribe to stderr: $e\n$st\n'); 2031 Logger.root.info('Failed to subscribe to stderr: $e\n$st\n');
1982 _stderrSubscriptionFuture = null; 2032 _stderrSubscriptionFuture = null;
1983 }); 2033 });
1984 } 2034 }
1985 _logSubscriptionFuture = 2035 _logSubscriptionFuture =
1986 app.vm.listenEventStream(Isolate.kLoggingStream, debugger.onEvent); 2036 app.vm.listenEventStream(S.Isolate.kLoggingStream, _debugger.onEvent);
1987 // Turn on the periodic poll timer for this page. 2037 // Turn on the periodic poll timer for this page.
1988 pollPeriod = const Duration(milliseconds:100); 2038 _timer = new Timer.periodic(const Duration(milliseconds:100), (_) {
2039 _debugger.flushStdio();
2040 });
1989 2041
1990 onClick.listen((event) { 2042 onClick.listen((event) {
1991 // Random clicks should focus on the text box. If the user selects 2043 // Random clicks should focus on the text box. If the user selects
1992 // a range, don't interfere. 2044 // a range, don't interfere.
1993 var selection = window.getSelection(); 2045 var selection = window.getSelection();
1994 if (selection == null || 2046 if (selection == null ||
1995 (selection.type != 'Range' && selection.type != 'text')) { 2047 (selection.type != 'Range' && selection.type != 'text')) {
1996 debugger.input.focus(); 2048 _debugger.input.focus();
1997 } 2049 }
1998 }); 2050 });
1999 } 2051 }
2000 2052
2001 void onPoll() {
2002 debugger.flushStdio();
2003 }
2004
2005 void _onResize(_) {
2006 var navbarDiv = $['navbarDiv'];
2007 var stackDiv = $['stackDiv'];
2008 var splitterDiv = $['splitterDiv'];
2009 var cmdDiv = $['commandDiv'];
2010
2011 // For now, force navbar height to 40px in the debugger.
2012 // TODO (cbernaschina) check if this is needed.
2013 const navbarHeight = 40;
2014 int splitterHeight = splitterDiv.clientHeight;
2015 int cmdHeight = cmdDiv.clientHeight;
2016
2017 int windowHeight = window.innerHeight;
2018 int fixedHeight = navbarHeight + splitterHeight + cmdHeight;
2019 int available = windowHeight - fixedHeight;
2020 int stackHeight = available ~/ 1.6;
2021 navbarDiv.style.setProperty('height', '${navbarHeight}px');
2022 stackDiv.style.setProperty('height', '${stackHeight}px');
2023 }
2024
2025 @override 2053 @override
2026 void detached() { 2054 void detached() {
2027 debugger.isolate = null; 2055 _timer.cancel();
2028 _resizeSubscription.cancel(); 2056 children = const [];
2029 _resizeSubscription = null; 2057 S.cancelFutureSubscription(_vmSubscriptionFuture);
2030 cancelFutureSubscription(_vmSubscriptionFuture);
2031 _vmSubscriptionFuture = null; 2058 _vmSubscriptionFuture = null;
2032 cancelFutureSubscription(_isolateSubscriptionFuture); 2059 S.cancelFutureSubscription(_isolateSubscriptionFuture);
2033 _isolateSubscriptionFuture = null; 2060 _isolateSubscriptionFuture = null;
2034 cancelFutureSubscription(_debugSubscriptionFuture); 2061 S.cancelFutureSubscription(_debugSubscriptionFuture);
2035 _debugSubscriptionFuture = null; 2062 _debugSubscriptionFuture = null;
2036 cancelFutureSubscription(_stdoutSubscriptionFuture); 2063 S.cancelFutureSubscription(_stdoutSubscriptionFuture);
2037 _stdoutSubscriptionFuture = null; 2064 _stdoutSubscriptionFuture = null;
2038 cancelFutureSubscription(_stderrSubscriptionFuture); 2065 S.cancelFutureSubscription(_stderrSubscriptionFuture);
2039 _stderrSubscriptionFuture = null; 2066 _stderrSubscriptionFuture = null;
2040 cancelFutureSubscription(_logSubscriptionFuture); 2067 S.cancelFutureSubscription(_logSubscriptionFuture);
2041 _logSubscriptionFuture = null; 2068 _logSubscriptionFuture = null;
2042 super.detached(); 2069 super.detached();
2043 } 2070 }
2044 } 2071 }
2045 2072
2046 @CustomTag('debugger-stack') 2073 class DebuggerStackElement extends HtmlElement implements Renderable {
2047 class DebuggerStackElement extends ObservatoryElement { 2074 static const tag = const Tag<DebuggerStackElement>('debugger-stack');
2048 @published Isolate isolate;
2049 @published Element scroller;
2050 @observable bool hasStack = false;
2051 @observable bool hasMessages = false;
2052 @observable bool isSampled = false;
2053 @observable int currentFrame;
2054 ObservatoryDebugger debugger;
2055 2075
2056 _addFrame(List frameList, Frame frameInfo) { 2076 S.Isolate _isolate;
2057 DebuggerFrameElement frameElement = new Element.tag('debugger-frame'); 2077 M.InstanceRepository _instances;
2058 frameElement.frame = frameInfo; 2078 M.ScriptRepository _scripts;
2059 frameElement.scroller = scroller; 2079 M.EventRepository _events;
2080 Element _scroller;
2081 DivElement _isSampled;
2082 bool get isSampled => !_isSampled.classes.contains('hidden');
2083 set isSampled(bool value) {
2084 if (value != isSampled) {
2085 _isSampled.classes.toggle('hidden');
2086 }
2087 }
2088 DivElement _hasStack;
2089 bool get hasStack => _hasStack.classes.contains('hidden');
2090 set hasStack(bool value) {
2091 if (value != hasStack) {
2092 _hasStack.classes.toggle('hidden');
2093 }
2094 }
2095 DivElement _hasMessages;
2096 bool get hasMessages => _hasMessages.classes.contains('hidden');
2097 set hasMessages(bool value) {
2098 if (value != hasMessages) {
2099 _hasMessages.classes.toggle('hidden');
2100 }
2101 }
2102 UListElement _frameList;
2103 UListElement _messageList;
2104 int currentFrame;
2105 ObservatoryDebugger _debugger;
2106
2107 factory DebuggerStackElement(S.Isolate isolate,
2108 ObservatoryDebugger debugger,
2109 Element scroller,
2110 M.InstanceRepository instances,
2111 M.ScriptRepository scripts,
2112 M.EventRepository events) {
2113 assert(isolate != null);
2114 assert(debugger != null);
2115 assert(scroller != null);
2116 assert(instances != null);
2117 assert(scripts != null);
2118 assert(events != null);
2119 final e = document.createElement(tag.name);
2120 e._isolate = isolate;
2121 e._debugger = debugger;
2122 e._scroller = scroller;
2123 e._instances = instances;
2124 e._scripts = scripts;
2125 e._events = events;
2126
2127 var btnPause;
2128 var btnRefresh;
2129 e.children = [
2130 e._isSampled = new DivElement()..classes = ['sampledMessage', 'hidden']
2131 ..children = [
2132 new SpanElement()
2133 ..text = 'The program is not paused. '
2134 'The stack trace below may be out of date.',
2135 new BRElement(),
2136 new BRElement(),
2137 btnPause = new ButtonElement()
2138 ..text = '[Pause Isolate]'
2139 ..onClick.listen((_) async {
2140 btnPause.disabled = true;
2141 try {
2142 await debugger.isolate.pause();
2143 }
2144 finally {
2145 btnPause.disabled = false;
2146 }
2147 }),
2148 btnRefresh = new ButtonElement()
2149 ..text = '[Refresh Stack]'
2150 ..onClick.listen((_) async {
2151 btnRefresh.disabled = true;
2152 try {
2153 await debugger.refreshStack();
2154 }
2155 finally {
2156 btnRefresh.disabled = false;
2157 }
2158 }),
2159 new BRElement(),
2160 new BRElement(),
2161 new HRElement()..classes = ['splitter']
2162 ],
2163 e._hasStack = new DivElement()..classes = ['noStack', 'hidden']
2164 ..text = 'No stack',
2165 e._frameList = new UListElement()..classes = ['list-group'],
2166 new HRElement(),
2167 e._hasMessages = new DivElement()..classes = ['noMessages', 'hidden']
2168 ..text = 'No pending messages',
2169 e._messageList = new UListElement()..classes = ['messageList']
2170 ];
2171 return e;
2172 }
2173
2174 _addFrame(List frameList, S.Frame frameInfo) {
2175 final frameElement = new DebuggerFrameElement(_isolate,
2176 frameInfo,
2177 _scroller,
2178 _instances,
2179 _scripts,
2180 _events,
2181 queue: app.queue);
2060 2182
2061 if (frameInfo.index == currentFrame) { 2183 if (frameInfo.index == currentFrame) {
2062 frameElement.setCurrent(true); 2184 frameElement.setCurrent(true);
2063 } else { 2185 } else {
2064 frameElement.setCurrent(false); 2186 frameElement.setCurrent(false);
2065 } 2187 }
2066 2188
2067 var li = new LIElement(); 2189 var li = new LIElement();
2068 li.classes.add('list-group-item'); 2190 li.classes.add('list-group-item');
2069 li.children.insert(0, frameElement); 2191 li.children.insert(0, frameElement);
2070 2192
2071 frameList.insert(0, li); 2193 frameList.insert(0, li);
2072 } 2194 }
2073 2195
2074 _addMessage(List messageList, ServiceMessage messageInfo) { 2196 _addMessage(List messageList, S.ServiceMessage messageInfo) {
2075 DebuggerMessageElement messageElement = new Element.tag('debugger-message'); 2197 final messageElement = new DebuggerMessageElement(_isolate,
2076 messageElement.message = messageInfo; 2198 messageInfo,
2199 _instances,
2200 _scripts,
2201 _events,
2202 queue: app.queue);
2077 2203
2078 var li = new LIElement(); 2204 var li = new LIElement();
2079 li.classes.add('list-group-item'); 2205 li.classes.add('list-group-item');
2080 li.children.insert(0, messageElement); 2206 li.children.insert(0, messageElement);
2081 2207
2082 messageList.add(li); 2208 messageList.add(li);
2083 } 2209 }
2084 2210
2085 void updateStackFrames(ServiceMap newStack) { 2211 ObservatoryApplication get app => ObservatoryApplication.app;
2086 List frameElements = $['frameList'].children; 2212
2213 void updateStackFrames(S.ServiceMap newStack) {
2214 List frameElements = _frameList.children;
2087 List newFrames = newStack['frames']; 2215 List newFrames = newStack['frames'];
2088 2216
2089 // Remove any frames whose functions don't match, starting from 2217 // Remove any frames whose functions don't match, starting from
2090 // bottom of stack. 2218 // bottom of stack.
2091 int oldPos = frameElements.length - 1; 2219 int oldPos = frameElements.length - 1;
2092 int newPos = newFrames.length - 1; 2220 int newPos = newFrames.length - 1;
2093 while (oldPos >= 0 && newPos >= 0) { 2221 while (oldPos >= 0 && newPos >= 0) {
2094 if (!frameElements[oldPos].children[0].matchFrame(newFrames[newPos])) { 2222 if (!frameElements[oldPos].children[0].matchFrame(newFrames[newPos])) {
2095 // The rest of the frame elements no longer match. Remove them. 2223 // The rest of the frame elements no longer match. Remove them.
2096 for (int i = 0; i <= oldPos; i++) { 2224 for (int i = 0; i <= oldPos; i++) {
(...skipping 28 matching lines...) Expand all
2125 2253
2126 if (frameElements.isNotEmpty) { 2254 if (frameElements.isNotEmpty) {
2127 for (int i = newCount; i < frameElements.length; i++) { 2255 for (int i = newCount; i < frameElements.length; i++) {
2128 frameElements[i].children[0].updateFrame(newFrames[i]); 2256 frameElements[i].children[0].updateFrame(newFrames[i]);
2129 } 2257 }
2130 } 2258 }
2131 2259
2132 hasStack = frameElements.isNotEmpty; 2260 hasStack = frameElements.isNotEmpty;
2133 } 2261 }
2134 2262
2135 void updateStackMessages(ServiceMap newStack) { 2263 void updateStackMessages(S.ServiceMap newStack) {
2136 List messageElements = $['messageList'].children; 2264 List messageElements = _messageList.children;
2137 List newMessages = newStack['messages']; 2265 List newMessages = newStack['messages'];
2138 2266
2139 // Remove any extra message elements. 2267 // Remove any extra message elements.
2140 if (messageElements.length > newMessages.length) { 2268 if (messageElements.length > newMessages.length) {
2141 // Remove old messages from the front of the queue. 2269 // Remove old messages from the front of the queue.
2142 int removeCount = messageElements.length - newMessages.length; 2270 int removeCount = messageElements.length - newMessages.length;
2143 for (int i = 0; i < removeCount; i++) { 2271 for (int i = 0; i < removeCount; i++) {
2144 messageElements.removeAt(0); 2272 messageElements.removeAt(0);
2145 } 2273 }
2146 } 2274 }
2147 2275
2148 // Add any new messages to the tail of the queue. 2276 // Add any new messages to the tail of the queue.
2149 int newStartingIndex = messageElements.length; 2277 int newStartingIndex = messageElements.length;
2150 if (messageElements.length < newMessages.length) { 2278 if (messageElements.length < newMessages.length) {
2151 for (int i = newStartingIndex; i < newMessages.length; i++) { 2279 for (int i = newStartingIndex; i < newMessages.length; i++) {
2152 _addMessage(messageElements, newMessages[i]); 2280 _addMessage(messageElements, newMessages[i]);
2153 } 2281 }
2154 } 2282 }
2155 assert(messageElements.length == newMessages.length); 2283 assert(messageElements.length == newMessages.length);
2156 2284
2157 if (messageElements.isNotEmpty) { 2285 if (messageElements.isNotEmpty) {
2158 // Update old messages. 2286 // Update old messages.
2159 for (int i = 0; i < newStartingIndex; i++) { 2287 for (int i = 0; i < newStartingIndex; i++) {
2160 messageElements[i].children[0].updateMessage(newMessages[i]); 2288 DebuggerMessageElement e = messageElements[i].children[0];
2289 e.updateMessage(newMessages[i]);
2161 } 2290 }
2162 } 2291 }
2163 2292
2164 hasMessages = messageElements.isNotEmpty; 2293 hasMessages = messageElements.isNotEmpty;
2165 } 2294 }
2166 2295
2167 void updateStack(ServiceMap newStack, M.DebugEvent pauseEvent) { 2296 void updateStack(S.ServiceMap newStack, M.DebugEvent pauseEvent) {
2168 updateStackFrames(newStack); 2297 updateStackFrames(newStack);
2169 updateStackMessages(newStack); 2298 updateStackMessages(newStack);
2170 isSampled = pauseEvent == null; 2299 isSampled = pauseEvent == null;
2171 } 2300 }
2172 2301
2173 void setCurrentFrame(int value) { 2302 void setCurrentFrame(int value) {
2174 currentFrame = value; 2303 currentFrame = value;
2175 List frameElements = $['frameList'].children; 2304 List frameElements = _frameList.children;
2176 for (var frameElement in frameElements) { 2305 for (var frameElement in frameElements) {
2177 var dbgFrameElement = frameElement.children[0]; 2306 DebuggerFrameElement dbgFrameElement = frameElement.children[0];
2178 if (dbgFrameElement.frame.index == currentFrame) { 2307 if (dbgFrameElement.frame.index == currentFrame) {
2179 dbgFrameElement.setCurrent(true); 2308 dbgFrameElement.setCurrent(true);
2180 } else { 2309 } else {
2181 dbgFrameElement.setCurrent(false); 2310 dbgFrameElement.setCurrent(false);
2182 } 2311 }
2183 } 2312 }
2184 } 2313 }
2185 2314
2186 Future doPauseIsolate() {
2187 if (debugger != null) {
2188 return debugger.isolate.pause();
2189 } else {
2190 return new Future.value(null);
2191 }
2192 }
2193
2194 Future doRefreshStack() {
2195 if (debugger != null) {
2196 return debugger.refreshStack();
2197 } else {
2198 return new Future.value(null);
2199 }
2200 }
2201
2202 DebuggerStackElement.created() : super.created(); 2315 DebuggerStackElement.created() : super.created();
2203 } 2316 }
2204 2317
2205 @CustomTag('debugger-frame') 2318 class DebuggerFrameElement extends HtmlElement implements Renderable {
2206 class DebuggerFrameElement extends ObservatoryElement { 2319 static const tag = const Tag<DebuggerFrameElement>('debugger-frame');
2207 @published Frame frame; 2320
2208 @published Element scroller; 2321 RenderingScheduler<DebuggerMessageElement> _r;
2322
2323 Stream<RenderedEvent<DebuggerMessageElement>> get onRendered => _r.onRendered;
2324
2325 Element _scroller;
2326 DivElement _varsDiv;
2327 M.Isolate _isolate;
2328 S.Frame _frame;
2329 S.Frame get frame => _frame;
2330 M.InstanceRepository _instances;
2331 M.ScriptRepository _scripts;
2332 M.EventRepository _events;
2209 2333
2210 // Is this the current frame? 2334 // Is this the current frame?
2211 bool _current = false; 2335 bool _current = false;
2212 2336
2213 // Has this frame been pinned open? 2337 // Has this frame been pinned open?
2214 bool _pinned = false; 2338 bool _pinned = false;
2215 2339
2340 bool _expanded = false;
2341
2216 void setCurrent(bool value) { 2342 void setCurrent(bool value) {
2217 busy = true; 2343 _frame.function.load().then((func) {
2218 frame.function.load().then((func) {
2219 _current = value; 2344 _current = value;
2220 var frameOuter = $['frameOuter'];
2221 if (_current) { 2345 if (_current) {
2222 frameOuter.classes.add('current');
2223 _expand(); 2346 _expand();
2224 scrollIntoView(); 2347 scrollIntoView();
2225 } else { 2348 } else {
2226 frameOuter.classes.remove('current');
2227 if (_pinned) { 2349 if (_pinned) {
2228 _expand(); 2350 _expand();
2229 } else { 2351 } else {
2230 _unexpand(); 2352 _unexpand();
2231 } 2353 }
2232 } 2354 }
2233 busy = false;
2234 }); 2355 });
2235 } 2356 }
2236 2357
2237 @observable String scriptHeight; 2358 factory DebuggerFrameElement(M.Isolate isolate,
2238 @observable bool expanded = false; 2359 S.Frame frame,
2239 @observable bool busy = false; 2360 Element scroller,
2361 M.InstanceRepository instances,
2362 M.ScriptRepository scripts,
2363 M.EventRepository events,
2364 {RenderingQueue queue}) {
2365 assert(isolate != null);
2366 assert(frame != null);
2367 assert(scroller != null);
2368 assert(instances != null);
2369 assert(scripts != null);
2370 assert(events != null);
2371 final DebuggerFrameElement e = document.createElement(tag.name);
2372 e._r = new RenderingScheduler(e, queue: queue);
2373 e._isolate = isolate;
2374 e._frame = frame;
2375 e._scroller = scroller;
2376 e._instances = instances;
2377 e._scripts = scripts;
2378 e._events = events;
2379 return e;
2380 }
2240 2381
2241 DebuggerFrameElement.created() : super.created(); 2382 DebuggerFrameElement.created() : super.created();
2242 2383
2384 void render() {
2385 if (_pinned) {
2386 classes.add('shadow');
2387 } else {
2388 classes.remove('shadow');
2389 }
2390 if (_current) {
2391 classes.add('current');
2392 } else {
2393 classes.remove('current');
2394 }
2395 ButtonElement expandButton;
2396 final content = <Element>[
2397 expandButton = new ButtonElement()
2398 ..children = _createHeader()
2399 ..onClick.listen((e) async {
2400 if (e.target is AnchorElement) {
2401 return;
2402 }
2403 expandButton.disabled = true;
2404 await _toggleExpand();
2405 expandButton.disabled = false;
2406 })
2407 ];
2408 if (_expanded) {
2409 final homeMethod = _frame.function.homeMethod;
2410 String homeMethodName;
2411 if ((homeMethod.dartOwner is S.Class) && homeMethod.isStatic) {
2412 homeMethodName = '<class>';
2413 } else if (homeMethod.dartOwner is S.Library) {
2414 homeMethodName = '<library>';
2415 }
2416 ButtonElement collapseButton;
2417 content.addAll([
2418 new DivElement()..classes = ['frameDetails']
2419 ..children = [
2420 new DivElement()..classes = ['flex-row-wrap']
2421 ..children = [
2422 new DivElement()..classes = ['flex-item-script']
2423 ..children = _frame.function?.location == null ? const []
2424 : [
2425 new SourceInsetElement(_isolate,
2426 _frame.function.location, _scripts, _instances,
2427 _events, currentPos: _frame.location.tokenPos,
2428 variables: _frame.variables, inDebuggerContext: true,
2429 queue: _r.queue)
2430 ],
2431 new DivElement()..classes = ['flex-item-vars']
2432 ..children = [
2433 _varsDiv = new DivElement()
2434 ..classes = ['memberList', 'frameVars']
2435 ..children = ([
2436 new DivElement()..classes = ['memberItem']
2437 ..children = homeMethodName == null ? const []
2438 : [
2439 new DivElement()..classes = ['memberName']
2440 ..text = homeMethodName,
2441 new DivElement()..classes = ['memberName']
2442 ..children = [
2443 anyRef(_isolate, homeMethod.dartOwner,
2444 _instances, queue: _r.queue)
2445 ]
2446 ]
2447 ]..addAll(_frame.variables.map((v) =>
2448 new DivElement()..classes = ['memberItem']
2449 ..children = [
2450 new DivElement()..classes = ['memberName']
2451 ..text = v.name,
2452 new DivElement()..classes = ['memberName']
2453 ..children = [
2454 anyRef(_isolate, v['value'], _instances,
2455 queue: _r.queue)
2456 ]
2457 ]
2458 ).toList()))
2459 ]
2460 ],
2461 new DivElement()..classes = ['frameContractor']
2462 ..children = [
2463 collapseButton = new ButtonElement()
2464 ..onClick.listen((e) async {
2465 collapseButton.disabled = true;
2466 await _toggleExpand();
2467 collapseButton.disabled = false;
2468 })
2469 ..children = [
2470 iconExpandLess.clone(true)
2471 ]
2472 ]
2473 ]
2474 ]);
2475 }
2476 children = content;
2477 }
2478
2479 List<Element> _createHeader() {
2480 final content = [
2481 new DivElement()..classes = ['frameSummaryText']
2482 ..children = [
2483 new DivElement()..classes = ['frameId']
2484 ..text = 'Frame ${_frame.index}',
2485 new SpanElement()
2486 ..children = _frame.function == null ? const []
2487 : [
2488 new FunctionRefElement(_isolate, _frame.function,
2489 queue: _r.queue)
2490 ],
2491 new SpanElement()..text = ' ( ',
2492 new SpanElement()
2493 ..children = _frame.function?.location == null ? const []
2494 : [
2495 new SourceLinkElement(_isolate, _frame.function.location,
2496 _scripts,
2497 queue: _r.queue)
2498 ],
2499 new SpanElement()..text = ' )'
2500 ]
2501 ];
2502 if (!_expanded) {
2503 content.add(new DivElement()..classes = ['frameExpander']
2504 ..children = [
2505 iconExpandMore.clone(true)
2506 ]);
2507 }
2508 return [
2509 new DivElement()..classes = ['frameSummary']
2510 ..children = content
2511 ];
2512 }
2513
2243 String makeExpandKey(String key) { 2514 String makeExpandKey(String key) {
2244 return '${frame.function.qualifiedName}/${key}'; 2515 return '${_frame.function.qualifiedName}/${key}';
2245 } 2516 }
2246 2517
2247 bool matchFrame(Frame newFrame) { 2518 bool matchFrame(S.Frame newFrame) {
2248 return newFrame.function.id == frame.function.id; 2519 return newFrame.function.id == _frame.function.id;
2249 } 2520 }
2250 2521
2251 void updateFrame(Frame newFrame) { 2522 void updateFrame(S.Frame newFrame) {
2252 assert(matchFrame(newFrame)); 2523 assert(matchFrame(newFrame));
2253 frame = newFrame; 2524 _frame = newFrame;
2254 } 2525 }
2255 2526
2256 Script get script => frame.location.script; 2527 S.Script get script => _frame.location.script;
2257 2528
2258 int _varsTop(varsDiv) { 2529 int _varsTop(varsDiv) {
2259 const minTop = 5; 2530 const minTop = 0;
2260 if (varsDiv == null) { 2531 if (varsDiv == null) {
2261 return minTop; 2532 return minTop;
2262 } 2533 }
2263 // TODO (cbernaschina) check if this is needed. 2534 final paddingTop = document.body.contentEdge.top;
2264 const navbarHeight = 40; 2535 final parent = varsDiv.parent.getBoundingClientRect();
2265 const bottomPad = 6; 2536 final varsHeight = varsDiv.clientHeight;
2266 var parent = varsDiv.parent.getBoundingClientRect(); 2537 final maxTop = parent.height - varsHeight;
2267 var varsHeight = varsDiv.clientHeight; 2538 final adjustedTop = paddingTop - parent.top;
2268 var maxTop = parent.height - (varsHeight + bottomPad);
2269 var adjustedTop = navbarHeight - parent.top;
2270 return (max(minTop, min(maxTop, adjustedTop))); 2539 return (max(minTop, min(maxTop, adjustedTop)));
2271 } 2540 }
2272 2541
2273 void _onScroll(event) { 2542 void _onScroll(event) {
2274 if (!expanded) { 2543 if (!_expanded || _varsDiv == null) {
2275 return; 2544 return;
2276 } 2545 }
2277 var varsDiv = shadowRoot.querySelector('#vars'); 2546 var currentTop = _varsDiv.style.top;
2278 if (varsDiv == null) { 2547 var newTop = _varsTop(_varsDiv);
2279 return;
2280 }
2281 var currentTop = varsDiv.style.top;
2282 var newTop = _varsTop(varsDiv);
2283 if (currentTop != newTop) { 2548 if (currentTop != newTop) {
2284 varsDiv.style.top = '${newTop}px'; 2549 _varsDiv.style.top = '${newTop}px';
2285 } 2550 }
2286 } 2551 }
2287 2552
2288 void _expand() { 2553 void _expand() {
2289 var frameOuter = $['frameOuter']; 2554 _expanded = true;
2290 expanded = true;
2291 frameOuter.classes.add('shadow');
2292 _subscribeToScroll(); 2555 _subscribeToScroll();
2556 _r.dirty();
2293 } 2557 }
2294 2558
2295 void _unexpand() { 2559 void _unexpand() {
2296 var frameOuter = $['frameOuter']; 2560 _expanded = false;
2297 expanded = false;
2298 _unsubscribeToScroll(); 2561 _unsubscribeToScroll();
2299 frameOuter.classes.remove('shadow'); 2562 _r.dirty();
2300 } 2563 }
2301 2564
2302 StreamSubscription _scrollSubscription; 2565 StreamSubscription _scrollSubscription;
2303 StreamSubscription _resizeSubscription; 2566 StreamSubscription _resizeSubscription;
2304 2567
2305 void _subscribeToScroll() { 2568 void _subscribeToScroll() {
2306 if (scroller != null) { 2569 if (_scroller != null) {
2307 if (_scrollSubscription == null) { 2570 if (_scrollSubscription == null) {
2308 _scrollSubscription = scroller.onScroll.listen(_onScroll); 2571 _scrollSubscription = _scroller.onScroll.listen(_onScroll);
2309 } 2572 }
2310 if (_resizeSubscription == null) { 2573 if (_resizeSubscription == null) {
2311 _resizeSubscription = window.onResize.listen(_onScroll); 2574 _resizeSubscription = window.onResize.listen(_onScroll);
2312 } 2575 }
2313 } 2576 }
2314 } 2577 }
2315 2578
2316 void _unsubscribeToScroll() { 2579 void _unsubscribeToScroll() {
2317 if (_scrollSubscription != null) { 2580 if (_scrollSubscription != null) {
2318 _scrollSubscription.cancel(); 2581 _scrollSubscription.cancel();
2319 _scrollSubscription = null; 2582 _scrollSubscription = null;
2320 } 2583 }
2321 if (_resizeSubscription != null) { 2584 if (_resizeSubscription != null) {
2322 _resizeSubscription.cancel(); 2585 _resizeSubscription.cancel();
2323 _resizeSubscription = null; 2586 _resizeSubscription = null;
2324 } 2587 }
2325 } 2588 }
2326 2589
2327 @override 2590 @override
2328 void attached() { 2591 void attached() {
2329 super.attached(); 2592 super.attached();
2330 int windowHeight = window.innerHeight; 2593 _r.enable();
2331 scriptHeight = '${windowHeight ~/ 1.6}px'; 2594 if (_expanded) {
2332 if (expanded) {
2333 _subscribeToScroll(); 2595 _subscribeToScroll();
2334 } 2596 }
2335 } 2597 }
2336 2598
2337 void detached() { 2599 void detached() {
2600 _r.disable(notify: true);
2601 super.detached();
2338 _unsubscribeToScroll(); 2602 _unsubscribeToScroll();
2339 super.detached();
2340 } 2603 }
2341 2604
2342 void toggleExpand(var a, var b, var c) { 2605 Future _toggleExpand() async {
2343 if (busy) { 2606 await _frame.function.load();
2344 return; 2607 _pinned = !_pinned;
2608 if (_pinned) {
2609 _expand();
2610 } else {
2611 _unexpand();
2345 } 2612 }
2346 busy = true;
2347 frame.function.load().then((func) {
2348 _pinned = !_pinned;
2349 if (_pinned) {
2350 _expand();
2351 } else {
2352 _unexpand();
2353 }
2354 busy = false;
2355 });
2356 }
2357
2358 @observable
2359 get properLocals {
2360 var locals = new List();
2361 var homeMethod = frame.function.homeMethod;
2362 if (homeMethod.dartOwner is Class && homeMethod.isStatic) {
2363 locals.add(
2364 {'name' : '<class>',
2365 'value' : homeMethod.dartOwner});
2366 } else if (homeMethod.dartOwner is Library) {
2367 locals.add(
2368 {'name' : '<library>',
2369 'value' : homeMethod.dartOwner});
2370 }
2371 locals.addAll(frame.variables);
2372 return locals;
2373 } 2613 }
2374 } 2614 }
2375 2615
2376 @CustomTag('debugger-message') 2616 class DebuggerMessageElement extends HtmlElement implements Renderable {
2377 class DebuggerMessageElement extends ObservatoryElement { 2617 static const tag = const Tag<DebuggerMessageElement>('debugger-message');
2378 @published ServiceMessage message; 2618
2379 @observable ServiceObject preview; 2619 RenderingScheduler<DebuggerMessageElement> _r;
2620
2621 Stream<RenderedEvent<DebuggerMessageElement>> get onRendered => _r.onRendered;
2622
2623 S.Isolate _isolate;
2624 S.ServiceMessage _message;
2625 S.ServiceObject _preview;
2626 M.InstanceRepository _instances;
2627 M.ScriptRepository _scripts;
2628 M.EventRepository _events;
2380 2629
2381 // Is this the current message? 2630 // Is this the current message?
2382 bool _current = false; 2631 bool _current = false;
2383 2632
2384 // Has this message been pinned open? 2633 // Has this message been pinned open?
2385 bool _pinned = false; 2634 bool _pinned = false;
2386 2635
2636 bool _expanded = false;
2637
2638 factory DebuggerMessageElement(S.Isolate isolate,
2639 S.ServiceMessage message,
2640 M.InstanceRepository instances,
2641 M.ScriptRepository scripts,
2642 M.EventRepository events,
2643 {RenderingQueue queue}) {
2644 assert(isolate != null);
2645 assert(message != null);
2646 assert(instances != null);
2647 assert(instances != null);
2648 assert(events != null);
2649 final DebuggerMessageElement e = document.createElement(tag.name);
2650 e._r = new RenderingScheduler(e, queue: queue);
2651 e._isolate = isolate;
2652 e._message = message;
2653 e._instances = instances;
2654 e._scripts = scripts;
2655 e._events = events;
2656 return e;
2657 }
2658
2659 DebuggerMessageElement.created() : super.created();
2660
2661 void render() {
2662 if (_pinned) {
2663 classes.add('shadow');
2664 } else {
2665 classes.remove('shadow');
2666 }
2667 if (_current) {
2668 classes.add('current');
2669 } else {
2670 classes.remove('current');
2671 }
2672 ButtonElement expandButton;
2673 final content = <Element>[
2674 expandButton = new ButtonElement()
2675 ..children = _createHeader()
2676 ..onClick.listen((e) async {
2677 if (e.target is AnchorElement) {
2678 return;
2679 }
2680 expandButton.disabled = true;
2681 await _toggleExpand();
2682 expandButton.disabled = false;
2683 })
2684 ];
2685 if (_expanded) {
2686 ButtonElement collapseButton;
2687 ButtonElement previewButton;
2688 content.addAll([
2689 new DivElement()..classes = ['messageDetails']
2690 ..children = [
2691 new DivElement()..classes = ['flex-row-wrap']
2692 ..children = [
2693 new DivElement()..classes = ['flex-item-script']
2694 ..children = _message.handler == null ? const []
2695 : [
2696 new SourceInsetElement(_isolate,
2697 _message.handler.location,
2698 _scripts,
2699 _instances,
2700 _events,
2701 inDebuggerContext: true,
2702 queue: _r.queue)
2703 ],
2704 new DivElement()..classes = ['flex-item-vars']
2705 ..children = [
2706 new DivElement()..classes = ['memberItem']
2707 ..children = [
2708 new DivElement()..classes = ['memberName'],
2709 new DivElement()..classes = ['memberValue']
2710 ..children = ([
2711 previewButton = new ButtonElement()
2712 ..text = 'preview'
2713 ..onClick.listen((_) {
2714 previewButton.disabled = true;
2715
2716 })
2717 ]..addAll(
2718 _preview == null ? const []
2719 : [
2720 anyRef(_isolate, _preview, _instances,
2721 queue: _r.queue)
2722 ]
2723 ))
2724 ]
2725 ]
2726 ],
2727 new DivElement()..classes = ['messageContractor']
2728 ..children = [
2729 collapseButton = new ButtonElement()
2730 ..onClick.listen((e) async {
2731 collapseButton.disabled = true;
2732 await _toggleExpand();
2733 collapseButton.disabled = false;
2734 })
2735 ..children = [
2736 iconExpandLess.clone(true)
2737 ]
2738 ]
2739 ]
2740 ]);
2741 }
2742 children = content;
2743 }
2744
2745 void updateMessage(S.ServiceMessage message) {
2746 assert(_message != null);
2747 _message = message;
2748 _r.dirty();
2749 }
2750
2751 List<Element> _createHeader() {
2752 final content = [
2753 new DivElement()..classes = ['messageSummaryText']
2754 ..children = [
2755 new DivElement()..classes = ['messageId']
2756 ..text = 'message ${_message.index}',
2757 new SpanElement()
2758 ..children = _message.handler == null ? const []
2759 : [
2760 new FunctionRefElement(_isolate, _message.handler,
2761 queue: _r.queue)
2762 ],
2763 new SpanElement()..text = ' ( ',
2764 new SpanElement()
2765 ..children = _message.location == null ? const []
2766 : [
2767 new SourceLinkElement(_isolate, _message.location, _scripts,
2768 queue: _r.queue)
2769 ],
2770 new SpanElement()..text = ' )'
2771 ]
2772 ];
2773 if (!_expanded) {
2774 content.add(new DivElement()..classes = ['messageExpander']
2775 ..children = [
2776 iconExpandMore.clone(true)
2777 ]);
2778 }
2779 return [
2780 new DivElement()..classes = ['messageSummary']
2781 ..children = content
2782 ];
2783 }
2784
2387 void setCurrent(bool value) { 2785 void setCurrent(bool value) {
2388 _current = value; 2786 _current = value;
2389 var messageOuter = $['messageOuter'];
2390 if (_current) { 2787 if (_current) {
2391 messageOuter.classes.add('current'); 2788 _expanded = true;
2392 expanded = true;
2393 messageOuter.classes.add('shadow');
2394 scrollIntoView(); 2789 scrollIntoView();
2790 _r.dirty();
2395 } else { 2791 } else {
2396 messageOuter.classes.remove('current'); 2792 _expanded = _pinned;
2397 if (_pinned) {
2398 expanded = true;
2399 messageOuter.classes.add('shadow');
2400 } else {
2401 expanded = false;
2402 messageOuter.classes.remove('shadow');
2403 }
2404 }
2405 }
2406
2407 @observable String scriptHeight;
2408 @observable bool expanded = false;
2409 @observable bool busy = false;
2410
2411 DebuggerMessageElement.created() : super.created();
2412
2413 void updateMessage(ServiceMessage newMessage) {
2414 bool messageChanged =
2415 (message.messageObjectId != newMessage.messageObjectId);
2416 message = newMessage;
2417 if (messageChanged) {
2418 // Message object id has changed: clear preview and collapse.
2419 preview = null;
2420 if (expanded) {
2421 toggleExpand(null, null, null);
2422 }
2423 } 2793 }
2424 } 2794 }
2425 2795
2426 @override 2796 @override
2427 void attached() { 2797 void attached() {
2428 super.attached(); 2798 super.attached();
2429 int windowHeight = window.innerHeight; 2799 _r.enable();
2430 scriptHeight = '${windowHeight ~/ 1.6}px'; 2800 }
2431 } 2801
2432 2802 @override
2433 void toggleExpand(var a, var b, var c) { 2803 void detached() {
2434 if (busy) { 2804 super.detached();
2435 return; 2805 _r.disable(notify: true);
2436 } 2806 children = [];
2437 busy = true; 2807 }
2438 var function = message.handler; 2808
2439 var loadedFunction; 2809 Future _toggleExpand() async {
2440 if (function == null) { 2810 var function = _message.handler;
2441 // Complete immediately. 2811 if (function != null) {
2442 loadedFunction = new Future.value(null); 2812 await function.load();
2443 } else { 2813 }
2444 loadedFunction = function.load(); 2814 _pinned = _pinned;
2445 } 2815 _expanded = true;
2446 loadedFunction.then((_) { 2816 _r.dirty();
2447 _pinned = !_pinned; 2817 }
2448 var messageOuter = $['messageOuter']; 2818
2449 if (_pinned) { 2819 Future<S.ServiceObject> previewMessage(_) {
2450 expanded = true; 2820 return _message.isolate.getObject(_message.messageObjectId).then((result) {
2451 messageOuter.classes.add('shadow'); 2821 _preview = result;
2452 } else {
2453 expanded = false;
2454 messageOuter.classes.remove('shadow');
2455 }
2456 busy = false;
2457 });
2458 }
2459
2460 Future<ServiceObject> previewMessage(_) {
2461 return message.isolate.getObject(message.messageObjectId).then((result) {
2462 preview = result;
2463 return result; 2822 return result;
2464 }); 2823 });
2465 } 2824 }
2466 } 2825 }
2467 2826
2468 @CustomTag('debugger-console') 2827 class DebuggerConsoleElement extends HtmlElement implements Renderable {
2469 class DebuggerConsoleElement extends ObservatoryElement { 2828 static const tag = const Tag<DebuggerConsoleElement>('debugger-console');
2470 @published Isolate isolate; 2829
2830 factory DebuggerConsoleElement() {
2831 final DebuggerConsoleElement e = document.createElement(tag.name);
2832 e.children = [
2833 new BRElement()
2834 ];
2835 return e;
2836 }
2471 2837
2472 DebuggerConsoleElement.created() : super.created(); 2838 DebuggerConsoleElement.created() : super.created();
2473 2839
2474 /// Is [container] scrolled to the within [threshold] pixels of the bottom? 2840 /// Is [container] scrolled to the within [threshold] pixels of the bottom?
2475 static bool _isScrolledToBottom(DivElement container, [int threshold = 2]) { 2841 static bool _isScrolledToBottom(DivElement container, [int threshold = 2]) {
2476 if (container == null) { 2842 if (container == null) {
2477 return false; 2843 return false;
2478 } 2844 }
2479 // scrollHeight -> complete height of element including scrollable area. 2845 // scrollHeight -> complete height of element including scrollable area.
2480 // clientHeight -> height of element on page. 2846 // clientHeight -> height of element on page.
2481 // scrollTop -> how far is an element scrolled (from 0 to scrollHeight). 2847 // scrollTop -> how far is an element scrolled (from 0 to scrollHeight).
2482 final distanceFromBottom = 2848 final distanceFromBottom =
2483 container.scrollHeight - container.clientHeight - container.scrollTop; 2849 container.scrollHeight - container.clientHeight - container.scrollTop;
2484 const threshold = 2; // 2 pixel slop. 2850 const threshold = 2; // 2 pixel slop.
2485 return distanceFromBottom <= threshold; 2851 return distanceFromBottom <= threshold;
2486 } 2852 }
2487 2853
2488 /// Scroll [container] so the bottom content is visible. 2854 /// Scroll [container] so the bottom content is visible.
2489 static _scrollToBottom(DivElement container) { 2855 static _scrollToBottom(DivElement container) {
2490 if (container == null) { 2856 if (container == null) {
2491 return; 2857 return;
2492 } 2858 }
2493 // Adjust scroll so that the bottom of the content is visible. 2859 // Adjust scroll so that the bottom of the content is visible.
2494 container.scrollTop = container.scrollHeight - container.clientHeight; 2860 container.scrollTop = container.scrollHeight - container.clientHeight;
2495 } 2861 }
2496 2862
2497 void _append(HtmlElement span) { 2863 void _append(HtmlElement span) {
2498 var consoleTextElement = $['consoleText'];
2499 bool autoScroll = _isScrolledToBottom(parent); 2864 bool autoScroll = _isScrolledToBottom(parent);
2500 consoleTextElement.children.add(span); 2865 children.add(span);
2501 if (autoScroll) { 2866 if (autoScroll) {
2502 _scrollToBottom(parent); 2867 _scrollToBottom(parent);
2503 } 2868 }
2504 } 2869 }
2505 2870
2506 void print(String line, { bool newline:true }) { 2871 void print(String line, { bool newline:true }) {
2507 var span = new SpanElement(); 2872 var span = new SpanElement();
2508 span.classes.add('normal'); 2873 span.classes.add('normal');
2509 span.appendText(line); 2874 span.appendText(line);
2510 if (newline) { 2875 if (newline) {
(...skipping 16 matching lines...) Expand all
2527 var span = new SpanElement(); 2892 var span = new SpanElement();
2528 span.classes.add('red'); 2893 span.classes.add('red');
2529 span.appendText(line); 2894 span.appendText(line);
2530 if (newline) { 2895 if (newline) {
2531 span.appendText('\n'); 2896 span.appendText('\n');
2532 } 2897 }
2533 _append(span); 2898 _append(span);
2534 } 2899 }
2535 2900
2536 void printStdio(List<String> lines) { 2901 void printStdio(List<String> lines) {
2537 var consoleTextElement = $['consoleText'];
2538 bool autoScroll = _isScrolledToBottom(parent); 2902 bool autoScroll = _isScrolledToBottom(parent);
2539 for (var line in lines) { 2903 for (var line in lines) {
2540 var span = new SpanElement(); 2904 var span = new SpanElement();
2541 span.classes.add('green'); 2905 span.classes.add('green');
2542 span.appendText(line); 2906 span.appendText(line);
2543 span.appendText('\n'); 2907 span.appendText('\n');
2544 consoleTextElement.children.add(span); 2908 children.add(span);
2545 } 2909 }
2546 if (autoScroll) { 2910 if (autoScroll) {
2547 _scrollToBottom(parent); 2911 _scrollToBottom(parent);
2548 } 2912 }
2549 } 2913 }
2550 2914
2551 void printRef(Instance ref, { bool newline:true }) { 2915 void printRef(S.Isolate isolate, S.Instance ref,
2552 var refElement = new Element.tag('instance-ref'); 2916 M.InstanceRepository instances,{ bool newline:true }) {
2553 refElement.ref = ref; 2917 _append(new InstanceRefElement(isolate, ref, instances,
2554 _append(refElement); 2918 queue: app.queue));
2555 if (newline) { 2919 if (newline) {
2556 this.newline(); 2920 this.newline();
2557 } 2921 }
2558 } 2922 }
2559 2923
2560 void newline() { 2924 void newline() {
2561 _append(new BRElement()); 2925 _append(new BRElement());
2562 } 2926 }
2563 2927
2564 void clear() { 2928 void clear() {
2565 var consoleTextElement = $['consoleText']; 2929 children.clear();
2566 consoleTextElement.children.clear();
2567 } 2930 }
2931
2932 ObservatoryApplication get app => ObservatoryApplication.app;
2568 } 2933 }
2569 2934
2570 @CustomTag('debugger-input') 2935 class DebuggerInputElement extends HtmlElement implements Renderable {
2571 class DebuggerInputElement extends ObservatoryElement { 2936 static const tag = const Tag<DebuggerInputElement>('debugger-input');
2572 @published Isolate isolate; 2937
2573 @published String text = ''; 2938 S.Isolate _isolate;
2574 @observable ObservatoryDebugger debugger; 2939 ObservatoryDebugger _debugger;
2575 @observable bool busy = false; 2940 bool _busy = false;
2576 @observable String modalPrompt = null; 2941 final _modalPromptDiv = new DivElement()
2942 ..classes = ['modalPrompt', 'hidden'];
2943 final _textBox = new TextInputElement()
2944 ..classes = ['textBox']
2945 ..autofocus = true;
2946 String get modalPrompt => _modalPromptDiv.text;
2947 set modalPrompt(String value) {
2948 if (_modalPromptDiv.text == '') {
2949 _modalPromptDiv.classes.remove('hidden');
2950 }
2951 _modalPromptDiv.text = value;
2952 if (_modalPromptDiv.text == '') {
2953 _modalPromptDiv.classes.add('hidden');
2954 }
2955 }
2956 String get text => _textBox.value;
2957 set text(String value) => _textBox.value = value;
2577 var modalCallback = null; 2958 var modalCallback = null;
2578 2959
2960 factory DebuggerInputElement(S.Isolate isolate,
2961 ObservatoryDebugger debugger) {
2962 final DebuggerInputElement e = document.createElement(tag.name);
2963 e.children = [
2964 e._modalPromptDiv,
2965 e._textBox
2966 ];
2967 e._textBox.select();
2968 e._textBox.onKeyDown.listen(e._onKeyDown);
2969 return e;
2970 }
2971
2972 DebuggerInputElement.created() : super.created();
2973
2974 void _onKeyDown(KeyboardEvent e) {
2975 if (_busy) {
2976 e.preventDefault();
2977 return;
2978 }
2979 _busy = true;
2980 if (modalCallback != null) {
2981 if (e.keyCode == KeyCode.ENTER) {
2982 var response = text;
2983 modalCallback(response).whenComplete(() {
2984 text = '';
2985 _busy = false;
2986 });
2987 } else {
2988 _busy = false;
2989 }
2990 return;
2991 }
2992 switch (e.keyCode) {
2993 case KeyCode.TAB:
2994 e.preventDefault();
2995 int cursorPos = _textBox.selectionStart;
2996 _debugger.complete(text.substring(0, cursorPos)).then((completion) {
2997 text = completion + text.substring(cursorPos);
2998 // TODO(turnidge): Move the cursor to the end of the
2999 // completion, rather than the end of the string.
3000 }).whenComplete(() {
3001 _busy = false;
3002 });
3003 break;
3004
3005 case KeyCode.ENTER:
3006 var command = text;
3007 _debugger.run(command).whenComplete(() {
3008 text = '';
3009 _busy = false;
3010 });
3011 break;
3012
3013 case KeyCode.UP:
3014 e.preventDefault();
3015 text = _debugger.historyPrev(text);
3016 _busy = false;
3017 break;
3018
3019 case KeyCode.DOWN:
3020 e.preventDefault();
3021 text = _debugger.historyNext(text);
3022 _busy = false;
3023 break;
3024
3025 case KeyCode.PAGE_UP:
3026 e.preventDefault();
3027 try {
3028 _debugger.upFrame(1);
3029 } on RangeError catch (_) {
3030 // Ignore.
3031 }
3032 _busy = false;
3033 break;
3034
3035 case KeyCode.PAGE_DOWN:
3036 e.preventDefault();
3037 try {
3038 _debugger.downFrame(1);
3039 } on RangeError catch (_) {
3040 // Ignore.
3041 }
3042 _busy = false;
3043 break;
3044
3045 case KeyCode.F7:
3046 e.preventDefault();
3047 _debugger.resume().whenComplete(() {
3048 _busy = false;
3049 });
3050 break;
3051
3052 case KeyCode.F8:
3053 e.preventDefault();
3054 _debugger.toggleBreakpoint().whenComplete(() {
3055 _busy = false;
3056 });
3057 break;
3058
3059 case KeyCode.F9:
3060 e.preventDefault();
3061 _debugger.smartNext().whenComplete(() {
3062 _busy = false;
3063 });
3064 break;
3065
3066 case KeyCode.F10:
3067 e.preventDefault();
3068 _debugger.step().whenComplete(() {
3069 _busy = false;
3070 });
3071 break;
3072
3073 case KeyCode.SEMICOLON:
3074 if (e.ctrlKey) {
3075 e.preventDefault();
3076 _debugger.console.printRed('^;');
3077 _debugger.pause().whenComplete(() {
3078 _busy = false;
3079 });
3080 } else {
3081 _busy = false;
3082 }
3083 break;
3084
3085 default:
3086 _busy = false;
3087 break;
3088 }
3089 }
3090
2579 void enterMode(String prompt, callback) { 3091 void enterMode(String prompt, callback) {
2580 assert(modalPrompt == null); 3092 assert(modalPrompt == null);
2581 modalPrompt = prompt; 3093 modalPrompt = prompt;
2582 modalCallback = callback; 3094 modalCallback = callback;
2583 } 3095 }
2584 3096
2585 void exitMode() { 3097 void exitMode() {
2586 assert(modalPrompt != null); 3098 assert(modalPrompt != null);
2587 modalPrompt = null; 3099 modalPrompt = null;
2588 modalCallback = null; 3100 modalCallback = null;
2589 } 3101 }
2590 3102
2591 @override 3103 void focus() {
2592 void ready() { 3104 _textBox.focus();
2593 super.ready(); 3105 }
2594 var textBox = $['textBox']; 3106 }
2595 textBox.select();
2596 textBox.onKeyDown.listen((KeyboardEvent e) {
2597 if (busy) {
2598 e.preventDefault();
2599 return;
2600 }
2601 busy = true;
2602 if (modalCallback != null) {
2603 if (e.keyCode == KeyCode.ENTER) {
2604 var response = text;
2605 modalCallback(response).whenComplete(() {
2606 text = '';
2607 busy = false;
2608 });
2609 } else {
2610 busy = false;
2611 }
2612 return;
2613 }
2614 switch (e.keyCode) {
2615 case KeyCode.TAB:
2616 e.preventDefault();
2617 int cursorPos = textBox.selectionStart;
2618 debugger.complete(text.substring(0, cursorPos)).then((completion) {
2619 text = completion + text.substring(cursorPos);
2620 // TODO(turnidge): Move the cursor to the end of the
2621 // completion, rather than the end of the string.
2622 }).whenComplete(() {
2623 busy = false;
2624 });
2625 break;
2626 3107
2627 case KeyCode.ENTER: 3108 final SvgSvgElement iconExpandLess = new SvgSvgElement()
2628 var command = text; 3109 ..setAttribute('width', '24')
2629 debugger.run(command).whenComplete(() { 3110 ..setAttribute('height', '24')
2630 text = ''; 3111 ..children = [
2631 busy = false; 3112 new PolygonElement()
2632 }); 3113 ..setAttribute('points', '12,8 6,14 7.4,15.4 12,10.8 16.6,15.4 18,14 ')
2633 break; 3114 ];
2634 3115
2635 case KeyCode.UP: 3116 final SvgSvgElement iconExpandMore = new SvgSvgElement()
2636 e.preventDefault(); 3117 ..setAttribute('width', '24')
2637 text = debugger.historyPrev(text); 3118 ..setAttribute('height', '24')
2638 busy = false; 3119 ..children = [
2639 break; 3120 new PolygonElement()
3121 ..setAttribute('points', '16.6,8.6 12,13.2 7.4,8.6 6,10 12,16 18,10 ')
3122 ];
2640 3123
2641 case KeyCode.DOWN: 3124 final SvgSvgElement iconChevronRight = new SvgSvgElement()
2642 e.preventDefault(); 3125 ..setAttribute('width', '24')
2643 text = debugger.historyNext(text); 3126 ..setAttribute('height', '24')
2644 busy = false; 3127 ..children = [
2645 break; 3128 new PathElement()
3129 ..setAttribute('d', 'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z')
3130 ];
2646 3131
2647 case KeyCode.PAGE_UP: 3132 final SvgSvgElement iconChevronLeft = new SvgSvgElement()
2648 e.preventDefault(); 3133 ..setAttribute('width', '24')
2649 try { 3134 ..setAttribute('height', '24')
2650 debugger.upFrame(1); 3135 ..children = [
2651 } on RangeError catch (_) { 3136 new PathElement()
2652 // Ignore. 3137 ..setAttribute('d', 'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z')
2653 } 3138 ];
2654 busy = false;
2655 break;
2656 3139
2657 case KeyCode.PAGE_DOWN: 3140 final SvgSvgElement iconHorizontalThreeDot = new SvgSvgElement()
2658 e.preventDefault(); 3141 ..setAttribute('width', '24')
2659 try { 3142 ..setAttribute('height', '24')
2660 debugger.downFrame(1); 3143 ..children = [
2661 } on RangeError catch (_) { 3144 new PathElement()
2662 // Ignore. 3145 ..setAttribute('d', 'M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
2663 } 3146 '2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
2664 busy = false; 3147 '2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
2665 break; 3148 '2-2-.9-2-2-2z')
3149 ];
2666 3150
2667 case KeyCode.F7: 3151 final SvgSvgElement iconVerticalThreeDot = new SvgSvgElement()
2668 e.preventDefault(); 3152 ..setAttribute('width', '24')
2669 debugger.resume().whenComplete(() { 3153 ..setAttribute('height', '24')
2670 busy = false; 3154 ..children = [
2671 }); 3155 new PathElement()
2672 break; 3156 ..setAttribute('d', 'M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 '
3157 '2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
3158 '2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 '
3159 '2-.9 2-2-.9-2-2-2z')
3160 ];
2673 3161
2674 case KeyCode.F8: 3162 final SvgSvgElement iconInfo = new SvgSvgElement()
2675 e.preventDefault(); 3163 ..setAttribute('width', '24')
2676 debugger.toggleBreakpoint().whenComplete(() { 3164 ..setAttribute('height', '24')
2677 busy = false; 3165 ..children = [
2678 }); 3166 new PathElement()
2679 break; 3167 ..setAttribute('d', 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 '
3168 '10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z')
3169 ];
2680 3170
2681 case KeyCode.F9: 3171 final SvgSvgElement iconInfoOutline = new SvgSvgElement()
2682 e.preventDefault(); 3172 ..setAttribute('width', '24')
2683 debugger.smartNext().whenComplete(() { 3173 ..setAttribute('height', '24')
2684 busy = false; 3174 ..children = [
2685 }); 3175 new PathElement()
2686 break; 3176 ..setAttribute('d', 'M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 '
2687 3177 '10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 '
2688 case KeyCode.F10: 3178 '0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 '
2689 e.preventDefault(); 3179 '9h2V7h-2v2z')
2690 debugger.step().whenComplete(() { 3180 ];
2691 busy = false;
2692 });
2693 break;
2694
2695 case KeyCode.SEMICOLON:
2696 if (e.ctrlKey) {
2697 e.preventDefault();
2698 debugger.console.printRed('^;');
2699 debugger.pause().whenComplete(() {
2700 busy = false;
2701 });
2702 } else {
2703 busy = false;
2704 }
2705 break;
2706
2707 default:
2708 busy = false;
2709 break;
2710 }
2711 });
2712 }
2713
2714 void focus() {
2715 $['textBox'].focus();
2716 }
2717
2718 DebuggerInputElement.created() : super.created();
2719 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/css/shared.css ('k') | runtime/observatory/lib/src/elements/debugger.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698