summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md7
-rwxr-xr-xbin/fzf-preview.sh15
-rw-r--r--src/terminal.go30
3 files changed, 39 insertions, 13 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a02e12cd..0a041f8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,12 @@ CHANGELOG
```sh
fzf --preview='fzf-preview.sh {}'
```
-- (Experimental) Sixel and Kitty image support now also available on Windows
+- (Experimental) iTerm2 inline image protocol support in preview window
+ ```sh
+ # Using https://iterm2.com/utilities/imgcat
+ fzf --preview 'imgcat -W $FZF_PREVIEW_COLUMNS -H $FZF_PREVIEW_LINES {}'
+ ```
+- (Experimental) Sixel, Kitty, and iTerm2 image support now also available on Windows
- HTTP server can be configured to accept remote connections
```sh
# FZF_API_KEY is required for a non-localhost listen address
diff --git a/bin/fzf-preview.sh b/bin/fzf-preview.sh
index d72cd2d4..8991e3de 100755
--- a/bin/fzf-preview.sh
+++ b/bin/fzf-preview.sh
@@ -4,8 +4,9 @@
# image in the preview window of fzf.
#
# Dependencies:
-# - https://github.com/hpjansson/chafa
# - https://github.com/sharkdp/bat
+# - https://github.com/hpjansson/chafa
+# - https://iterm2.com/utilities/imgcat
if [[ $# -ne 1 ]]; then
>&2 echo "usage: $0 FILENAME"
@@ -44,6 +45,7 @@ elif ! [[ $KITTY_WINDOW_ID ]] && (( FZF_PREVIEW_TOP + FZF_PREVIEW_LINES == $(stt
dim=${FZF_PREVIEW_COLUMNS}x$((FZF_PREVIEW_LINES - 1))
fi
+# 1. Use kitty icat on kitty terminal
if [[ $KITTY_WINDOW_ID ]]; then
# 1. 'memory' is the fastest option but if you want the image to be scrollable,
# you have to use 'stream'.
@@ -52,10 +54,21 @@ if [[ $KITTY_WINDOW_ID ]]; then
# This confuses fzf and makes it render scroll offset indicator.
# So we remove the last line and append the reset code to its previous line.
kitty icat --clear --transfer-mode=memory --stdin=no --place="$dim@0x0" "$file" | sed '$d' | sed $'$s/$/\e[m/'
+
+# 2. Use chafa with Sixel output
elif command -v chafa > /dev/null; then
chafa -f sixel -s "$dim" "$file"
# Add a new line character so that fzf can display multiple images in the preview window
echo
+
+# 3. If chafa is not found but imgcat is available, use it on iTerm2
+elif command -v imgcat > /dev/null; then
+ # NOTE: We should use https://iterm2.com/utilities/it2check to check if the
+ # user is running iTerm2. But for the sake of simplicty, we just assume
+ # that's the case here.
+ imgcat -W "${dim%%x*}" -H "${dim##*x}" "$file"
+
+# 4. Cannot find any suitable method to preview the image
else
file "$file"
fi
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
}