`AnsiConsoleFactory` should be an internal static class. Creating an `IAnsiConsole` can be achieved through `Spectre.Console.AnsiConsole.Create(AnsiConsoleSettings)`
Since `AnsiConsoleFactory` is public, it can't be changed from a non static class to a static class so obsoleting it is the second best thing to do.
Eventually, when `AnsiConsoleFactory` becomes internal and static, `AnsiConsole.Create` can be simplified to this (and the private static field `_factory` can be removed)
```
public static IAnsiConsole Create(AnsiConsoleSettings settings)
{
return AnsiConsoleFactory.Create(settings);
}
```
Now that exceptions are not _parsed_ anymore (#513 and #637), keeping the `ExceptionInfo` and `StackFrameInfo` internal classes doesn't make much sense anymore. The `Exception` and `StackFrame` types can be used by the `ExceptionFormatter` class directly, without conversion.
This is the natural extension of #513 which already removed a lot of regex parsing.
The `ExceptionParser` class is renamed into `ExceptionConverter` because there is no more string parsing performed at all. `Exception` is converted into `ExceptionInfo` and `StackFrame` is converted into `StackFrameInfo`.
The generic parameters were double escaped and would display as `[[T0,T1,TRet]]` instead of `[T0,T1,TRet]`. This is because the `builder.AppendWithStyle` method already escapes its value so the caller must not escape the passed value.
* Invert `#if NET5_0` conditions so that when adding net6.0 target framework, the _new_ APIs are used.
* Use `NET5_0_OR_GREATER` instead of `NET5_0` to ensure consistent behaviour on future target frameworks.
The style parameter is actually nullable. Also, the documentation of the style parameter has been made explicit that `Style.Plain` is used when a `null` style is passed.
When running on .NET Framework, the `Should_Report_Max_Remaining_Time_For_Extremely_Small_Progress` would intermittently fail with the following error:
```
task.RemainingTime
should be
10675199.02:48:05.4775807
but was
null
```
This is because it's possible that the two increment share the same timestamp thus making the `RemainingTime` null. To ensure the two increments don't share the same timestamp, we sleep for one millisecond.
Although I have only observed this issue on .NET Framework it would be possible that it occasionally also occur on .NET Core.
On .NET Framework, `exception.ToString()` uses a slightly different format than on .NET Core.
So in order to properly transform an `Exception` into an `ExceptionInfo` on both .NET Core and .NET Framework we use `exception.StackTrace` + `exception.InnerException`. As an added benefit, it greatly simplifies the implementation of the `ExceptionParser` class.
Since Spectre.Console targets .NET Standard 2.0 it makes sense to also run tests on .NET Framework (Windows only)
This makes two tests fail: `Should_Write_Exception_With_Inner_Exception` and `Should_Write_Exceptions_With_Generic_Type_Parameters_In_Callsite_As_Expected`.
Received (inner exception not handled):
```
System.InvalidOperationException: Something threw!System.InvalidOperationException: Throwing!
at Spectre.Console.Tests.Data.TestExceptions.MethodThatThrows(Nullable`1 number) in /xyz/Exceptions.cs:nn
at Spectre.Console.Tests.Data.TestExceptions.ThrowWithInnerException() in /xyz/Exceptions.cs:nn
```
Verified:
```
System.InvalidOperationException: Something threw!
System.InvalidOperationException: Throwing!
at Spectre.Console.Tests.Data.TestExceptions.MethodThatThrows(Nullable`1 number) in /xyz/Exceptions.cs:nn
at Spectre.Console.Tests.Data.TestExceptions.ThrowWithInnerException() in /xyz/Exceptions.cs:nn
at Spectre.Console.Tests.Data.TestExceptions.ThrowWithInnerException() in /xyz/Exceptions.cs:nn
at Spectre.Console.Tests.Unit.ExceptionTests.<>c.<Should_Write_Exception_With_Inner_Exception>b__3_0() in /xyz/ExceptionTests.cs:nn
at Spectre.Console.Tests.Unit.ExceptionTests.GetException(Action action) in /xyz/ExceptionTests.cs:nn
```