Autocomplete with Fzf
Tags: devops, tooling, fzf
Published: 2022-07-07 19:45:13

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](https://github.com/junegunn/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](https://github.com/jesseduffield/lazydocker), but it was after)

```shell
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"
}
```



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.
 

```shell
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"
}
```

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**
 
```shell
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/[^/]*/##")
}
```

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

```shell
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
}
```

## Navigation

I am a big fan of [Lf file manager](https://github.com/gokcehan/lf) 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
 
```shell
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
}
```

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.
 

```shell
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
}
```

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](https://github.com/antgubarev/dotfiles). 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!