Chromium Code Reviews| Index: runtime/observatory/lib/src/elements/instance_ref.dart |
| diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart |
| index cbf5eae1e83c03c7bed1108b34a91eda07aa208b..bf00296d0e69361dc353f79b7b990bb087b6c1eb 100644 |
| --- a/runtime/observatory/lib/src/elements/instance_ref.dart |
| +++ b/runtime/observatory/lib/src/elements/instance_ref.dart |
| @@ -2,41 +2,346 @@ |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| -library instance_ref_element; |
| - |
| +import 'dart:html'; |
| import 'dart:async'; |
| -import 'package:polymer/polymer.dart'; |
| -import 'package:observatory/service.dart'; |
| -import 'service_ref.dart'; |
| +import 'package:observatory/models.dart' as M; |
| +import 'package:observatory/src/elements/curly_block.dart'; |
| +import 'package:observatory/src/elements/field_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/sentinel_value.dart'; |
| + |
| +class InstanceRefElement extends HtmlElement implements Renderable { |
| + static const tag = const Tag<InstanceRefElement>('instance-ref-wrapped'); |
| + |
| + RenderingScheduler<InstanceRefElement> _r; |
| + |
| + Stream<RenderedEvent<InstanceRefElement>> get onRendered => _r.onRendered; |
| + |
| + M.IsolateRef _isolate; |
| + M.InstanceRef _instance; |
| + M.InstanceRepository _instances; |
| + M.Instance _loadedInstance; |
| + bool _expanded = false; |
| + |
| + M.IsolateRef get isolate => _isolate; |
| + M.InstanceRef get instance => _instance; |
| + |
| + factory InstanceRefElement(M.IsolateRef isolate, M.InstanceRef instance, |
| + M.InstanceRepository instances, {RenderingQueue queue}) { |
| + assert(isolate != null); |
| + assert(instance != null); |
| + assert(instances != null); |
| + InstanceRefElement e = document.createElement(tag.name); |
| + e._r = new RenderingScheduler(e, queue: queue); |
| + e._isolate = isolate; |
| + e._instance = instance; |
| + e._instances = instances; |
| + return e; |
| + } |
| -@CustomTag('instance-ref') |
| -class InstanceRefElement extends ServiceRefElement { |
| InstanceRefElement.created() : super.created(); |
| - String get hoverText { |
| - if (ref != null) { |
| - if (ref.type == 'Sentinel') { |
| - if (ref.id == 'objects/optimized-out') { |
| - return 'This object is no longer needed and has been removed by the optimizing compiler.'; |
| - } else if (ref.id == 'objects/collected') { |
| - return 'This object has been reclaimed by the garbage collector.'; |
| - } else if (ref.id == 'objects/expired') { |
| - return 'The handle to this object has expired. Consider refreshing the page.'; |
| - } else if (ref.id == 'objects/not-initialized') { |
| - return 'This object will be initialized once it is accessed by the program.'; |
| - } else if (ref.id == 'objects/being-initialized') { |
| - return 'This object is currently being initialized.'; |
| - } |
| - } |
| + @override |
| + void attached() { |
| + super.attached(); |
| + _r.enable(); |
| + } |
|
Cutch
2016/08/15 23:27:07
long line?
cbernaschina
2016/08/16 00:01:43
The long line was in the previous version.
|
| + |
| + @override |
| + void detached() { |
| + super.detached(); |
| + children = []; |
| + _r.disable(notify: true); |
| + } |
| + |
| + void render() { |
| + final content = _createLink(); |
| + |
| + if (_hasValue()) { |
| + content.addAll([ |
| + new SpanElement()..text = ' ', |
| + new CurlyBlockElement(expanded: _expanded, queue: _r.queue) |
| + ..children = [ |
| + new DivElement()..classes = ['indent'] |
| + ..children = _createValue() |
| + ] |
| + ..onToggle.listen((e) async { |
| + _expanded = e.control.expanded; |
| + if (_expanded) { |
| + e.control.disabled = true; |
| + await _refresh(); |
| + e.control.disabled = false; |
| + } |
| + }) |
| + ]); |
| + } |
| + |
| + children = content; |
| + } |
| + |
| + Future _refresh() async { |
| + _loadedInstance = await _instances.get(_instance.id); |
| + _r.dirty(); |
| + } |
| + |
| + List<Element> _createShowMoreButton() { |
| + if (_loadedInstance.count == null) { |
| + return []; |
| + } |
| + final count = _loadedInstance.count; |
| + final button = new ButtonElement() |
| + ..text = 'show next ${count}'; |
| + button.onClick.listen((_) async { |
| + button.disabled = true; |
| + _loadedInstance = await _instances.get(_instance.id, count: count * 2); |
| + _r.dirty(); |
| + }); |
| + return [button]; |
| + } |
| + |
| + List<Element> _createLink() { |
| + switch (_instance.kind) { |
| + case M.InstanceKind.vNull: |
| + case M.InstanceKind.bool: |
| + case M.InstanceKind.int: |
| + case M.InstanceKind.double: |
| + case M.InstanceKind.float32x4: |
| + case M.InstanceKind.float64x2: |
| + case M.InstanceKind.int32x4: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..text = _instance.valueAsString |
| + ]; |
| + case M.InstanceKind.string: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..text = asStringLiteral(_instance.valueAsString, |
| + _instance.valueAsStringIsTruncated) |
| + ]; |
| + case M.InstanceKind.type: |
| + case M.InstanceKind.typeRef: |
| + case M.InstanceKind.typeParameter: |
| + case M.InstanceKind.boundedType: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..text = _instance.name |
| + ]; |
| + case M.InstanceKind.closure: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..children = [ |
| + new SpanElement()..classes = ['empathize']..text = 'Closure', |
| + new SpanElement()..text = _instance.closureFunction.name |
| + ] |
| + ]; |
| + case M.InstanceKind.regExp: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..children = [ |
| + new SpanElement()..classes = ['empathize'] |
| + ..text = _instance.clazz.name, |
| + new SpanElement()..text = _instance.pattern.name |
| + ] |
| + ]; |
| + case M.InstanceKind.stackTrace: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..text = _instance.clazz.name, |
| + new CurlyBlockElement(queue: _r.queue) |
| + ..children = [ |
| + new DivElement()..classes = ['stackTraceBox'] |
| + ..text = _instance.valueAsString |
| + ] |
| + ]; |
| + case M.InstanceKind.plainInstance: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..classes = ['empathize'] |
| + ..text = _instance.clazz.name |
| + ]; |
| + case M.InstanceKind.list: |
| + case M.InstanceKind.map: |
| + case M.InstanceKind.uint8ClampedList: |
| + case M.InstanceKind.uint8List: |
| + case M.InstanceKind.uint16List: |
| + case M.InstanceKind.uint32List: |
| + case M.InstanceKind.uint64List: |
| + case M.InstanceKind.int8List: |
| + case M.InstanceKind.int16List: |
| + case M.InstanceKind.int32List: |
| + case M.InstanceKind.int64List: |
| + case M.InstanceKind.float32List: |
| + case M.InstanceKind.float64List: |
| + case M.InstanceKind.int32x4List: |
| + case M.InstanceKind.float32x4List: |
| + case M.InstanceKind.float64x2List: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..children = [ |
| + new SpanElement()..classes = ['empathize'] |
| + ..text = _instance.clazz.name, |
| + new SpanElement()..text = ' (${_instance.length})' |
| + ] |
| + ]; |
| + case M.InstanceKind.mirrorReference: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..classes = ['empathize'] |
| + ..text = _instance.clazz.name |
| + ]; |
| + case M.InstanceKind.weakProperty: |
| + return [ |
| + new AnchorElement(href: Uris.inspect(_isolate, object: _instance)) |
| + ..classes = ['empathize'] |
| + ..text = _instance.clazz.name |
| + ]; |
| + } |
| + throw new Exception('Unkown InstanceKind: ${_instance.kind}'); |
| + } |
| + |
| + bool _hasValue() { |
| + switch (_instance.kind) { |
| + case M.InstanceKind.plainInstance: |
| + case M.InstanceKind.mirrorReference: |
| + case M.InstanceKind.weakProperty: |
| + return true; |
| + case M.InstanceKind.list: |
| + case M.InstanceKind.map: |
| + case M.InstanceKind.uint8ClampedList: |
| + case M.InstanceKind.uint8List: |
| + case M.InstanceKind.uint16List: |
| + case M.InstanceKind.uint32List: |
| + case M.InstanceKind.uint64List: |
| + case M.InstanceKind.int8List: |
| + case M.InstanceKind.int16List: |
| + case M.InstanceKind.int32List: |
| + case M.InstanceKind.int64List: |
| + case M.InstanceKind.float32List: |
| + case M.InstanceKind.float64List: |
| + case M.InstanceKind.int32x4List: |
| + case M.InstanceKind.float32x4List: |
| + case M.InstanceKind.float64x2List: |
| + return _instance.length > 0; |
| + default: |
| + return false; |
| + } |
| + } |
| + List<Element> _createValue() { |
| + if (_loadedInstance == null) { |
| + return [new SpanElement()..text = 'Loading...']; |
| + } |
| + print(_instance.kind); |
| + switch (_instance.kind) { |
| + case M.InstanceKind.plainInstance: |
| + return _loadedInstance.fields.map((f) => |
| + new DivElement() |
| + ..children = [ |
| + new FieldRefElement(_isolate, f.decl, _instances, |
| + queue: _r.queue), |
| + new SpanElement()..text = ' = ', |
| + f.value.isSentinel |
| + ? new SentinelValueElement(f.value.asSentinel, queue: _r.queue) |
| + : new InstanceRefElement(_isolate, f.value.asValue, _instances, |
| + queue: _r.queue) |
| + ]).toList(); |
| + case M.InstanceKind.list: |
| + var index = 0; |
| + return _loadedInstance.elements.map((e) => |
| + new DivElement() |
| + ..children = [ |
| + new SpanElement()..text = '[ ${index++} ] : ', |
| + e.isSentinel |
| + ? new SentinelValueElement(e.asSentinel, queue: _r.queue) |
| + : anyRef(_isolate, e.asValue, _instances, queue: _r.queue) |
| + // should be: |
| + // new InstanceRefElement(_isolate, e.asValue, _instances, queue: _r.queue) |
|
Cutch
2016/08/15 23:27:07
weird indentation. Please fix the code or write a
cbernaschina
2016/08/16 00:01:43
Done.
|
| + // in some situations we obtain values that are not InstanceRef. |
| + ]).toList()..addAll(_createShowMoreButton()); |
| + case M.InstanceKind.map: |
| + return _loadedInstance.associations.map((a) => |
| + new DivElement() |
| + ..children = [ |
| + new SpanElement()..text = '[ ', |
| + a.key.isSentinel |
| + ? new SentinelValueElement(a.key.asSentinel, queue: _r.queue) |
| + : new InstanceRefElement(_isolate, a.key.asValue, _instances, |
| + queue: _r.queue), |
| + new SpanElement()..text = ' ] : ', |
| + a.value.isSentinel |
| + ? new SentinelValueElement(a.value.asSentinel, queue: _r.queue) |
| + : new InstanceRefElement(_isolate, a.value.asValue, _instances, |
| + queue: _r.queue) |
| + ]).toList()..addAll(_createShowMoreButton()); |
| + case M.InstanceKind.uint8ClampedList: |
| + case M.InstanceKind.uint8List: |
| + case M.InstanceKind.uint16List: |
| + case M.InstanceKind.uint32List: |
| + case M.InstanceKind.uint64List: |
| + case M.InstanceKind.int8List: |
| + case M.InstanceKind.int16List: |
| + case M.InstanceKind.int32List: |
| + case M.InstanceKind.int64List: |
| + case M.InstanceKind.float32List: |
| + case M.InstanceKind.float64List: |
| + case M.InstanceKind.int32x4List: |
| + case M.InstanceKind.float32x4List: |
| + case M.InstanceKind.float64x2List: |
| + var index = 0; |
| + return _loadedInstance.typedElements |
| + .map((e) => new DivElement()..text = '[ ${index++} ] : $e') |
| + .toList()..addAll(_createShowMoreButton()); |
| + break; |
| + case M.InstanceKind.mirrorReference: |
| + return [ |
| + new SpanElement()..text = '<referent> : ', |
| + new InstanceRefElement(_isolate, _loadedInstance.referent, _instances, |
| + queue: _r.queue) |
| + ]; |
| + case M.InstanceKind.weakProperty: |
| + return [ |
| + new SpanElement()..text = '<key> : ', |
| + new InstanceRefElement(_isolate, _loadedInstance.key, _instances, |
| + queue: _r.queue), |
| + new BRElement(), |
| + new SpanElement()..text = '<value> : ', |
| + new InstanceRefElement(_isolate, _loadedInstance.value, _instances, |
| + queue: _r.queue), |
| + ]; |
| + default: |
| + return []; |
| } |
| - return super.hoverText; |
| } |
| - // TODO(turnidge): This is here to workaround vm/dart2js differences. |
| - dynamic expander() { |
| - return expandEvent; |
| + static String asStringLiteral(String value, [bool wasTruncated=false]) { |
| + var result = new List(); |
| + result.add("'".codeUnitAt(0)); |
| + for (int codeUnit in value.codeUnits) { |
| + if (codeUnit == '\n'.codeUnitAt(0)) result.addAll('\\n'.codeUnits); |
| + else if (codeUnit == '\r'.codeUnitAt(0)) result.addAll('\\r'.codeUnits); |
| + else if (codeUnit == '\f'.codeUnitAt(0)) result.addAll('\\f'.codeUnits); |
| + else if (codeUnit == '\b'.codeUnitAt(0)) result.addAll('\\b'.codeUnits); |
| + else if (codeUnit == '\t'.codeUnitAt(0)) result.addAll('\\t'.codeUnits); |
| + else if (codeUnit == '\v'.codeUnitAt(0)) result.addAll('\\v'.codeUnits); |
| + else if (codeUnit == '\$'.codeUnitAt(0)) result.addAll('\\\$'.codeUnits); |
| + else if (codeUnit == '\\'.codeUnitAt(0)) result.addAll('\\\\'.codeUnits); |
| + else if (codeUnit == "'".codeUnitAt(0)) result.addAll("'".codeUnits); |
| + else if (codeUnit < 32) { |
| + var escapeSequence = "\\u" + codeUnit.toRadixString(16).padLeft(4, "0"); |
| + result.addAll(escapeSequence.codeUnits); |
| + } else result.add(codeUnit); |
| + } |
| + if (wasTruncated) { |
| + result.addAll("...".codeUnits); |
| + } else { |
| + result.add("'".codeUnitAt(0)); |
| + } |
| + return new String.fromCharCodes(result); |
| } |
| + /* |
|
Cutch
2016/08/15 23:27:07
dead code?
cbernaschina
2016/08/16 00:01:43
Done.
|
| void expandEvent(bool expand, Function onDone) { |
| assert(ref is Instance); |
| if (expand) { |
| @@ -70,4 +375,5 @@ class InstanceRefElement extends ServiceRefElement { |
| await instance.reload(count: instance.typedElements.length * 2); |
| } |
| } |
| + */ |
| } |