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

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

Issue 1232193003: Provide stdout and stderr output in the Observatory debugger. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: before commit Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library debugger_page_element; 5 library debugger_page_element;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:html'; 8 import 'dart:html';
9 import 'observatory_element.dart'; 9 import 'observatory_element.dart';
10 import 'package:observatory/cli.dart'; 10 import 'package:observatory/cli.dart';
(...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after
847 } 847 }
848 848
849 String helpShort = 'Refresh debugging information of various sorts'; 849 String helpShort = 'Refresh debugging information of various sorts';
850 850
851 String helpLong = 851 String helpLong =
852 'Refresh debugging information of various sorts.\n' 852 'Refresh debugging information of various sorts.\n'
853 '\n' 853 '\n'
854 'Syntax: refresh <subcommand>\n'; 854 'Syntax: refresh <subcommand>\n';
855 } 855 }
856 856
857 class _VMStreamPrinter {
858 ObservatoryDebugger _debugger;
859
860 _VMStreamPrinter(this._debugger);
861
862 String _savedStream;
863 String _savedIsolate;
864 String _savedLine;
865 List<String> _buffer = [];
866
867 void onEvent(String streamName, ServiceEvent event) {
868 String isolateName = event.isolate.name;
869 // If we get a line from a different isolate/stream, flush
870 // any pending output, even if it is not newline-terminated.
871 if ((_savedIsolate != null && isolateName != _savedIsolate) ||
872 (_savedStream != null && streamName != _savedStream)) {
873 flush();
874 }
875 String data = event.bytesAsString;
876 bool hasNewline = data.endsWith('\n');
877 if (_savedLine != null) {
878 data = _savedLine + data;
879 _savedIsolate = null;
880 _savedStream = null;
881 _savedLine = null;
882 }
883 var lines = data.split('\n').where((line) => line != '').toList();
884 if (lines.isEmpty) {
885 return;
886 }
887 int limit = (hasNewline ? lines.length : lines.length - 1);
888 for (int i = 0; i < limit; i++) {
889 _buffer.add(_format(isolateName, streamName, lines[i]));
890 }
891 // If there is no newline, we save the last line of output for next time.
892 if (!hasNewline) {
893 _savedIsolate = isolateName;
894 _savedStream = streamName;
895 _savedLine = lines[lines.length - 1];
896 }
897 }
898
899 void flush() {
900 // If there is any saved output, flush it now.
901 if (_savedLine != null) {
902 _buffer.add(_format(_savedIsolate, _savedStream, _savedLine));
903 _savedIsolate = null;
904 _savedStream = null;
905 _savedLine = null;
906 }
907 if (_buffer.isNotEmpty) {
908 _debugger.console.printStdio(_buffer);
909 _buffer.clear();
910 }
911 }
912
913 String _format(String isolateName, String streamName, String line) {
914 return '${isolateName}:${streamName}> ${line}';
915 }
916 }
917
857 // Tracks the state for an isolate debugging session. 918 // Tracks the state for an isolate debugging session.
858 class ObservatoryDebugger extends Debugger { 919 class ObservatoryDebugger extends Debugger {
859 RootCommand cmd; 920 RootCommand cmd;
860 DebuggerPageElement page; 921 DebuggerPageElement page;
861 DebuggerConsoleElement console; 922 DebuggerConsoleElement console;
862 DebuggerInputElement input; 923 DebuggerInputElement input;
863 DebuggerStackElement stackElement; 924 DebuggerStackElement stackElement;
864 ServiceMap stack; 925 ServiceMap stack;
865 String exceptions = "none"; // Last known setting. 926 String exceptions = "none"; // Last known setting.
866 927
(...skipping 24 matching lines...) Expand all
891 new StepCommand(this), 952 new StepCommand(this),
892 new FinishCommand(this), 953 new FinishCommand(this),
893 new BreakCommand(this), 954 new BreakCommand(this),
894 new SetCommand(this), 955 new SetCommand(this),
895 new ClearCommand(this), 956 new ClearCommand(this),
896 new DeleteCommand(this), 957 new DeleteCommand(this),
897 new InfoCommand(this), 958 new InfoCommand(this),
898 new IsolateCommand(this), 959 new IsolateCommand(this),
899 new RefreshCommand(this), 960 new RefreshCommand(this),
900 ]); 961 ]);
962 _stdioPrinter = new _VMStreamPrinter(this);
901 } 963 }
902 964
903 VM get vm => page.app.vm; 965 VM get vm => page.app.vm;
904 966
905 void updateIsolate(Isolate iso) { 967 void updateIsolate(Isolate iso) {
906 _isolate = iso; 968 _isolate = iso;
907 if (_isolate != null) { 969 if (_isolate != null) {
908 if (exceptions != iso.exceptionsPauseInfo) { 970 if (exceptions != iso.exceptionsPauseInfo) {
909 exceptions = iso.exceptionsPauseInfo; 971 exceptions = iso.exceptionsPauseInfo;
910 console.print("Now pausing for $exceptions exceptions"); 972 console.print("Now pausing for $exceptions exceptions");
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
990 if (stack['frames'].length > 0) { 1052 if (stack['frames'].length > 0) {
991 currentFrame = 0; 1053 currentFrame = 0;
992 } else { 1054 } else {
993 currentFrame = null; 1055 currentFrame = null;
994 } 1056 }
995 input.focus(); 1057 input.focus();
996 }); 1058 });
997 } 1059 }
998 1060
999 void reportStatus() { 1061 void reportStatus() {
1062 flushStdio();
1000 if (_isolate == null) { 1063 if (_isolate == null) {
1001 console.print('No current isolate'); 1064 console.print('No current isolate');
1002 } else if (_isolate.idle) { 1065 } else if (_isolate.idle) {
1003 console.print('Isolate is idle'); 1066 console.print('Isolate is idle');
1004 } else if (_isolate.running) { 1067 } else if (_isolate.running) {
1005 console.print("Isolate is running (type 'pause' to interrupt)"); 1068 console.print("Isolate is running (type 'pause' to interrupt)");
1006 } else if (_isolate.pauseEvent != null) { 1069 } else if (_isolate.pauseEvent != null) {
1007 _reportPause(_isolate.pauseEvent); 1070 _reportPause(_isolate.pauseEvent);
1008 } else { 1071 } else {
1009 console.print('Isolate is in unknown state'); 1072 console.print('Isolate is in unknown state');
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1109 console.print("Isolate ${iso.number} renamed to '${iso.name}'"); 1172 console.print("Isolate ${iso.number} renamed to '${iso.name}'");
1110 break; 1173 break;
1111 1174
1112 case ServiceEvent.kPauseStart: 1175 case ServiceEvent.kPauseStart:
1113 case ServiceEvent.kPauseExit: 1176 case ServiceEvent.kPauseExit:
1114 case ServiceEvent.kPauseBreakpoint: 1177 case ServiceEvent.kPauseBreakpoint:
1115 case ServiceEvent.kPauseInterrupted: 1178 case ServiceEvent.kPauseInterrupted:
1116 case ServiceEvent.kPauseException: 1179 case ServiceEvent.kPauseException:
1117 if (event.owner == isolate) { 1180 if (event.owner == isolate) {
1118 _refreshStack(event).then((_) { 1181 _refreshStack(event).then((_) {
1182 flushStdio();
1119 _reportPause(event); 1183 _reportPause(event);
1120 }); 1184 });
1121 } 1185 }
1122 break; 1186 break;
1123 1187
1124 case ServiceEvent.kResume: 1188 case ServiceEvent.kResume:
1125 if (event.owner == isolate) { 1189 if (event.owner == isolate) {
1190 flushStdio();
1126 console.print('Continuing...'); 1191 console.print('Continuing...');
1127 } 1192 }
1128 break; 1193 break;
1129 1194
1130 case ServiceEvent.kBreakpointAdded: 1195 case ServiceEvent.kBreakpointAdded:
1131 case ServiceEvent.kBreakpointResolved: 1196 case ServiceEvent.kBreakpointResolved:
1132 case ServiceEvent.kBreakpointRemoved: 1197 case ServiceEvent.kBreakpointRemoved:
1133 if (event.owner == isolate) { 1198 if (event.owner == isolate) {
1134 _reportBreakpointEvent(event); 1199 _reportBreakpointEvent(event);
1135 } 1200 }
1136 break; 1201 break;
1137 1202
1138 case ServiceEvent.kIsolateStart: 1203 case ServiceEvent.kIsolateStart:
1139 case ServiceEvent.kGraph: 1204 case ServiceEvent.kGraph:
1140 case ServiceEvent.kGC: 1205 case ServiceEvent.kGC:
1141 case ServiceEvent.kInspect: 1206 case ServiceEvent.kInspect:
1142 break; 1207 break;
1143 1208
1144 default: 1209 default:
1145 console.print('Unrecognized event: $event'); 1210 console.print('Unrecognized event: $event');
1146 break; 1211 break;
1147 } 1212 }
1148 } 1213 }
1149 1214
1215 _VMStreamPrinter _stdioPrinter;
1216
1217 void flushStdio() {
1218 _stdioPrinter.flush();
1219 }
1220
1221 void onStdout(ServiceEvent event) {
1222 _stdioPrinter.onEvent('stdout', event);
1223 }
1224
1225 void onStderr(ServiceEvent event) {
1226 _stdioPrinter.onEvent('stderr', event);
1227 }
1228
1150 static String _commonPrefix(String a, String b) { 1229 static String _commonPrefix(String a, String b) {
1151 int pos = 0; 1230 int pos = 0;
1152 while (pos < a.length && pos < b.length) { 1231 while (pos < a.length && pos < b.length) {
1153 if (a.codeUnitAt(pos) != b.codeUnitAt(pos)) { 1232 if (a.codeUnitAt(pos) != b.codeUnitAt(pos)) {
1154 break; 1233 break;
1155 } 1234 }
1156 pos++; 1235 pos++;
1157 } 1236 }
1158 return a.substring(0, pos); 1237 return a.substring(0, pos);
1159 } 1238 }
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1229 } 1308 }
1230 } 1309 }
1231 ObservatoryDebugger debugger = new ObservatoryDebugger(); 1310 ObservatoryDebugger debugger = new ObservatoryDebugger();
1232 1311
1233 DebuggerPageElement.created() : super.created() { 1312 DebuggerPageElement.created() : super.created() {
1234 debugger.page = this; 1313 debugger.page = this;
1235 } 1314 }
1236 1315
1237 Future<StreamSubscription> _isolateSubscriptionFuture; 1316 Future<StreamSubscription> _isolateSubscriptionFuture;
1238 Future<StreamSubscription> _debugSubscriptionFuture; 1317 Future<StreamSubscription> _debugSubscriptionFuture;
1318 Future<StreamSubscription> _stdoutSubscriptionFuture;
1319 Future<StreamSubscription> _stderrSubscriptionFuture;
1239 1320
1240 @override 1321 @override
1241 void attached() { 1322 void attached() {
1242 super.attached(); 1323 super.attached();
1243 1324
1244 var navbarDiv = $['navbarDiv']; 1325 var navbarDiv = $['navbarDiv'];
1245 var stackDiv = $['stackDiv']; 1326 var stackDiv = $['stackDiv'];
1246 var splitterDiv = $['splitterDiv']; 1327 var splitterDiv = $['splitterDiv'];
1247 var cmdDiv = $['commandDiv']; 1328 var cmdDiv = $['commandDiv'];
1248 1329
(...skipping 13 matching lines...) Expand all
1262 stackElement.debugger = debugger; 1343 stackElement.debugger = debugger;
1263 debugger.console = $['console']; 1344 debugger.console = $['console'];
1264 debugger.input = $['commandline']; 1345 debugger.input = $['commandline'];
1265 debugger.input.debugger = debugger; 1346 debugger.input.debugger = debugger;
1266 debugger.init(); 1347 debugger.init();
1267 1348
1268 _isolateSubscriptionFuture = 1349 _isolateSubscriptionFuture =
1269 app.vm.listenEventStream(VM.kIsolateStream, debugger.onEvent); 1350 app.vm.listenEventStream(VM.kIsolateStream, debugger.onEvent);
1270 _debugSubscriptionFuture = 1351 _debugSubscriptionFuture =
1271 app.vm.listenEventStream(VM.kDebugStream, debugger.onEvent); 1352 app.vm.listenEventStream(VM.kDebugStream, debugger.onEvent);
1353 _stdoutSubscriptionFuture =
1354 app.vm.listenEventStream(VM.kStdoutStream, debugger.onStdout);
1355 _stderrSubscriptionFuture =
1356 app.vm.listenEventStream(VM.kStderrStream, debugger.onStderr);
1357
1358 // Turn on the periodic poll timer for this page.
1359 pollPeriod = const Duration(milliseconds:100);
1272 1360
1273 onClick.listen((event) { 1361 onClick.listen((event) {
1274 // Random clicks should focus on the text box. If the user selects 1362 // Random clicks should focus on the text box. If the user selects
1275 // a range, don't interfere. 1363 // a range, don't interfere.
1276 var selection = window.getSelection(); 1364 var selection = window.getSelection();
1277 if (selection == null || selection.type == 'Caret') { 1365 if (selection == null || selection.type == 'Caret') {
1278 debugger.input.focus(); 1366 debugger.input.focus();
1279 } 1367 }
1280 }); 1368 });
1281 } 1369 }
1282 1370
1371 void onPoll() {
1372 debugger.flushStdio();
1373 }
1374
1283 @override 1375 @override
1284 void detached() { 1376 void detached() {
1285 cancelFutureSubscription(_isolateSubscriptionFuture); 1377 cancelFutureSubscription(_isolateSubscriptionFuture);
1286 _isolateSubscriptionFuture = null; 1378 _isolateSubscriptionFuture = null;
1287 cancelFutureSubscription(_debugSubscriptionFuture); 1379 cancelFutureSubscription(_debugSubscriptionFuture);
1288 _debugSubscriptionFuture = null; 1380 _debugSubscriptionFuture = null;
1381 cancelFutureSubscription(_stdoutSubscriptionFuture);
1382 _stdoutSubscriptionFuture = null;
1383 cancelFutureSubscription(_stderrSubscriptionFuture);
1384 _stderrSubscriptionFuture = null;
1289 super.detached(); 1385 super.detached();
1290 } 1386 }
1291 } 1387 }
1292 1388
1293 @CustomTag('debugger-stack') 1389 @CustomTag('debugger-stack')
1294 class DebuggerStackElement extends ObservatoryElement { 1390 class DebuggerStackElement extends ObservatoryElement {
1295 @published Isolate isolate; 1391 @published Isolate isolate;
1296 @observable bool hasStack = false; 1392 @observable bool hasStack = false;
1297 @observable bool hasMessages = false; 1393 @observable bool hasMessages = false;
1298 @observable bool isSampled = false; 1394 @observable bool isSampled = false;
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after
1658 var span = new SpanElement(); 1754 var span = new SpanElement();
1659 span.classes.add('red'); 1755 span.classes.add('red');
1660 span.appendText(line); 1756 span.appendText(line);
1661 if (newline) { 1757 if (newline) {
1662 span.appendText('\n'); 1758 span.appendText('\n');
1663 } 1759 }
1664 $['consoleText'].children.add(span); 1760 $['consoleText'].children.add(span);
1665 span.scrollIntoView(); 1761 span.scrollIntoView();
1666 } 1762 }
1667 1763
1764 void printStdio(List<String> lines) {
1765 var lastSpan;
1766 for (var line in lines) {
1767 var span = new SpanElement();
1768 span.classes.add('green');
1769 span.appendText(line);
1770 span.appendText('\n');
1771 $['consoleText'].children.add(span);
1772 lastSpan = span;
1773 }
1774 if (lastSpan != null) {
1775 lastSpan.scrollIntoView();
1776 }
1777 }
1778
1668 void printRef(Instance ref, { bool newline:true }) { 1779 void printRef(Instance ref, { bool newline:true }) {
1669 var refElement = new Element.tag('instance-ref'); 1780 var refElement = new Element.tag('instance-ref');
1670 refElement.ref = ref; 1781 refElement.ref = ref;
1671 $['consoleText'].children.add(refElement); 1782 $['consoleText'].children.add(refElement);
1672 if (newline) { 1783 if (newline) {
1673 this.newline(); 1784 this.newline();
1674 } 1785 }
1675 refElement.scrollIntoView(); 1786 refElement.scrollIntoView();
1676 } 1787 }
1677 1788
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1740 }); 1851 });
1741 } 1852 }
1742 1853
1743 void focus() { 1854 void focus() {
1744 $['textBox'].focus(); 1855 $['textBox'].focus();
1745 } 1856 }
1746 1857
1747 DebuggerInputElement.created() : super.created(); 1858 DebuggerInputElement.created() : super.created();
1748 } 1859 }
1749 1860
OLDNEW
« no previous file with comments | « runtime/observatory/lib/service.dart ('k') | runtime/observatory/lib/src/elements/debugger.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698