Writing in the previous post in the series about the way I like my interactive shell to be configured, I did touch on the context aspect briefly:

Well, OK, maybe the other nicety is using a right-hand prompt as well for some stuff (mainly context info, like venv etc.)

I want to expand on it as it's one of the most important aspects of my shell interactions. I'm not sure if it was always the case (I think so) or whether something that happened over time while I aged (might be), but having the context at hand is essential to me. I need to know who am I, where am I, and why am I there to begin with (to be fair, not all of these questions can be answered by my shell, but, well, most can).

What do I mean by context? Here are a bunch of examples:

  • pwd
  • git status (no fancy icons necessary)
  • software version (nodejs, golang, terraform etc.)
  • virtual environment (if applicable, python for example)
  • shell drops from nnn or vim etc.
  • ssh connection (as opposed to local one)
  • gcloud project
  • kubernetes context

The key is that this information needs to be available at a glance, but only when I need it. I have no problem with pwd being truncated in some places, focusing more on readability for a single-line prompt over going into multiple lines. Pretty much all of these things are handled automatically by romkatv/powerlevel10k.

Quick showcase of context info provided by powerlevel10k

One really cool feature of powerlevel10k is showing some context information only when the defined command is being typed in the prompt. Kubernetes is a good example of this—it will show me the currently set context only when I type kubectl, kubectx, kubens, or helm commands, and that's about it. It's one of the reasons I prefer olets/zsh-abbr over aliases like k=kubectl or g=git.

dctx

Context is also important in some of the tools I'm using. Main examples of such context might be Docker, Kubernetes, or Google Project. While powerlevel10k prompt can handle showing me the context, it doesn't provide ways to switch it. That's where my terrible shell scripting can come in handy.

Funnily enough Docker context is not covered by powerlevel10k (it's too slow). I'm sorta OK with that as I tend to switch it less often than in Kubernetes. There were a bunch of things I wanted from the script:

  • easy way to display what's currently set
  • fast switch to default context
  • list of all available contexts
  • fuzzy finding the context I'm after

The last step is, obviously, powered by fzf. The way I wanted it to work was to just type the command and have a fuzzy finder kick in or pass in an argument with some part of the context name, and then on a single match to just switch to it, and on ambiguous match to show me the fuzzy picker.

As my memory has never been my top strength, having -h|--help flag is a must in the majority of my scripts. Speaking of which, I tend to start most of them more or less like so:

#!/usr/bin/env bash
set -euo pipefail

# Check for required dependencies
for dep in docker fzf jq; do
  command -v "$dep" >/dev/null 2>&1 || {
    printf "Missing dependency: %s :(\n" "$dep" >&2
    exit 1
  }
done

# It's a simple script, print a simple help please
usage() {
  printf '%s\n' "Usage: ${0##*/} [-c] [-d] [-h] [-l] [context name]

FLAGS
    -c, --current   Show current context
    -d, --default   Set default context
    -h, --help      Print help
    -l, --list      List all contexts" 1>&2
  exit 3
}

Of course, dependencies and help content differ, but the overall "shape" of the script remains the same. If I feel particularly inspired I might even throw in some examples into the mix, especially for a bit more complex beasts. As mentioned before, I made my peace with just using bash. I tend to gravitate towards using a case instead of the plethora of if statements, though I don't mind going either way.

Unlike in Kubernetes, the context in Docker is always set (i.e. it's either default or something else, but it is never unset). Knowing that and because powerlevel10k doesn't support showing Docker context, I knew I'd want to do two things:

  1. show the currently set context in the prompt
  2. exclude currently set context from fuzzy finding

Catching the current context is as simple as docker context show, but showing only the ones that aren't set was a bit trickier and, sadly, it introduced one additional dependency on jq:

docker context list --format=json | jq -r 'select(.Current==false).Name'

I gotta be honest: I'm immensely impressed by the capabilities of jq, but I find its syntax absolutely horrendous and non-intuitive. If I ever need to deal with JSON, I'm most certainly going to use python instead of bash. Rewriting an entire, super simple script for a single line into another language is another story, though. If there's a better way of achieving the above filtering that doesn't require third-party dependency on jq, please lemme know.

dctx in all its glory!

You can find the script here. Ain't gonna lie, it's one of those I use quite a bit. I've got a bunch of Docker-enabled machines out there that I set up contexts for via SSH, and being able to quickly and reliably switch between them is very convenient. default context remains always pointed at local machine. Works like a charm 👌🏻

kctx

To all the people already typing: chill, I know about ahmetb/kubectx. In fact, I still use it occasionally whenever I need to switch to particular namespace for multiple commands. As you probably deduced, I'm using kubens more often of the two, because there's one thing I'm missing big time in kubectx: auto-switching via argument on a single hit. Let's assume I've got a context named do-ams3-cluster-apps. I can use kubectx to switch to it directly either by invoking fuzzy matching (by act of passing no arguments) or by specifying the full name of it (by act of passing exactly one argument with the full name of the context). That's no way to live. I need to be able to pass just ams or less and it needs to switch to the correct context, and pronto!

That's, in essence, what kctx does. You can find the script here. It's one of my favorites, simply because it does exactly what I need it to do for my lazy ass, but it also feels faster than kubectx (it's probably just a feeling). It's definitely faster to type 🤷🏻‍♂️

kctx in all its glory!

Wrap up

I spawned up a repository on GitHub where I'm going to gradually fill in with some pretty terrible shell scripting. I'll do my best to cover most of these scripts on this blog, so there will probably be more parts to this series. You can find the previous one, where I covered my interactive shell setup, here:

In case you've got any feedback, feel free to reach me on Mastodon!