I am trying to use fzf in the following manner, I would like to be able to search for a term within my codebase and then with the preview window be able to see the file which contains the string I am searching for at the line where the string is found.
So far I have managed to fuzzy search through the codebase for various terms by piping a ripgrep search of all files in the directory and below. And I have used cut to parse out the file name for cat or tail to read and print to the preview window. This is the command used for that.
rg . -n | fzf --preview-"cut -d":" -f1 <<< {} | xargs cat"
Note the string represented by {} is in the following format:
myfile.c:72:The string I am fuzzy searching
My issue is that I cannot parse out both the filename and the line number.
I have tried passing a bashscript within the preview command as well as using $() in the following example. (Note that here I use tail with the --lines+N
argument to print the file after line N)
rg . -n | fzf --preview-"tail $(cut -d":" -f1 <<< {}) --lines=+$(cut -d":" -f2 <<< {})"
This does not work nor does a variety of variants on this attempt. Any help or feedback is appreciated.
Edit(1) :
I've tried to split it into an array like so
rg . -n | fzf --preview="IFS=":" read -r -a arr <<< {}| xargs tail ${arr[0]} --lines=+${arr[1]}"
This works in that the preview does show the file at the line where the string is found however it does not update as I cycle through other fuzzy found suggestions.
So I eventually figured out a solution that works.
It involves calling a separate script from my subprocess running inside --preview. I used the following script to take the string which fzf passes to --preview (in the format of filename:linenumber:found_string) and then used bat to render a preview window with syntax highlighting.
This method is pretty good but is somewhat resource intensive. I'm hoping to lessen the load by adding to the ignore glob and using ripgrep rather then find as it seems that is more efficient.
The bashscript I call string2arg.sh
#!/bin/bash
string2arg() {
export arg_filename=$(cut -d":" -f1 <<< $1);
export arg_linenum=$(cut -d":" -f2 <<< $1);
min_offset=25
let max_offset="min_offset*3"
min=0
if (($min_offset < $arg_linenum)); then
let min="arg_linenum-$min_offset"
fi
let max="arg_linenum+$max_offset"
bat --color=always --highlight-line $arg_linenum --style=header,grid,numbers --line-range $min:$max $arg_filename;
}
This is then called from my fzf alias for searching as such:
alias fsearch='rg . -n -g "!*.html" | fzf --preview="source $SC/string2arg.sh; string2arg {}"'
where $SC is the path to my bashscript string2arg.sh.
If I'm searching for a term with the intent to open the file its found in at the line its found in I use the following bash alias.
alias vfsearch='export vfile=$(fsearch);vim +$(cut -d":" -f2 <<< $vfile) $(cut -d":" -f1 <<< $vfile)'
Also I happen to use the following defaults for fzf and find them to work for me although since I've moved to tmux I find it sometimes better to show the preview window above rather then to the side.
export FZF_DEFAULT_COMMAND="fd --type file --color=always"
export FZF_DEFAULT_OPTS="--reverse --inline-info --ansi"
export FZF_COMPLETION_TRIGGER=']]'
I find this extremely useful and am planning on moving it inside of my vim sessions. Hope it helps others !
Screenshot to better illustrate the use case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With