Fix generic exception formatting with shortened types

Fixes #1754
This commit is contained in:
Cédric Luthi 2025-02-05 15:30:47 +01:00
parent 7e1142df58
commit 9d8d3c1d6d
2 changed files with 21 additions and 23 deletions

View File

@ -33,11 +33,12 @@ internal static class ExceptionFormatter
{ {
var shortenTypes = (settings.Format & ExceptionFormats.ShortenTypes) != 0; var shortenTypes = (settings.Format & ExceptionFormats.ShortenTypes) != 0;
var exceptionType = ex.GetType(); var exceptionType = ex.GetType();
var exceptionTypeFullName = exceptionType.FullName ?? exceptionType.Name; var exceptionTypeName = TypeNameHelper.GetTypeDisplayName(exceptionType, fullName: !shortenTypes, includeSystemNamespace: true);
var type = Emphasize(exceptionTypeFullName, new[] { '.' }, settings.Style.Exception, shortenTypes, settings); var type = new StringBuilder();
Emphasize(type, exceptionTypeName, new[] { '.' }, settings.Style.Exception, shortenTypes, settings, limit: '<');
var message = $"[{settings.Style.Message.ToMarkup()}]{ex.Message.EscapeMarkup()}[/]"; var message = $"[{settings.Style.Message.ToMarkup()}]{ex.Message.EscapeMarkup()}[/]";
return new Markup(string.Concat(type, ": ", message)); return new Markup($"{type}: {message}");
} }
private static Grid GetStackFrames(Exception ex, ExceptionSettings settings) private static Grid GetStackFrames(Exception ex, ExceptionSettings settings)
@ -101,7 +102,7 @@ internal static class ExceptionFormatter
builder.Append(' '); builder.Append(' ');
} }
builder.Append(Emphasize(methodName, new[] { '.' }, styles.Method, shortenMethods, settings)); Emphasize(builder, methodName, new[] { '.' }, styles.Method, shortenMethods, settings);
builder.AppendWithStyle(styles.Parenthesis, "("); builder.AppendWithStyle(styles.Parenthesis, "(");
AppendParameters(builder, method, settings); AppendParameters(builder, method, settings);
builder.AppendWithStyle(styles.Parenthesis, ")"); builder.AppendWithStyle(styles.Parenthesis, ")");
@ -168,7 +169,7 @@ internal static class ExceptionFormatter
void AppendPath() void AppendPath()
{ {
var shortenPaths = (settings.Format & ExceptionFormats.ShortenPaths) != 0; var shortenPaths = (settings.Format & ExceptionFormats.ShortenPaths) != 0;
builder.Append(Emphasize(path, new[] { '/', '\\' }, settings.Style.Path, shortenPaths, settings)); Emphasize(builder, path, new[] { '/', '\\' }, settings.Style.Path, shortenPaths, settings);
} }
if ((settings.Format & ExceptionFormats.ShowLinks) != 0) if ((settings.Format & ExceptionFormats.ShowLinks) != 0)
@ -192,32 +193,25 @@ internal static class ExceptionFormatter
} }
} }
private static string Emphasize(string input, char[] separators, Style color, bool compact, private static void Emphasize(StringBuilder builder, string input, char[] separators, Style color, bool compact,
ExceptionSettings settings) ExceptionSettings settings, char? limit = null)
{ {
var builder = new StringBuilder(); var limitIndex = limit.HasValue ? input.IndexOf(limit.Value) : -1;
var type = input; var index = limitIndex != -1 ? input[..limitIndex].LastIndexOfAny(separators) : input.LastIndexOfAny(separators);
var index = type.LastIndexOfAny(separators);
if (index != -1) if (index != -1)
{ {
if (!compact) if (!compact)
{ {
builder.AppendWithStyle( builder.AppendWithStyle(settings.Style.NonEmphasized, input[..(index + 1)]);
settings.Style.NonEmphasized,
type.Substring(0, index + 1));
} }
builder.AppendWithStyle( builder.AppendWithStyle(color, input[(index + 1)..]);
color,
type.Substring(index + 1, type.Length - index - 1));
} }
else else
{ {
builder.Append(type.EscapeMarkup()); builder.AppendWithStyle(color, input);
} }
return builder.ToString();
} }
private static bool ShowInStackTrace(StackFrame frame) private static bool ShowInStackTrace(StackFrame frame)

View File

@ -39,11 +39,12 @@ internal static class TypeNameHelper
/// <param name="type">The <see cref="Type"/>.</param> /// <param name="type">The <see cref="Type"/>.</param>
/// <param name="fullName"><c>true</c> to print a fully qualified name.</param> /// <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> /// <param name="includeGenericParameterNames"><c>true</c> to include generic parameter names.</param>
/// <param name="includeSystemNamespace"><c>true</c> to include the <c>System</c> namespace.</param>
/// <returns>The pretty printed type name.</returns> /// <returns>The pretty printed type name.</returns>
public static string GetTypeDisplayName(Type type, bool fullName = false, bool includeGenericParameterNames = true) public static string GetTypeDisplayName(Type type, bool fullName = false, bool includeGenericParameterNames = true, bool includeSystemNamespace = false)
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames)); ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames, includeSystemNamespace));
return builder.ToString(); return builder.ToString();
} }
@ -71,7 +72,7 @@ internal static class TypeNameHelper
{ {
builder.Append(builtInName); builder.Append(builtInName);
} }
else if (type.Namespace == nameof(System)) else if (type.Namespace == nameof(System) && !options.IncludeSystemNamespace)
{ {
builder.Append(type.Name); builder.Append(type.Name);
} }
@ -181,14 +182,17 @@ internal static class TypeNameHelper
private struct DisplayNameOptions private struct DisplayNameOptions
{ {
public DisplayNameOptions(bool fullName, bool includeGenericParameterNames) public DisplayNameOptions(bool fullName, bool includeGenericParameterNames, bool includeSystemNamespace)
{ {
FullName = fullName; FullName = fullName;
IncludeGenericParameterNames = includeGenericParameterNames; IncludeGenericParameterNames = includeGenericParameterNames;
IncludeSystemNamespace = includeSystemNamespace;
} }
public bool FullName { get; } public bool FullName { get; }
public bool IncludeGenericParameterNames { get; } public bool IncludeGenericParameterNames { get; }
public bool IncludeSystemNamespace { get; }
} }
} }