mirror of
https://github.com/spectreconsole/spectre.console.git
synced 2025-10-25 15:19:23 +00:00
137 lines
5.2 KiB
C#
137 lines
5.2 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.RegularExpressions;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Portions of this code was ported from the supports-ansi project by Qingrong Ke
|
|
// https://github.com/keqingrong/supports-ansi/blob/master/index.js
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace Spectre.Console.Internal
|
|
{
|
|
internal static class AnsiDetector
|
|
{
|
|
private static readonly Regex[] _regexes = new[]
|
|
{
|
|
new Regex("^xterm"), // xterm, PuTTY, Mintty
|
|
new Regex("^rxvt"), // RXVT
|
|
new Regex("^eterm"), // Eterm
|
|
new Regex("^screen"), // GNU screen, tmux
|
|
new Regex("tmux"), // tmux
|
|
new Regex("^vt100"), // DEC VT series
|
|
new Regex("^vt102"), // DEC VT series
|
|
new Regex("^vt220"), // DEC VT series
|
|
new Regex("^vt320"), // DEC VT series
|
|
new Regex("ansi"), // ANSI
|
|
new Regex("scoansi"), // SCO ANSI
|
|
new Regex("cygwin"), // Cygwin, MinGW
|
|
new Regex("linux"), // Linux console
|
|
new Regex("konsole"), // Konsole
|
|
new Regex("bvterm"), // Bitvise SSH Client
|
|
};
|
|
|
|
public static (bool SupportsAnsi, bool LegacyConsole) Detect(bool upgrade)
|
|
{
|
|
// Github action doesn't setup a correct PTY but supports ANSI.
|
|
if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("GITHUB_ACTION")))
|
|
{
|
|
return (true, false);
|
|
}
|
|
|
|
// Running on Windows?
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
// Running under ConEmu?
|
|
var conEmu = Environment.GetEnvironmentVariable("ConEmuANSI");
|
|
if (!string.IsNullOrEmpty(conEmu) && conEmu.Equals("On", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return (true, false);
|
|
}
|
|
|
|
var supportsAnsi = Windows.SupportsAnsi(upgrade, out var legacyConsole);
|
|
return (supportsAnsi, legacyConsole);
|
|
}
|
|
|
|
// Check if the terminal is of type ANSI/VT100/xterm compatible.
|
|
var term = Environment.GetEnvironmentVariable("TERM");
|
|
if (!string.IsNullOrWhiteSpace(term))
|
|
{
|
|
if (_regexes.Any(regex => regex.IsMatch(term)))
|
|
{
|
|
return (true, false);
|
|
}
|
|
}
|
|
|
|
return (false, true);
|
|
}
|
|
|
|
[SuppressMessage("Design", "CA1060:Move pinvokes to native methods class")]
|
|
internal static class Windows
|
|
{
|
|
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
|
private const int STD_OUTPUT_HANDLE = -11;
|
|
|
|
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
|
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
|
|
|
|
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
|
private const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008;
|
|
|
|
[DllImport("kernel32.dll")]
|
|
private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern IntPtr GetStdHandle(int nStdHandle);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
public static extern uint GetLastError();
|
|
|
|
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
|
|
public static bool SupportsAnsi(bool upgrade, out bool isLegacy)
|
|
{
|
|
isLegacy = false;
|
|
|
|
try
|
|
{
|
|
var @out = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (!GetConsoleMode(@out, out var mode))
|
|
{
|
|
// Could not get console mode.
|
|
return false;
|
|
}
|
|
|
|
if ((mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)
|
|
{
|
|
isLegacy = true;
|
|
|
|
if (!upgrade)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Try enable ANSI support.
|
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
|
if (!SetConsoleMode(@out, mode))
|
|
{
|
|
// Enabling failed.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
// All we know here is that we don't support ANSI.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|