navi - an interactive cheatsheet tool for the command-line

Posted May 18, 2022 by Adrian Wyssmann ‐ 3 min read

While I am already fond of cheat.sh and pet, I found another exciting tool, navi

What is it

What I actually love, is that navi combines two nice features I have seen in other tools. One is the support of multiple sources - like cheat.sh - and the use of parametrized commands and executes them - just like pet.

How to use it

After installation, you can just type navi, which does not yet provide that much info. So you can type navi repo browse to browse featured cheatsheets and download them locally, so navi uses them.

search cheatsheets

It uses fzf for searching, which is very powerful. Once you select the comment it eventually asks you to provide the parameters, if the command expects some. Once you hit enter it runs the command. The downside of this is, that the command you have executed. To overcome this, you can install it as a shell widget, so you can hit Ctrl+G to open navi:

search cheatsheets

You can use cheatsheets from tldr using --tldr or cheat.sh using --cheatsh. So for example, let’s search for ansible stuff in cheat.sh

search cheat.sh

As you can see, the command is not executed yet but shown in the command line - so you still can modify it before executing it.

One nice feature is the ability to limit your search to certain tags, by using --tag-rules. For example navi --tag-rules git would only offer snippets, tagged with git.

use tag git

You can also exclude tags. navi --tag-rules='git,!branch' will show snippets which contain the tag git, but not the tag branch. I also tried to only exclude tags like navi --tag-rules='!fly', this however did not work (yet).

Your own cheatsheets

Also very cool is, that you can create your own cheatsheets, using it’s own [cheatsheet syntax]. You can import cheatsheets from any git repository that includes .cheat files, so I created my own repo, currently with one cheatsheet kubernetes.cheat

% kubernetes, k8s

# kubectl: Get object names of a kubernetes context
kubectl get <object>  --no-headers -o custom-columns=':metadata.name' --context <context>

# kubectl: Get pvc names for a given namespace
kubectl get pvc -n <ns>  --context <context>  -o=jsonpath=\"{range .items[?(@.spec.storageClassName=='<storageclass>')]}{.metadata.name}{' '}{end}\"

# kubectl: get label 'managed-by'"
kubectl get <type> -n <namespace> --context <context>  -o=jsonpath=\"{range .items[*]}{.spec.volumeclaimtemplates[?(@.kind=='PersistentVolumeClaim')]}{.metadata.name}{' --- '}{.spec.template.metadata.labels.app\\.kubernetes\\.io/managed-by}{'\\n'}{end}\"

# kubectl: Remove claimRef from pv (patch)
kubectl patch pv <pv_name> -n <namespace> --context <context> -p '{\"spec\":{\"claimRef\": null}}

I then add this to the collection of cheats:

navi repo add https://github.com/papanito/cheats

Parametrization

cheetsheet syntax allows you to use list

$: should contain commands that generate a list of possible values for a given argument information_source

So let’s have a command like this

kubectl get <object> --no-headers -o custom-columns=':metadata.name' --context <context>

The <context> can be read by kubectl so I define this in my cheat-sheet:

$ context: kubectl config get-contexts --- --column 2 --header-lines 1

For the <object> we define a list with pre-defined values:

$ object: echo -e "ns\ndeploy\nsts\npod\npvc\n"

Now let us see that in action:

use lists in snippets

Synchronizing cheatsheets

As mentioned in the documentation, auto-updating-repositories is not (yet) implemented. I currently use and adaption of this proposal and use git to synchronize:

#!/bin/bash
CHEATS_PATH=$(navi info cheats-path)

cd $CHEATS_PATH

for REPO_PATH in $(ls -d *); do
    echo "Get changes from $REPO_PATH"
    cd $REPO_PATH
    if [ -d ".git" ]; then
        DEFAULT_BRANCH=$(git branch -r | grep -Po 'HEAD -> \K.*$' | cut -d'/' -f2)
        echo $DEFAULT_BRANCH
        git pull -q origin $DEFAULT_BRANCH
    else
        repo_details=($(echo $REPO_PATH | sed  's/__/ /g'))
        repo_user=${repo_details[0]}
        repo_name=$(echo ${repo_details[1]} | cut -d'/' -f1)
        rm *
        git clone "https://github.com/${repo_user}/${repo_name}" .
    fi
    cd ..
done

Conclusion

navi is blazing fast and with using community driven cheatsheets, this is probably the only cheats tool you might want.