| Index: runtime/observatory/lib/src/elements/debugger.dart
|
| diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
|
| index 9bd4eff7468217b95756ca696146adbd41629e3b..3f7d8191ce4db3a68263f64f4f52b258ba6ad1c2 100644
|
| --- a/runtime/observatory/lib/src/elements/debugger.dart
|
| +++ b/runtime/observatory/lib/src/elements/debugger.dart
|
| @@ -5,17 +5,30 @@
|
| library debugger_page_element;
|
|
|
| import 'dart:async';
|
| +import 'dart:svg';
|
| import 'dart:html';
|
| import 'dart:math';
|
| -import 'observatory_element.dart';
|
| import 'package:observatory/event.dart';
|
| import 'package:observatory/models.dart' as M;
|
| import 'package:observatory/app.dart';
|
| import 'package:observatory/cli.dart';
|
| import 'package:observatory/debugger.dart';
|
| -import 'package:observatory/service.dart';
|
| +import 'package:observatory/src/elements/function_ref.dart';
|
| +import 'package:observatory/src/elements/helpers/any_ref.dart';
|
| +import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
|
| +import 'package:observatory/src/elements/helpers/tag.dart';
|
| +import 'package:observatory/src/elements/helpers/uris.dart';
|
| +import 'package:observatory/src/elements/instance_ref.dart';
|
| +import 'package:observatory/src/elements/nav/bar.dart';
|
| +import 'package:observatory/src/elements/nav/isolate_menu.dart';
|
| +import 'package:observatory/src/elements/nav/menu.dart';
|
| +import 'package:observatory/src/elements/nav/notify.dart';
|
| +import 'package:observatory/src/elements/nav/top_menu.dart';
|
| +import 'package:observatory/src/elements/nav/vm_menu.dart';
|
| +import 'package:observatory/src/elements/source_inset.dart';
|
| +import 'package:observatory/src/elements/source_link.dart';
|
| +import 'package:observatory/service.dart' as S;
|
| import 'package:logging/logging.dart';
|
| -import 'package:polymer/polymer.dart';
|
|
|
| // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library.
|
| abstract class DebuggerCommand extends Command {
|
| @@ -161,11 +174,11 @@ class PrintCommand extends DebuggerCommand {
|
| var expression = args.join('');
|
| var response = await debugger.isolate.evalFrame(debugger.currentFrame,
|
| expression);
|
| - if (response is DartError) {
|
| + if (response is S.DartError) {
|
| debugger.console.print(response.message);
|
| } else {
|
| debugger.console.print('= ', newline:false);
|
| - debugger.console.printRef(response);
|
| + debugger.console.printRef(debugger.isolate, response, debugger.instances);
|
| }
|
| }
|
|
|
| @@ -648,8 +661,8 @@ class BreakCommand extends DebuggerCommand {
|
| if (loc.function != null) {
|
| try {
|
| await debugger.isolate.addBreakpointAtEntry(loc.function);
|
| - } on ServerRpcException catch(e) {
|
| - if (e.code == ServerRpcException.kCannotAddBreakpoint) {
|
| + } on S.ServerRpcException catch(e) {
|
| + if (e.code == S.ServerRpcException.kCannotAddBreakpoint) {
|
| debugger.console.print('Unable to set breakpoint at ${loc}');
|
| } else {
|
| rethrow;
|
| @@ -666,8 +679,8 @@ class BreakCommand extends DebuggerCommand {
|
| }
|
| try {
|
| await debugger.isolate.addBreakpoint(script, loc.line, loc.col);
|
| - } on ServerRpcException catch(e) {
|
| - if (e.code == ServerRpcException.kCannotAddBreakpoint) {
|
| + } on S.ServerRpcException catch(e) {
|
| + if (e.code == S.ServerRpcException.kCannotAddBreakpoint) {
|
| debugger.console.print('Unable to set breakpoint at ${loc}');
|
| } else {
|
| rethrow;
|
| @@ -756,7 +769,7 @@ class ClearCommand extends DebuggerCommand {
|
| loc.col == script.tokenToCol(bpt.location.tokenPos)) {
|
| foundBreakpoint = true;
|
| var result = await debugger.isolate.removeBreakpoint(bpt);
|
| - if (result is DartError) {
|
| + if (result is S.DartError) {
|
| debugger.console.print(
|
| 'Error clearing breakpoint ${bpt.number}: ${result.message}');
|
| }
|
| @@ -938,9 +951,7 @@ class IsolateCommand extends DebuggerCommand {
|
| debugger.console.print(
|
| "Current isolate is already ${candidate.number} '${candidate.name}'");
|
| } else {
|
| - debugger.console.print(
|
| - "Switching to isolate ${candidate.number} '${candidate.name}'");
|
| - debugger.isolate = candidate;
|
| + new AnchorElement(href: Uris.debugger(candidate)).click();
|
| }
|
| }
|
| return new Future.value(null);
|
| @@ -973,7 +984,7 @@ class IsolateCommand extends DebuggerCommand {
|
| ' isolate <name>\n';
|
| }
|
|
|
| -String _isolateRunState(Isolate isolate) {
|
| +String _isolateRunState(S.Isolate isolate) {
|
| if (isolate.paused) {
|
| return 'paused';
|
| } else if (isolate.running) {
|
| @@ -1248,8 +1259,8 @@ class _ConsoleStreamPrinter {
|
| String _savedLine;
|
| List<String> _buffer = [];
|
|
|
| - void onEvent(String streamName, ServiceEvent event) {
|
| - if (event.kind == ServiceEvent.kLogging) {
|
| + void onEvent(String streamName, S.ServiceEvent event) {
|
| + if (event.kind == S.ServiceEvent.kLogging) {
|
| // Check if we should print this log message.
|
| if (event.logRecord['level'].value < _minimumLogLevel.value) {
|
| return;
|
| @@ -1264,7 +1275,7 @@ class _ConsoleStreamPrinter {
|
| }
|
| String data;
|
| bool hasNewline;
|
| - if (event.kind == ServiceEvent.kLogging) {
|
| + if (event.kind == S.ServiceEvent.kLogging) {
|
| data = event.logRecord["message"].valueAsString;
|
| hasNewline = true;
|
| } else {
|
| @@ -1320,7 +1331,8 @@ class ObservatoryDebugger extends Debugger {
|
| DebuggerConsoleElement console;
|
| DebuggerInputElement input;
|
| DebuggerStackElement stackElement;
|
| - ServiceMap stack;
|
| + S.ServiceMap stack;
|
| + final S.Isolate isolate;
|
| String breakOnException = "none"; // Last known setting.
|
|
|
| int get currentFrame => _currentFrame;
|
| @@ -1361,7 +1373,9 @@ class ObservatoryDebugger extends Debugger {
|
|
|
| int get stackDepth => stack['frames'].length;
|
|
|
| - ObservatoryDebugger() {
|
| + static final _history = [''];
|
| +
|
| + ObservatoryDebugger(this.isolate) {
|
| _loadSettings();
|
| cmd = new RootCommand([
|
| new AsyncNextCommand(this),
|
| @@ -1386,7 +1400,7 @@ class ObservatoryDebugger extends Debugger {
|
| new SyncNextCommand(this),
|
| new UpCommand(this),
|
| new VmCommand(this),
|
| - ]);
|
| + ], _history);
|
| _consolePrinter = new _ConsoleStreamPrinter(this);
|
| }
|
|
|
| @@ -1394,55 +1408,12 @@ class ObservatoryDebugger extends Debugger {
|
| _upIsDown = settings.get('up-is-down');
|
| }
|
|
|
| - VM get vm => page.app.vm;
|
| -
|
| - void updateIsolate(Isolate iso) {
|
| - _isolate = iso;
|
| - if (_isolate != null) {
|
| - if ((breakOnException != iso.exceptionsPauseInfo) &&
|
| - (iso.exceptionsPauseInfo != null)) {
|
| - breakOnException = iso.exceptionsPauseInfo;
|
| - }
|
| -
|
| - _isolate.reload().then((response) {
|
| - if (response.isSentinel) {
|
| - // The isolate has gone away. The IsolateExit event will
|
| - // clear the isolate for the debugger page.
|
| - return;
|
| - }
|
| - // TODO(turnidge): Currently the debugger relies on all libs
|
| - // being loaded. Fix this.
|
| - var pending = [];
|
| - for (var lib in response.libraries) {
|
| - if (!lib.loaded) {
|
| - pending.add(lib.load());
|
| - }
|
| - }
|
| - Future.wait(pending).then((_) {
|
| - refreshStack();
|
| - }).catchError((e) {
|
| - print("UNEXPECTED ERROR $e");
|
| - reportStatus();
|
| - });
|
| - });
|
| - } else {
|
| - reportStatus();
|
| - }
|
| - }
|
| -
|
| - set isolate(Isolate iso) {
|
| - // Setting the page's isolate will trigger updateIsolate to be called.
|
| - //
|
| - // TODO(turnidge): Rework ownership of the ObservatoryDebugger in another
|
| - // change.
|
| - page.isolate = iso;
|
| - }
|
| - Isolate get isolate => _isolate;
|
| - Isolate _isolate;
|
| + S.VM get vm => page.app.vm;
|
|
|
| void init() {
|
| - console.newline();
|
| - console.printBold("Type 'h' for help");
|
| + console.printBold('Debugging isolate isolate ${isolate.number} '
|
| + '\'${isolate.name}\' ');
|
| + console.printBold('Type \'h\' for help');
|
| // Wait a bit and if polymer still hasn't set up the isolate,
|
| // report this to the user.
|
| new Timer(const Duration(seconds:1), () {
|
| @@ -1450,12 +1421,39 @@ class ObservatoryDebugger extends Debugger {
|
| reportStatus();
|
| }
|
| });
|
| +
|
| + if ((breakOnException != isolate.exceptionsPauseInfo) &&
|
| + (isolate.exceptionsPauseInfo != null)) {
|
| + breakOnException = isolate.exceptionsPauseInfo;
|
| + }
|
| +
|
| + isolate.reload().then((response) {
|
| + if (response.isSentinel) {
|
| + // The isolate has gone away. The IsolateExit event will
|
| + // clear the isolate for the debugger page.
|
| + return;
|
| + }
|
| + // TODO(turnidge): Currently the debugger relies on all libs
|
| + // being loaded. Fix this.
|
| + var pending = [];
|
| + for (var lib in response.libraries) {
|
| + if (!lib.loaded) {
|
| + pending.add(lib.load());
|
| + }
|
| + }
|
| + Future.wait(pending).then((_) {
|
| + refreshStack();
|
| + }).catchError((e) {
|
| + print("UNEXPECTED ERROR $e");
|
| + reportStatus();
|
| + });
|
| + });
|
| }
|
|
|
| Future refreshStack() async {
|
| try {
|
| - if (_isolate != null) {
|
| - await _refreshStack(_isolate.pauseEvent);
|
| + if (isolate != null) {
|
| + await _refreshStack(isolate.pauseEvent);
|
| }
|
| flushStdio();
|
| reportStatus();
|
| @@ -1468,9 +1466,7 @@ class ObservatoryDebugger extends Debugger {
|
| // TODO(turnidge): Stop relying on the isolate to track the last
|
| // pause event. Since we listen to events directly in the
|
| // debugger, this could introduce a race.
|
| - return (isolate != null &&
|
| - isolate.pauseEvent != null &&
|
| - isolate.pauseEvent is M.ResumeEvent);
|
| + return isolate.status == M.IsolateStatus.paused;
|
| }
|
|
|
| void warnOutOfDate() {
|
| @@ -1482,7 +1478,7 @@ class ObservatoryDebugger extends Debugger {
|
| });
|
| }
|
|
|
| - Future<ServiceMap> _refreshStack(M.DebugEvent pauseEvent) {
|
| + Future<S.ServiceMap> _refreshStack(M.DebugEvent pauseEvent) {
|
| return isolate.getStack().then((result) {
|
| if (result.isSentinel) {
|
| // The isolate has gone away. The IsolateExit event will
|
| @@ -1502,25 +1498,25 @@ class ObservatoryDebugger extends Debugger {
|
|
|
| void reportStatus() {
|
| flushStdio();
|
| - if (_isolate == null) {
|
| + if (isolate == null) {
|
| console.print('No current isolate');
|
| - } else if (_isolate.idle) {
|
| + } else if (isolate.idle) {
|
| console.print('Isolate is idle');
|
| - } else if (_isolate.running) {
|
| + } else if (isolate.running) {
|
| console.print("Isolate is running (type 'pause' to interrupt)");
|
| - } else if (_isolate.pauseEvent != null) {
|
| - _reportPause(_isolate.pauseEvent);
|
| + } else if (isolate.pauseEvent != null) {
|
| + _reportPause(isolate.pauseEvent);
|
| } else {
|
| console.print('Isolate is in unknown state');
|
| }
|
| warnOutOfDate();
|
| }
|
|
|
| - void _reportIsolateError(Isolate isolate, M.DebugEvent event) {
|
| + void _reportIsolateError(S.Isolate isolate, M.DebugEvent event) {
|
| if (isolate == null) {
|
| return;
|
| }
|
| - DartError error = isolate.error;
|
| + S.DartError error = isolate.error;
|
| if (error == null) {
|
| return;
|
| }
|
| @@ -1565,7 +1561,7 @@ class ObservatoryDebugger extends Debugger {
|
| "(type 'continue' or [F7] to exit the isolate')");
|
| _reportIsolateError(isolate, event);
|
| } else if (stack['frames'].length > 0) {
|
| - Frame frame = stack['frames'][0];
|
| + S.Frame frame = stack['frames'][0];
|
| var script = frame.location.script;
|
| script.load().then((_) {
|
| var line = script.tokenToLine(frame.location.tokenPos);
|
| @@ -1582,7 +1578,7 @@ class ObservatoryDebugger extends Debugger {
|
| // This seems to be missing if we are paused-at-exception after
|
| // paused-at-isolate-exit. Maybe we shutdown part of the debugger too
|
| // soon?
|
| - console.printRef(event.exception);
|
| + console.printRef(isolate, event.exception, instances);
|
| } else {
|
| console.print('Paused at ${script.name}:${line}:${col}');
|
| }
|
| @@ -1593,17 +1589,17 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
| }
|
|
|
| - Future _reportBreakpointEvent(ServiceEvent event) async {
|
| + Future _reportBreakpointEvent(S.ServiceEvent event) async {
|
| var bpt = event.breakpoint;
|
| var verb = null;
|
| switch (event.kind) {
|
| - case ServiceEvent.kBreakpointAdded:
|
| + case S.ServiceEvent.kBreakpointAdded:
|
| verb = 'added';
|
| break;
|
| - case ServiceEvent.kBreakpointResolved:
|
| + case S.ServiceEvent.kBreakpointResolved:
|
| verb = 'resolved';
|
| break;
|
| - case ServiceEvent.kBreakpointRemoved:
|
| + case S.ServiceEvent.kBreakpointRemoved:
|
| verb = 'removed';
|
| break;
|
| default:
|
| @@ -1623,26 +1619,22 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
| }
|
|
|
| - void onEvent(ServiceEvent event) {
|
| + void onEvent(S.ServiceEvent event) {
|
| switch(event.kind) {
|
| - case ServiceEvent.kVMUpdate:
|
| + case S.ServiceEvent.kVMUpdate:
|
| var vm = event.owner;
|
| console.print("VM ${vm.target.networkAddress} renamed to '${vm.name}'");
|
| break;
|
|
|
| - case ServiceEvent.kIsolateStart:
|
| + case S.ServiceEvent.kIsolateStart:
|
| {
|
| var iso = event.owner;
|
| console.print(
|
| "Isolate ${iso.number} '${iso.name}' has been created");
|
| - if (isolate == null) {
|
| - console.print("Switching to isolate ${iso.number} '${iso.name}'");
|
| - isolate = iso;
|
| - }
|
| }
|
| break;
|
|
|
| - case ServiceEvent.kIsolateExit:
|
| + case S.ServiceEvent.kIsolateExit:
|
| {
|
| var iso = event.owner;
|
| if (iso == isolate) {
|
| @@ -1651,11 +1643,9 @@ class ObservatoryDebugger extends Debugger {
|
| var isolates = vm.isolates;
|
| if (isolates.length > 0) {
|
| var newIsolate = isolates.first;
|
| - console.print("Switching to isolate "
|
| - "${newIsolate.number} '${newIsolate.name}'");
|
| - isolate = newIsolate;
|
| + new AnchorElement(href: Uris.debugger(newIsolate)).click();
|
| } else {
|
| - isolate = null;
|
| + new AnchorElement(href: Uris.vm()).click();
|
| }
|
| } else {
|
| console.print(
|
| @@ -1664,19 +1654,19 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
| break;
|
|
|
| - case ServiceEvent.kDebuggerSettingsUpdate:
|
| + case S.ServiceEvent.kDebuggerSettingsUpdate:
|
| if (breakOnException != event.exceptions) {
|
| breakOnException = event.exceptions;
|
| console.print("Now pausing for exceptions: $breakOnException");
|
| }
|
| break;
|
|
|
| - case ServiceEvent.kIsolateUpdate:
|
| + case S.ServiceEvent.kIsolateUpdate:
|
| var iso = event.owner;
|
| console.print("Isolate ${iso.number} renamed to '${iso.name}'");
|
| break;
|
|
|
| - case ServiceEvent.kIsolateReload:
|
| + case S.ServiceEvent.kIsolateReload:
|
| var reloadError = event.reloadError;
|
| if (reloadError != null) {
|
| console.print('Isolate reload failed: ${event.reloadError}');
|
| @@ -1685,11 +1675,11 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
| break;
|
|
|
| - case ServiceEvent.kPauseStart:
|
| - case ServiceEvent.kPauseExit:
|
| - case ServiceEvent.kPauseBreakpoint:
|
| - case ServiceEvent.kPauseInterrupted:
|
| - case ServiceEvent.kPauseException:
|
| + case S.ServiceEvent.kPauseStart:
|
| + case S.ServiceEvent.kPauseExit:
|
| + case S.ServiceEvent.kPauseBreakpoint:
|
| + case S.ServiceEvent.kPauseInterrupted:
|
| + case S.ServiceEvent.kPauseException:
|
| if (event.owner == isolate) {
|
| var e = createEventFromServiceEvent(event);
|
| _refreshStack(e).then((_) async {
|
| @@ -1702,29 +1692,29 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
| break;
|
|
|
| - case ServiceEvent.kResume:
|
| + case S.ServiceEvent.kResume:
|
| if (event.owner == isolate) {
|
| flushStdio();
|
| console.print('Continuing...');
|
| }
|
| break;
|
|
|
| - case ServiceEvent.kBreakpointAdded:
|
| - case ServiceEvent.kBreakpointResolved:
|
| - case ServiceEvent.kBreakpointRemoved:
|
| + case S.ServiceEvent.kBreakpointAdded:
|
| + case S.ServiceEvent.kBreakpointResolved:
|
| + case S.ServiceEvent.kBreakpointRemoved:
|
| if (event.owner == isolate) {
|
| _reportBreakpointEvent(event);
|
| }
|
| break;
|
|
|
| - case ServiceEvent.kIsolateRunnable:
|
| - case ServiceEvent.kGraph:
|
| - case ServiceEvent.kGC:
|
| - case ServiceEvent.kInspect:
|
| + case S.ServiceEvent.kIsolateRunnable:
|
| + case S.ServiceEvent.kGraph:
|
| + case S.ServiceEvent.kGC:
|
| + case S.ServiceEvent.kInspect:
|
| // Ignore.
|
| break;
|
|
|
| - case ServiceEvent.kLogging:
|
| + case S.ServiceEvent.kLogging:
|
| _consolePrinter.onEvent(event.logRecord['level'].name, event);
|
| break;
|
|
|
| @@ -1740,11 +1730,11 @@ class ObservatoryDebugger extends Debugger {
|
| _consolePrinter.flush();
|
| }
|
|
|
| - void onStdout(ServiceEvent event) {
|
| + void onStdout(S.ServiceEvent event) {
|
| _consolePrinter.onEvent('stdout', event);
|
| }
|
|
|
| - void onStderr(ServiceEvent event) {
|
| + void onStderr(S.ServiceEvent event) {
|
| _consolePrinter.onEvent('stderr', event);
|
| }
|
|
|
| @@ -1798,7 +1788,7 @@ class ObservatoryDebugger extends Debugger {
|
| return cmd.runCommand(command).then((_) {
|
| lastCommand = command;
|
| }).catchError((e, s) {
|
| - if (e is NetworkRpcException) {
|
| + if (e is S.NetworkRpcException) {
|
| console.printRed('Unable to execute command because the connection '
|
| 'to the VM has been closed');
|
| } else {
|
| @@ -1921,20 +1911,44 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
| }
|
|
|
| -@CustomTag('debugger-page')
|
| -class DebuggerPageElement extends ObservatoryElement {
|
| - @published Isolate isolate;
|
| -
|
| - isolateChanged(oldValue) {
|
| - debugger.updateIsolate(isolate);
|
| - }
|
| - ObservatoryDebugger debugger = new ObservatoryDebugger();
|
| -
|
| - DebuggerPageElement.created() : super.created() {
|
| - debugger.page = this;
|
| - }
|
| +class DebuggerPageElement extends HtmlElement implements Renderable {
|
| + static const tag = const Tag<DebuggerPageElement>('debugger-page',
|
| + dependencies: const [
|
| + NavBarElement.tag,
|
| + NavTopMenuElement.tag,
|
| + NavVMMenuElement.tag,
|
| + NavIsolateMenuElement.tag,
|
| + NavMenuElement.tag,
|
| + NavNotifyElement.tag,
|
| + ]);
|
| +
|
| + S.Isolate _isolate;
|
| + ObservatoryDebugger _debugger;
|
| + M.InstanceRepository _instances;
|
| + M.ScriptRepository _scripts;
|
| + M.EventRepository _events;
|
| +
|
| + factory DebuggerPageElement(S.Isolate isolate,
|
| + M.InstanceRepository instances,
|
| + M.ScriptRepository scripts,
|
| + M.EventRepository events) {
|
| + assert(isolate != null);
|
| + assert(instances != null);
|
| + assert(scripts != null);
|
| + assert(events != null);
|
| + final e = document.createElement(tag.name);
|
| + final debugger = new ObservatoryDebugger(isolate);
|
| + debugger.page = e;
|
| + e._isolate = isolate;
|
| + e._debugger = debugger;
|
| + e._instances = instances;
|
| + e._scripts = scripts;
|
| + e._events = events;
|
| + return e;
|
| + }
|
| +
|
| + DebuggerPageElement.created() : super.created();
|
|
|
| - StreamSubscription _resizeSubscription;
|
| Future<StreamSubscription> _vmSubscriptionFuture;
|
| Future<StreamSubscription> _isolateSubscriptionFuture;
|
| Future<StreamSubscription> _debugSubscriptionFuture;
|
| @@ -1942,30 +1956,66 @@ class DebuggerPageElement extends ObservatoryElement {
|
| Future<StreamSubscription> _stderrSubscriptionFuture;
|
| Future<StreamSubscription> _logSubscriptionFuture;
|
|
|
| + ObservatoryApplication get app => ObservatoryApplication.app;
|
| +
|
| + Timer _timer;
|
| +
|
| + static final consoleElement = new DebuggerConsoleElement();
|
| +
|
| @override
|
| void attached() {
|
| super.attached();
|
| - _onResize(null);
|
| +
|
| + final stackDiv = new DivElement()..classes = ['stack'];
|
| + final stackElement = new DebuggerStackElement(_isolate, _debugger, stackDiv,
|
| + _instances, _scripts,
|
| + _events);
|
| + stackDiv.children = [stackElement];
|
| + final consoleDiv = new DivElement()..classes = ['console']
|
| + ..children = [consoleElement];
|
| + final commandElement = new DebuggerInputElement(_isolate, _debugger);
|
| + final commandDiv = new DivElement()..classes = ['commandline']
|
| + ..children = [commandElement];
|
| +
|
| + children = [
|
| + new NavBarElement(queue: app.queue)
|
| + ..children = [
|
| + new NavTopMenuElement(queue: app.queue),
|
| + new NavVMMenuElement(app.vm, app.events, queue: app.queue),
|
| + new NavIsolateMenuElement(_isolate, app.events, queue: app.queue),
|
| + new NavMenuElement('debugger', last: true, queue: app.queue),
|
| + new NavNotifyElement(app.notifications, notifyOnPause: false,
|
| + queue: app.queue)
|
| + ],
|
| + new DivElement()..classes = ['variable']
|
| + ..children = [
|
| + stackDiv,
|
| + new DivElement()
|
| + ..children = [
|
| + new HRElement()..classes = ['splitter']
|
| + ],
|
| + consoleDiv,
|
| + ],
|
| + commandDiv
|
| + ];
|
| +
|
| + DebuggerConsoleElement._scrollToBottom(consoleDiv);
|
|
|
| // Wire the debugger object to the stack, console, and command line.
|
| - var stackElement = $['stackElement'];
|
| - debugger.stackElement = stackElement;
|
| - stackElement.debugger = debugger;
|
| - stackElement.scroller = $['stackDiv'];
|
| - debugger.console = $['console'];
|
| - debugger.input = $['commandline'];
|
| - debugger.input.debugger = debugger;
|
| - debugger.init();
|
| -
|
| - _resizeSubscription = window.onResize.listen(_onResize);
|
| + _debugger.stackElement = stackElement;
|
| + _debugger.console = consoleElement;
|
| + _debugger.input = commandElement;
|
| + _debugger.input._debugger = _debugger;
|
| + _debugger.init();
|
| +
|
| _vmSubscriptionFuture =
|
| - app.vm.listenEventStream(VM.kVMStream, debugger.onEvent);
|
| + app.vm.listenEventStream(S.VM.kVMStream, _debugger.onEvent);
|
| _isolateSubscriptionFuture =
|
| - app.vm.listenEventStream(VM.kIsolateStream, debugger.onEvent);
|
| + app.vm.listenEventStream(S.VM.kIsolateStream, _debugger.onEvent);
|
| _debugSubscriptionFuture =
|
| - app.vm.listenEventStream(VM.kDebugStream, debugger.onEvent);
|
| + app.vm.listenEventStream(S.VM.kDebugStream, _debugger.onEvent);
|
| _stdoutSubscriptionFuture =
|
| - app.vm.listenEventStream(VM.kStdoutStream, debugger.onStdout);
|
| + app.vm.listenEventStream(S.VM.kStdoutStream, _debugger.onStdout);
|
| if (_stdoutSubscriptionFuture != null) {
|
| // TODO(turnidge): How do we want to handle this in general?
|
| _stdoutSubscriptionFuture.catchError((e, st) {
|
| @@ -1974,7 +2024,7 @@ class DebuggerPageElement extends ObservatoryElement {
|
| });
|
| }
|
| _stderrSubscriptionFuture =
|
| - app.vm.listenEventStream(VM.kStderrStream, debugger.onStderr);
|
| + app.vm.listenEventStream(S.VM.kStderrStream, _debugger.onStderr);
|
| if (_stderrSubscriptionFuture != null) {
|
| // TODO(turnidge): How do we want to handle this in general?
|
| _stderrSubscriptionFuture.catchError((e, st) {
|
| @@ -1983,9 +2033,11 @@ class DebuggerPageElement extends ObservatoryElement {
|
| });
|
| }
|
| _logSubscriptionFuture =
|
| - app.vm.listenEventStream(Isolate.kLoggingStream, debugger.onEvent);
|
| + app.vm.listenEventStream(S.Isolate.kLoggingStream, _debugger.onEvent);
|
| // Turn on the periodic poll timer for this page.
|
| - pollPeriod = const Duration(milliseconds:100);
|
| + _timer = new Timer.periodic(const Duration(milliseconds:100), (_) {
|
| + _debugger.flushStdio();
|
| + });
|
|
|
| onClick.listen((event) {
|
| // Random clicks should focus on the text box. If the user selects
|
| @@ -1993,70 +2045,140 @@ class DebuggerPageElement extends ObservatoryElement {
|
| var selection = window.getSelection();
|
| if (selection == null ||
|
| (selection.type != 'Range' && selection.type != 'text')) {
|
| - debugger.input.focus();
|
| + _debugger.input.focus();
|
| }
|
| });
|
| }
|
|
|
| - void onPoll() {
|
| - debugger.flushStdio();
|
| - }
|
| -
|
| - void _onResize(_) {
|
| - var navbarDiv = $['navbarDiv'];
|
| - var stackDiv = $['stackDiv'];
|
| - var splitterDiv = $['splitterDiv'];
|
| - var cmdDiv = $['commandDiv'];
|
| -
|
| - // For now, force navbar height to 40px in the debugger.
|
| - // TODO (cbernaschina) check if this is needed.
|
| - const navbarHeight = 40;
|
| - int splitterHeight = splitterDiv.clientHeight;
|
| - int cmdHeight = cmdDiv.clientHeight;
|
| -
|
| - int windowHeight = window.innerHeight;
|
| - int fixedHeight = navbarHeight + splitterHeight + cmdHeight;
|
| - int available = windowHeight - fixedHeight;
|
| - int stackHeight = available ~/ 1.6;
|
| - navbarDiv.style.setProperty('height', '${navbarHeight}px');
|
| - stackDiv.style.setProperty('height', '${stackHeight}px');
|
| - }
|
| -
|
| @override
|
| void detached() {
|
| - debugger.isolate = null;
|
| - _resizeSubscription.cancel();
|
| - _resizeSubscription = null;
|
| - cancelFutureSubscription(_vmSubscriptionFuture);
|
| + _timer.cancel();
|
| + children = const [];
|
| + S.cancelFutureSubscription(_vmSubscriptionFuture);
|
| _vmSubscriptionFuture = null;
|
| - cancelFutureSubscription(_isolateSubscriptionFuture);
|
| + S.cancelFutureSubscription(_isolateSubscriptionFuture);
|
| _isolateSubscriptionFuture = null;
|
| - cancelFutureSubscription(_debugSubscriptionFuture);
|
| + S.cancelFutureSubscription(_debugSubscriptionFuture);
|
| _debugSubscriptionFuture = null;
|
| - cancelFutureSubscription(_stdoutSubscriptionFuture);
|
| + S.cancelFutureSubscription(_stdoutSubscriptionFuture);
|
| _stdoutSubscriptionFuture = null;
|
| - cancelFutureSubscription(_stderrSubscriptionFuture);
|
| + S.cancelFutureSubscription(_stderrSubscriptionFuture);
|
| _stderrSubscriptionFuture = null;
|
| - cancelFutureSubscription(_logSubscriptionFuture);
|
| + S.cancelFutureSubscription(_logSubscriptionFuture);
|
| _logSubscriptionFuture = null;
|
| super.detached();
|
| }
|
| }
|
|
|
| -@CustomTag('debugger-stack')
|
| -class DebuggerStackElement extends ObservatoryElement {
|
| - @published Isolate isolate;
|
| - @published Element scroller;
|
| - @observable bool hasStack = false;
|
| - @observable bool hasMessages = false;
|
| - @observable bool isSampled = false;
|
| - @observable int currentFrame;
|
| - ObservatoryDebugger debugger;
|
| +class DebuggerStackElement extends HtmlElement implements Renderable {
|
| + static const tag = const Tag<DebuggerStackElement>('debugger-stack');
|
|
|
| - _addFrame(List frameList, Frame frameInfo) {
|
| - DebuggerFrameElement frameElement = new Element.tag('debugger-frame');
|
| - frameElement.frame = frameInfo;
|
| - frameElement.scroller = scroller;
|
| + S.Isolate _isolate;
|
| + M.InstanceRepository _instances;
|
| + M.ScriptRepository _scripts;
|
| + M.EventRepository _events;
|
| + Element _scroller;
|
| + DivElement _isSampled;
|
| + bool get isSampled => !_isSampled.classes.contains('hidden');
|
| + set isSampled(bool value) {
|
| + if (value != isSampled) {
|
| + _isSampled.classes.toggle('hidden');
|
| + }
|
| + }
|
| + DivElement _hasStack;
|
| + bool get hasStack => _hasStack.classes.contains('hidden');
|
| + set hasStack(bool value) {
|
| + if (value != hasStack) {
|
| + _hasStack.classes.toggle('hidden');
|
| + }
|
| + }
|
| + DivElement _hasMessages;
|
| + bool get hasMessages => _hasMessages.classes.contains('hidden');
|
| + set hasMessages(bool value) {
|
| + if (value != hasMessages) {
|
| + _hasMessages.classes.toggle('hidden');
|
| + }
|
| + }
|
| + UListElement _frameList;
|
| + UListElement _messageList;
|
| + int currentFrame;
|
| + ObservatoryDebugger _debugger;
|
| +
|
| + factory DebuggerStackElement(S.Isolate isolate,
|
| + ObservatoryDebugger debugger,
|
| + Element scroller,
|
| + M.InstanceRepository instances,
|
| + M.ScriptRepository scripts,
|
| + M.EventRepository events) {
|
| + assert(isolate != null);
|
| + assert(debugger != null);
|
| + assert(scroller != null);
|
| + assert(instances != null);
|
| + assert(scripts != null);
|
| + assert(events != null);
|
| + final e = document.createElement(tag.name);
|
| + e._isolate = isolate;
|
| + e._debugger = debugger;
|
| + e._scroller = scroller;
|
| + e._instances = instances;
|
| + e._scripts = scripts;
|
| + e._events = events;
|
| +
|
| + var btnPause;
|
| + var btnRefresh;
|
| + e.children = [
|
| + e._isSampled = new DivElement()..classes = ['sampledMessage', 'hidden']
|
| + ..children = [
|
| + new SpanElement()
|
| + ..text = 'The program is not paused. '
|
| + 'The stack trace below may be out of date.',
|
| + new BRElement(),
|
| + new BRElement(),
|
| + btnPause = new ButtonElement()
|
| + ..text = '[Pause Isolate]'
|
| + ..onClick.listen((_) async {
|
| + btnPause.disabled = true;
|
| + try {
|
| + await debugger.isolate.pause();
|
| + }
|
| + finally {
|
| + btnPause.disabled = false;
|
| + }
|
| + }),
|
| + btnRefresh = new ButtonElement()
|
| + ..text = '[Refresh Stack]'
|
| + ..onClick.listen((_) async {
|
| + btnRefresh.disabled = true;
|
| + try {
|
| + await debugger.refreshStack();
|
| + }
|
| + finally {
|
| + btnRefresh.disabled = false;
|
| + }
|
| + }),
|
| + new BRElement(),
|
| + new BRElement(),
|
| + new HRElement()..classes = ['splitter']
|
| + ],
|
| + e._hasStack = new DivElement()..classes = ['noStack', 'hidden']
|
| + ..text = 'No stack',
|
| + e._frameList = new UListElement()..classes = ['list-group'],
|
| + new HRElement(),
|
| + e._hasMessages = new DivElement()..classes = ['noMessages', 'hidden']
|
| + ..text = 'No pending messages',
|
| + e._messageList = new UListElement()..classes = ['messageList']
|
| + ];
|
| + return e;
|
| + }
|
| +
|
| + _addFrame(List frameList, S.Frame frameInfo) {
|
| + final frameElement = new DebuggerFrameElement(_isolate,
|
| + frameInfo,
|
| + _scroller,
|
| + _instances,
|
| + _scripts,
|
| + _events,
|
| + queue: app.queue);
|
|
|
| if (frameInfo.index == currentFrame) {
|
| frameElement.setCurrent(true);
|
| @@ -2071,9 +2193,13 @@ class DebuggerStackElement extends ObservatoryElement {
|
| frameList.insert(0, li);
|
| }
|
|
|
| - _addMessage(List messageList, ServiceMessage messageInfo) {
|
| - DebuggerMessageElement messageElement = new Element.tag('debugger-message');
|
| - messageElement.message = messageInfo;
|
| + _addMessage(List messageList, S.ServiceMessage messageInfo) {
|
| + final messageElement = new DebuggerMessageElement(_isolate,
|
| + messageInfo,
|
| + _instances,
|
| + _scripts,
|
| + _events,
|
| + queue: app.queue);
|
|
|
| var li = new LIElement();
|
| li.classes.add('list-group-item');
|
| @@ -2082,8 +2208,10 @@ class DebuggerStackElement extends ObservatoryElement {
|
| messageList.add(li);
|
| }
|
|
|
| - void updateStackFrames(ServiceMap newStack) {
|
| - List frameElements = $['frameList'].children;
|
| + ObservatoryApplication get app => ObservatoryApplication.app;
|
| +
|
| + void updateStackFrames(S.ServiceMap newStack) {
|
| + List frameElements = _frameList.children;
|
| List newFrames = newStack['frames'];
|
|
|
| // Remove any frames whose functions don't match, starting from
|
| @@ -2132,8 +2260,8 @@ class DebuggerStackElement extends ObservatoryElement {
|
| hasStack = frameElements.isNotEmpty;
|
| }
|
|
|
| - void updateStackMessages(ServiceMap newStack) {
|
| - List messageElements = $['messageList'].children;
|
| + void updateStackMessages(S.ServiceMap newStack) {
|
| + List messageElements = _messageList.children;
|
| List newMessages = newStack['messages'];
|
|
|
| // Remove any extra message elements.
|
| @@ -2157,14 +2285,15 @@ class DebuggerStackElement extends ObservatoryElement {
|
| if (messageElements.isNotEmpty) {
|
| // Update old messages.
|
| for (int i = 0; i < newStartingIndex; i++) {
|
| - messageElements[i].children[0].updateMessage(newMessages[i]);
|
| + DebuggerMessageElement e = messageElements[i].children[0];
|
| + e.updateMessage(newMessages[i]);
|
| }
|
| }
|
|
|
| hasMessages = messageElements.isNotEmpty;
|
| }
|
|
|
| - void updateStack(ServiceMap newStack, M.DebugEvent pauseEvent) {
|
| + void updateStack(S.ServiceMap newStack, M.DebugEvent pauseEvent) {
|
| updateStackFrames(newStack);
|
| updateStackMessages(newStack);
|
| isSampled = pauseEvent == null;
|
| @@ -2172,9 +2301,9 @@ class DebuggerStackElement extends ObservatoryElement {
|
|
|
| void setCurrentFrame(int value) {
|
| currentFrame = value;
|
| - List frameElements = $['frameList'].children;
|
| + List frameElements = _frameList.children;
|
| for (var frameElement in frameElements) {
|
| - var dbgFrameElement = frameElement.children[0];
|
| + DebuggerFrameElement dbgFrameElement = frameElement.children[0];
|
| if (dbgFrameElement.frame.index == currentFrame) {
|
| dbgFrameElement.setCurrent(true);
|
| } else {
|
| @@ -2183,29 +2312,24 @@ class DebuggerStackElement extends ObservatoryElement {
|
| }
|
| }
|
|
|
| - Future doPauseIsolate() {
|
| - if (debugger != null) {
|
| - return debugger.isolate.pause();
|
| - } else {
|
| - return new Future.value(null);
|
| - }
|
| - }
|
| -
|
| - Future doRefreshStack() {
|
| - if (debugger != null) {
|
| - return debugger.refreshStack();
|
| - } else {
|
| - return new Future.value(null);
|
| - }
|
| - }
|
| -
|
| DebuggerStackElement.created() : super.created();
|
| }
|
|
|
| -@CustomTag('debugger-frame')
|
| -class DebuggerFrameElement extends ObservatoryElement {
|
| - @published Frame frame;
|
| - @published Element scroller;
|
| +class DebuggerFrameElement extends HtmlElement implements Renderable {
|
| + static const tag = const Tag<DebuggerFrameElement>('debugger-frame');
|
| +
|
| + RenderingScheduler<DebuggerMessageElement> _r;
|
| +
|
| + Stream<RenderedEvent<DebuggerMessageElement>> get onRendered => _r.onRendered;
|
| +
|
| + Element _scroller;
|
| + DivElement _varsDiv;
|
| + M.Isolate _isolate;
|
| + S.Frame _frame;
|
| + S.Frame get frame => _frame;
|
| + M.InstanceRepository _instances;
|
| + M.ScriptRepository _scripts;
|
| + M.EventRepository _events;
|
|
|
| // Is this the current frame?
|
| bool _current = false;
|
| @@ -2213,99 +2337,238 @@ class DebuggerFrameElement extends ObservatoryElement {
|
| // Has this frame been pinned open?
|
| bool _pinned = false;
|
|
|
| + bool _expanded = false;
|
| +
|
| void setCurrent(bool value) {
|
| - busy = true;
|
| - frame.function.load().then((func) {
|
| + _frame.function.load().then((func) {
|
| _current = value;
|
| - var frameOuter = $['frameOuter'];
|
| if (_current) {
|
| - frameOuter.classes.add('current');
|
| _expand();
|
| scrollIntoView();
|
| } else {
|
| - frameOuter.classes.remove('current');
|
| if (_pinned) {
|
| _expand();
|
| } else {
|
| _unexpand();
|
| }
|
| }
|
| - busy = false;
|
| });
|
| }
|
|
|
| - @observable String scriptHeight;
|
| - @observable bool expanded = false;
|
| - @observable bool busy = false;
|
| + factory DebuggerFrameElement(M.Isolate isolate,
|
| + S.Frame frame,
|
| + Element scroller,
|
| + M.InstanceRepository instances,
|
| + M.ScriptRepository scripts,
|
| + M.EventRepository events,
|
| + {RenderingQueue queue}) {
|
| + assert(isolate != null);
|
| + assert(frame != null);
|
| + assert(scroller != null);
|
| + assert(instances != null);
|
| + assert(scripts != null);
|
| + assert(events != null);
|
| + final DebuggerFrameElement e = document.createElement(tag.name);
|
| + e._r = new RenderingScheduler(e, queue: queue);
|
| + e._isolate = isolate;
|
| + e._frame = frame;
|
| + e._scroller = scroller;
|
| + e._instances = instances;
|
| + e._scripts = scripts;
|
| + e._events = events;
|
| + return e;
|
| + }
|
|
|
| DebuggerFrameElement.created() : super.created();
|
|
|
| + void render() {
|
| + if (_pinned) {
|
| + classes.add('shadow');
|
| + } else {
|
| + classes.remove('shadow');
|
| + }
|
| + if (_current) {
|
| + classes.add('current');
|
| + } else {
|
| + classes.remove('current');
|
| + }
|
| + ButtonElement expandButton;
|
| + final content = <Element>[
|
| + expandButton = new ButtonElement()
|
| + ..children = _createHeader()
|
| + ..onClick.listen((e) async {
|
| + if (e.target is AnchorElement) {
|
| + return;
|
| + }
|
| + expandButton.disabled = true;
|
| + await _toggleExpand();
|
| + expandButton.disabled = false;
|
| + })
|
| + ];
|
| + if (_expanded) {
|
| + final homeMethod = _frame.function.homeMethod;
|
| + String homeMethodName;
|
| + if ((homeMethod.dartOwner is S.Class) && homeMethod.isStatic) {
|
| + homeMethodName = '<class>';
|
| + } else if (homeMethod.dartOwner is S.Library) {
|
| + homeMethodName = '<library>';
|
| + }
|
| + ButtonElement collapseButton;
|
| + content.addAll([
|
| + new DivElement()..classes = ['frameDetails']
|
| + ..children = [
|
| + new DivElement()..classes = ['flex-row-wrap']
|
| + ..children = [
|
| + new DivElement()..classes = ['flex-item-script']
|
| + ..children = _frame.function?.location == null ? const []
|
| + : [
|
| + new SourceInsetElement(_isolate,
|
| + _frame.function.location, _scripts, _instances,
|
| + _events, currentPos: _frame.location.tokenPos,
|
| + variables: _frame.variables, inDebuggerContext: true,
|
| + queue: _r.queue)
|
| + ],
|
| + new DivElement()..classes = ['flex-item-vars']
|
| + ..children = [
|
| + _varsDiv = new DivElement()
|
| + ..classes = ['memberList', 'frameVars']
|
| + ..children = ([
|
| + new DivElement()..classes = ['memberItem']
|
| + ..children = homeMethodName == null ? const []
|
| + : [
|
| + new DivElement()..classes = ['memberName']
|
| + ..text = homeMethodName,
|
| + new DivElement()..classes = ['memberName']
|
| + ..children = [
|
| + anyRef(_isolate, homeMethod.dartOwner,
|
| + _instances, queue: _r.queue)
|
| + ]
|
| + ]
|
| + ]..addAll(_frame.variables.map((v) =>
|
| + new DivElement()..classes = ['memberItem']
|
| + ..children = [
|
| + new DivElement()..classes = ['memberName']
|
| + ..text = v.name,
|
| + new DivElement()..classes = ['memberName']
|
| + ..children = [
|
| + anyRef(_isolate, v['value'], _instances,
|
| + queue: _r.queue)
|
| + ]
|
| + ]
|
| + ).toList()))
|
| + ]
|
| + ],
|
| + new DivElement()..classes = ['frameContractor']
|
| + ..children = [
|
| + collapseButton = new ButtonElement()
|
| + ..onClick.listen((e) async {
|
| + collapseButton.disabled = true;
|
| + await _toggleExpand();
|
| + collapseButton.disabled = false;
|
| + })
|
| + ..children = [
|
| + iconExpandLess.clone(true)
|
| + ]
|
| + ]
|
| + ]
|
| + ]);
|
| + }
|
| + children = content;
|
| + }
|
| +
|
| + List<Element> _createHeader() {
|
| + final content = [
|
| + new DivElement()..classes = ['frameSummaryText']
|
| + ..children = [
|
| + new DivElement()..classes = ['frameId']
|
| + ..text = 'Frame ${_frame.index}',
|
| + new SpanElement()
|
| + ..children = _frame.function == null ? const []
|
| + : [
|
| + new FunctionRefElement(_isolate, _frame.function,
|
| + queue: _r.queue)
|
| + ],
|
| + new SpanElement()..text = ' ( ',
|
| + new SpanElement()
|
| + ..children = _frame.function?.location == null ? const []
|
| + : [
|
| + new SourceLinkElement(_isolate, _frame.function.location,
|
| + _scripts,
|
| + queue: _r.queue)
|
| + ],
|
| + new SpanElement()..text = ' )'
|
| + ]
|
| + ];
|
| + if (!_expanded) {
|
| + content.add(new DivElement()..classes = ['frameExpander']
|
| + ..children = [
|
| + iconExpandMore.clone(true)
|
| + ]);
|
| + }
|
| + return [
|
| + new DivElement()..classes = ['frameSummary']
|
| + ..children = content
|
| + ];
|
| + }
|
| +
|
| String makeExpandKey(String key) {
|
| - return '${frame.function.qualifiedName}/${key}';
|
| + return '${_frame.function.qualifiedName}/${key}';
|
| }
|
|
|
| - bool matchFrame(Frame newFrame) {
|
| - return newFrame.function.id == frame.function.id;
|
| + bool matchFrame(S.Frame newFrame) {
|
| + return newFrame.function.id == _frame.function.id;
|
| }
|
|
|
| - void updateFrame(Frame newFrame) {
|
| + void updateFrame(S.Frame newFrame) {
|
| assert(matchFrame(newFrame));
|
| - frame = newFrame;
|
| + _frame = newFrame;
|
| }
|
|
|
| - Script get script => frame.location.script;
|
| + S.Script get script => _frame.location.script;
|
|
|
| int _varsTop(varsDiv) {
|
| - const minTop = 5;
|
| + const minTop = 0;
|
| if (varsDiv == null) {
|
| return minTop;
|
| }
|
| - // TODO (cbernaschina) check if this is needed.
|
| - const navbarHeight = 40;
|
| - const bottomPad = 6;
|
| - var parent = varsDiv.parent.getBoundingClientRect();
|
| - var varsHeight = varsDiv.clientHeight;
|
| - var maxTop = parent.height - (varsHeight + bottomPad);
|
| - var adjustedTop = navbarHeight - parent.top;
|
| + final paddingTop = document.body.contentEdge.top;
|
| + final parent = varsDiv.parent.getBoundingClientRect();
|
| + final varsHeight = varsDiv.clientHeight;
|
| + final maxTop = parent.height - varsHeight;
|
| + final adjustedTop = paddingTop - parent.top;
|
| return (max(minTop, min(maxTop, adjustedTop)));
|
| }
|
|
|
| void _onScroll(event) {
|
| - if (!expanded) {
|
| + if (!_expanded || _varsDiv == null) {
|
| return;
|
| }
|
| - var varsDiv = shadowRoot.querySelector('#vars');
|
| - if (varsDiv == null) {
|
| - return;
|
| - }
|
| - var currentTop = varsDiv.style.top;
|
| - var newTop = _varsTop(varsDiv);
|
| + var currentTop = _varsDiv.style.top;
|
| + var newTop = _varsTop(_varsDiv);
|
| if (currentTop != newTop) {
|
| - varsDiv.style.top = '${newTop}px';
|
| + _varsDiv.style.top = '${newTop}px';
|
| }
|
| }
|
|
|
| void _expand() {
|
| - var frameOuter = $['frameOuter'];
|
| - expanded = true;
|
| - frameOuter.classes.add('shadow');
|
| + _expanded = true;
|
| _subscribeToScroll();
|
| + _r.dirty();
|
| }
|
|
|
| void _unexpand() {
|
| - var frameOuter = $['frameOuter'];
|
| - expanded = false;
|
| + _expanded = false;
|
| _unsubscribeToScroll();
|
| - frameOuter.classes.remove('shadow');
|
| + _r.dirty();
|
| }
|
|
|
| StreamSubscription _scrollSubscription;
|
| StreamSubscription _resizeSubscription;
|
|
|
| void _subscribeToScroll() {
|
| - if (scroller != null) {
|
| + if (_scroller != null) {
|
| if (_scrollSubscription == null) {
|
| - _scrollSubscription = scroller.onScroll.listen(_onScroll);
|
| + _scrollSubscription = _scroller.onScroll.listen(_onScroll);
|
| }
|
| if (_resizeSubscription == null) {
|
| _resizeSubscription = window.onResize.listen(_onScroll);
|
| @@ -2327,56 +2590,42 @@ class DebuggerFrameElement extends ObservatoryElement {
|
| @override
|
| void attached() {
|
| super.attached();
|
| - int windowHeight = window.innerHeight;
|
| - scriptHeight = '${windowHeight ~/ 1.6}px';
|
| - if (expanded) {
|
| + _r.enable();
|
| + if (_expanded) {
|
| _subscribeToScroll();
|
| }
|
| }
|
|
|
| void detached() {
|
| - _unsubscribeToScroll();
|
| + _r.disable(notify: true);
|
| super.detached();
|
| + _unsubscribeToScroll();
|
| }
|
|
|
| - void toggleExpand(var a, var b, var c) {
|
| - if (busy) {
|
| - return;
|
| - }
|
| - busy = true;
|
| - frame.function.load().then((func) {
|
| - _pinned = !_pinned;
|
| - if (_pinned) {
|
| - _expand();
|
| - } else {
|
| - _unexpand();
|
| - }
|
| - busy = false;
|
| - });
|
| - }
|
| -
|
| - @observable
|
| - get properLocals {
|
| - var locals = new List();
|
| - var homeMethod = frame.function.homeMethod;
|
| - if (homeMethod.dartOwner is Class && homeMethod.isStatic) {
|
| - locals.add(
|
| - {'name' : '<class>',
|
| - 'value' : homeMethod.dartOwner});
|
| - } else if (homeMethod.dartOwner is Library) {
|
| - locals.add(
|
| - {'name' : '<library>',
|
| - 'value' : homeMethod.dartOwner});
|
| + Future _toggleExpand() async {
|
| + await _frame.function.load();
|
| + _pinned = !_pinned;
|
| + if (_pinned) {
|
| + _expand();
|
| + } else {
|
| + _unexpand();
|
| }
|
| - locals.addAll(frame.variables);
|
| - return locals;
|
| }
|
| }
|
|
|
| -@CustomTag('debugger-message')
|
| -class DebuggerMessageElement extends ObservatoryElement {
|
| - @published ServiceMessage message;
|
| - @observable ServiceObject preview;
|
| +class DebuggerMessageElement extends HtmlElement implements Renderable {
|
| + static const tag = const Tag<DebuggerMessageElement>('debugger-message');
|
| +
|
| + RenderingScheduler<DebuggerMessageElement> _r;
|
| +
|
| + Stream<RenderedEvent<DebuggerMessageElement>> get onRendered => _r.onRendered;
|
| +
|
| + S.Isolate _isolate;
|
| + S.ServiceMessage _message;
|
| + S.ServiceObject _preview;
|
| + M.InstanceRepository _instances;
|
| + M.ScriptRepository _scripts;
|
| + M.EventRepository _events;
|
|
|
| // Is this the current message?
|
| bool _current = false;
|
| @@ -2384,90 +2633,207 @@ class DebuggerMessageElement extends ObservatoryElement {
|
| // Has this message been pinned open?
|
| bool _pinned = false;
|
|
|
| + bool _expanded = false;
|
| +
|
| + factory DebuggerMessageElement(S.Isolate isolate,
|
| + S.ServiceMessage message,
|
| + M.InstanceRepository instances,
|
| + M.ScriptRepository scripts,
|
| + M.EventRepository events,
|
| + {RenderingQueue queue}) {
|
| + assert(isolate != null);
|
| + assert(message != null);
|
| + assert(instances != null);
|
| + assert(instances != null);
|
| + assert(events != null);
|
| + final DebuggerMessageElement e = document.createElement(tag.name);
|
| + e._r = new RenderingScheduler(e, queue: queue);
|
| + e._isolate = isolate;
|
| + e._message = message;
|
| + e._instances = instances;
|
| + e._scripts = scripts;
|
| + e._events = events;
|
| + return e;
|
| + }
|
| +
|
| + DebuggerMessageElement.created() : super.created();
|
| +
|
| + void render() {
|
| + if (_pinned) {
|
| + classes.add('shadow');
|
| + } else {
|
| + classes.remove('shadow');
|
| + }
|
| + if (_current) {
|
| + classes.add('current');
|
| + } else {
|
| + classes.remove('current');
|
| + }
|
| + ButtonElement expandButton;
|
| + final content = <Element>[
|
| + expandButton = new ButtonElement()
|
| + ..children = _createHeader()
|
| + ..onClick.listen((e) async {
|
| + if (e.target is AnchorElement) {
|
| + return;
|
| + }
|
| + expandButton.disabled = true;
|
| + await _toggleExpand();
|
| + expandButton.disabled = false;
|
| + })
|
| + ];
|
| + if (_expanded) {
|
| + ButtonElement collapseButton;
|
| + ButtonElement previewButton;
|
| + content.addAll([
|
| + new DivElement()..classes = ['messageDetails']
|
| + ..children = [
|
| + new DivElement()..classes = ['flex-row-wrap']
|
| + ..children = [
|
| + new DivElement()..classes = ['flex-item-script']
|
| + ..children = _message.handler == null ? const []
|
| + : [
|
| + new SourceInsetElement(_isolate,
|
| + _message.handler.location,
|
| + _scripts,
|
| + _instances,
|
| + _events,
|
| + inDebuggerContext: true,
|
| + queue: _r.queue)
|
| + ],
|
| + new DivElement()..classes = ['flex-item-vars']
|
| + ..children = [
|
| + new DivElement()..classes = ['memberItem']
|
| + ..children = [
|
| + new DivElement()..classes = ['memberName'],
|
| + new DivElement()..classes = ['memberValue']
|
| + ..children = ([
|
| + previewButton = new ButtonElement()
|
| + ..text = 'preview'
|
| + ..onClick.listen((_) {
|
| + previewButton.disabled = true;
|
| +
|
| + })
|
| + ]..addAll(
|
| + _preview == null ? const []
|
| + : [
|
| + anyRef(_isolate, _preview, _instances,
|
| + queue: _r.queue)
|
| + ]
|
| + ))
|
| + ]
|
| + ]
|
| + ],
|
| + new DivElement()..classes = ['messageContractor']
|
| + ..children = [
|
| + collapseButton = new ButtonElement()
|
| + ..onClick.listen((e) async {
|
| + collapseButton.disabled = true;
|
| + await _toggleExpand();
|
| + collapseButton.disabled = false;
|
| + })
|
| + ..children = [
|
| + iconExpandLess.clone(true)
|
| + ]
|
| + ]
|
| + ]
|
| + ]);
|
| + }
|
| + children = content;
|
| + }
|
| +
|
| + void updateMessage(S.ServiceMessage message) {
|
| + assert(_message != null);
|
| + _message = message;
|
| + _r.dirty();
|
| + }
|
| +
|
| + List<Element> _createHeader() {
|
| + final content = [
|
| + new DivElement()..classes = ['messageSummaryText']
|
| + ..children = [
|
| + new DivElement()..classes = ['messageId']
|
| + ..text = 'message ${_message.index}',
|
| + new SpanElement()
|
| + ..children = _message.handler == null ? const []
|
| + : [
|
| + new FunctionRefElement(_isolate, _message.handler,
|
| + queue: _r.queue)
|
| + ],
|
| + new SpanElement()..text = ' ( ',
|
| + new SpanElement()
|
| + ..children = _message.location == null ? const []
|
| + : [
|
| + new SourceLinkElement(_isolate, _message.location, _scripts,
|
| + queue: _r.queue)
|
| + ],
|
| + new SpanElement()..text = ' )'
|
| + ]
|
| + ];
|
| + if (!_expanded) {
|
| + content.add(new DivElement()..classes = ['messageExpander']
|
| + ..children = [
|
| + iconExpandMore.clone(true)
|
| + ]);
|
| + }
|
| + return [
|
| + new DivElement()..classes = ['messageSummary']
|
| + ..children = content
|
| + ];
|
| + }
|
| +
|
| void setCurrent(bool value) {
|
| _current = value;
|
| - var messageOuter = $['messageOuter'];
|
| if (_current) {
|
| - messageOuter.classes.add('current');
|
| - expanded = true;
|
| - messageOuter.classes.add('shadow');
|
| + _expanded = true;
|
| scrollIntoView();
|
| + _r.dirty();
|
| } else {
|
| - messageOuter.classes.remove('current');
|
| - if (_pinned) {
|
| - expanded = true;
|
| - messageOuter.classes.add('shadow');
|
| - } else {
|
| - expanded = false;
|
| - messageOuter.classes.remove('shadow');
|
| - }
|
| - }
|
| - }
|
| -
|
| - @observable String scriptHeight;
|
| - @observable bool expanded = false;
|
| - @observable bool busy = false;
|
| -
|
| - DebuggerMessageElement.created() : super.created();
|
| -
|
| - void updateMessage(ServiceMessage newMessage) {
|
| - bool messageChanged =
|
| - (message.messageObjectId != newMessage.messageObjectId);
|
| - message = newMessage;
|
| - if (messageChanged) {
|
| - // Message object id has changed: clear preview and collapse.
|
| - preview = null;
|
| - if (expanded) {
|
| - toggleExpand(null, null, null);
|
| - }
|
| + _expanded = _pinned;
|
| }
|
| }
|
|
|
| @override
|
| void attached() {
|
| super.attached();
|
| - int windowHeight = window.innerHeight;
|
| - scriptHeight = '${windowHeight ~/ 1.6}px';
|
| + _r.enable();
|
| }
|
|
|
| - void toggleExpand(var a, var b, var c) {
|
| - if (busy) {
|
| - return;
|
| + @override
|
| + void detached() {
|
| + super.detached();
|
| + _r.disable(notify: true);
|
| + children = [];
|
| + }
|
| +
|
| + Future _toggleExpand() async {
|
| + var function = _message.handler;
|
| + if (function != null) {
|
| + await function.load();
|
| }
|
| - busy = true;
|
| - var function = message.handler;
|
| - var loadedFunction;
|
| - if (function == null) {
|
| - // Complete immediately.
|
| - loadedFunction = new Future.value(null);
|
| - } else {
|
| - loadedFunction = function.load();
|
| - }
|
| - loadedFunction.then((_) {
|
| - _pinned = !_pinned;
|
| - var messageOuter = $['messageOuter'];
|
| - if (_pinned) {
|
| - expanded = true;
|
| - messageOuter.classes.add('shadow');
|
| - } else {
|
| - expanded = false;
|
| - messageOuter.classes.remove('shadow');
|
| - }
|
| - busy = false;
|
| - });
|
| + _pinned = _pinned;
|
| + _expanded = true;
|
| + _r.dirty();
|
| }
|
|
|
| - Future<ServiceObject> previewMessage(_) {
|
| - return message.isolate.getObject(message.messageObjectId).then((result) {
|
| - preview = result;
|
| + Future<S.ServiceObject> previewMessage(_) {
|
| + return _message.isolate.getObject(_message.messageObjectId).then((result) {
|
| + _preview = result;
|
| return result;
|
| });
|
| }
|
| }
|
|
|
| -@CustomTag('debugger-console')
|
| -class DebuggerConsoleElement extends ObservatoryElement {
|
| - @published Isolate isolate;
|
| +class DebuggerConsoleElement extends HtmlElement implements Renderable {
|
| + static const tag = const Tag<DebuggerConsoleElement>('debugger-console');
|
| +
|
| + factory DebuggerConsoleElement() {
|
| + final DebuggerConsoleElement e = document.createElement(tag.name);
|
| + e.children = [
|
| + new BRElement()
|
| + ];
|
| + return e;
|
| + }
|
|
|
| DebuggerConsoleElement.created() : super.created();
|
|
|
| @@ -2495,9 +2861,8 @@ class DebuggerConsoleElement extends ObservatoryElement {
|
| }
|
|
|
| void _append(HtmlElement span) {
|
| - var consoleTextElement = $['consoleText'];
|
| bool autoScroll = _isScrolledToBottom(parent);
|
| - consoleTextElement.children.add(span);
|
| + children.add(span);
|
| if (autoScroll) {
|
| _scrollToBottom(parent);
|
| }
|
| @@ -2534,24 +2899,23 @@ class DebuggerConsoleElement extends ObservatoryElement {
|
| }
|
|
|
| void printStdio(List<String> lines) {
|
| - var consoleTextElement = $['consoleText'];
|
| bool autoScroll = _isScrolledToBottom(parent);
|
| for (var line in lines) {
|
| var span = new SpanElement();
|
| span.classes.add('green');
|
| span.appendText(line);
|
| span.appendText('\n');
|
| - consoleTextElement.children.add(span);
|
| + children.add(span);
|
| }
|
| if (autoScroll) {
|
| _scrollToBottom(parent);
|
| }
|
| }
|
|
|
| - void printRef(Instance ref, { bool newline:true }) {
|
| - var refElement = new Element.tag('instance-ref');
|
| - refElement.ref = ref;
|
| - _append(refElement);
|
| + void printRef(S.Isolate isolate, S.Instance ref,
|
| + M.InstanceRepository instances,{ bool newline:true }) {
|
| + _append(new InstanceRefElement(isolate, ref, instances,
|
| + queue: app.queue));
|
| if (newline) {
|
| this.newline();
|
| }
|
| @@ -2562,20 +2926,168 @@ class DebuggerConsoleElement extends ObservatoryElement {
|
| }
|
|
|
| void clear() {
|
| - var consoleTextElement = $['consoleText'];
|
| - consoleTextElement.children.clear();
|
| + children.clear();
|
| }
|
| +
|
| + ObservatoryApplication get app => ObservatoryApplication.app;
|
| }
|
|
|
| -@CustomTag('debugger-input')
|
| -class DebuggerInputElement extends ObservatoryElement {
|
| - @published Isolate isolate;
|
| - @published String text = '';
|
| - @observable ObservatoryDebugger debugger;
|
| - @observable bool busy = false;
|
| - @observable String modalPrompt = null;
|
| +class DebuggerInputElement extends HtmlElement implements Renderable {
|
| + static const tag = const Tag<DebuggerInputElement>('debugger-input');
|
| +
|
| + S.Isolate _isolate;
|
| + ObservatoryDebugger _debugger;
|
| + bool _busy = false;
|
| + final _modalPromptDiv = new DivElement()
|
| + ..classes = ['modalPrompt', 'hidden'];
|
| + final _textBox = new TextInputElement()
|
| + ..classes = ['textBox']
|
| + ..autofocus = true;
|
| + String get modalPrompt => _modalPromptDiv.text;
|
| + set modalPrompt(String value) {
|
| + if (_modalPromptDiv.text == '') {
|
| + _modalPromptDiv.classes.remove('hidden');
|
| + }
|
| + _modalPromptDiv.text = value;
|
| + if (_modalPromptDiv.text == '') {
|
| + _modalPromptDiv.classes.add('hidden');
|
| + }
|
| + }
|
| + String get text => _textBox.value;
|
| + set text(String value) => _textBox.value = value;
|
| var modalCallback = null;
|
|
|
| + factory DebuggerInputElement(S.Isolate isolate,
|
| + ObservatoryDebugger debugger) {
|
| + final DebuggerInputElement e = document.createElement(tag.name);
|
| + e.children = [
|
| + e._modalPromptDiv,
|
| + e._textBox
|
| + ];
|
| + e._textBox.select();
|
| + e._textBox.onKeyDown.listen(e._onKeyDown);
|
| + return e;
|
| + }
|
| +
|
| + DebuggerInputElement.created() : super.created();
|
| +
|
| + void _onKeyDown(KeyboardEvent e) {
|
| + if (_busy) {
|
| + e.preventDefault();
|
| + return;
|
| + }
|
| + _busy = true;
|
| + if (modalCallback != null) {
|
| + if (e.keyCode == KeyCode.ENTER) {
|
| + var response = text;
|
| + modalCallback(response).whenComplete(() {
|
| + text = '';
|
| + _busy = false;
|
| + });
|
| + } else {
|
| + _busy = false;
|
| + }
|
| + return;
|
| + }
|
| + switch (e.keyCode) {
|
| + case KeyCode.TAB:
|
| + e.preventDefault();
|
| + int cursorPos = _textBox.selectionStart;
|
| + _debugger.complete(text.substring(0, cursorPos)).then((completion) {
|
| + text = completion + text.substring(cursorPos);
|
| + // TODO(turnidge): Move the cursor to the end of the
|
| + // completion, rather than the end of the string.
|
| + }).whenComplete(() {
|
| + _busy = false;
|
| + });
|
| + break;
|
| +
|
| + case KeyCode.ENTER:
|
| + var command = text;
|
| + _debugger.run(command).whenComplete(() {
|
| + text = '';
|
| + _busy = false;
|
| + });
|
| + break;
|
| +
|
| + case KeyCode.UP:
|
| + e.preventDefault();
|
| + text = _debugger.historyPrev(text);
|
| + _busy = false;
|
| + break;
|
| +
|
| + case KeyCode.DOWN:
|
| + e.preventDefault();
|
| + text = _debugger.historyNext(text);
|
| + _busy = false;
|
| + break;
|
| +
|
| + case KeyCode.PAGE_UP:
|
| + e.preventDefault();
|
| + try {
|
| + _debugger.upFrame(1);
|
| + } on RangeError catch (_) {
|
| + // Ignore.
|
| + }
|
| + _busy = false;
|
| + break;
|
| +
|
| + case KeyCode.PAGE_DOWN:
|
| + e.preventDefault();
|
| + try {
|
| + _debugger.downFrame(1);
|
| + } on RangeError catch (_) {
|
| + // Ignore.
|
| + }
|
| + _busy = false;
|
| + break;
|
| +
|
| + case KeyCode.F7:
|
| + e.preventDefault();
|
| + _debugger.resume().whenComplete(() {
|
| + _busy = false;
|
| + });
|
| + break;
|
| +
|
| + case KeyCode.F8:
|
| + e.preventDefault();
|
| + _debugger.toggleBreakpoint().whenComplete(() {
|
| + _busy = false;
|
| + });
|
| + break;
|
| +
|
| + case KeyCode.F9:
|
| + e.preventDefault();
|
| + _debugger.smartNext().whenComplete(() {
|
| + _busy = false;
|
| + });
|
| + break;
|
| +
|
| + case KeyCode.F10:
|
| + e.preventDefault();
|
| + _debugger.step().whenComplete(() {
|
| + _busy = false;
|
| + });
|
| + break;
|
| +
|
| + case KeyCode.SEMICOLON:
|
| + if (e.ctrlKey) {
|
| + e.preventDefault();
|
| + _debugger.console.printRed('^;');
|
| + _debugger.pause().whenComplete(() {
|
| + _busy = false;
|
| + });
|
| + } else {
|
| + _busy = false;
|
| + }
|
| + break;
|
| +
|
| + default:
|
| + _busy = false;
|
| + break;
|
| + }
|
| + }
|
| +
|
| void enterMode(String prompt, callback) {
|
| assert(modalPrompt == null);
|
| modalPrompt = prompt;
|
| @@ -2588,132 +3100,81 @@ class DebuggerInputElement extends ObservatoryElement {
|
| modalCallback = null;
|
| }
|
|
|
| - @override
|
| - void ready() {
|
| - super.ready();
|
| - var textBox = $['textBox'];
|
| - textBox.select();
|
| - textBox.onKeyDown.listen((KeyboardEvent e) {
|
| - if (busy) {
|
| - e.preventDefault();
|
| - return;
|
| - }
|
| - busy = true;
|
| - if (modalCallback != null) {
|
| - if (e.keyCode == KeyCode.ENTER) {
|
| - var response = text;
|
| - modalCallback(response).whenComplete(() {
|
| - text = '';
|
| - busy = false;
|
| - });
|
| - } else {
|
| - busy = false;
|
| - }
|
| - return;
|
| - }
|
| - switch (e.keyCode) {
|
| - case KeyCode.TAB:
|
| - e.preventDefault();
|
| - int cursorPos = textBox.selectionStart;
|
| - debugger.complete(text.substring(0, cursorPos)).then((completion) {
|
| - text = completion + text.substring(cursorPos);
|
| - // TODO(turnidge): Move the cursor to the end of the
|
| - // completion, rather than the end of the string.
|
| - }).whenComplete(() {
|
| - busy = false;
|
| - });
|
| - break;
|
| -
|
| - case KeyCode.ENTER:
|
| - var command = text;
|
| - debugger.run(command).whenComplete(() {
|
| - text = '';
|
| - busy = false;
|
| - });
|
| - break;
|
| -
|
| - case KeyCode.UP:
|
| - e.preventDefault();
|
| - text = debugger.historyPrev(text);
|
| - busy = false;
|
| - break;
|
| -
|
| - case KeyCode.DOWN:
|
| - e.preventDefault();
|
| - text = debugger.historyNext(text);
|
| - busy = false;
|
| - break;
|
| -
|
| - case KeyCode.PAGE_UP:
|
| - e.preventDefault();
|
| - try {
|
| - debugger.upFrame(1);
|
| - } on RangeError catch (_) {
|
| - // Ignore.
|
| - }
|
| - busy = false;
|
| - break;
|
| -
|
| - case KeyCode.PAGE_DOWN:
|
| - e.preventDefault();
|
| - try {
|
| - debugger.downFrame(1);
|
| - } on RangeError catch (_) {
|
| - // Ignore.
|
| - }
|
| - busy = false;
|
| - break;
|
| -
|
| - case KeyCode.F7:
|
| - e.preventDefault();
|
| - debugger.resume().whenComplete(() {
|
| - busy = false;
|
| - });
|
| - break;
|
| -
|
| - case KeyCode.F8:
|
| - e.preventDefault();
|
| - debugger.toggleBreakpoint().whenComplete(() {
|
| - busy = false;
|
| - });
|
| - break;
|
| -
|
| - case KeyCode.F9:
|
| - e.preventDefault();
|
| - debugger.smartNext().whenComplete(() {
|
| - busy = false;
|
| - });
|
| - break;
|
| -
|
| - case KeyCode.F10:
|
| - e.preventDefault();
|
| - debugger.step().whenComplete(() {
|
| - busy = false;
|
| - });
|
| - break;
|
| -
|
| - case KeyCode.SEMICOLON:
|
| - if (e.ctrlKey) {
|
| - e.preventDefault();
|
| - debugger.console.printRed('^;');
|
| - debugger.pause().whenComplete(() {
|
| - busy = false;
|
| - });
|
| - } else {
|
| - busy = false;
|
| - }
|
| - break;
|
| -
|
| - default:
|
| - busy = false;
|
| - break;
|
| - }
|
| - });
|
| - }
|
| -
|
| void focus() {
|
| - $['textBox'].focus();
|
| + _textBox.focus();
|
| }
|
| -
|
| - DebuggerInputElement.created() : super.created();
|
| }
|
| +
|
| +final SvgSvgElement iconExpandLess = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PolygonElement()
|
| + ..setAttribute('points', '12,8 6,14 7.4,15.4 12,10.8 16.6,15.4 18,14 ')
|
| + ];
|
| +
|
| +final SvgSvgElement iconExpandMore = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PolygonElement()
|
| + ..setAttribute('points', '16.6,8.6 12,13.2 7.4,8.6 6,10 12,16 18,10 ')
|
| + ];
|
| +
|
| +final SvgSvgElement iconChevronRight = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PathElement()
|
| + ..setAttribute('d', 'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z')
|
| + ];
|
| +
|
| +final SvgSvgElement iconChevronLeft = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PathElement()
|
| + ..setAttribute('d', 'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z')
|
| + ];
|
| +
|
| +final SvgSvgElement iconHorizontalThreeDot = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PathElement()
|
| + ..setAttribute('d', 'M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
|
| + '2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
|
| + '2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
|
| + '2-2-.9-2-2-2z')
|
| + ];
|
| +
|
| +final SvgSvgElement iconVerticalThreeDot = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PathElement()
|
| + ..setAttribute('d', 'M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 '
|
| + '2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
|
| + '2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 '
|
| + '2-.9 2-2-.9-2-2-2z')
|
| + ];
|
| +
|
| +final SvgSvgElement iconInfo = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PathElement()
|
| + ..setAttribute('d', 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 '
|
| + '10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z')
|
| + ];
|
| +
|
| +final SvgSvgElement iconInfoOutline = new SvgSvgElement()
|
| + ..setAttribute('width', '24')
|
| + ..setAttribute('height', '24')
|
| + ..children = [
|
| + new PathElement()
|
| + ..setAttribute('d', 'M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 '
|
| + '10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 '
|
| + '0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 '
|
| + '9h2V7h-2v2z')
|
| + ];
|
|
|