Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

term: add functions for detecting Sixel support + example #21665

Merged
1 change: 1 addition & 0 deletions examples/assets/v.six
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
P0;0;0q"1;1;128;128#0;2;0;0;0#1;2;26;35;45#2;2;27;35;45#3;2;27;35;45#4;2;27;35;45#5;2;27;35;45#6;2;27;35;45#7;2;27;35;45#8;2;27;35;46#9;2;27;36;46#10;2;27;35;45#11;2;27;36;45#12;2;27;36;46#13;2;28;36;46#14;2;27;36;47#15;2;28;36;46#16;2;28;36;47#17;2;28;36;47#18;2;27;36;47#19;2;27;36;48#20;2;27;37;48#21;2;28;37;49#22;2;28;36;47#23;2;29;37;47#24;2;29;37;48#25;2;29;37;48#26;2;29;38;48#27;2;29;38;49#28;2;29;38;49#29;2;29;38;49#30;2;29;38;50#31;2;30;38;49#32;2;30;38;49#33;2;30;38;50#34;2;30;39;50#35;2;29;38;51#36;2;29;39;51#37;2;30;39;50#38;2;30;39;51#39;2;30;39;51#40;2;31;39;51#41;2;31;40;51#42;2;31;40;51#43;2;31;40;52#44;2;30;40;53#45;2;29;40;53#46;2;31;41;55#47;2;31;40;51#48;2;31;40;52#49;2;31;41;53#50;2;32;41;53#51;2;32;41;53#52;2;32;41;53#53;2;32;41;53#54;2;32;42;53#55;2;32;42;54#56;2;33;42;54#57;2;32;42;54#58;2;33;42;54#59;2;32;42;55#60;2;33;42;54#61;2;32;42;54#62;2;33;42;54#63;2;32;42;55#64;2;33;42;55#65;2;33;42;54#66;2;33;42;54#67;2;33;42;54#68;2;33;42;55#69;2;32;42;54#70;2;33;42;54#71;2;32;42;54#72;2;33;42;54#73;2;33;42;55#74;2;33;42;54#75;2;33;43;56#76;2;32;43;57#77;2;33;43;56#78;2;33;44;58#79;2;33;44;59#80;2;35;45;58#81;2;33;45;61#82;2;34;45;61#83;2;36;47;61#84;2;36;47;63#85;2;36;48;63#86;2;36;49;65#87;2;38;49;65#88;2;37;51;67#89;2;36;51;72#90;2;36;52;73#91;2;36;53;74#92;2;36;53;74#93;2;36;53;75#94;2;36;53;75#95;2;36;53;75#96;2;36;53;75#97;2;36;53;75#98;2;37;53;75#99;2;36;53;75#100;2;36;53;75#101;2;36;53;75#102;2;37;53;75#103;2;37;53;75#104;2;37;54;75#105;2;39;51;67#106;2;39;51;68#107;2;40;52;70#108;2;40;53;71#109;2;42;54;69#110;2;41;53;70#111;2;42;54;71#112;2;39;53;73#113;2;39;53;72#114;2;40;55;73#115;2;38;54;74#116;2;38;54;74#117;2;38;54;75#118;2;38;54;75#119;2;39;54;75#120;2;40;54;74#121;2;39;54;74#122;2;41;54;72#123;2;36;53;75#124;2;36;53;75#125;2;36;53;75#126;2;37;53;75#127;2;37;53;75#128;2;36;53;75#129;2;36;53;75#130;2;38;54;75#0!128~-!9~^!8N!11^!70~!11^!8N^!9~$#97!9?_ooo_oo_o!8_#129??_#67!70?_#72___#58!7_o_!6o_$#125!13?O??O!9?__#67!83?O-#0!9~}o#101_#125!22?@#101??@!5?C#58!38?_w{!6}!26~N@$#125!9?@K#0!28?!4@BF^!36~^FB!4@#67@@#0!26?o}!9~$#97!10?B^!22~}~~}~!4}ww_-#0!11~}o!33?B^!32~^B!33?o}!11~$#125!11?@?_#129!33?_#58!32?_{!33~N@$#97!12?F^!32~{$#129!12?G-#0!14~w!33?@N!28~NB!33?w!14~$#97!14?Bn!32~}_#58!28?o{!33~F$#125!14?CO#129!33?O-#0!16~w#125O#0!32?@N!24~N@#74!32?_#0w!16~$#97!16?Fn!32~{O#58!24?ow!32~^B$#101!50?A#125_#67!25?C#72!33?C$#73!77?A-#0!18~{_!32?@N!20~N@!32?_{!18~$#97!18?B^!32~}_#58!20?o}!32~^B$#125!53?O-#0!20~{_!32?@F!16~N@!32?_{!20~$#97!20?BN!32~{o#58!16?o}!32~VB$#101!21?O#129!32?A#125G#67!50?G-#0!22~}o#129!32?@#0F!12~F@!32?o}!22~$#97!22?@N!32~}o#58!12?w}!32~N@$#101!57?G-#0!24~}o#125_!31?A#0F!8~F!33?o}!24~$#101!24?@#97N^!31~|w#58!8?o!33~N@$#72!68?G-#0!26~}w#125!32?@?_#58???o}!32~F#72@$#97!26?@F!32~}w#64!4?G#72@#0!32?w}!26~$!61?F^~~~F-!29~w!33?BF#58FN^!29~nB$#97!29?F!33~w#41G?_#72!30?OC$#90!63?C#77O#52GO_#0!30?w!29~$#109!64?_#23_$#37!65?O-#0!31~{_#119!31?@#58A??BN!25~^B$#97!31?B^!31~}o#31@?_#0!26?_{!31~$#7!65?@C#41AO$#109!65?C#23AO#52Co$#130!65?G#1G#48@G$#75!66?O#4_$#111!66?_#28G$#37!67?C-#0!33~{_#101!31?@#7@G#31C_#0!22?_{!33~$#97!33?BN!31~}w#4C_#58@N!21~^B$#125!34?O#80!32?A#17AO#52Eo$#122!67?C#28@#41AO$#83!68?O#48@G$#114!68?_#26G-#0!35~{o#120!32?C_#31C_#0!18?o{!35~$#101!35?@#97F!32~w#4C_#58BN!17~FB$#125!35?A#129G#19!32?@#23@G#52Co#72!17?G$#85!69?A#16A#41AO$#21!70?G#44@G$#87!70?O#7O-#0!37~}o#119!32?C_#31C_#0!14?o}!37~$#125!37?@G#36!32?@#44G@G$#97!38?F!32~w#7Ao#58@N!13~N@$#105!71?A#23@G#52Eo$#4!72?C#41A#37O$#106!72?O-#0!39~}w#46!32?@#7EO#58@N!9~F#67@$#125!39?@#97F!32~w_#28C_#0!10?w}!39~$#101!73?C#23@G#48C_$#107!73?A#76G#37AO$#108!74?O#19_#52AO$#44!75?@#41G-#0!42~w#101o#79!31?@#23@G#48C_#0!5?w!42~$#97!42?FN!31~{_#41@G#58F!5~F$#114!75?A#4A#7O#52BW$#19!76?C#21_#26_$#82!76?G#28C#31O$#112!76?O#37A-#0!44~w_#119!31?AO#31AO#58F^B$#97!44?F^!31~{_#41@G#0?_w!44~$#84!77?@#4A#7O#48C_#72?C$#17!78?@#16G#52BW$#36!78?C#26C#28_$#86!78?G#45_-#0!46~{w!33o{!46~$#97!46?@FF!30NK#23@#44@$#125!46?A#89?G#88!30?@#28A#47A$#101!79?A#78C$#81!80?G-#0!128~-!128B-\
24 changes: 24 additions & 0 deletions examples/term_display_sixel.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module main

import os
import term

fn main() {
println('If your terminal supports the sixel graphics format,')
println('you should see a small green "HI" and a V logo below this text.\n')
if term.supports_sixel() {
// Prints the original "HI" sixel image from the spec:
// https://www.digiater.nl/openvms/decus/vax90b1/krypton-nasa/all-about-sixels.text (See "V. EXAMPLE SIXEL IMAGE" section)
println('\ePq
#0;2;0;0;0#1;2;100;100;0#2;2;0;100;0
#1~~@@vv@@~~@@~~$
#2??}}GG}}??}}??-
#1!14@
\e\\')
// Prints a 128x128 pixels V logo
bytes := os.read_bytes(os.resource_abs_path('assets/v.six'))!
println(bytes.bytestr())
dump(term.supports_sixel())
dump(term.graphics_num_colors())
}
}
104 changes: 104 additions & 0 deletions vlib/term/term_nix.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,107 @@ pub fn clear() bool {
flush_stdout()
return true
}

// supports_sixel returns `true` if the terminal supports Sixel graphics
//
// For more info on the sixel format:
// See https://en.wikipedia.org/wiki/Sixel
// See https://www.digiater.nl/openvms/decus/vax90b1/krypton-nasa/all-about-sixels.text
// For more info on terminal support:
// See https://www.arewesixelyet.com
pub fn supports_sixel() bool {
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
return false
}
if os.getenv('TERM') == 'yaft' {
return true
}

mut old_state := termios.Termios{}
if termios.tcgetattr(0, mut old_state) != 0 {
return false
}
defer {
// restore the old terminal state:
termios.tcsetattr(0, C.TCSANOW, mut old_state)
}

mut state := termios.Termios{}
if termios.tcgetattr(0, mut state) != 0 {
return false
}

state.c_lflag &= termios.invert(u32(C.ICANON) | u32(C.ECHO))
termios.tcsetattr(0, C.TCSANOW, mut state)

// Send a "Query Device Code"
print('\e[c')
flush_stdout()

// Terminal answers with a "Report Device Code" in the format `\e[<code>`
mut buf := []u8{cap: 20}

for {
w := unsafe { C.getchar() }
if w < 0 {
return false
} else if w == `c` {
break
} else {
buf << u8(w)
}
}
// returns `true` if the digit literal "4" is found anywhere before the ending `c`.
return 52 in buf
}

// graphics_num_colors returns the number of color registers the terminal
// graphic attribute is set to use. This can be useful to know if the terminal
// is configured to support Sixel graphics.
//
// See "CSI ? Pi ; Pa ; Pv S" from https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
pub fn graphics_num_colors() u16 {
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
return 0
}

if os.getenv('TERM') == 'yaft' {
return 256
}

mut old_state := termios.Termios{}
if termios.tcgetattr(0, mut old_state) != 0 {
return 0
}
defer {
// restore the old terminal state:
termios.tcsetattr(0, C.TCSANOW, mut old_state)
}

mut state := termios.Termios{}
if termios.tcgetattr(0, mut state) != 0 {
return 0
}

state.c_lflag &= termios.invert(u32(C.ICANON) | u32(C.ECHO))
termios.tcsetattr(0, C.TCSANOW, mut state)

// Send "CSI ? Pi ; Pa ; Pv S"
print('\e[?1;1;0S')
flush_stdout()

mut buf := []u8{cap: 20}
for {
w := unsafe { C.getchar() }
if w < 0 {
return 0
} else if w == `S` {
break
} else if w == `;` {
buf.clear()
} else {
buf << u8(w)
}
}
return buf.bytestr().u16()
}
23 changes: 23 additions & 0 deletions vlib/term/term_windows.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,26 @@ pub fn clear() bool {
C.SetConsoleCursorPosition(hconsole, csbi.dwCursorPosition)
return true
}

// supports_sixel returns `true` if the terminal supports Sixel graphics
//
// For more info on the sixel format:
// See https://en.wikipedia.org/wiki/Sixel
// See https://www.digiater.nl/openvms/decus/vax90b1/krypton-nasa/all-about-sixels.text
// For more info on terminal support:
// See https://www.arewesixelyet.com
pub fn supports_sixel() bool {
// According to (2024) https://www.arewesixelyet.com/#windows-console there's no support
return false
}

// graphics_num_colors returns the number of color registers the terminal
// graphic attribute is set to use. This can be useful to know if the terminal
// is configured to support Sixel graphics.
//
// See "CSI ? Pi ; Pa ; Pv S" from https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
pub fn graphics_num_colors() u16 {
// Since this call is related to sixel terminal graphics and Windows Console and Terminal
// does not have support for querying the graphics setup this call returns 0
return 0
}
Loading