mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-30 17:57:57 +01:00
Refactor SixelSupportDetector for cleaner reading
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
@@ -20,68 +19,115 @@ public class SixelSupportDetector
|
||||
{
|
||||
var result = new SixelSupportResult ();
|
||||
|
||||
result.IsSupported =
|
||||
AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_SendDeviceAttributes, out AnsiEscapeSequenceResponse darResponse)
|
||||
? darResponse.Response.Split (';').Contains ("4")
|
||||
: false;
|
||||
result.IsSupported = IsSixelSupportedByDar ();
|
||||
|
||||
if (result.IsSupported)
|
||||
{
|
||||
// Expect something like:
|
||||
//<esc>[6;20;10t
|
||||
|
||||
bool gotResolutionDirectly = false;
|
||||
|
||||
if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestSixelResolution, out var resolution))
|
||||
if (TryGetResolutionDirectly (out var res))
|
||||
{
|
||||
// Terminal supports directly responding with resolution
|
||||
var match = Regex.Match (resolution.Response, @"\[\d+;(\d+);(\d+)t$");
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse (match.Groups [1].Value, out var ry) &&
|
||||
int.TryParse (match.Groups [2].Value, out var rx))
|
||||
{
|
||||
result.Resolution = new Size (rx, ry);
|
||||
gotResolutionDirectly = true;
|
||||
}
|
||||
}
|
||||
result.Resolution = res;
|
||||
}
|
||||
else if(TryComputeResolution(out res))
|
||||
{
|
||||
result.Resolution = res;
|
||||
}
|
||||
|
||||
if (!gotResolutionDirectly)
|
||||
{
|
||||
// Fallback to window size in pixels and characters
|
||||
if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestWindowSizeInPixels, out var pixelSizeResponse) &&
|
||||
AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_ReportTerminalSizeInChars, out var charSizeResponse))
|
||||
{
|
||||
// Example [4;600;1200t
|
||||
var pixelMatch = Regex.Match (pixelSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$");
|
||||
|
||||
// Example [8;30;120t
|
||||
var charMatch = Regex.Match (charSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$");
|
||||
|
||||
if (pixelMatch.Success && charMatch.Success)
|
||||
{
|
||||
// Extract pixel dimensions
|
||||
if (int.TryParse (pixelMatch.Groups [1].Value, out var pixelHeight) &&
|
||||
int.TryParse (pixelMatch.Groups [2].Value, out var pixelWidth) &&
|
||||
// Extract character dimensions
|
||||
int.TryParse (charMatch.Groups [1].Value, out var charHeight) &&
|
||||
int.TryParse (charMatch.Groups [2].Value, out var charWidth) &&
|
||||
charWidth != 0 && charHeight != 0) // Avoid divide by zero
|
||||
{
|
||||
// Calculate the character cell size in pixels
|
||||
var cellWidth = (int)Math.Round ((double)pixelWidth / charWidth);
|
||||
var cellHeight = (int)Math.Round ((double)pixelHeight / charHeight);
|
||||
|
||||
// Set the resolution based on the character cell size
|
||||
result.Resolution = new Size (cellWidth, cellHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.SupportsTransparency = IsWindowsTerminal () || IsXtermWithTransparency ();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private bool TryGetResolutionDirectly (out Size resolution)
|
||||
{
|
||||
// Expect something like:
|
||||
//<esc>[6;20;10t
|
||||
|
||||
if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestSixelResolution, out var response))
|
||||
{
|
||||
// Terminal supports directly responding with resolution
|
||||
var match = Regex.Match (response.Response, @"\[\d+;(\d+);(\d+)t$");
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse (match.Groups [1].Value, out var ry) &&
|
||||
int.TryParse (match.Groups [2].Value, out var rx))
|
||||
{
|
||||
resolution = new Size (rx, ry);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolution = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private bool TryComputeResolution (out Size resolution)
|
||||
{
|
||||
// Fallback to window size in pixels and characters
|
||||
if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestWindowSizeInPixels, out var pixelSizeResponse)
|
||||
&& AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_ReportTerminalSizeInChars, out var charSizeResponse))
|
||||
{
|
||||
// Example [4;600;1200t
|
||||
var pixelMatch = Regex.Match (pixelSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$");
|
||||
|
||||
// Example [8;30;120t
|
||||
var charMatch = Regex.Match (charSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$");
|
||||
|
||||
if (pixelMatch.Success && charMatch.Success)
|
||||
{
|
||||
// Extract pixel dimensions
|
||||
if (int.TryParse (pixelMatch.Groups [1].Value, out var pixelHeight)
|
||||
&& int.TryParse (pixelMatch.Groups [2].Value, out var pixelWidth)
|
||||
&&
|
||||
|
||||
// Extract character dimensions
|
||||
int.TryParse (charMatch.Groups [1].Value, out var charHeight)
|
||||
&& int.TryParse (charMatch.Groups [2].Value, out var charWidth)
|
||||
&& charWidth != 0
|
||||
&& charHeight != 0) // Avoid divide by zero
|
||||
{
|
||||
// Calculate the character cell size in pixels
|
||||
var cellWidth = (int)Math.Round ((double)pixelWidth / charWidth);
|
||||
var cellHeight = (int)Math.Round ((double)pixelHeight / charHeight);
|
||||
|
||||
// Set the resolution based on the character cell size
|
||||
resolution = new Size (cellWidth, cellHeight);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolution = default;
|
||||
return false;
|
||||
}
|
||||
private bool IsSixelSupportedByDar ()
|
||||
{
|
||||
return AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_SendDeviceAttributes, out AnsiEscapeSequenceResponse darResponse)
|
||||
? darResponse.Response.Split (';').Contains ("4")
|
||||
: false;
|
||||
}
|
||||
|
||||
private bool IsWindowsTerminal ()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable ("WT_SESSION"));;
|
||||
}
|
||||
private bool IsXtermWithTransparency ()
|
||||
{
|
||||
// Check if running in real xterm (XTERM_VERSION is more reliable than TERM)
|
||||
var xtermVersionStr = Environment.GetEnvironmentVariable ("XTERM_VERSION");
|
||||
|
||||
// If XTERM_VERSION exists, we are in a real xterm
|
||||
if (!string.IsNullOrWhiteSpace (xtermVersionStr) && int.TryParse (xtermVersionStr, out var xtermVersion) && xtermVersion >= 370)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
public class SixelSupportResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the current driver supports sixel graphic format.
|
||||
/// Whether the terminal supports sixel graphic format.
|
||||
/// Defaults to false.
|
||||
/// </summary>
|
||||
public bool IsSupported { get; set; }
|
||||
@@ -24,4 +24,10 @@ public class SixelSupportResult
|
||||
/// to 256.
|
||||
/// </summary>
|
||||
public int MaxPaletteColors { get; set; } = 256;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the terminal supports transparent background sixels.
|
||||
/// Defaults to false
|
||||
/// </summary>
|
||||
public bool SupportsTransparency { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user