mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
135 lines
4.3 KiB
C#
135 lines
4.3 KiB
C#
using System;
|
|
using System.IO;
|
|
using CliFx.Exceptions;
|
|
using CliFx.Infrastructure;
|
|
using CliFx.Utils;
|
|
|
|
namespace CliFx.Formatting
|
|
{
|
|
internal class ExceptionConsoleFormatter : ConsoleFormatter
|
|
{
|
|
public ExceptionConsoleFormatter(ConsoleWriter consoleWriter)
|
|
: base(consoleWriter)
|
|
{
|
|
}
|
|
|
|
private void WriteStackFrame(StackFrame stackFrame, int indentLevel)
|
|
{
|
|
WriteHorizontalMargin(2 + 4 * indentLevel);
|
|
Write("at ");
|
|
|
|
// Fully qualified method name
|
|
Write(stackFrame.ParentType + '.');
|
|
Write(ConsoleColor.Yellow, stackFrame.MethodName);
|
|
|
|
// Method parameters
|
|
|
|
Write('(');
|
|
|
|
for (var i = 0; i < stackFrame.Parameters.Count; i++)
|
|
{
|
|
var parameter = stackFrame.Parameters[i];
|
|
|
|
// Separator
|
|
if (i > 0)
|
|
{
|
|
Write(", ");
|
|
}
|
|
|
|
// Parameter type
|
|
Write(ConsoleColor.Blue, parameter.Type);
|
|
|
|
// Parameter name (can be null for dynamically generated methods)
|
|
if (!string.IsNullOrWhiteSpace(parameter.Name))
|
|
{
|
|
Write(' ');
|
|
Write(ConsoleColor.White, parameter.Name);
|
|
}
|
|
}
|
|
|
|
Write(") ");
|
|
|
|
// Location
|
|
if (!string.IsNullOrWhiteSpace(stackFrame.FilePath))
|
|
{
|
|
var stackFrameDirectoryPath =
|
|
Path.GetDirectoryName(stackFrame.FilePath) + Path.DirectorySeparatorChar;
|
|
|
|
var stackFrameFileName = Path.GetFileName(stackFrame.FilePath);
|
|
|
|
Write("in ");
|
|
|
|
// File path
|
|
Write(stackFrameDirectoryPath);
|
|
Write(ConsoleColor.Yellow, stackFrameFileName);
|
|
|
|
// Source position
|
|
if (!string.IsNullOrWhiteSpace(stackFrame.LineNumber))
|
|
{
|
|
Write(':');
|
|
Write(ConsoleColor.Blue, stackFrame.LineNumber);
|
|
}
|
|
}
|
|
|
|
WriteLine();
|
|
}
|
|
|
|
private void WriteException(Exception exception, int indentLevel)
|
|
{
|
|
WriteHorizontalMargin(4 * indentLevel);
|
|
|
|
// Fully qualified exception type
|
|
var exceptionType = exception.GetType();
|
|
Write(exceptionType.Namespace + '.');
|
|
Write(ConsoleColor.White, exceptionType.Name);
|
|
Write(": ");
|
|
|
|
// Exception message
|
|
Write(ConsoleColor.Red, exception.Message);
|
|
WriteLine();
|
|
|
|
// Recurse into inner exceptions
|
|
if (exception.InnerException is not null)
|
|
{
|
|
WriteException(exception.InnerException, indentLevel + 1);
|
|
}
|
|
|
|
// Non-thrown exceptions (e.g. inner exceptions) have no stacktrace
|
|
if (!string.IsNullOrWhiteSpace(exception.StackTrace))
|
|
{
|
|
// Parse and pretty-print the stacktrace
|
|
foreach (var stackFrame in StackFrame.ParseMany(exception.StackTrace))
|
|
{
|
|
WriteStackFrame(stackFrame, indentLevel);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void WriteException(Exception exception)
|
|
{
|
|
// Domain exceptions should be printed with minimal information
|
|
// because they are meant for the user of the application,
|
|
// not the user of the library.
|
|
if (exception is CliFxException cliFxException &&
|
|
!string.IsNullOrWhiteSpace(cliFxException.ActualMessage))
|
|
{
|
|
Write(ConsoleColor.Red, cliFxException.ActualMessage);
|
|
WriteLine();
|
|
}
|
|
// All other exceptions most likely indicate an actual bug
|
|
// and should include stacktrace and other detailed information.
|
|
else
|
|
{
|
|
Write(ConsoleColor.White, ConsoleColor.DarkRed, "ERROR");
|
|
WriteLine();
|
|
WriteException(exception, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static class ExceptionConsoleFormatterExtensions
|
|
{
|
|
public static void WriteException(this ConsoleWriter consoleWriter, Exception exception) =>
|
|
new ExceptionConsoleFormatter(consoleWriter).WriteException(exception);
|
|
}
|
|
} |