@@ -198,9 +198,85 @@ func ghosttySupported() bool {
198198 return os .Getenv ("GHOSTTY_RESOURCES_DIR" ) != ""
199199}
200200
201+ func iterm2Supported () bool {
202+ termProgram := strings .ToLower (os .Getenv ("TERM_PROGRAM" ))
203+ if termProgram == "iterm.app" {
204+ return true
205+ }
206+
207+ // Check for iTerm2-specific environment variables
208+ if os .Getenv ("ITERM_SESSION_ID" ) != "" || os .Getenv ("ITERM_PROFILE" ) != "" {
209+ return true
210+ }
211+
212+ return false
213+ }
214+
215+ func weztermSupported () bool {
216+ // Check for WezTerm-specific environment variables
217+ if os .Getenv ("WEZTERM_EXECUTABLE" ) != "" || os .Getenv ("WEZTERM_CONFIG_FILE" ) != "" {
218+ return true
219+ }
220+
221+ termProgram := strings .ToLower (os .Getenv ("TERM_PROGRAM" ))
222+ if termProgram == "wezterm" {
223+ return true
224+ }
225+
226+ term := strings .ToLower (os .Getenv ("TERM" ))
227+ if strings .Contains (term , "wezterm" ) {
228+ return true
229+ }
230+
231+ return false
232+ }
233+
234+ func waystSupported () bool {
235+ term := strings .ToLower (os .Getenv ("TERM" ))
236+ if strings .Contains (term , "wayst" ) {
237+ return true
238+ }
239+
240+ termProgram := strings .ToLower (os .Getenv ("TERM_PROGRAM" ))
241+ if termProgram == "wayst" {
242+ return true
243+ }
244+
245+ return false
246+ }
247+
248+ func warpSupported () bool {
249+ termProgram := strings .ToLower (os .Getenv ("TERM_PROGRAM" ))
250+ if termProgram == "warp" {
251+ return true
252+ }
253+
254+ // Check for Warp-specific environment variables
255+ if os .Getenv ("WARP_IS_LOCAL_SHELL_SESSION" ) != "" || os .Getenv ("WARP_COMBINED_PROMPT_COMMAND_FINISHED" ) != "" {
256+ return true
257+ }
258+
259+ return false
260+ }
261+
262+ func konsoleSupported () bool {
263+ // Check for Konsole-specific environment variables
264+ if os .Getenv ("KONSOLE_DBUS_SESSION" ) != "" || os .Getenv ("KONSOLE_VERSION" ) != "" {
265+ return true
266+ }
267+
268+ termProgram := strings .ToLower (os .Getenv ("TERM_PROGRAM" ))
269+ if termProgram == "konsole" {
270+ return true
271+ }
272+
273+ return false
274+ }
275+
201276// imageProtocolSupported checks if any supported image protocol terminal is detected.
202277func imageProtocolSupported () bool {
203- return kittySupported () || ghosttySupported ()
278+ return kittySupported () || ghosttySupported () || iterm2Supported () ||
279+ weztermSupported () || waystSupported () || warpSupported () || konsoleSupported ()
204280}
205281
206282func debugImageProtocol (format string , args ... interface {}) {
@@ -326,6 +402,52 @@ func kittyInlineImage(payload string) string {
326402 return b .String ()
327403}
328404
405+ // iterm2InlineImage renders an image using iTerm2's image protocol
406+ func iterm2InlineImage (payload string ) string {
407+ if payload == "" {
408+ return ""
409+ }
410+
411+ // Calculate rows for cursor positioning
412+ rows := 1
413+ if data , err := base64 .StdEncoding .DecodeString (payload ); err == nil {
414+ if img , _ , err := image .Decode (bytes .NewReader (data )); err == nil {
415+ cellHeight := getTerminalCellSize ()
416+ h := img .Bounds ().Dy ()
417+ rows = (h + cellHeight - 1 ) / cellHeight
418+ if rows < 1 {
419+ rows = 1
420+ }
421+ debugImageProtocol ("image height: %d pixels, cell height: %d pixels, rows needed: %d" , h , cellHeight , rows )
422+ }
423+ }
424+
425+ // iTerm2 image protocol: ESC]1337;File=inline=1:<base64_data>BEL
426+ result := fmt .Sprintf ("\x1b ]1337;File=inline=1:%s\x07 \n " , payload )
427+
428+ // Add placeholder for row spacing
429+ result += fmt .Sprintf ("%s%d%s\n " , imageRowPlaceholderPrefix , rows , imageRowPlaceholderSuffix )
430+
431+ return result
432+ }
433+
434+ // renderInlineImage renders an image using the appropriate protocol for the detected terminal
435+ func renderInlineImage (payload string ) string {
436+ if payload == "" {
437+ return ""
438+ }
439+
440+ if kittySupported () || ghosttySupported () || weztermSupported () || waystSupported () || konsoleSupported () {
441+ // These terminals use the Kitty graphics protocol
442+ return kittyInlineImage (payload )
443+ } else if iterm2Supported () || warpSupported () {
444+ // iTerm2 and Warp use the iTerm2 image protocol
445+ return iterm2InlineImage (payload )
446+ }
447+
448+ return ""
449+ }
450+
329451// expandImageRowPlaceholders replaces image row placeholders with actual newlines.
330452func expandImageRowPlaceholders (text string ) string {
331453 re := regexp .MustCompile (regexp .QuoteMeta (imageRowPlaceholderPrefix ) + `(\d+)` + regexp .QuoteMeta (imageRowPlaceholderSuffix ))
@@ -441,8 +563,8 @@ func processBody(rawBody string, inline map[string]string, h1Style, h2Style, bod
441563 }
442564
443565 if payload != "" {
444- if rendered := kittyInlineImage (payload ); rendered != "" {
445- debugImageProtocol ("rendered inline image src=%s len=%d dataURI=%t cid=%t (kitty=%t ghostty=%t)" , src , len (payload ), strings .HasPrefix (src , "data:" ), strings .HasPrefix (src , "cid:" ), kittySupported (), ghosttySupported ())
566+ if rendered := renderInlineImage (payload ); rendered != "" {
567+ debugImageProtocol ("rendered inline image src=%s len=%d dataURI=%t cid=%t (kitty=%t ghostty=%t iterm2=%t wezterm=%t wayst=%t warp=%t konsole=%t )" , src , len (payload ), strings .HasPrefix (src , "data:" ), strings .HasPrefix (src , "cid:" ), kittySupported (), ghosttySupported (), iterm2Supported (), weztermSupported (), waystSupported (), warpSupported (), konsoleSupported ())
446568 s .ReplaceWithHtml ("\n " + rendered + "\n " )
447569 return
448570 }
@@ -451,7 +573,7 @@ func processBody(rawBody string, inline map[string]string, h1Style, h2Style, bod
451573 debugImageProtocol ("no payload for src=%s dataURI=%t cid=%t" , src , strings .HasPrefix (src , "data:" ), strings .HasPrefix (src , "cid:" ))
452574 }
453575 } else {
454- debugImageProtocol ("image protocol not supported for src=%s (kitty=%t ghostty=%t)" , src , kittySupported (), ghosttySupported ())
576+ debugImageProtocol ("image protocol not supported for src=%s (kitty=%t ghostty=%t iterm2=%t wezterm=%t wayst=%t warp=%t konsole=%t )" , src , kittySupported (), ghosttySupported (), iterm2Supported (), weztermSupported (), waystSupported (), warpSupported (), konsoleSupported ())
455577 }
456578 if hyperlinkSupported () {
457579 s .ReplaceWithHtml (hyperlink (src , fmt .Sprintf ("\n [Click here to view image: %s] \n " , alt )))
0 commit comments