mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 21:38:16 +08:00
Making tuples pretty too
This commit is contained in:

committed by
Patrik Svensson

parent
e8eb5b85b9
commit
74a2e10ff0
@ -276,16 +276,85 @@ internal static class ExceptionFormatter
|
||||
var prefix = GetPrefix(parameter);
|
||||
var parameterType = parameter.ParameterType;
|
||||
|
||||
if (parameterType.IsByRef && parameterType.GetElementType() is { } elementType)
|
||||
string typeName;
|
||||
if (parameterType.IsGenericType && TryGetTupleName(parameter, parameterType, out var s))
|
||||
{
|
||||
parameterType = elementType;
|
||||
typeName = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parameterType.IsByRef && parameterType.GetElementType() is { } elementType)
|
||||
{
|
||||
parameterType = elementType;
|
||||
}
|
||||
|
||||
typeName = TypeNameHelper.GetTypeDisplayName(parameterType);
|
||||
}
|
||||
|
||||
var typeName = TypeNameHelper.GetTypeDisplayName(parameterType, false, true);
|
||||
|
||||
return string.IsNullOrWhiteSpace(prefix) ? typeName : $"{prefix} {typeName}";
|
||||
}
|
||||
|
||||
private static bool TryGetTupleName(ParameterInfo parameter, Type parameterType, [NotNullWhen(true)] out string? tupleName)
|
||||
{
|
||||
var customAttribs = parameter.GetCustomAttributes(inherit: false);
|
||||
|
||||
var tupleNameAttribute = customAttribs
|
||||
.OfType<Attribute>()
|
||||
.FirstOrDefault(a =>
|
||||
{
|
||||
var attributeType = a.GetType();
|
||||
return attributeType.Namespace == "System.Runtime.CompilerServices" &&
|
||||
attributeType.Name == "TupleElementNamesAttribute";
|
||||
});
|
||||
|
||||
if (tupleNameAttribute != null)
|
||||
{
|
||||
var propertyInfo = tupleNameAttribute.GetType()
|
||||
.GetProperty("TransformNames", BindingFlags.Instance | BindingFlags.Public)!;
|
||||
var tupleNames = propertyInfo.GetValue(tupleNameAttribute) as IList<string>;
|
||||
if (tupleNames?.Count > 0)
|
||||
{
|
||||
var args = parameterType.GetGenericArguments();
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append('(');
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(TypeNameHelper.GetTypeDisplayName(args[i]));
|
||||
|
||||
if (i >= tupleNames.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var argName = tupleNames[i];
|
||||
|
||||
sb.Append(' ');
|
||||
sb.Append(argName);
|
||||
}
|
||||
|
||||
sb.Append(')');
|
||||
|
||||
tupleName = sb.ToString();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (parameterType.Namespace == "System" && parameterType.Name.Contains("ValueTuple`"))
|
||||
{
|
||||
var args = parameterType.GetGenericArguments().Select(i => TypeNameHelper.GetTypeDisplayName(i));
|
||||
tupleName = $"({string.Join(", ", args)})";
|
||||
return true;
|
||||
}
|
||||
|
||||
tupleName = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string GetMethodName(ref MethodBase method, out bool isAsync)
|
||||
{
|
||||
var declaringType = method.DeclaringType;
|
||||
|
@ -40,35 +40,13 @@ internal static class TypeNameHelper
|
||||
/// <param name="fullName"><c>true</c> to print a fully qualified name.</param>
|
||||
/// <param name="includeGenericParameterNames"><c>true</c> to include generic parameter names.</param>
|
||||
/// <returns>The pretty printed type name.</returns>
|
||||
public static string GetTypeDisplayName(Type type, bool fullName = true, bool includeGenericParameterNames = false)
|
||||
public static string GetTypeDisplayName(Type type, bool fullName = false, bool includeGenericParameterNames = true)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static StringBuilder AppendTypeDisplayName(this StringBuilder builder, Type type, bool fullName = true,
|
||||
bool includeGenericParameterNames = false)
|
||||
{
|
||||
ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a name of given generic type without '`'.
|
||||
/// </summary>
|
||||
public static string GetTypeNameForGenericType(Type type)
|
||||
{
|
||||
if (!type.IsGenericType)
|
||||
{
|
||||
throw new ArgumentException("The given type should be generic", nameof(type));
|
||||
}
|
||||
|
||||
var genericPartIndex = type.Name.IndexOf('`');
|
||||
|
||||
return (genericPartIndex >= 0) ? type.Name.Substring(0, genericPartIndex) : type.Name;
|
||||
}
|
||||
|
||||
private static void ProcessType(StringBuilder builder, Type type, DisplayNameOptions options)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
|
Reference in New Issue
Block a user