From 1f6ee6c86d4a727b5ef5d6f59f69e36360b21ab9 Mon Sep 17 00:00:00 2001 From: Mel Massadian Date: Thu, 16 Jan 2025 20:00:54 +0100 Subject: [PATCH] =?UTF-8?q?chore:=20=F0=9F=A7=B9=20update=20imgcat=20and?= =?UTF-8?q?=20add=20support=20for=20kitty=20(#1017)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This could be done better by exposing more options from the protocol, but it should be a good start! --- sourced/imaging/imgcat.nu | 187 +++++++++++++++++++++++++------------- 1 file changed, 122 insertions(+), 65 deletions(-) diff --git a/sourced/imaging/imgcat.nu b/sourced/imaging/imgcat.nu index 81e715e..add2a5b 100644 --- a/sourced/imaging/imgcat.nu +++ b/sourced/imaging/imgcat.nu @@ -1,91 +1,148 @@ # https://iterm2.com/documentation-images.html +# https://sw.kovidgoyal.net/kitty/graphics-protocol/ + +def is-screen-term [] { + $env.TERM =~ ^screen +} def print_osc [] { - if $env.TERM == screen* { - "\ePtmux;\e\e]" - } else { - "\e]" - } + if (is-screen-term) { + return "\ePtmux;\e\e]" + } + ansi escape_right } def print_st [] { - if $env.TERM == screen* { - "\a\e\\" - } else { - "\a" - } + if (is-screen-term) { + return "\a\e\\" + } + "\a" } -def --env b64_encode [fn] { - open $fn | encode base64 +def b64_encode [fn] { + open -r $fn | encode base64 } -def --env b64_decode [fn] { - $fn | decode base64 -} - -def print_image [ - filename # Filename to convey to client - inline # 0 or 1 - base64contents # Base64-encoded contents - print_filename # If non-empty, print the filename before outputting the image +# Print an image using the iTerm protocol +def print_iterm_image [ + filename: path + base64contents: string + --inline + --print_filename ] { - let a = (print_osc) - let b = "1337;File=" - let c = (if ($filename | length) > 0 { - let b64_enc_data = (b64_encode $filename) + let b64_enc_data = (b64_encode $filename) + let b64_dec_data = ($base64contents | decode base64) + let query = ( + [(print_osc)] + | append "1337;File=" + | append ( + if ($filename | str length) > 0 { $"name=($b64_enc_data);" - }) - let b64_dec_data = (b64_decode $base64contents) - let d = $"size=($b64_dec_data | bytes length)" - let e = $";inline=($inline)" - let f = ":" - let g = $base64contents - let h = print_st - let i = "\n" - let j = (if ($print_filename | length) > 0 { - print -n $filename - }) + } + ) + | append $"size=($b64_dec_data | bytes length)" + | append ( + if $inline { + $";inline=1" + } + ) + | append ":" + | append $base64contents + | append (print_st) + | append "\n" + ) - [ $a $b $c $d $e $f $g $h $i $j ] | str join + if $print_filename { + print -n $filename + } + + $query | str join +} + +# Print an image using the Kitty protocol +def print_kitty_image [ + filename: path + base64contents: string + --print_filename +] { + + let b64_dec_data = ($base64contents | decode base64) + let size = ($b64_dec_data | bytes length) + + let result = ( + ["\e"] + | append "_G" + | append $"a=T,f=100,t=d,s=($size);" + | append $base64contents + | append (ansi st) + ) + + if $print_filename { + print -n $filename + } + + $result | str join +} + +# Determine the appropriate protocol and print the image +def print_image [ + filename: path + base64contents: string + --inline # Only for iTerm; ignored for Kitty + --print_filename +] { + if (detect_kitty_support) { + print_kitty_image $filename $base64contents --print_filename=$print_filename + } else { + print_iterm_image $filename $base64contents --inline=$inline --print_filename=$print_filename + } } def error [] { - print "Error: ($env.LAST_EXIT_CODE)" + print "Error: ($env.LAST_EXIT_CODE)" } def show_help [] { - print "Usage: imgcat [-p] filename ..." - print " or: cat filename | imgcat" + print "Usage: imgcat [-p] filename ..." + print " or: cat filename | imgcat" +} + +# Detect Kitty support by querying the terminal +# https://sw.kovidgoyal.net/kitty/graphics-protocol/#querying-support-and-available-transmission-mediums +def detect_kitty_support [] { + let is_kitty_supported = $"(ansi esc)_Gi=1234,s=1,v=1,a=q,t=d,f=24;AAAA(ansi st)" + return (term query $is_kitty_supported --terminator (ansi st) | "OK" in ($in | decode)) +} + +export def detected [] { + print $"Kitty support: (detect_kitty_support)" + print $"Is Screen term: (is-screen-term)" } # imgcat.nu shows images in your terminal if your terminal supports it -def imgcat [ - --help(-h) # Help/Usage message - --print(-p) # Print filename - --url(-u) # Use a URL - filename # The filename to show +# it uses either the Iterm or the Kitty protocol +export def main [ + --help (-h) # Help/Usage message + --print (-p) # Print filename + --url (-u) # Use a URL + --inline (-i) # Inline image (only for iTerm; ignored for Kitty) + filename # The filename to show ] { - if $help { - show_help + if $help { + show_help + } + + let url_img = ( + if $url { + let encoded_image = (b64_encode (http get $url)) + print_image $url $encoded_image --inline=$inline --print_filename=$print } + ) - let print_filename = ( - if $print { - 1 - } - ) - - let url_img = ( - if $url { - let encoded_image = (b64_encode (http get $url)) - print_image $url 1 $encoded_image $print_filename - } - ) - - if ($filename | path exists) { - print_image $filename 1 (b64_encode $filename) $print_filename - } else { - print $"imgcat: ($filename): No such file or directory" - } + if ($filename | path exists) { + let filename = ($filename | path expand) + print_image $filename (b64_encode $filename) --inline=$inline --print_filename=$print + } else { + print $"imgcat: ($filename): No such file or directory" + } }