您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
1585 行
52 KiB
1585 行
52 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Unity.UIWidgets.ui;
|
|
|
|
namespace Unity.UIWidgets.foundation {
|
|
public enum DiagnosticLevel {
|
|
hidden,
|
|
fine,
|
|
debug,
|
|
info,
|
|
warning,
|
|
error,
|
|
off,
|
|
}
|
|
|
|
public enum DiagnosticsTreeStyle {
|
|
sparse,
|
|
offstage,
|
|
dense,
|
|
transition,
|
|
whitespace,
|
|
singleLine,
|
|
}
|
|
|
|
public class TextTreeConfiguration {
|
|
public TextTreeConfiguration(
|
|
string prefixLineOne = null,
|
|
string prefixOtherLines = null,
|
|
string prefixLastChildLineOne = null,
|
|
string prefixOtherLinesRootNode = null,
|
|
string linkCharacter = null,
|
|
string propertyPrefixIfChildren = null,
|
|
string propertyPrefixNoChildren = null,
|
|
string lineBreak = "\n",
|
|
bool lineBreakProperties = true,
|
|
string afterName = ":",
|
|
string afterDescriptionIfBody = "",
|
|
string beforeProperties = "",
|
|
string afterProperties = "",
|
|
string propertySeparator = "",
|
|
string bodyIndent = "",
|
|
string footer = "",
|
|
bool showChildren = true,
|
|
bool addBlankLineIfNoChildren = true,
|
|
bool isNameOnOwnLine = false,
|
|
bool isBlankLineBetweenPropertiesAndChildren = true
|
|
) {
|
|
D.assert(prefixLineOne != null);
|
|
D.assert(prefixOtherLines != null);
|
|
D.assert(prefixLastChildLineOne != null);
|
|
D.assert(prefixOtherLinesRootNode != null);
|
|
D.assert(linkCharacter != null);
|
|
D.assert(propertyPrefixIfChildren != null);
|
|
D.assert(propertyPrefixNoChildren != null);
|
|
D.assert(lineBreak != null);
|
|
D.assert(afterName != null);
|
|
D.assert(afterDescriptionIfBody != null);
|
|
D.assert(beforeProperties != null);
|
|
D.assert(afterProperties != null);
|
|
D.assert(propertySeparator != null);
|
|
D.assert(bodyIndent != null);
|
|
D.assert(footer != null);
|
|
|
|
this.prefixLineOne = prefixLineOne;
|
|
this.prefixOtherLines = prefixOtherLines;
|
|
this.prefixLastChildLineOne = prefixLastChildLineOne;
|
|
this.prefixOtherLinesRootNode = prefixOtherLinesRootNode;
|
|
this.propertyPrefixIfChildren = propertyPrefixIfChildren;
|
|
this.propertyPrefixNoChildren = propertyPrefixNoChildren;
|
|
this.linkCharacter = linkCharacter;
|
|
this.childLinkSpace = new string(' ', linkCharacter.Length);
|
|
this.lineBreak = lineBreak;
|
|
this.lineBreakProperties = lineBreakProperties;
|
|
this.afterName = afterName;
|
|
this.afterDescriptionIfBody = afterDescriptionIfBody;
|
|
this.beforeProperties = beforeProperties;
|
|
this.afterProperties = afterProperties;
|
|
this.propertySeparator = propertySeparator;
|
|
this.bodyIndent = bodyIndent;
|
|
this.showChildren = showChildren;
|
|
this.addBlankLineIfNoChildren = addBlankLineIfNoChildren;
|
|
this.isNameOnOwnLine = isNameOnOwnLine;
|
|
this.footer = footer;
|
|
this.isBlankLineBetweenPropertiesAndChildren = isBlankLineBetweenPropertiesAndChildren;
|
|
}
|
|
|
|
public readonly string prefixLineOne;
|
|
|
|
public readonly string prefixOtherLines;
|
|
|
|
public readonly string prefixLastChildLineOne;
|
|
|
|
public readonly string prefixOtherLinesRootNode;
|
|
|
|
public readonly string propertyPrefixIfChildren;
|
|
|
|
public readonly string propertyPrefixNoChildren;
|
|
|
|
public readonly string linkCharacter;
|
|
|
|
public readonly string childLinkSpace;
|
|
|
|
public readonly string lineBreak;
|
|
|
|
public readonly bool lineBreakProperties;
|
|
|
|
public readonly string afterName;
|
|
|
|
public readonly string afterDescriptionIfBody;
|
|
|
|
public readonly string beforeProperties;
|
|
|
|
public readonly string afterProperties;
|
|
|
|
public readonly string propertySeparator;
|
|
|
|
public readonly string bodyIndent;
|
|
|
|
public readonly bool showChildren;
|
|
|
|
public readonly bool addBlankLineIfNoChildren;
|
|
|
|
public readonly bool isNameOnOwnLine;
|
|
|
|
public readonly string footer;
|
|
|
|
public readonly bool isBlankLineBetweenPropertiesAndChildren;
|
|
}
|
|
|
|
class _PrefixedstringBuilder {
|
|
internal _PrefixedstringBuilder(string prefixLineOne, string prefixOtherLines) {
|
|
this.prefixLineOne = prefixLineOne;
|
|
this.prefixOtherLines = prefixOtherLines;
|
|
}
|
|
|
|
public readonly string prefixLineOne;
|
|
|
|
public string prefixOtherLines;
|
|
|
|
readonly StringBuilder _buffer = new StringBuilder();
|
|
bool _atLineStart = true;
|
|
bool _hasMultipleLines = false;
|
|
|
|
public bool hasMultipleLines {
|
|
get { return this._hasMultipleLines; }
|
|
}
|
|
|
|
public void write(string s) {
|
|
if (s.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
if (s == "\n") {
|
|
if (this._buffer.Length == 0) {
|
|
this._buffer.Append(this.prefixLineOne.TrimEnd());
|
|
}
|
|
else if (this._atLineStart) {
|
|
this._buffer.Append(this.prefixOtherLines.TrimEnd());
|
|
this._hasMultipleLines = true;
|
|
}
|
|
|
|
this._buffer.Append("\n");
|
|
this._atLineStart = true;
|
|
return;
|
|
}
|
|
|
|
if (this._buffer.Length == 0) {
|
|
this._buffer.Append(this.prefixLineOne);
|
|
}
|
|
else if (this._atLineStart) {
|
|
this._buffer.Append(this.prefixOtherLines);
|
|
this._hasMultipleLines = true;
|
|
}
|
|
|
|
bool lineTerminated = false;
|
|
|
|
if (s.EndsWith("\n")) {
|
|
s = s.Substring(0, s.Length - 1);
|
|
lineTerminated = true;
|
|
}
|
|
|
|
var parts = s.Split('\n');
|
|
this._buffer.Append(parts[0]);
|
|
for (int i = 1; i < parts.Length; ++i) {
|
|
this._buffer.Append("\n")
|
|
.Append(this.prefixOtherLines)
|
|
.Append(parts[i]);
|
|
}
|
|
|
|
if (lineTerminated) {
|
|
this._buffer.Append("\n");
|
|
}
|
|
|
|
this._atLineStart = lineTerminated;
|
|
}
|
|
|
|
public void writeRaw(string text) {
|
|
if (text.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
this._buffer.Append(text);
|
|
this._atLineStart = text.EndsWith("\n");
|
|
}
|
|
|
|
|
|
public void writeRawLine(string line) {
|
|
if (line.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
this._buffer.Append(line);
|
|
if (!line.EndsWith("\n")) {
|
|
this._buffer.Append('\n');
|
|
}
|
|
|
|
this._atLineStart = true;
|
|
}
|
|
|
|
public override string ToString() {
|
|
return this._buffer.ToString();
|
|
}
|
|
}
|
|
|
|
class _NoDefaultValue {
|
|
internal _NoDefaultValue() {
|
|
}
|
|
}
|
|
|
|
class _NullDefaultValue {
|
|
internal _NullDefaultValue() {
|
|
}
|
|
}
|
|
|
|
public abstract class DiagnosticsNode {
|
|
protected DiagnosticsNode(
|
|
string name = null,
|
|
DiagnosticsTreeStyle? style = null,
|
|
bool showName = true,
|
|
bool showSeparator = true
|
|
) {
|
|
D.assert(name == null || !name.EndsWith(":"),
|
|
"Names of diagnostic nodes must not end with colons.");
|
|
this.name = name;
|
|
this._style = style;
|
|
this._showName = showName;
|
|
this.showSeparator = showSeparator;
|
|
}
|
|
|
|
public static DiagnosticsNode message(
|
|
string message,
|
|
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.singleLine,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) {
|
|
return new DiagnosticsProperty<object>(
|
|
"",
|
|
null,
|
|
description: message,
|
|
style: style,
|
|
showName: false,
|
|
level: level
|
|
);
|
|
}
|
|
|
|
public readonly string name;
|
|
|
|
public abstract string toDescription(
|
|
TextTreeConfiguration parentConfiguration = null
|
|
);
|
|
|
|
public readonly bool showSeparator;
|
|
|
|
public bool isFiltered(DiagnosticLevel minLevel) {
|
|
return this.level < minLevel;
|
|
}
|
|
|
|
public virtual DiagnosticLevel level {
|
|
get { return DiagnosticLevel.info; }
|
|
}
|
|
|
|
public virtual bool showName {
|
|
get { return this._showName; }
|
|
}
|
|
|
|
readonly bool _showName;
|
|
|
|
public virtual string emptyBodyDescription {
|
|
get { return null; }
|
|
}
|
|
|
|
public abstract object valueObject { get; }
|
|
|
|
public virtual DiagnosticsTreeStyle? style {
|
|
get { return this._style; }
|
|
}
|
|
|
|
readonly DiagnosticsTreeStyle? _style;
|
|
|
|
public abstract List<DiagnosticsNode> getProperties();
|
|
|
|
public abstract List<DiagnosticsNode> getChildren();
|
|
|
|
string _separator {
|
|
get { return this.showSeparator ? ":" : ""; }
|
|
}
|
|
|
|
public virtual Dictionary<string, object> toJsonMap() {
|
|
var data = new Dictionary<string, object> {
|
|
{"name", this.name},
|
|
{"showSeparator", this.showSeparator},
|
|
{"description", this.toDescription()},
|
|
{"level", Convert.ToString(this.level)},
|
|
{"showName", this.showName},
|
|
{"emptyBodyDescription", this.emptyBodyDescription},
|
|
{"style", Convert.ToString(this.style)},
|
|
{"valueToString", Convert.ToString(this.valueObject)},
|
|
{"type", this.GetType().ToString()},
|
|
{"hasChildren", this.getChildren().isNotEmpty()}
|
|
};
|
|
return data;
|
|
}
|
|
|
|
public override string ToString() {
|
|
return this.toString();
|
|
}
|
|
|
|
public virtual string toString(
|
|
TextTreeConfiguration parentConfiguration = null,
|
|
DiagnosticLevel minLevel = DiagnosticLevel.info
|
|
) {
|
|
D.assert(this.style != null);
|
|
if (this.style == DiagnosticsTreeStyle.singleLine) {
|
|
return this.toStringDeep(parentConfiguration: parentConfiguration, minLevel: minLevel);
|
|
}
|
|
|
|
var description = this.toDescription(parentConfiguration: parentConfiguration);
|
|
if (this.name.isEmpty() || !this.showName) {
|
|
return description;
|
|
}
|
|
|
|
return description.Contains("\n")
|
|
? this.name + this._separator + "\n" + description
|
|
: this.name + this._separator + description;
|
|
}
|
|
|
|
protected TextTreeConfiguration textTreeConfiguration {
|
|
get {
|
|
D.assert(this.style != null);
|
|
switch (this.style) {
|
|
case DiagnosticsTreeStyle.dense:
|
|
return Diagnostics.denseTextConfiguration;
|
|
case DiagnosticsTreeStyle.sparse:
|
|
return Diagnostics.sparseTextConfiguration;
|
|
case DiagnosticsTreeStyle.offstage:
|
|
return Diagnostics.dashedTextConfiguration;
|
|
case DiagnosticsTreeStyle.whitespace:
|
|
return Diagnostics.whitespaceTextConfiguration;
|
|
case DiagnosticsTreeStyle.transition:
|
|
return Diagnostics.transitionTextConfiguration;
|
|
case DiagnosticsTreeStyle.singleLine:
|
|
return Diagnostics.singleLineTextConfiguration;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
TextTreeConfiguration _childTextConfiguration(
|
|
DiagnosticsNode child,
|
|
TextTreeConfiguration textStyle
|
|
) {
|
|
return child != null && child.style != DiagnosticsTreeStyle.singleLine
|
|
? child.textTreeConfiguration
|
|
: textStyle;
|
|
}
|
|
|
|
public string toStringDeep(
|
|
string prefixLineOne = "",
|
|
string prefixOtherLines = null,
|
|
TextTreeConfiguration parentConfiguration = null,
|
|
DiagnosticLevel minLevel = DiagnosticLevel.debug
|
|
) {
|
|
prefixOtherLines = prefixOtherLines ?? prefixLineOne;
|
|
|
|
var children = this.getChildren();
|
|
var config = this.textTreeConfiguration;
|
|
if (prefixOtherLines.isEmpty()) {
|
|
prefixOtherLines += config.prefixOtherLinesRootNode;
|
|
}
|
|
|
|
var builder = new _PrefixedstringBuilder(
|
|
prefixLineOne,
|
|
prefixOtherLines
|
|
);
|
|
|
|
var description = this.toDescription(parentConfiguration: parentConfiguration);
|
|
if (description.isEmpty()) {
|
|
if (this.name.isNotEmpty() && this.showName) {
|
|
builder.write(this.name);
|
|
}
|
|
}
|
|
else {
|
|
if (this.name.isNotEmpty() && this.showName) {
|
|
builder.write(this.name);
|
|
if (this.showSeparator) {
|
|
builder.write(config.afterName);
|
|
}
|
|
|
|
builder.write(
|
|
config.isNameOnOwnLine || description.Contains("\n") ? "\n" : "");
|
|
if (description.Contains("\n") && this.style == DiagnosticsTreeStyle.singleLine) {
|
|
builder.prefixOtherLines += " ";
|
|
}
|
|
}
|
|
|
|
builder.prefixOtherLines +=
|
|
children.isEmpty() ? config.propertyPrefixNoChildren : config.propertyPrefixIfChildren;
|
|
builder.write(description);
|
|
}
|
|
|
|
var properties = this.getProperties().Where(n => !n.isFiltered(minLevel)).ToList();
|
|
|
|
if (properties.isNotEmpty() || children.isNotEmpty() || this.emptyBodyDescription != null) {
|
|
builder.write(config.afterDescriptionIfBody);
|
|
}
|
|
|
|
if (config.lineBreakProperties) {
|
|
builder.write(config.lineBreak);
|
|
}
|
|
|
|
if (properties.isNotEmpty()) {
|
|
builder.write(config.beforeProperties);
|
|
}
|
|
|
|
builder.prefixOtherLines += config.bodyIndent;
|
|
if (this.emptyBodyDescription != null &&
|
|
properties.isEmpty() &&
|
|
children.isEmpty() &&
|
|
prefixLineOne.isNotEmpty()) {
|
|
builder.write(this.emptyBodyDescription);
|
|
if (config.lineBreakProperties) {
|
|
builder.write(config.lineBreak);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < properties.Count; ++i) {
|
|
DiagnosticsNode property = properties[i];
|
|
if (i > 0) {
|
|
builder.write(config.propertySeparator);
|
|
}
|
|
|
|
const int kWrapWidth = 65;
|
|
if (property.style != DiagnosticsTreeStyle.singleLine) {
|
|
TextTreeConfiguration propertyStyle = property.textTreeConfiguration;
|
|
builder.writeRaw(property.toStringDeep(
|
|
prefixLineOne: builder.prefixOtherLines + propertyStyle.prefixLineOne,
|
|
prefixOtherLines: builder.prefixOtherLines + propertyStyle.linkCharacter +
|
|
propertyStyle.prefixOtherLines,
|
|
parentConfiguration: config,
|
|
minLevel: minLevel
|
|
));
|
|
continue;
|
|
}
|
|
|
|
D.assert(property.style == DiagnosticsTreeStyle.singleLine);
|
|
string message = property.toString(parentConfiguration: config, minLevel: minLevel);
|
|
if (!config.lineBreakProperties || message.Length < kWrapWidth) {
|
|
builder.write(message);
|
|
}
|
|
else {
|
|
var lines = message.Split('\n');
|
|
for (int j = 0; j < lines.Length; ++j) {
|
|
string line = lines[j];
|
|
if (j > 0) {
|
|
builder.write(config.lineBreak);
|
|
}
|
|
|
|
builder.write(string.Join("\n",
|
|
DebugPrint.debugWordWrap(line, kWrapWidth, wrapIndent: " ").ToArray()));
|
|
}
|
|
}
|
|
|
|
if (config.lineBreakProperties) {
|
|
builder.write(config.lineBreak);
|
|
}
|
|
}
|
|
|
|
if (properties.isNotEmpty()) {
|
|
builder.write(config.afterProperties);
|
|
}
|
|
|
|
if (!config.lineBreakProperties) {
|
|
builder.write(config.lineBreak);
|
|
}
|
|
|
|
var prefixChildren = prefixOtherLines + config.bodyIndent;
|
|
if (children.isEmpty() &&
|
|
config.addBlankLineIfNoChildren &&
|
|
builder.hasMultipleLines) {
|
|
string prefix = prefixChildren.TrimEnd();
|
|
if (prefix.isNotEmpty()) {
|
|
builder.writeRaw(prefix + config.lineBreak);
|
|
}
|
|
}
|
|
|
|
if (children.isNotEmpty() && config.showChildren) {
|
|
if (config.isBlankLineBetweenPropertiesAndChildren &&
|
|
properties.isNotEmpty() &&
|
|
children.First().textTreeConfiguration.isBlankLineBetweenPropertiesAndChildren) {
|
|
builder.write(config.lineBreak);
|
|
}
|
|
|
|
for (int i = 0; i < children.Count; i++) {
|
|
DiagnosticsNode child = children[i];
|
|
D.assert(child != null);
|
|
TextTreeConfiguration childConfig = this._childTextConfiguration(child, config);
|
|
if (i == children.Count - 1) {
|
|
string lastChildPrefixLineOne = prefixChildren + childConfig.prefixLastChildLineOne;
|
|
builder.writeRawLine(child.toStringDeep(
|
|
prefixLineOne: lastChildPrefixLineOne,
|
|
prefixOtherLines: prefixChildren + childConfig.childLinkSpace +
|
|
childConfig.prefixOtherLines,
|
|
parentConfiguration: config,
|
|
minLevel: minLevel
|
|
));
|
|
if (childConfig.footer.isNotEmpty()) {
|
|
builder.writeRaw(prefixChildren + childConfig.childLinkSpace + childConfig.footer);
|
|
}
|
|
}
|
|
else {
|
|
TextTreeConfiguration nextChildStyle = this._childTextConfiguration(children[i + 1], config);
|
|
string childPrefixLineOne = prefixChildren + childConfig.prefixLineOne;
|
|
string childPrefixOtherLines =
|
|
prefixChildren + nextChildStyle.linkCharacter + childConfig.prefixOtherLines;
|
|
builder.writeRawLine(child.toStringDeep(
|
|
prefixLineOne: childPrefixLineOne,
|
|
prefixOtherLines: childPrefixOtherLines,
|
|
parentConfiguration: config,
|
|
minLevel: minLevel
|
|
));
|
|
if (childConfig.footer.isNotEmpty()) {
|
|
builder.writeRaw(prefixChildren + nextChildStyle.linkCharacter + childConfig.footer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
}
|
|
|
|
public class MessageProperty : DiagnosticsProperty<object> {
|
|
public MessageProperty(string name, string message,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(name, null, description: message, level: level) {
|
|
D.assert(name != null);
|
|
D.assert(message != null);
|
|
}
|
|
}
|
|
|
|
public class StringProperty : DiagnosticsProperty<string> {
|
|
public StringProperty(string name, string value,
|
|
string description = null,
|
|
string tooltip = null,
|
|
bool showName = true,
|
|
object defaultValue = null,
|
|
bool quoted = true,
|
|
string ifEmpty = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(name,
|
|
value,
|
|
description: description,
|
|
defaultValue: defaultValue,
|
|
tooltip: tooltip,
|
|
showName: showName,
|
|
ifEmpty: ifEmpty,
|
|
level: level) {
|
|
this.quoted = quoted;
|
|
}
|
|
|
|
public readonly bool quoted;
|
|
|
|
public override Dictionary<string, object> toJsonMap() {
|
|
var json = base.toJsonMap();
|
|
json["quoted"] = this.quoted;
|
|
return json;
|
|
}
|
|
|
|
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
|
|
string text = this._description ?? this.value;
|
|
if (parentConfiguration != null &&
|
|
!parentConfiguration.lineBreakProperties &&
|
|
text != null) {
|
|
text = text.Replace("\n", "\\n");
|
|
}
|
|
|
|
if (this.quoted && text != null) {
|
|
if (this.ifEmpty != null && text.isEmpty()) {
|
|
return this.ifEmpty;
|
|
}
|
|
|
|
return "\"" + text + "\"";
|
|
}
|
|
|
|
return text ?? "null";
|
|
}
|
|
}
|
|
|
|
public abstract class _NumProperty<T> : DiagnosticsProperty<T> {
|
|
internal _NumProperty(string name,
|
|
T value,
|
|
string ifNull = null,
|
|
string unit = null,
|
|
bool showName = true,
|
|
object defaultValue = null,
|
|
string tooltip = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
value,
|
|
ifNull: ifNull,
|
|
showName: showName,
|
|
defaultValue: defaultValue,
|
|
tooltip: tooltip,
|
|
level: level
|
|
) {
|
|
this.unit = unit;
|
|
}
|
|
|
|
internal _NumProperty(string name,
|
|
ComputePropertyValueCallback<T> computeValue,
|
|
string ifNull = null,
|
|
string unit = null,
|
|
bool showName = true,
|
|
object defaultValue = null,
|
|
string tooltip = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
computeValue,
|
|
ifNull: ifNull,
|
|
showName: showName,
|
|
defaultValue: defaultValue,
|
|
tooltip: tooltip,
|
|
level: level
|
|
) {
|
|
this.unit = unit;
|
|
}
|
|
|
|
public override Dictionary<string, object> toJsonMap() {
|
|
var json = base.toJsonMap();
|
|
if (this.unit != null) {
|
|
json["unit"] = this.unit;
|
|
}
|
|
|
|
json["numberToString"] = this.numberToString();
|
|
return json;
|
|
}
|
|
|
|
public readonly string unit;
|
|
|
|
protected abstract string numberToString();
|
|
|
|
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
|
|
if (this.value == null) {
|
|
return "null";
|
|
}
|
|
|
|
return this.unit != null ? this.numberToString() + this.unit : this.numberToString();
|
|
}
|
|
}
|
|
|
|
public class IntProperty : _NumProperty<int?> {
|
|
public IntProperty(string name, int? value,
|
|
string ifNull = null,
|
|
bool showName = true,
|
|
string unit = null,
|
|
object defaultValue = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
value,
|
|
ifNull: ifNull,
|
|
showName: showName,
|
|
unit: unit,
|
|
defaultValue: defaultValue,
|
|
level: level
|
|
) {
|
|
}
|
|
|
|
protected override string numberToString() {
|
|
if (this.value == null) {
|
|
return "null";
|
|
}
|
|
|
|
return this.value.Value.ToString();
|
|
}
|
|
}
|
|
|
|
public class FloatProperty : _NumProperty<float?> {
|
|
public FloatProperty(string name, float? value,
|
|
string ifNull = null,
|
|
string unit = null,
|
|
string tooltip = null,
|
|
object defaultValue = null,
|
|
bool showName = true,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
value,
|
|
ifNull: ifNull,
|
|
unit: unit,
|
|
tooltip: tooltip,
|
|
defaultValue: defaultValue,
|
|
showName: showName,
|
|
level: level
|
|
) {
|
|
}
|
|
|
|
FloatProperty(
|
|
string name,
|
|
ComputePropertyValueCallback<float?> computeValue,
|
|
string ifNull = null,
|
|
bool showName = true,
|
|
string unit = null,
|
|
string tooltip = null,
|
|
object defaultValue = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
computeValue,
|
|
showName: showName,
|
|
ifNull: ifNull,
|
|
unit: unit,
|
|
tooltip: tooltip,
|
|
defaultValue: defaultValue,
|
|
level: level
|
|
) {
|
|
}
|
|
|
|
public static FloatProperty lazy(
|
|
string name,
|
|
ComputePropertyValueCallback<float?> computeValue,
|
|
string ifNull = null,
|
|
bool showName = true,
|
|
string unit = null,
|
|
string tooltip = null,
|
|
object defaultValue = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) {
|
|
return new FloatProperty(
|
|
name,
|
|
computeValue,
|
|
showName: showName,
|
|
ifNull: ifNull,
|
|
unit: unit,
|
|
tooltip: tooltip,
|
|
defaultValue: defaultValue,
|
|
level: level
|
|
);
|
|
}
|
|
|
|
protected override string numberToString() {
|
|
if (this.value != null) {
|
|
return this.value.Value.ToString("F1");
|
|
}
|
|
|
|
return "null";
|
|
}
|
|
}
|
|
|
|
public class PercentProperty : FloatProperty {
|
|
public PercentProperty(string name, float fraction,
|
|
string ifNull = null,
|
|
bool showName = true,
|
|
string tooltip = null,
|
|
string unit = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
fraction,
|
|
ifNull: ifNull,
|
|
showName: showName,
|
|
tooltip: tooltip,
|
|
unit: unit,
|
|
level: level
|
|
) {
|
|
}
|
|
|
|
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
|
|
if (this.value == null) {
|
|
return "null";
|
|
}
|
|
|
|
return this.unit != null ? this.numberToString() + " " + this.unit : this.numberToString();
|
|
}
|
|
|
|
protected override string numberToString() {
|
|
if (this.value == null) {
|
|
return "null";
|
|
}
|
|
|
|
return (this.value.Value.clamp(0.0f, 1.0f) * 100).ToString("F1") + "%";
|
|
}
|
|
}
|
|
|
|
public class FlagProperty : DiagnosticsProperty<bool?> {
|
|
public FlagProperty(string name,
|
|
bool? value,
|
|
string ifTrue = null,
|
|
string ifFalse = null,
|
|
bool showName = false,
|
|
object defaultValue = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(name,
|
|
value,
|
|
showName: showName,
|
|
defaultValue: defaultValue,
|
|
level: level
|
|
) {
|
|
D.assert(ifTrue != null || ifFalse != null);
|
|
}
|
|
|
|
public override Dictionary<string, object> toJsonMap() {
|
|
var json = base.toJsonMap();
|
|
if (this.ifTrue != null) {
|
|
json["ifTrue"] = this.ifTrue;
|
|
}
|
|
|
|
if (this.ifFalse != null) {
|
|
json["ifFalse"] = this.ifFalse;
|
|
}
|
|
|
|
return json;
|
|
}
|
|
|
|
public readonly string ifTrue;
|
|
|
|
public readonly string ifFalse;
|
|
|
|
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
|
|
if (this.value == true) {
|
|
if (this.ifTrue != null) {
|
|
return this.ifTrue;
|
|
}
|
|
}
|
|
else if (this.value == false) {
|
|
if (this.ifFalse != null) {
|
|
return this.ifFalse;
|
|
}
|
|
}
|
|
|
|
return base.valueToString(parentConfiguration: parentConfiguration);
|
|
}
|
|
|
|
public override bool showName {
|
|
get {
|
|
if (this.value == null || this.value == true && this.ifTrue == null ||
|
|
this.value == false && this.ifFalse == null) {
|
|
return true;
|
|
}
|
|
|
|
return base.showName;
|
|
}
|
|
}
|
|
|
|
public override DiagnosticLevel level {
|
|
get {
|
|
if (this.value == true) {
|
|
if (this.ifTrue == null) {
|
|
return DiagnosticLevel.hidden;
|
|
}
|
|
}
|
|
|
|
if (this.value == false) {
|
|
if (this.ifFalse == null) {
|
|
return DiagnosticLevel.hidden;
|
|
}
|
|
}
|
|
|
|
return base.level;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class EnumerableProperty<T> : DiagnosticsProperty<IEnumerable<T>> {
|
|
public EnumerableProperty(
|
|
string name,
|
|
IEnumerable<T> value,
|
|
object defaultValue = null,
|
|
string ifNull = null,
|
|
string ifEmpty = "[]",
|
|
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.singleLine,
|
|
bool showName = true,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
value,
|
|
defaultValue: defaultValue,
|
|
ifNull: ifNull,
|
|
ifEmpty: ifEmpty,
|
|
style: style,
|
|
showName: showName,
|
|
level: level
|
|
) {
|
|
}
|
|
|
|
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
|
|
if (this.value == null) {
|
|
return "null";
|
|
}
|
|
|
|
if (!this.value.Any()) {
|
|
return this.ifEmpty ?? "[]";
|
|
}
|
|
|
|
if (parentConfiguration != null && !parentConfiguration.lineBreakProperties) {
|
|
return string.Join(", ", this.value.Select(v => v.ToString()).ToArray());
|
|
}
|
|
|
|
return string.Join(this.style == DiagnosticsTreeStyle.singleLine ? ", " : "\n",
|
|
this.value.Select(v => v.ToString()).ToArray());
|
|
}
|
|
|
|
public override DiagnosticLevel level {
|
|
get {
|
|
if (this.ifEmpty == null &&
|
|
this.value != null && !this.value.Any()
|
|
&& base.level != DiagnosticLevel.hidden) {
|
|
return DiagnosticLevel.fine;
|
|
}
|
|
|
|
return base.level;
|
|
}
|
|
}
|
|
|
|
public override Dictionary<string, object> toJsonMap() {
|
|
var json = base.toJsonMap();
|
|
if (this.value != null) {
|
|
json["values"] = this.value.Select(v => v.ToString()).ToList();
|
|
}
|
|
|
|
return json;
|
|
}
|
|
}
|
|
|
|
|
|
public class EnumProperty<T> : DiagnosticsProperty<T> {
|
|
public EnumProperty(string name, T value,
|
|
object defaultValue = null,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
value,
|
|
defaultValue: defaultValue,
|
|
level: level
|
|
) {
|
|
}
|
|
|
|
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
|
|
if (this.value == null) {
|
|
return "null";
|
|
}
|
|
|
|
return this.value.ToString();
|
|
}
|
|
}
|
|
|
|
public class ObjectFlagProperty<T> : DiagnosticsProperty<T> {
|
|
public ObjectFlagProperty(string name, T value,
|
|
string ifPresent = null,
|
|
string ifNull = null,
|
|
bool showName = false,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
value,
|
|
showName: showName,
|
|
ifNull: ifNull,
|
|
level: level
|
|
) {
|
|
D.assert(ifPresent != null || ifNull != null);
|
|
}
|
|
|
|
ObjectFlagProperty(
|
|
string name,
|
|
T value,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name,
|
|
value,
|
|
showName: false,
|
|
level: level
|
|
) {
|
|
D.assert(name != null);
|
|
this.ifPresent = "has " + name;
|
|
}
|
|
|
|
public static ObjectFlagProperty<T> has(
|
|
string name,
|
|
T value,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) {
|
|
return new ObjectFlagProperty<T>(name, value, level);
|
|
}
|
|
|
|
public readonly string ifPresent;
|
|
|
|
protected override string valueToString(
|
|
TextTreeConfiguration parentConfiguration = null) {
|
|
if (this.value != null) {
|
|
if (this.ifPresent != null) {
|
|
return this.ifPresent;
|
|
}
|
|
}
|
|
else {
|
|
if (this.ifNull != null) {
|
|
return this.ifNull;
|
|
}
|
|
}
|
|
|
|
return base.valueToString(parentConfiguration: parentConfiguration);
|
|
}
|
|
|
|
public override bool showName {
|
|
get {
|
|
if ((this.value != null && this.ifPresent == null) || (this.value == null && this.ifNull == null)) {
|
|
return true;
|
|
}
|
|
|
|
return base.showName;
|
|
}
|
|
}
|
|
|
|
public override DiagnosticLevel level {
|
|
get {
|
|
if (this.value != null) {
|
|
if (this.ifPresent == null) {
|
|
return DiagnosticLevel.hidden;
|
|
}
|
|
}
|
|
else {
|
|
if (this.ifNull == null) {
|
|
return DiagnosticLevel.hidden;
|
|
}
|
|
}
|
|
|
|
return base.level;
|
|
}
|
|
}
|
|
|
|
public override Dictionary<string, object> toJsonMap() {
|
|
var json = base.toJsonMap();
|
|
if (this.ifPresent != null) {
|
|
json["ifPresent"] = this.ifPresent;
|
|
}
|
|
|
|
return json;
|
|
}
|
|
}
|
|
|
|
public delegate T ComputePropertyValueCallback<T>();
|
|
|
|
public class DiagnosticsProperty<T> : DiagnosticsNode {
|
|
public DiagnosticsProperty(
|
|
string name,
|
|
T value,
|
|
string description = null,
|
|
string ifNull = null,
|
|
string ifEmpty = null,
|
|
bool showName = true,
|
|
bool showSeparator = true,
|
|
object defaultValue = null,
|
|
string tooltip = null,
|
|
bool missingIfNull = false,
|
|
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.singleLine,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name: name,
|
|
showName: showName,
|
|
showSeparator: showSeparator,
|
|
style: style
|
|
) {
|
|
defaultValue = defaultValue ?? Diagnostics.kNoDefaultValue;
|
|
if (defaultValue == Diagnostics.kNullDefaultValue) {
|
|
defaultValue = null;
|
|
}
|
|
|
|
D.assert(defaultValue == null || defaultValue == Diagnostics.kNoDefaultValue || defaultValue is T);
|
|
this._description = description;
|
|
this._valueComputed = true;
|
|
this._value = value;
|
|
this._computeValue = null;
|
|
this.ifNull = ifNull ?? (missingIfNull ? "MISSING" : null);
|
|
this._defaultLevel = level;
|
|
this.ifEmpty = ifEmpty;
|
|
this.defaultValue = defaultValue;
|
|
this.tooltip = tooltip;
|
|
this.missingIfNull = missingIfNull;
|
|
}
|
|
|
|
internal DiagnosticsProperty(
|
|
string name,
|
|
ComputePropertyValueCallback<T> computeValue,
|
|
string description = null,
|
|
string ifNull = null,
|
|
string ifEmpty = null,
|
|
bool showName = true,
|
|
bool showSeparator = true,
|
|
object defaultValue = null,
|
|
string tooltip = null,
|
|
bool missingIfNull = false,
|
|
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.singleLine,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) : base(
|
|
name: name,
|
|
showName: showName,
|
|
showSeparator: showSeparator,
|
|
style: style
|
|
) {
|
|
defaultValue = defaultValue ?? Diagnostics.kNoDefaultValue;
|
|
if (defaultValue == Diagnostics.kNullDefaultValue) {
|
|
defaultValue = null;
|
|
}
|
|
|
|
D.assert(defaultValue == null || defaultValue == Diagnostics.kNoDefaultValue || defaultValue is T);
|
|
this._description = description;
|
|
this._valueComputed = false;
|
|
this._value = default(T);
|
|
this._computeValue = computeValue;
|
|
this._defaultLevel = level;
|
|
this.ifNull = ifNull ?? (missingIfNull ? "MISSING" : null);
|
|
this.ifEmpty = ifEmpty;
|
|
this.defaultValue = defaultValue;
|
|
this.tooltip = tooltip;
|
|
this.missingIfNull = missingIfNull;
|
|
}
|
|
|
|
public static DiagnosticsProperty<T> lazy(
|
|
string name,
|
|
ComputePropertyValueCallback<T> computeValue,
|
|
string description = null,
|
|
string ifNull = null,
|
|
string ifEmpty = null,
|
|
bool showName = true,
|
|
bool showSeparator = true,
|
|
object defaultValue = null,
|
|
string tooltip = null,
|
|
bool missingIfNull = false,
|
|
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.singleLine,
|
|
DiagnosticLevel level = DiagnosticLevel.info
|
|
) {
|
|
return new DiagnosticsProperty<T>(
|
|
name,
|
|
computeValue,
|
|
description,
|
|
ifNull,
|
|
ifEmpty,
|
|
showName,
|
|
showSeparator,
|
|
defaultValue,
|
|
tooltip,
|
|
missingIfNull,
|
|
style,
|
|
level);
|
|
}
|
|
|
|
internal readonly string _description;
|
|
|
|
public override Dictionary<string, object> toJsonMap() {
|
|
var json = base.toJsonMap();
|
|
if (this.defaultValue != Diagnostics.kNoDefaultValue) {
|
|
json["defaultValue"] = Convert.ToString(this.defaultValue);
|
|
}
|
|
|
|
if (this.ifEmpty != null) {
|
|
json["ifEmpty"] = this.ifEmpty;
|
|
}
|
|
|
|
if (this.ifNull != null) {
|
|
json["ifNull"] = this.ifNull;
|
|
}
|
|
|
|
if (this.tooltip != null) {
|
|
json["tooltip"] = this.tooltip;
|
|
}
|
|
|
|
json["missingIfNull"] = this.missingIfNull;
|
|
if (this.exception != null) {
|
|
json["exception"] = this.exception.ToString();
|
|
}
|
|
|
|
json["propertyType"] = this.propertyType.ToString();
|
|
json["valueToString"] = this.valueToString();
|
|
json["defaultLevel"] = Convert.ToString(this._defaultLevel);
|
|
if (typeof(Diagnosticable).IsAssignableFrom(typeof(T))) {
|
|
json["isDiagnosticableValue"] = true;
|
|
}
|
|
|
|
return json;
|
|
}
|
|
|
|
protected virtual string valueToString(
|
|
TextTreeConfiguration parentConfiguration = null
|
|
) {
|
|
var v = this.value;
|
|
var tree = v as DiagnosticableTree;
|
|
return tree != null ? tree.toStringShort() : v != null ? v.ToString() : "null";
|
|
}
|
|
|
|
public override string toDescription(
|
|
TextTreeConfiguration parentConfiguration = null
|
|
) {
|
|
if (this._description != null) {
|
|
return this._addTooltip(this._description);
|
|
}
|
|
|
|
if (this.exception != null) {
|
|
return "EXCEPTION (" + this.exception.GetType() + ")";
|
|
}
|
|
|
|
if (this.ifNull != null && this.value == null) {
|
|
return this._addTooltip(this.ifNull);
|
|
}
|
|
|
|
string result = this.valueToString(parentConfiguration: parentConfiguration);
|
|
if (result.isEmpty() && this.ifEmpty != null) {
|
|
result = this.ifEmpty;
|
|
}
|
|
|
|
return this._addTooltip(result);
|
|
}
|
|
|
|
string _addTooltip(string text) {
|
|
D.assert(text != null);
|
|
return this.tooltip == null ? text : text + "(" + this.tooltip + ")";
|
|
}
|
|
|
|
public readonly string ifNull;
|
|
public readonly string ifEmpty;
|
|
public readonly string tooltip;
|
|
public readonly bool missingIfNull;
|
|
|
|
public Type propertyType {
|
|
get { return typeof(T); }
|
|
}
|
|
|
|
public override object valueObject {
|
|
get { return this.value; }
|
|
}
|
|
|
|
public T value {
|
|
get {
|
|
this._maybeCacheValue();
|
|
return this._value;
|
|
}
|
|
}
|
|
|
|
T _value;
|
|
bool _valueComputed;
|
|
Exception _exception;
|
|
|
|
public Exception exception {
|
|
get {
|
|
this._maybeCacheValue();
|
|
return this._exception;
|
|
}
|
|
}
|
|
|
|
void _maybeCacheValue() {
|
|
if (this._valueComputed) {
|
|
return;
|
|
}
|
|
|
|
this._valueComputed = true;
|
|
try {
|
|
this._value = this._computeValue();
|
|
}
|
|
catch (Exception ex) {
|
|
this._exception = ex;
|
|
this._value = default(T);
|
|
}
|
|
}
|
|
|
|
public readonly object defaultValue;
|
|
DiagnosticLevel _defaultLevel;
|
|
|
|
public override DiagnosticLevel level {
|
|
get {
|
|
if (this._defaultLevel == DiagnosticLevel.hidden) {
|
|
return this._defaultLevel;
|
|
}
|
|
|
|
if (this.exception != null) {
|
|
return DiagnosticLevel.error;
|
|
}
|
|
|
|
if (this.value == null && this.missingIfNull) {
|
|
return DiagnosticLevel.warning;
|
|
}
|
|
|
|
if (this.defaultValue != Diagnostics.kNoDefaultValue && Equals(this.value, this.defaultValue)) {
|
|
return DiagnosticLevel.fine;
|
|
}
|
|
|
|
return this._defaultLevel;
|
|
}
|
|
}
|
|
|
|
readonly ComputePropertyValueCallback<T> _computeValue;
|
|
|
|
public override List<DiagnosticsNode> getProperties() {
|
|
return new List<DiagnosticsNode>();
|
|
}
|
|
|
|
public override List<DiagnosticsNode> getChildren() {
|
|
return new List<DiagnosticsNode>();
|
|
}
|
|
}
|
|
|
|
public class DiagnosticableNode<T> : DiagnosticsNode where T : Diagnosticable {
|
|
public DiagnosticableNode(
|
|
string name = null,
|
|
T value = null,
|
|
DiagnosticsTreeStyle? style = null
|
|
) : base(name: name, style: style) {
|
|
D.assert(value != null);
|
|
this._value = value;
|
|
}
|
|
|
|
public override object valueObject {
|
|
get { return this.value; }
|
|
}
|
|
|
|
public T value {
|
|
get { return this._value; }
|
|
}
|
|
|
|
readonly T _value;
|
|
DiagnosticPropertiesBuilder _cachedBuilder;
|
|
|
|
DiagnosticPropertiesBuilder _builder {
|
|
get {
|
|
if (this._cachedBuilder == null) {
|
|
this._cachedBuilder = new DiagnosticPropertiesBuilder();
|
|
if (this._value != null) {
|
|
this._value.debugFillProperties(this._cachedBuilder);
|
|
}
|
|
}
|
|
|
|
return this._cachedBuilder;
|
|
}
|
|
}
|
|
|
|
public override DiagnosticsTreeStyle? style {
|
|
get { return base.style ?? this._builder.defaultDiagnosticsTreeStyle; }
|
|
}
|
|
|
|
public override string emptyBodyDescription {
|
|
get { return this._builder.emptyBodyDescription; }
|
|
}
|
|
|
|
public override List<DiagnosticsNode> getProperties() {
|
|
return this._builder.properties;
|
|
}
|
|
|
|
public override List<DiagnosticsNode> getChildren() {
|
|
return new List<DiagnosticsNode>();
|
|
}
|
|
|
|
public override string toDescription(
|
|
TextTreeConfiguration parentConfiguration = null
|
|
) {
|
|
return this._value.toStringShort();
|
|
}
|
|
}
|
|
|
|
class _DiagnosticableTreeNode : DiagnosticableNode<DiagnosticableTree> {
|
|
internal _DiagnosticableTreeNode(
|
|
string name,
|
|
DiagnosticableTree value,
|
|
DiagnosticsTreeStyle style
|
|
) : base(
|
|
name: name,
|
|
value: value,
|
|
style: style
|
|
) {
|
|
}
|
|
|
|
public override List<DiagnosticsNode> getChildren() {
|
|
if (this.value != null) {
|
|
return this.value.debugDescribeChildren();
|
|
}
|
|
|
|
return new List<DiagnosticsNode>();
|
|
}
|
|
}
|
|
|
|
public class DiagnosticPropertiesBuilder {
|
|
public void add(DiagnosticsNode property) {
|
|
this.properties.Add(property);
|
|
}
|
|
|
|
public readonly List<DiagnosticsNode> properties = new List<DiagnosticsNode>();
|
|
public DiagnosticsTreeStyle defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.sparse;
|
|
public string emptyBodyDescription;
|
|
}
|
|
|
|
public abstract class Diagnosticable {
|
|
protected Diagnosticable() {
|
|
}
|
|
|
|
public virtual string toStringShort() {
|
|
return Diagnostics.describeIdentity(this);
|
|
}
|
|
|
|
public override string ToString() {
|
|
return this.toString();
|
|
}
|
|
|
|
public virtual string toString(DiagnosticLevel minLevel = DiagnosticLevel.debug) {
|
|
return this.toDiagnosticsNode(style: DiagnosticsTreeStyle.singleLine).toString(minLevel: minLevel);
|
|
}
|
|
|
|
public virtual DiagnosticsNode toDiagnosticsNode(
|
|
string name = null,
|
|
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.sparse) {
|
|
return new DiagnosticableNode<Diagnosticable>(
|
|
name: name, value: this, style: style
|
|
);
|
|
}
|
|
|
|
public virtual void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
}
|
|
}
|
|
|
|
public abstract class DiagnosticableTree : Diagnosticable {
|
|
protected DiagnosticableTree() {
|
|
}
|
|
|
|
public virtual string toStringShallow(
|
|
string joiner = ", ",
|
|
DiagnosticLevel minLevel = DiagnosticLevel.debug
|
|
) {
|
|
var result = new StringBuilder();
|
|
result.Append(this.ToString());
|
|
result.Append(joiner);
|
|
DiagnosticPropertiesBuilder builder = new DiagnosticPropertiesBuilder();
|
|
this.debugFillProperties(builder);
|
|
result.Append(string.Join(joiner,
|
|
builder.properties.Where(n => !n.isFiltered(minLevel)).Select(n => n.ToString()).ToArray())
|
|
);
|
|
return result.ToString();
|
|
}
|
|
|
|
public virtual string toStringDeep(
|
|
string prefixLineOne = "",
|
|
string prefixOtherLines = null,
|
|
DiagnosticLevel minLevel = DiagnosticLevel.debug
|
|
) {
|
|
return this.toDiagnosticsNode().toStringDeep(
|
|
prefixLineOne: prefixLineOne,
|
|
prefixOtherLines: prefixOtherLines,
|
|
minLevel: minLevel);
|
|
}
|
|
|
|
public override string toStringShort() {
|
|
return Diagnostics.describeIdentity(this);
|
|
}
|
|
|
|
public override DiagnosticsNode toDiagnosticsNode(
|
|
string name = null,
|
|
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.sparse) {
|
|
return new _DiagnosticableTreeNode(
|
|
name: name,
|
|
value: this,
|
|
style: style
|
|
);
|
|
}
|
|
|
|
public virtual List<DiagnosticsNode> debugDescribeChildren() {
|
|
return new List<DiagnosticsNode>();
|
|
}
|
|
}
|
|
|
|
public static class Diagnostics {
|
|
public static readonly TextTreeConfiguration sparseTextConfiguration = new TextTreeConfiguration(
|
|
prefixLineOne: "├─",
|
|
prefixOtherLines: " ",
|
|
prefixLastChildLineOne: "└─",
|
|
linkCharacter: "│",
|
|
propertyPrefixIfChildren: "│ ",
|
|
propertyPrefixNoChildren: " ",
|
|
prefixOtherLinesRootNode: " "
|
|
);
|
|
|
|
public static readonly TextTreeConfiguration dashedTextConfiguration = new TextTreeConfiguration(
|
|
prefixLineOne: "╎╌",
|
|
prefixLastChildLineOne: "└╌",
|
|
prefixOtherLines: " ",
|
|
linkCharacter: "╎",
|
|
propertyPrefixIfChildren: "│ ",
|
|
propertyPrefixNoChildren: " ",
|
|
prefixOtherLinesRootNode: " "
|
|
);
|
|
|
|
public static readonly TextTreeConfiguration denseTextConfiguration = new TextTreeConfiguration(
|
|
propertySeparator: ", ",
|
|
beforeProperties: "(",
|
|
afterProperties: ")",
|
|
lineBreakProperties: false,
|
|
prefixLineOne: "├",
|
|
prefixOtherLines: "",
|
|
prefixLastChildLineOne: "└",
|
|
linkCharacter: "│",
|
|
propertyPrefixIfChildren: "│",
|
|
propertyPrefixNoChildren: " ",
|
|
prefixOtherLinesRootNode: "",
|
|
addBlankLineIfNoChildren: false,
|
|
isBlankLineBetweenPropertiesAndChildren: false
|
|
);
|
|
|
|
public static readonly TextTreeConfiguration transitionTextConfiguration = new TextTreeConfiguration(
|
|
prefixLineOne: "╞═╦══ ",
|
|
prefixLastChildLineOne: "╘═╦══ ",
|
|
prefixOtherLines: " ║ ",
|
|
footer: " ╚═══════════\n",
|
|
linkCharacter: "│",
|
|
propertyPrefixIfChildren: "",
|
|
propertyPrefixNoChildren: "",
|
|
prefixOtherLinesRootNode: "",
|
|
afterName: " ═══",
|
|
afterDescriptionIfBody: ":",
|
|
bodyIndent: " ",
|
|
isNameOnOwnLine: true,
|
|
addBlankLineIfNoChildren: false,
|
|
isBlankLineBetweenPropertiesAndChildren: false
|
|
);
|
|
|
|
public static readonly TextTreeConfiguration whitespaceTextConfiguration = new TextTreeConfiguration(
|
|
prefixLineOne: "",
|
|
prefixLastChildLineOne: "",
|
|
prefixOtherLines: " ",
|
|
prefixOtherLinesRootNode: " ",
|
|
bodyIndent: "",
|
|
propertyPrefixIfChildren: "",
|
|
propertyPrefixNoChildren: "",
|
|
linkCharacter: " ",
|
|
addBlankLineIfNoChildren: false,
|
|
afterDescriptionIfBody: ":",
|
|
isBlankLineBetweenPropertiesAndChildren: false
|
|
);
|
|
|
|
public static readonly TextTreeConfiguration singleLineTextConfiguration = new TextTreeConfiguration(
|
|
propertySeparator: ", ",
|
|
beforeProperties: "(",
|
|
afterProperties: ")",
|
|
prefixLineOne: "",
|
|
prefixOtherLines: "",
|
|
prefixLastChildLineOne: "",
|
|
lineBreak: "",
|
|
lineBreakProperties: false,
|
|
addBlankLineIfNoChildren: false,
|
|
showChildren: false,
|
|
propertyPrefixIfChildren: "",
|
|
propertyPrefixNoChildren: "",
|
|
linkCharacter: "",
|
|
prefixOtherLinesRootNode: ""
|
|
);
|
|
|
|
internal static readonly _NoDefaultValue kNoDefaultValue = new _NoDefaultValue();
|
|
|
|
public static readonly object kNullDefaultValue = new _NullDefaultValue();
|
|
|
|
public static string shortHash(object o) {
|
|
return (o.GetHashCode() & 0xFFFFF).ToString("X").PadLeft(5, '0');
|
|
}
|
|
|
|
public static string describeIdentity(object o) {
|
|
return $"{o.GetType()}#{shortHash(o)}";
|
|
}
|
|
}
|
|
}
|