Improving an fzf example with null bytes

Date: — Topic: — Lang: — by Slatian

Table of Contents

What is the problem?

On the fzf manpage the --preview-window option is shown off using a combination of git grep for querying every line of every file in the current git repository, fzf for searching and bat for a preview with the line currently selected in fzf highlighted and scrolled into the middle of the preview window. (pretty awesome example if you asked me.)

The example from the manpage
# Preview with bat, matching line in the middle of the window below
# the fixed header of the top 3 lines
#
# […]

git grep --line-number '' |
fzf --delimiter : \
	--preview 'bat --style=full --color=always --highlight-line {2} {1}' \
	--preview-window '~3,+{2}+3/2'

The example works by relying on the fact that the output of the git grep looks like <filename>:<linenumber: …, split at the colon, {1} is the filename, {2} is the line number.

While the example is very good at explaining how the --preview-window interacts with the --delimiter (its primary purpose), it breaks once there is a colon somewhere in a filename, then {1} and {2} become two halves of an incomplete filename and bat has no idea what it should do with that.

Example output produced by git grep --line-number "". Note that the last line looks a bit funny.
test.txt:1:Lorem ipsum
test.txt:2:dolor sid …
throw:off:1:Does this filename confuse fzf?

Let's fix it!

The Solution is actually pretty simple: git grep supports a -z flag, making it use null bytes instead of colons for separating filename, line number and content, tell fzf to use that as the delimiter using --delimiter '\0' and, the preview isn't confused anymore.

One remaining problem is that the menu looks like this: test.txt1Lorem ipsum, not very readable because those nullbytes are invisible.

But there is nothing stopping us from replacing all null bytes with nullbytes followed by a colon and telling fzf to use that combination as a delimiter. git doesn't have something built in for that, but that is what sed was built for.

The example from the manpage modified to use null separators in addition to human readable ones.
git grep -z --line-number "" |
sed -E 's|\x00|\x00:|g' |
fzf --delimiter '\0:' \
    --preview 'bat --style=full --color=always --highlight-line {2} {1}' \
    --preview-window '~3,+{2}+3/2'

In case this looks a bit dull add a --color=auto to the git command and a --ansi to fzf.

Done

Given that the more correct version takes noticeably more brain-cycles to decode it is no surprise they used the simple version for the manual.

In case you want to: Learn more about null separation in the shell.

Happy experimenting!