Skip to content

Commit

Permalink
term: add functions for detecting Sixel support + example (#21665)
Browse files Browse the repository at this point in the history
  • Loading branch information
larpon authored Jun 11, 2024
1 parent dfdd752 commit 47e93d1
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
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: 64} // xterm's output can be long
for {
w := unsafe { C.getchar() }
if w < 0 {
return false
} else if w == `c` {
break
} else {
buf << u8(w)
}
}
sa := buf.bytestr().all_after('?').split(';')
// returns `true` if the digit literal "4" is found in a "slot" in the response, before the ending `c`.
return '4' in sa
}

// 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
}

0 comments on commit 47e93d1

Please sign in to comment.