You are not logged in.

#1 2023-09-16 18:03:42

meezoarch
Member
Registered: 2022-12-01
Posts: 42

fzf preview script/function

I use fzf very often, I want to use the preview option but I want fzf to use preview options depending on the file extension, if a directory use tree else if a file then if txt,md,log then bat and if pdf then pdf2txt, if image ueberzugpp etc.

I was thinking of defining a function in my zshrc and write it as a case statement [something like function fzf_preview ()] but not sure how to do so.

I should then be able to run a command and pipe it to | fzf_preview for e.g.

find . | fzf_preview

Can someone show me a template that achieves the above that I can work from?

I am happy also with any alternative suggestion/approach as long as it achieves what I am intending to do

I have tried the below just as a test before I actually write my preview options:

fzf_preview() {
  local preview_cmd
  local input_files=()
  
  # Read input files from stdin
  while IFS= read -r file; do
    input_files+=("$file")
  done
  
  # Process each file individually
  for file in "${input_files[@]}"; do
    if [[ -d "$file" ]]; then
      preview_cmd='tree'
    else
      case "$file" in
        *.jpg|*.jpeg|*.png|*.gif)
          preview_cmd='sxiv -a'
          ;;
        *.pdf)
          preview_cmd='pdftotext {} - | less'
          ;;
        *.zip|*.tar|*.gz|*.bz2|*.xz)
          preview_cmd='ls {} | less'
          ;;
        *)
          preview_cmd='bat --style=numbers --color=always {}'
          ;;
      esac
    fi
    
    # Execute fzf with the selected preview command
    fzf --preview "$preview_cmd" "$file"
  done
}

but it is not working and giving me unkonwn option error. It is also very slow :-(

Offline

#2 2023-09-16 18:14:59

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,330
Website

Re: fzf preview script/function

I have no idea how fzf works, but for your own function, note that the following two are functionally equivalent, but the second much simpler:

  local input_files=()
  
  # Read input files from stdin
  while IFS= read -r file; do
    input_files+=("$file")
  done
  
  # Process each file individually
  for file in "${input_files[@]}"; do
    # do stuff here
  done
  while IFS= read -r file; do
    # do stuff here
  done

Why the extra loop and variable?

EDIT: after briefly checking out fzf, I'm pretty sure you wouldn't want to loop through a bunch of files and run fzf on each - that's likely the cause of your problems.  You should run fzf once, and pass your function to the --preview flag.  Something like the following which is as-of-yet completely untested and probably not quite right:

fzf_preview() {
  if [ -d $1 ]; then echo tree; return; fi
  case $1 in
    *.jpg|*.jpeg|*.png|*.gif) echo 'svix -a' ;;
    # ... other cases here
  esac
}

fzf --preview='$(fzf_preview {}} {}'

Though this probably would not work as I suspect the content of the preview flag is run in a new shell (so your function would not be defined there) - but it would work if it were an external script / binary.

Here's a start, though I don't have sxiv to test whether that works - the bat condition works fine:

#!/bin/sh

[ "$1" == "--" ] || exec fzf "$@" --preview="$($0 -- {}) {}"

shift

[ -d $1 ] && exec echo tree

case $1 in
	*.jpg|*.jpeg|*.png|*.gif) echo 'sxiv -a' ;;
	# other types here
	*) echo 'bat --style=numbers --color=always'
esac

Out of curiousity, are you familiar with Ranger?  It is more well suited for this kind of task as it has it's own built in system to determine the right preview mechanism by filetype which you can just customize to your tastes rather than having to write it from scratch.

Last edited by Trilby (2023-09-16 19:02:17)


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#3 2023-09-16 19:38:28

meezoarch
Member
Registered: 2022-12-01
Posts: 42

Re: fzf preview script/function

Thank you very much, I really appreciate your help.

I have been trying to use both approaches.
The first one did not work; just like what you expected the fzf_preview function was not defined and returned an unknown command error.
I am not sure how to use the script approach: I saved the script as fzf_preview.sh and I executed:

find . | fzf --preview="$(./fzf_preview.sh -- {})"

It appears to be only using the bat command and not applying the relevant preview when it is a directory or a file with pdf, jpg etc.

Offline

#4 2023-09-16 19:44:44

meezoarch
Member
Registered: 2022-12-01
Posts: 42

Re: fzf preview script/function

Trilby wrote:

Out of curiousity, are you familiar with Ranger?  It is more well suited for this kind of task as it has it's own built in system to determine the right preview mechanism by filetype which you can just customize to your tastes rather than having to write it from scratch.

I am familiar with ranger, but I currently use lf.
I already have file preview on lf and this is what inspired me to apply the same concept to fzf. When I call fzf inside my lf file manager (or elsewhere) I loose the native file manager preview function.
I dont really have to write a whole thing from scratch as I will use my preview case statement of lf file manager and modify it to work for fzf.
I hope that explains my situation.

Offline

#5 2023-09-16 20:17:24

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,330
Website

Re: fzf preview script/function

meezoarch wrote:

I saved the script as fzf_preview.sh and I executed:

find . | fzf --preview="$(./fzf_preview.sh -- {})"

No, just run the script itself.  The first code line determines whether it was run from fzf or not.

meezoarch wrote:

It appears to be only using the bat command...

That may be due to trying to invoke it as you did rather than just running the script directly.  Of course, you also need to build on my example script to include other file types in the case statement.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#6 2023-09-17 07:40:55

meezoarch
Member
Registered: 2022-12-01
Posts: 42

Re: fzf preview script/function

The script is not working for me it only uses bat; I did try to execute the script itself and yes of course I added more case statements. Even with the template above it should run the tree command when scrolling through directories on fzf search but the preview outputs bat command error the '/current path on fzf/' is a directory

Offline

#7 2023-09-17 11:01:50

seth
Member
Registered: 2012-09-03
Posts: 58,967

Re: fzf preview script/function

You might have to quote the "$1" for the directory test…

Online

#8 2023-09-17 21:06:00

meezoarch
Member
Registered: 2022-12-01
Posts: 42

Re: fzf preview script/function

The double quotes did not fix the script either.
I tried Trilby's script as it is and tested it for directories and jpg and it is using bat command for everything.

#!/bin/sh

[ "$1" == "--" ] || exec fzf "$@" --preview="$($0 -- {}) {}"

shift

[ -d "$1" ] && exec echo tree

case "$1" in
	*.jpg|*.jpeg|*.png|*.gif) echo 'sxiv -a' ;;
	# other types here
	*) echo 'bat --style=numbers --color=always'
esac

saved as trial.sh

./trial.sh

Same problem; the preview is only using the bat command.

Offline

#9 2023-09-17 21:27:02

seth
Member
Registered: 2012-09-03
Posts: 58,967

Re: fzf preview script/function

That script won't show directories as such anyway, so [ -d ] will never hit.

#!/bin/sh

[ "$1" == "--" ] || exec ls | fzf --preview="$0 -- {}"

shift

[ -d "$1" ] && exec ls "$1"

case "$1" in
	*.jpg|*.jpeg|*.png|*.gif) sxiv -a "$1";;
	# other types here
	*) head "$1"
esac

Online

Board footer

Powered by FluxBB