Fixes color system detection bug

If an application runs on Windows 10.0.15063 or above, on a
runtime prior to net5.0, the color system detection will fail
and fall back to 8-bit color support.

The reason for this is because the behavior of
Environment.OSVersion.Version differs between runtimes. Unless you're
running on net5.0, both the major and build version components will
not reflect those in the actual Windows version.
This commit is contained in:
Patrik Svensson 2021-04-07 00:28:55 +02:00 committed by Phil Scott
parent 39b59c8d4a
commit fe5096dceb

View File

@ -1,41 +1,47 @@
using System;
using System.Runtime.InteropServices;
#if !NET5_0
using System.Text.RegularExpressions;
#endif
namespace Spectre.Console
{
internal static class ColorSystemDetector
{
// Adapted from https://github.com/willmcgugan/rich/blob/f0c29052c22d1e49579956a9207324d9072beed7/rich/console.py#L391
// which I think is battletested enough to trust.
public static ColorSystem Detect(bool supportsAnsi)
{
// No colors?
if (Environment.GetEnvironmentVariables().Contains("NO_COLOR"))
{
// No colors supported
return ColorSystem.NoColors;
}
// Windows?
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (!supportsAnsi)
{
// Figure out what we should do here.
// Does really all Windows terminals support
// eight-bit colors? Probably not...
return ColorSystem.EightBit;
}
var os = Environment.OSVersion;
var major = os.Version.Major;
var build = os.Version.Build;
if (major > 10)
// Windows 10.0.15063 and above support true color,
// and we can probably assume that the next major
// version of Windows will support true color as well.
if (GetWindowsVersionInformation(out var major, out var build))
{
// Future Patrik will thank me.
return ColorSystem.TrueColor;
}
if (major == 10 && build >= 15063)
{
return ColorSystem.TrueColor;
if (major == 10 && build >= 15063)
{
return ColorSystem.TrueColor;
}
else if (major > 10)
{
return ColorSystem.TrueColor;
}
}
}
else
@ -51,7 +57,41 @@ namespace Spectre.Console
}
}
// Should we default to eight-bit colors?
return ColorSystem.EightBit;
}
// See https://docs.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/5.0/environment-osversion-returns-correct-version
private static bool GetWindowsVersionInformation(out int major, out int build)
{
major = 0;
build = 0;
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return false;
}
#if NET5_0
// The reason we're not always using this, is because it
// will return wrong values on other runtimes than net5.0
var version = Environment.OSVersion.Version;
major = version.Major;
build = version.Build;
return true;
#else
var regex = new Regex("Microsoft Windows (?'major'[0-9]*).(?'minor'[0-9]*).(?'build'[0-9]*)\\s*$");
var match = regex.Match(RuntimeInformation.OSDescription);
if (match.Success && int.TryParse(match.Groups["major"].Value, out major))
{
if (int.TryParse(match.Groups["build"].Value, out build))
{
return true;
}
}
return false;
#endif
}
}
}