diff options
author | Junegunn Choi <junegunn.c@gmail.com> | 2023-11-07 11:42:32 +0900 |
---|---|---|
committer | Junegunn Choi <junegunn.c@gmail.com> | 2023-11-07 11:51:21 +0900 |
commit | 230fc49ae216169f9812adcf8942bba3993e61e0 (patch) | |
tree | 381b3739db998a35e3a8b276c59c9b7c11f477b8 /src/terminal.go | |
parent | 250d507bdfe370045a32c8cd85fc2b4f34c8df5c (diff) |
(Experimental) Add support for iTerm2 inline image protocol
Close #1102
fzf --preview 'imgcat -W $FZF_PREVIEW_COLUMNS -H $FZF_PREVIEW_LINES {}'
Notes:
* There is no good way to determine the height of the rendered image,
so we assume that the image takes the full height of the preview
window. So the image cannot be displayed with the other text.
* fzf-preview.sh script was updated to use `imgcat` if it's available
but `chafa` is not.
* iTerm2 also supports Sixel, so adding support for this protocol is not
quite necessary but it renders animated GIFs much better (e.g. looping).
Diffstat (limited to 'src/terminal.go')
-rw-r--r-- | src/terminal.go | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/src/terminal.go b/src/terminal.go index 747001ef..f48e5f25 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -66,7 +66,8 @@ func init() { // * https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it // * https://sw.kovidgoyal.net/kitty/graphics-protocol // * https://en.wikipedia.org/wiki/Sixel - passThroughRegex = regexp.MustCompile(`\x1bPtmux;\x1b\x1b.*?[^\x1b]\x1b\\|\x1b(_G|P[0-9;]*q).*?\x1b\\\r?`) + // * https://iterm2.com/documentation-images.html + passThroughRegex = regexp.MustCompile(`\x1bPtmux;\x1b\x1b.*?[^\x1b]\x1b\\|\x1b(_G|P[0-9;]*q).*?\x1b\\\r?|\x1b]1337;.*?\a`) } type jumpMode int @@ -125,7 +126,7 @@ type previewed struct { numLines int offset int filled bool - sixel bool + image bool wipe bool wireframe bool } @@ -2027,7 +2028,7 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc var ansi *ansiState spinnerRedraw := t.pwindow.Y() == 0 wiped := false - sixel := false + image := false wireframe := false Loop: for _, line := range lines { @@ -2055,18 +2056,25 @@ Loop: t.pwindow.Move(y, x) } for idx, passThrough := range passThroughs { - // Handling Sixel output + // Handling Sixel/iTerm image requiredLines := 0 isSixel := strings.HasPrefix(passThrough, "\x1bP") - if isSixel { + isItermImage := strings.HasPrefix(passThrough, "\x1b]1337;") + isImage := isSixel || isItermImage + if isImage { t.previewed.wipe = true - if t.termSize.PxHeight > 0 { + // NOTE: We don't have a good way to get the height of an iTerm image, + // so we assume that it requires the full height of the preview + // window. + requiredLines = height + + if isSixel && t.termSize.PxHeight > 0 { rows := strings.Count(passThrough, "-") requiredLines = int(math.Ceil(float64(rows*6*t.termSize.Lines) / float64(t.termSize.PxHeight))) } } - // Render wireframe when Sixel image cannot be displayed entirely + // Render wireframe when the image cannot be displayed entirely if requiredLines > 0 && y+requiredLines > height { top := true for ; y < height; y++ { @@ -2081,17 +2089,17 @@ Loop: } // Clear previous wireframe or any other text - if (t.previewed.wireframe || isSixel && !t.previewed.sixel) && !wiped { + if (t.previewed.wireframe || isImage && !t.previewed.image) && !wiped { wiped = true for i := y + 1; i < height; i++ { t.pwindow.MoveAndClear(i, 0) } // Required for tcell to clear the previous text - if !t.previewed.sixel { + if !t.previewed.image { t.tui.Sync(false) } } - sixel = sixel || isSixel + image = image || isImage if idx == 0 { t.pwindow.MoveAndClear(y, x) } else { @@ -2154,7 +2162,7 @@ Loop: } lineNo++ } - t.previewed.sixel = sixel + t.previewed.image = image t.previewed.wireframe = wireframe } |