DEV Community

Cover image for Autocomplete with Fzf
Anton Gubarev
Anton Gubarev

Posted on • Edited on

Autocomplete with Fzf

Since I spend a lot of time in the console, I constantly improve the configuration of my console tools. My experience is that the costs of tools are often paid back many times over. Increasing the speed and pleasure of automating routine operations, which makes me a much happier engineer. To date, I have grown up with enough different tools and scripts to share with some of them.

One such of my any tools is fzf. It is a tool for fuzzy search on a given set of elements that is passed to it. It can also be integrated with other tools (and there are already many ready-made integrations). It is a very simple yet powerful tool with which to facilitate your work. In the examples below I will show how I use fzf and automate part of my routine. All the examples below are personally convenient for me, but I hope it will give you ideas for applying it to yourself.

Docker
It was very tiring for me to stop and remove containers with these commands

  • docker ps -a
  • copy container id
  • docker stop {id}
  • docker rm {id}

(Yes then I found lazydocker, but it was after)

function ds() {
  cid=$(docker ps | sed 1d | fzf -q "$1" | awk '{print $1}')
    [ -n "$cid" ] && docker stop "$cid"
}

function drm() {
  cid=$(docker ps -a | sed 1d | fzf -q "$1" | awk '{print $1}')
  [ -n "$cid" ] && docker rm "$cid"
}
Enter fullscreen mode Exit fullscreen mode

I mean, sure, it could be combined into one feature and stop and delete, but it was more convenient for me to do that.

Another example is removing old images that take up space. I prefer to delete by hand, because I know exactly what else I will need and I would not like to reload them.

function ds() {
  cid=$(docker ps | sed 1d | fzf -q "$1" | awk '{print $1}')
    [ -n "$cid" ] && docker stop "$cid"
}

function drm() {
  cid=$(docker ps -a | sed 1d | fzf -q "$1" | awk '{print $1}')
  [ -n "$cid" ] && docker rm "$cid"
}
Enter fullscreen mode Exit fullscreen mode

With these two simple examples, you can understand how fzf works. It is transmitted strings that fzf shows and allows you to search for different templates. The result of the user’s choice is then passed on to the user to perform some actions with him. This way I organize myself into a autocomplete.

Git

More realistic and useful automation that I have implemented for myself

Checkout to a branch

gcor() {
  local branches branch
  branches=$(git branch --all | grep -v HEAD) &&
  branch=$(echo "$branches" |
           fzf-tmux -d $(( 2 + $(wc -l <<< "$branches") )) +m) &&
  git checkout $(echo "$branch" | sed "s/.* //" | sed "s#remotes/[^/]*/##")
}
Enter fullscreen mode Exit fullscreen mode

First I got a list of all the branches, and then I passed this list to fzf. But the truth sometimes has to be enchanted and cut out the extra information. The thing is that fzf transmits the entire string that the user has chosen, including numbers and other redundant information that makes further action impossible.

Delete a branch
Periodically cleaning old local branches that distract attention

gbd() {
    local branche_to_delete
    branch_to_delete=$(git branch | fzf | xargs)

    if [ -n "$branch_to_delete" ]; then
         git branch --delete --force $branch_to_delete
    fi
}
Enter fullscreen mode Exit fullscreen mode

Navigation

I am a big fan of Lf file manager and can move between directories with high speed. Especially using bookmarks in Lf. And because I’m working on a project that uses microservices architecture, you have to move between services quite often. But the thing is that in addition to directly moving to the desired directory I still perform some routine operations after being in the project folder:

make sure I’m in the main branch, not some old branch that’s already actually
make sure there are no uncommitted changes
pull the last changes from the repository
Remembering and keeping track of this prevents focusing on the current problem. So I solved this problem in the following way

function cdp() {
    local dirPathes
    IFS=';' 
    read -A PD <<< "$PROJECT_PATHES"
    for i in "${PD[@]}"; 
    do
        local dd=$(ls -d $HOME/$i/*)
        dirPathes=("${dirPathes} ${dd}")
    done

    local targerDir=$(echo $dirPathes | fzf)
    cd $targerDir

    local changes=$(git status --porcelain)
    if [ -z "$changes" ]
    then
        git checkout master
        git pull origin master
    else
        echo "There are uncommited changes. Can't checkout and update master"
    fi
}
Enter fullscreen mode Exit fullscreen mode

I get a list of directories from the project’s root directory. I pass it to fzf for selection. I make the selected directory the current one. If there are no uncommitted changes, I upload to the wizard and update it. And if there is, I do not do anything, as it is necessary to deal with them manually so as not to accidentally lose the work.

Now I am one team switching between projects. It saved me a lot of time in total.

Kubernetes

I could not avoid one of the most important tools that is found in most projects. I am a big fan of k9s. This is a great tool that allows me to easily and quickly navigate the cluster and learn what happens in the pods and quickly see the statuses. However, k9s is not always appropriate. For example, when I only need to look at the logs of the container, or perform some command inside the container. Running k9s for this seems redundant. So I wrote a small script that allows me to do frequent operations no less quickly.

kexe() {
    local namespace
    namespace=$(kubectl get ns --no-headers -o custom-columns=":metadata.name" | fzf )

    local pod
    pod=$(kubectl get po -n "$namespace" --no-headers -o custom-columns=":metadata.name" | fzf)
    echo "$pod"

    local container
    container=$(kubectl get pods "$pod" -n "$namespace" -o jsonpath='{range .spec.containers[*]}{.name}{"\n"}{end}' | fzf )


    kubectl exec -it "$pod" -n "$namespace" -c "$container" -- /bin/bash
}
Enter fullscreen mode Exit fullscreen mode

First I pick up the namespace from the list, then I pick up all the files from this namespace, and at the end of the container of the selected pod. Next I run kubectl exec and voila, I can work in the desired container.

Conclusion

This is just a small set of all the improvements I have accumulated. I gradually publish these scripts in this repository. Once they are adapted for publication, they are removed and sharpened for specific work projects.

Also a huge number of ready-made scripts can be found in the official fzf wiki. In addition, I often subscribe to other public repositories where authors publish their ideas. It is very interesting to observe the commits and the evolution of these projects. Thank you to all who make this work open!

Top comments (0)