Skip to content

Instantly share code, notes, and snippets.

@tkapias
Last active September 5, 2023 21:29
Show Gist options
  • Save tkapias/532e5ad7bc03b7a4000d9deed361096d to your computer and use it in GitHub Desktop.
Save tkapias/532e5ad7bc03b7a4000d9deed361096d to your computer and use it in GitHub Desktop.
fzf-img.sh - Image fuzzy finder with preview using fzf and ueberzug
#!/usr/bin/env bash
# This is just an example how ueberzug can be used with fzf.
# Copyright (C) 2019 Nico Bäurer
# Copyright (C) 2022 Tomasz Kapias
# - Updated:
# - optional PATH as only option
# - internal FDfind query for images
# - display SVGs after caching a converted png
# - Imagemagick's identify infos as header with margin
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
readonly BASH_BINARY="$(which bash)"
readonly REDRAW_COMMAND="toggle-preview+toggle-preview"
readonly REDRAW_KEY="µ"
declare -r -x DEFAULT_PREVIEW_POSITION="right"
declare -r -x UEBERZUG_FIFO="$(mktemp --dry-run --suffix "fzf-$$-ueberzug")"
declare -r -x PREVIEW_ID="preview"
function start_ueberzug {
mkfifo "${UEBERZUG_FIFO}"
<"${UEBERZUG_FIFO}" \
ueberzug layer --parser bash --silent &
# prevent EOF
3>"${UEBERZUG_FIFO}" \
exec
}
function finalise {
3>&- \
exec
&>/dev/null \
rm "${UEBERZUG_FIFO}"
&>/dev/null \
kill $(jobs -p)
}
function calculate_position {
# TODO costs: creating processes > reading files
# so.. maybe we should store the terminal size in a temporary file
# on receiving SIGWINCH
# (in this case we will also need to use perl or something else
# as bash won't execute traps if a command is running)
< <(</dev/tty stty size) \
read TERMINAL_LINES TERMINAL_COLUMNS
case "${PREVIEW_POSITION:-${DEFAULT_PREVIEW_POSITION}}" in
left|up|top)
X=1
Y=1
;;
right)
X=$((TERMINAL_COLUMNS - COLUMNS - 2))
Y=1
;;
down|bottom)
X=1
Y=$((TERMINAL_LINES - LINES - 1))
;;
esac
}
function draw_preview {
calculate_position
>"${UEBERZUG_FIFO}" declare -A -p cmd=( \
[action]=add [identifier]="${PREVIEW_ID}" \
[x]="${X}" [y]="$(( ${Y} + 2 ))" \
[width]="${COLUMNS}" [height]="$(( ${LINES} - 2 ))" \
[scaler]=contain \
[path]="${@}")
# add [synchronously_draw]=True if you want to see each change
}
function svg_preview {
CACHEDIR="$HOME/.cache/fzf-img"
mkdir $CACHEDIR
SVGCACHE="$CACHEDIR/thumbnail.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | \
sha256sum | awk '{print $1}')"
[ ! -f "$SVGCACHE" ] && convert -background none "${@}" "${SVGCACHE}.png"
calculate_position
>"${UEBERZUG_FIFO}" declare -A -p cmd=( \
[action]=add [identifier]="${PREVIEW_ID}" \
[x]="${X}" [y]="$(( ${Y} + 2 ))" \
[width]="${COLUMNS}" [height]="$(( ${LINES} - 2 ))" \
[scaler]=contain \
[path]="${SVGCACHE}.png")
# add [synchronously_draw]=True if you want to see each change
}
function print_on_winch {
# print "$@" to stdin on receiving SIGWINCH
# use exec as we will only kill direct childs on exiting,
# also the additional bash process isn't needed
</dev/tty \
exec perl -e '
require "sys/ioctl.ph";
while (1) {
local $SIG{WINCH} = sub {
ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV;
};
sleep;
}' \
"${@}" &
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
trap finalise EXIT
# print the redraw key twice as there's a run condition we can't circumvent
# (we can't know the time fzf finished redrawing it's layout)
print_on_winch "${REDRAW_KEY}${REDRAW_KEY}"
start_ueberzug
export -f draw_preview svg_preview calculate_position
SHELL="${BASH_BINARY}" \
fdfind -0a -tf -tl -e jpg -e jpeg -e png -e gif -e svg -e ico -e webp -e tif "^.+$" "$([[ -z $1 ]] && echo $PWD || realpath $1)" | \
xargs -r -0 exa --colour=always | \
fzf -m --ansi --keep-right --header "jpg/jpeg/gif/svg/ico/tif/webp files in $([[ -z $1 ]] && echo $PWD || realpath $1)" \
--preview "identify {} | awk '{print \$2,\$3,\$4,\$5,\$6,\$7}'; [[ \$(file --mime {}) =~ svg ]] && svg_preview {} || draw_preview {}" \
--preview-window "${DEFAULT_PREVIEW_POSITION}" \
--bind "${REDRAW_KEY}:${REDRAW_COMMAND}"
fi
@eylles
Copy link

eylles commented Sep 2, 2023

so great, one of the most useful scripts for fzf improved nicely.

@tkapias
Copy link
Author

tkapias commented Sep 3, 2023

TODO: currently I use the file manager Joshuto and Überzug++ (C++ and maintained) but my new scripts are not yet really clean. I will update this gist or add a link to a new one soon.

I invite people to check Joshuto and Überzug++ for a better experience.

@eylles
Copy link

eylles commented Sep 5, 2023

welp, using this script as a base i built this thing... https://github.com/eylles/wal-choose

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment