Custom prompts or shell-depth-indicator for `nix shell` / `nix develop`?

The Problem

I make quite heavy use of nix shell and nix develop and find that I often forget what shell “level of depth” I’m at in my terminal session.

I’d love for some solution where I could keep track of what depth I’m at in my shell invocations, and potentially the name of the current shell if the shell is from a single shell derivation.

Judging by this issue and the requests for env vars or custom prompts, it appears I’m far from the only one.

https://github.com/NixOS/nix/issues/6677

Impure Solutions

It appears that some of the concerns with supporting environment variable solutions are w.r.t. shell reproducibility, which makes a lot of sense. This also implies custom prompts are a no-go, as they are normally indicated by an env var like PS1.

That said, it seems like it could at least be useful to allow the user to opt-in to these likely innocuous impurities in their Nix configuration?

Maybe we could contain the impurities by allowing user config to specify something like a special “prompt derivation” that just specifies PS1 as an output and is supplied the shell’s derivation and current depth as an input?

Temporary Workarounds?

Either way, I’m curious what folks are doing as a workaround here in the meantime? Some kind of visual indicator that didn’t require input would be ideal.

In the meantime, I’m thinking I might just make a short-hand for:

echo "${PATH//:/$'\n'}"

which lists the current PATH directories. This at least makes it obvious whether or not you’re in a nix shell as it lists all of the shell’s buildInputs paths individually. It also gives an idea of which shell you’re in as you can see all the inputs individually.

That said, this isn’t ideal as it requires input to find where you are, and the output can be noisey or hard to parse depending on how complicated the shell is.

Any other suggestions/solutions appreciated!

2 Likes

You can always check the SHLVL environment variable. As you do not want to use a custom prompt, you might have to do that manually.

2 Likes

You can always check the SHLVL environment variable

TIL about SHLVL, thanks!

As you do not want to use a custom prompt

I’d actually love a custom prompt to solve this! My comment above was more about acknowledging the impurity of the solution, and that I can understand why Nix hasn’t enable this yet as a result.

Do you happen to have an example of a custom prompt using SHLVL that continues to work with nix shell/nix develop?

nix shell should just start a new $SHELL which also should adhere to your regular shells configuration.

nix develop will always us a bash IIRC. And I do not remember how that deals with the shlvl and RC files. This command does basically not exist in my regular workflow. I use direnv + nix-direnv instead.

I use this patch to the pure prompt to display the amount of nested nix-shell (actually of nested shells):

Index: pure/pure.zsh
===================================================================
--- pure.orig/pure.zsh
+++ pure/pure.zsh
@@ -113,6 +113,15 @@ prompt_pure_preprompt_render() {
 
 	# Initialize the preprompt array.
 	local -a preprompt_parts
+	
+
+	# nix shell
+	if [[ -z $ORIG_SHLVL ]]; then
+		export ORIG_SHLVL=$SHLVL
+	fi;
+	if [[ $SHLVL -gt $ORIG_SHLVL ]]; then
+		preprompt_parts+=("%F{yellow}[$(($SHLVL - $ORIG_SHLVL))]%f")
+	fi;
 
 	# Set the path.
 	preprompt_parts+=('%F{blue}%~%f')

Some prompts like liquiprompt can display SHLVL without a patch, but in my experience SHLVL does not start at 1 in terminal emulators for some reason, so instead this patch stores the starting value in ORIG_SHLVL.

This isn’t what you asked, but a completely different approach worth considering: direnv. Direnv is a fantastic tool that does one thing, does it well, and stays out of your way. Before each prompt, it checks for the existence of a .envrc file in the current and parent directories. So just create a .envrc file with the following simple entry:

use nix

Then when you cd to that directory (or a child directory), it looks for a “*.nix” file and automatically sets up the environment, essentially replacing your current shell. (Actually, the first time it asks you to authorise the file, for safety.) It detects when something has changed and automatically reloads the environment s needed (but you can also force it with direnv reload).

With direnv, you don’t end up with lots of nested shells to get lost in.

2 Likes

Just to add in to limitations of using direnv, it does not play very well with buildFHSUserEnv

https://github.com/nix-community/nix-direnv/issues/72

2 Likes