| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } | |
| OLD | NEW |