Skip to content

Commit

Permalink
Fix generic exception formatting with shortened types
Browse files Browse the repository at this point in the history
Fixes #1754
  • Loading branch information
0xced committed Feb 5, 2025
1 parent 7e1142d commit 9d8d3c1
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 23 deletions.
32 changes: 13 additions & 19 deletions src/Spectre.Console/Widgets/Exceptions/ExceptionFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ private static Markup GetMessage(Exception ex, ExceptionSettings settings)
{
var shortenTypes = (settings.Format & ExceptionFormats.ShortenTypes) != 0;
var exceptionType = ex.GetType();
var exceptionTypeFullName = exceptionType.FullName ?? exceptionType.Name;
var type = Emphasize(exceptionTypeFullName, new[] { '.' }, settings.Style.Exception, shortenTypes, settings);
var exceptionTypeName = TypeNameHelper.GetTypeDisplayName(exceptionType, fullName: !shortenTypes, includeSystemNamespace: true);
var type = new StringBuilder();
Emphasize(type, exceptionTypeName, new[] { '.' }, settings.Style.Exception, shortenTypes, settings, limit: '<');

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)
Expand Down Expand Up @@ -101,7 +102,7 @@ private static Grid GetStackFrames(Exception ex, ExceptionSettings settings)
builder.Append(' ');
}

builder.Append(Emphasize(methodName, new[] { '.' }, styles.Method, shortenMethods, settings));
Emphasize(builder, methodName, new[] { '.' }, styles.Method, shortenMethods, settings);
builder.AppendWithStyle(styles.Parenthesis, "(");
AppendParameters(builder, method, settings);
builder.AppendWithStyle(styles.Parenthesis, ")");
Expand Down Expand Up @@ -168,7 +169,7 @@ private static void AppendPath(StringBuilder builder, string path, ExceptionSett
void AppendPath()
{
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)
Expand All @@ -192,32 +193,25 @@ void AppendPath()
}
}

private static string Emphasize(string input, char[] separators, Style color, bool compact,
ExceptionSettings settings)
private static void Emphasize(StringBuilder builder, string input, char[] separators, Style color, bool compact,
ExceptionSettings settings, char? limit = null)
{
var builder = new StringBuilder();
var limitIndex = limit.HasValue ? input.IndexOf(limit.Value) : -1;

var type = input;
var index = type.LastIndexOfAny(separators);
var index = limitIndex != -1 ? input[..limitIndex].LastIndexOfAny(separators) : input.LastIndexOfAny(separators);
if (index != -1)
{
if (!compact)
{
builder.AppendWithStyle(
settings.Style.NonEmphasized,
type.Substring(0, index + 1));
builder.AppendWithStyle(settings.Style.NonEmphasized, input[..(index + 1)]);
}

builder.AppendWithStyle(
color,
type.Substring(index + 1, type.Length - index - 1));
builder.AppendWithStyle(color, input[(index + 1)..]);
}
else
{
builder.Append(type.EscapeMarkup());
builder.AppendWithStyle(color, input);
}

return builder.ToString();
}

private static bool ShowInStackTrace(StackFrame frame)
Expand Down
12 changes: 8 additions & 4 deletions src/Spectre.Console/Widgets/Exceptions/TypeNameHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ internal static class TypeNameHelper
/// <param name="type">The <see cref="Type"/>.</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="includeSystemNamespace"><c>true</c> to include the <c>System</c> namespace.</param>
/// <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();
ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames, includeSystemNamespace));
return builder.ToString();
}

Expand Down Expand Up @@ -71,7 +72,7 @@ private static void ProcessType(StringBuilder builder, Type type, DisplayNameOpt
{
builder.Append(builtInName);
}
else if (type.Namespace == nameof(System))
else if (type.Namespace == nameof(System) && !options.IncludeSystemNamespace)
{
builder.Append(type.Name);
}
Expand Down Expand Up @@ -181,14 +182,17 @@ private static void ProcessGenericType(StringBuilder builder, Type type, Type[]

private struct DisplayNameOptions
{
public DisplayNameOptions(bool fullName, bool includeGenericParameterNames)
public DisplayNameOptions(bool fullName, bool includeGenericParameterNames, bool includeSystemNamespace)
{
FullName = fullName;
IncludeGenericParameterNames = includeGenericParameterNames;
IncludeSystemNamespace = includeSystemNamespace;
}

public bool FullName { get; }

public bool IncludeGenericParameterNames { get; }

public bool IncludeSystemNamespace { get; }
}
}

0 comments on commit 9d8d3c1

Please sign in to comment.