Commit 1f40d96f authored by Hixie's avatar Hixie

Improve debugging output

Teach dumpRenderTree() to draw actual trees.
Make the TextStyle output terser so it doesn't overflow the output.
Make debugDumpApp() say what mode we're in (checked vs release).
Hide lifecycle state from release mode dumps (since it's checked-only state).
parent 6e91cfa4
...@@ -11,6 +11,7 @@ import 'dart:ui' as ui; ...@@ -11,6 +11,7 @@ import 'dart:ui' as ui;
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'stock_data.dart'; import 'stock_data.dart';
......
...@@ -112,7 +112,7 @@ class StockHomeState extends State<StockHome> { ...@@ -112,7 +112,7 @@ class StockHomeState extends State<StockHome> {
), ),
new DrawerItem( new DrawerItem(
icon: 'device/dvr', icon: 'device/dvr',
onPressed: () { debugDumpApp(); }, onPressed: () { debugDumpApp(); debugDumpRenderTree(); },
child: new Text('Dump App to Console') child: new Text('Dump App to Console')
), ),
new DrawerDivider(), new DrawerDivider(),
......
...@@ -252,25 +252,131 @@ class TextStyle { ...@@ -252,25 +252,131 @@ class TextStyle {
List<String> result = <String>[]; List<String> result = <String>[];
if (color != null) if (color != null)
result.add('${prefix}color: $color'); result.add('${prefix}color: $color');
// TODO(hansmuller): escape the fontFamily string.
if (fontFamily != null) if (fontFamily != null)
result.add('${prefix}fontFamily: "$fontFamily"'); result.add('${prefix}family: "$fontFamily"');
if (fontSize != null) if (fontSize != null)
result.add('${prefix}fontSize: $fontSize'); result.add('${prefix}size: $fontSize');
if (fontWeight != null) if (fontWeight != null) {
result.add('${prefix}fontWeight: $fontWeight'); switch (fontWeight) {
if (fontStyle != null) case FontWeight.w100:
result.add('${prefix}fontStyle: $fontStyle'); result.add('${prefix}weight: 100');
if (textAlign != null) break;
result.add('${prefix}textAlign: $textAlign'); case FontWeight.w200:
if (textBaseline != null) result.add('${prefix}weight: 200');
result.add('${prefix}textBaseline: $textBaseline'); break;
if (decoration != null) case FontWeight.w300:
result.add('${prefix}decoration: $decoration'); result.add('${prefix}weight: 300');
if (decorationColor != null) break;
result.add('${prefix}decorationColor: $decorationColor'); case FontWeight.w400:
if (decorationStyle != null) result.add('${prefix}weight: 400');
result.add('${prefix}decorationStyle: $decorationStyle'); break;
case FontWeight.w500:
result.add('${prefix}weight: 500');
break;
case FontWeight.w600:
result.add('${prefix}weight: 600');
break;
case FontWeight.w700:
result.add('${prefix}weight: 700');
break;
case FontWeight.w800:
result.add('${prefix}weight: 800');
break;
case FontWeight.w900:
result.add('${prefix}weight: 900');
break;
}
}
if (fontStyle != null) {
switch (fontStyle) {
case FontStyle.normal:
result.add('${prefix}style: normal');
break;
case FontStyle.italic:
result.add('${prefix}style: italic');
break;
}
}
if (textAlign != null) {
switch (textAlign) {
case TextAlign.left:
result.add('${prefix}align: left');
break;
case TextAlign.right:
result.add('${prefix}align: right');
break;
case TextAlign.center:
result.add('${prefix}align: center');
break;
}
}
if (textBaseline != null) {
switch (textBaseline) {
case TextBaseline.alphabetic:
result.add('${prefix}baseline: alphabetic');
break;
case TextBaseline.ideographic:
result.add('${prefix}baseline: ideographic');
break;
}
}
if (decoration != null || decorationColor != null || decorationStyle != null) {
String decorationDescription = '${prefix}decoration: ';
bool haveDecorationDescription = false;
if (decorationStyle != null) {
switch (decorationStyle) {
case TextDecorationStyle.solid:
decorationDescription += 'solid';
break;
case TextDecorationStyle.double:
decorationDescription += 'double';
break;
case TextDecorationStyle.dotted:
decorationDescription += 'dotted';
break;
case TextDecorationStyle.dashed:
decorationDescription += 'dashed';
break;
case TextDecorationStyle.wavy:
decorationDescription += 'wavy';
break;
}
haveDecorationDescription = true;
}
if (decorationColor != null) {
if (haveDecorationDescription)
decorationDescription += ' ';
decorationDescription += '$decorationColor';
haveDecorationDescription = true;
}
if (decoration != null) {
if (haveDecorationDescription)
decorationDescription += ' ';
bool multipleDecorations = false;
for (TextDecoration value in decoration) {
if (multipleDecorations)
decorationDescription += '+';
switch (value) {
case TextDecoration.none:
decorationDescription += 'none';
break;
case TextDecoration.underline:
decorationDescription += 'underline';
break;
case TextDecoration.overline:
decorationDescription += 'overline';
break;
case TextDecoration.lineThrough:
decorationDescription += 'line-through';
break;
}
multipleDecorations = true;
}
haveDecorationDescription = true;
}
assert(haveDecorationDescription);
result.add(decorationDescription);
}
if (result.isEmpty) if (result.isEmpty)
return '$prefix<no style specified>'; return '$prefix<no style specified>';
return result.join('\n'); return result.join('\n');
......
...@@ -1139,11 +1139,18 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -1139,11 +1139,18 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// Returns a description of the tree rooted at this node. /// Returns a description of the tree rooted at this node.
/// If the prefix argument is provided, then every line in the output /// If the prefix argument is provided, then every line in the output
/// will be prefixed by that string. /// will be prefixed by that string.
String toStringDeep([String prefix = '']) { String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) {
RenderObject debugPreviousActiveLayout = _debugActiveLayout; RenderObject debugPreviousActiveLayout = _debugActiveLayout;
_debugActiveLayout = null; _debugActiveLayout = null;
prefix += ' '; String result = '$prefixLineOne$this\n';
String result = '$this\n${debugDescribeSettings(prefix)}${debugDescribeChildren(prefix)}'; final String childrenDescription = debugDescribeChildren(prefixOtherLines);
final String settingsPrefix = childrenDescription != '' ? '$prefixOtherLines \u2502 ' : '$prefixOtherLines ';
result += debugDescribeSettings(settingsPrefix);
if (childrenDescription != '')
result += '$prefixOtherLines \u2502\n';
else
result += '$prefixOtherLines\n';
result += childrenDescription;
_debugActiveLayout = debugPreviousActiveLayout; _debugActiveLayout = debugPreviousActiveLayout;
return result; return result;
} }
...@@ -1198,7 +1205,7 @@ abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> implem ...@@ -1198,7 +1205,7 @@ abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> implem
} }
String debugDescribeChildren(String prefix) { String debugDescribeChildren(String prefix) {
if (child != null) if (child != null)
return '${prefix}child: ${child.toStringDeep(prefix)}'; return '${child.toStringDeep("$prefix \u2514\u2500child: ", "$prefix ")}';
return ''; return '';
} }
} }
...@@ -1442,13 +1449,19 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent ...@@ -1442,13 +1449,19 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
String debugDescribeChildren(String prefix) { String debugDescribeChildren(String prefix) {
String result = ''; String result = '';
int count = 1; if (_firstChild != null) {
ChildType child = _firstChild; ChildType child = _firstChild;
while (child != null) { int count = 1;
result += '${prefix}child $count: ${child.toStringDeep(prefix)}'; while (child != _lastChild) {
count += 1; result += '${child.toStringDeep("$prefix \u251C\u2500child $count: ", "$prefix \u2502")}';
final ParentDataType childParentData = child.parentData; count += 1;
child = childParentData.nextSibling; final ParentDataType childParentData = child.parentData;
child = childParentData.nextSibling;
}
if (child != null) {
assert(child == _lastChild);
result += '${child.toStringDeep("$prefix \u2514\u2500child $count: ", "$prefix ")}';
}
} }
return result; return result;
} }
......
...@@ -883,6 +883,7 @@ class FractionalOffset { ...@@ -883,6 +883,7 @@ class FractionalOffset {
value = 37 * value + y.hashCode; value = 37 * value + y.hashCode;
return value; return value;
} }
String toString() => '$runtimeType($x, $y)';
} }
/// Applies a transformation before painting its child /// Applies a transformation before painting its child
...@@ -1016,7 +1017,7 @@ class RenderTransform extends RenderProxyBox { ...@@ -1016,7 +1017,7 @@ class RenderTransform extends RenderProxyBox {
String debugDescribeSettings(String prefix) { String debugDescribeSettings(String prefix) {
List<String> result = _transform.toString().split('\n').map((String s) => '$prefix $s\n').toList(); List<String> result = _transform.toString().split('\n').map((String s) => '$prefix $s\n').toList();
result.removeLast(); result.removeLast();
return '${super.debugDescribeSettings(prefix)}${prefix}transform matrix:\n${result.join()}\n${prefix}origin: $origin\n'; return '${super.debugDescribeSettings(prefix)}${prefix}transform matrix:\n${result.join()}\n${prefix}origin: $origin\nalignment: $alignment\n';
} }
} }
......
...@@ -92,6 +92,9 @@ void runApp(Widget app) { ...@@ -92,6 +92,9 @@ void runApp(Widget app) {
void debugDumpApp() { void debugDumpApp() {
assert(WidgetFlutterBinding.instance != null); assert(WidgetFlutterBinding.instance != null);
assert(WidgetFlutterBinding.instance.renderViewElement != null); assert(WidgetFlutterBinding.instance.renderViewElement != null);
String mode = 'RELEASE MODE';
assert(() { mode = 'CHECKED MODE'; return true; });
print('${WidgetFlutterBinding.instance.runtimeType} - $mode');
WidgetFlutterBinding.instance.renderViewElement.toStringDeep().split('\n').forEach(print); WidgetFlutterBinding.instance.renderViewElement.toStringDeep().split('\n').forEach(print);
} }
......
...@@ -394,8 +394,11 @@ abstract class State<T extends StatefulComponent> { ...@@ -394,8 +394,11 @@ abstract class State<T extends StatefulComponent> {
void debugFillDescription(List<String> description) { void debugFillDescription(List<String> description) {
description.add('$hashCode'); description.add('$hashCode');
if (_debugLifecycleState != _StateLifecycle.ready) assert(() {
description.add('$_debugLifecycleState'); if (_debugLifecycleState != _StateLifecycle.ready)
description.add('$_debugLifecycleState');
return true;
});
if (_config == null) if (_config == null)
description.add('no config'); description.add('no config');
if (_element == null) if (_element == null)
...@@ -829,9 +832,7 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -829,9 +832,7 @@ abstract class Element<T extends Widget> implements BuildContext {
String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) { String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) {
String result = '$prefixLineOne$this\n'; String result = '$prefixLineOne$this\n';
List<Element> children = <Element>[]; List<Element> children = <Element>[];
visitChildren((Element child) { visitChildren(children.add);
children.add(child);
});
if (children.length > 0) { if (children.length > 0) {
Element last = children.removeLast(); Element last = children.removeLast();
for (Element child in children) for (Element child in children)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment