fzf can boost your workflow

Mehrad Mahmoudian published on
5 min, 957 words

Categories: Lovely Linux

Abstract

There are many things that a command line user can do, and also there are bunch of graphical application that can help user to boos their productivity. But of course the beauty of CLI software is that they can be chained together in a logical order to drastically improve workflow and reduce potential mistakes. In this post I am going to share some of these quick scripts that I personally use. All these use fzf as the title also suggests.

Main

There are few CLI tools that one can use in combination to classic gnu utils and etc. to have a more modern, safe, and fast experience. In this article I'm showing a subset of those that I'm using in daily basis. These tools are:

  • fzf: fuzzy finder
  • bat: improved cat

Quick file preview

The fzf already previews the file contents, but we can add color coding automatically to the preview window of fzf:

fzf --layout=reverse-list \
    --preview 'bat --style=numbers \
                   --wrap=auto \
                   --color=always \
                   --paging=never \
                   --line-range :500 "{}" '

Of course you can add more flags to the fzf based on your use-case. For instance the --exact and --multi are popular one by users.

Better history

Many people know about the history command, and a subset of them know about the Ctrlr to search through your history, but the look of it is a bit ancient and kind hurts my eyes. But as you can imaging, we can make our life much easier and smoother. In the following:

  • the print -z is responsible inserting the selected command in your terminal prompt.
  • the sed removed the line number.
  • the fzf is the fuzzy finder which is the main point of this article
  • the cut would remove the date. This is because I have configured my history to store the date and time of each record in history.
print -z "$(history \
            | sed -E "s/^ +[0-9]+ +//g" \
            | fzf --tac \
                  --no-sort \
                  --height=10 \
                  --layout="reverse" \
                  --border="rounded" \
            | cut --delimiter=" " \
                  --field="4-")"

This is a preliminary command here. I have a much better implementation that I will have a dedicated blog post about it.

Going through git commits

It is common that one goes through the git log and see previous commits. The problem is that with git log you can see the commit messages and commit hashes. You can even beautify it by adding --oneline and --graph to get a better view of the commits and branches and merging events, but you still have to use the commit hash and use it in git show to see the code changes of that commit. This is very suboptimal for me. I would like to see them side-by-side and have it interactive. So this is what I put together in couple of minutes to make my experience smoother:

git log --oneline \
        --graph \
        --color=always \
| nl \
| fzf --ansi \
      --track \
      --no-sort \
      --layout=reverse-list \
      --preview 'echo -n {} \
                 | head -n 1 \
                 | grep --only-matching \
                        --perl-regexp \
                        --regexp="[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]" \
                 | head -n 1 \
                 | xargs -I _ git show _ \
                 | bat --language=diff \
                       --color=always \
                       --style=numbers \
                       --wrap=auto \
                       --paging=never \
                       --line-range :500'

Just make sure you have installed git, fzf, bat on your computer.

Also, I should add that the regex here looks repetitive, but here is the issue, the better approach is /[0-9a-f]{7}/ but having the {7} in this regex will be replaced with the --preview of fzf. In fzf terms it means the 7th element if the selected string with space delimiter. Of course there is a way in fzf to change the {} with something else, but that needs setting an environmental variable, which is not an easy thing to do when using this as an alias.

Summary

As you can see (and you can test for yourself in your terminal), these can drastically improve your workflow and save you time and effort. It worth to mention that these are not exactly what I use on my machine and I have done some more tweaks that fits better my workflow. I encourage you to read the manpages of fzf, bat, and other tools and familiarize yourself with the flags and start tweaking this to your liking. :)

One last [obvious] note: perhaps the best way to use these codes is by turning them into aliases:

hash fzf 2> /dev/null \
  && alias fhist='print -z "$(history \
                              | \sed -E "s/^ +[0-9]+ +//g" \
                              | \fzf --tac \
                                     --no-sort \
                                     --height=10 \
                                     --layout="reverse" \
                                     --border="rounded" \
                              | \cut --delimiter=" " \
                                     --field="4-")"'

hash fzf 2> /dev/null \
  && alias fzfp="fzf --layout=reverse-list \
                     --preview 'bat --style=numbers \
                                    --wrap=auto \
                                    --color=always \
                                    --paging=never \
                                    --line-range :500 "{}" '"

hash git fzf bat 2> /dev/null \
  && alias fzfgl="git log \
                      --oneline \
                      --graph \
                      --color=always \
                  | nl \
                  | fzf --ansi \
                        --track \
                        --no-sort \
                        --layout=reverse-list \
                        --preview 'echo -n {} \
                                   | head -n 1 \
                                   | grep --only-matching \
                                          --perl-regexp \
                                          --regexp=\"[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]\" \
                                   | head -n 1 \
                                   | xargs -I _ git show _ \
                                   | bat --language=diff \
                                         --color=always \
                                         --style=numbers \
                                         --wrap=auto \
                                         --paging=never \
                                         --line-range :500'"

Note that in the code section above, I am using hash to make sure the tools I have used in these aliases are already installed. If they are not already installed, the alias will not be created.