Skip to content

Commit 38abd36

Browse files
committed
compatibility checks for kitty, experimental windowsizing stuff.
1 parent 0f09c67 commit 38abd36

File tree

7 files changed

+120
-10
lines changed

7 files changed

+120
-10
lines changed

docs/en-US/ConvertTo-Sixel.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ Accept wildcard characters: False
132132
133133
### -Protocol
134134
135-
Select the image protocol to output, supports Sixel & InlineImageProtocol (1337 xterm).
135+
Select the image protocol to output.
136+
Supports Sixel, InlineImageProtocol, KittyGraphicsProtocol
137+
138+
It will attempt to autoselect the supported image protocol for your terminal.
136139
137140
```yaml
138141
Type: ImageProtocol

src/Sixel/Sixel.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1919
<PrivateAssets>all</PrivateAssets>
2020
</PackageReference>
21-
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
21+
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />
2222
<PackageReference Include="System.Management.Automation" Version="7.4.6" PrivateAssets="all" />
2323
<ProjectReference Include="../Sixel.Shared/Sixel.Shared.csproj" />
2424
</ItemGroup>

src/Sixel/Terminal/Compatibility.cs

+74-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Sixel.Terminal.Models;
2+
using System.Diagnostics;
23

34
namespace Sixel.Terminal;
45

@@ -9,6 +10,11 @@ public static class Compatibility
910
/// </summary>
1011
private static bool? _terminalSupportsSixel;
1112

13+
/// <summary>
14+
/// Check if the terminal supports kitty graphics
15+
/// </summary>
16+
private static bool? _terminalSupportsKitty;
17+
1218
/// <summary>
1319
/// Memory-caches the result of the terminal cell size.
1420
/// </summary>
@@ -17,8 +23,12 @@ public static class Compatibility
1723
/// <summary>
1824
/// get the terminal info
1925
/// </summary>
20-
2126
private static TerminalInfo? _terminalInfo;
27+
28+
private static WindowSizePixels? _windowSizePixels;
29+
30+
private static WindowSizeCharacters? _windowSizeCharacters;
31+
2232
/// <summary>
2333
/// Get the cell size of the terminal in pixel-sixel size.
2434
/// The response to the command will look like [6;20;10t where the 20 is height and 10 is width.
@@ -52,9 +62,55 @@ public static CellSize GetCellSize()
5262
PixelHeight = 20
5363
};
5464
}
55-
5665
return _cellSize;
5766
}
67+
public static WindowSizePixels GetWindowSizePixels()
68+
{
69+
// this class should be able to re-run, people can resize the terminal
70+
// so should not cache the result.. hopefully this is not too slow
71+
var response14 = GetControlSequenceResponse("[14t");
72+
try
73+
{
74+
var parts14 = response14.Split(';', 't');
75+
_windowSizePixels = new WindowSizePixels
76+
{
77+
PixelWidth = int.Parse(parts14[2]),
78+
PixelHeight = int.Parse(parts14[1]),
79+
};
80+
}
81+
catch
82+
{
83+
_windowSizePixels = new WindowSizePixels
84+
{
85+
PixelWidth = 0,
86+
PixelHeight = 0
87+
};
88+
}
89+
return _windowSizePixels;
90+
}
91+
public static WindowSizeCharacters GetWindowSizeCharacters()
92+
{
93+
// this class should be able to re-run, people can resize the terminal
94+
// so should not cache the result.. hopefully this is not too slow
95+
var response18 = GetControlSequenceResponse("[18t");
96+
try
97+
{
98+
var parts18 = response18.Split(';', 't');
99+
_windowSizeCharacters = new WindowSizeCharacters
100+
{
101+
CharacterWidth = int.Parse(parts18[2]),
102+
CharacterHeight = int.Parse(parts18[1]),
103+
};
104+
}
105+
catch {
106+
_windowSizeCharacters = new WindowSizeCharacters
107+
{
108+
CharacterWidth = 0,
109+
CharacterHeight = 0
110+
};
111+
}
112+
return _windowSizeCharacters;
113+
}
58114

59115
/// <summary>
60116
/// Check if the terminal supports sixel graphics.
@@ -69,17 +125,28 @@ public static bool TerminalSupportsSixel()
69125
{
70126
return _terminalSupportsSixel.Value;
71127
}
72-
73128
_terminalSupportsSixel = GetControlSequenceResponse("[c").Contains(";4;");
74-
75129
return _terminalSupportsSixel.Value;
76130
}
77131

78132
/// <summary>
79-
/// Send a control sequence to the terminal and read back the response from STDIN.
133+
/// Check if the terminal supports kitty graphics.
134+
/// https://sw.kovidgoyal.net/kitty/graphics-protocol/
135+
// response: ␛_Gi=31;OK␛\␛[?62;c
80136
/// </summary>
81-
/// <param name="controlSequence"></param>
82-
/// <returns>The response from the terminal.</returns>
137+
/// <returns>True if the terminal supports sixel graphics, false otherwise.</returns>
138+
public static bool TerminalSupportsKitty()
139+
{
140+
if (_terminalSupportsKitty.HasValue)
141+
{
142+
return _terminalSupportsKitty.Value;
143+
}
144+
// string kittyTest = $"_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA{Constants.ESC}\\{Constants.ESC}[c";
145+
string kittyTest = $"_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA{Constants.ESC}\\";
146+
_terminalSupportsKitty = GetControlSequenceResponse(kittyTest).Contains(";OK");
147+
return _terminalSupportsKitty.Value;
148+
}
149+
83150
private static string GetControlSequenceResponse(string controlSequence)
84151
{
85152
char? c;

src/Sixel/Terminal/Load.cs

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ public static class Load
2727
}
2828
if (imageProtocol == ImageProtocol.KittyGraphicsProtocol)
2929
{
30+
if (Compatibility.TerminalSupportsKitty() == false && Force == false)
31+
{
32+
throw new InvalidOperationException("Terminal does not support Kitty, override with -Force");
33+
}
3034
if (width > 0)
3135
{
3236
// we need to resize the image to the target width
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Sixel.Terminal.Models;
2+
3+
/// <summary>
4+
/// Represents the size of the terminal window in characters.
5+
/// </summary>
6+
public class WindowSizeCharacters
7+
{
8+
/// <summary>
9+
/// Gets the width of the terminal in characters.
10+
/// </summary>
11+
public int CharacterWidth { get; set; }
12+
13+
/// <summary>
14+
/// Gets the height of the terminal in characters.
15+
/// </summary>
16+
public int CharacterHeight { get; set; }
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Sixel.Terminal.Models;
2+
3+
/// <summary>
4+
/// Represents the size of the terminal window in pixels
5+
/// not supported in all terminals.
6+
/// like WezTerm, Alacritty
7+
/// </summary>
8+
public class WindowSizePixels
9+
{
10+
/// <summary>
11+
/// Gets the width of the terminal in pixels.
12+
/// </summary>
13+
public int PixelWidth { get; set; }
14+
15+
/// <summary>
16+
/// Gets the height of the terminal in pixels.
17+
/// </summary>
18+
public int PixelHeight { get; set; }
19+
}

src/Sixel/Terminal/Validate.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin
1010
{
1111
var requestedWidth = (int)arguments;
1212
var hostWidth = engineIntrinsics.Host.UI.RawUI.WindowSize.Width;
13-
if (requestedWidth > hostWidth)
13+
if (requestedWidth > hostWidth)
1414
{
1515
throw new ValidationMetadataException($"{requestedWidth} width is greater than terminal width ({hostWidth}).");
1616
}

0 commit comments

Comments
 (0)