BT  ·  2026-10-16

devenv.nix

  1# devkit — shared devenv module: personal tools + the customized interactive
  2# bash environment.
  3#
  4# Consumers import this from their devenv.yaml:
  5#
  6#   inputs:
  7#     devkit:
  8#       url: path:../devkit        # or git+https://git.kilimanjaro.io/devenv-base
  9#       flake: false
 10#     # devenv#2205: an imported input's devenv.yaml is NOT evaluated, so each
 11#     # consumer must declare the tool inputs its own config here.
 12#     bug: { url: git+https://git.kilimanjaro.io/bug }
 13#     local-code-review: { url: git+https://git.kilimanjaro.io/local-code-review }
 14#     secrets: { url: git+https://git.kilimanjaro.io/secrets }
 15#   imports:
 16#     - devkit
 17#
 18# Each tool is added automatically when its input is declared. Disable one with
 19# e.g. `devkit.bug.enable = false` (a project that ships its own wrapper).
 20#
 21# Changes to this file are picked up on the next `devenv shell` (path inputs,
 22# devenv 2.2+). Once promoted to a git input, consumers pull them with
 23# `devenv update devkit`.
 24{ pkgs, lib, config, inputs, ... }:
 25
 26let
 27  cfg = config.devkit;
 28  hasInput = name: lib.hasAttr name inputs;
 29in
 30
 31{
 32  options.devkit = {
 33    enable = lib.mkOption {
 34      type = lib.types.bool;
 35      default = true;
 36      description = "Add the devkit toolchain and customized bash environment.";
 37    };
 38    bug.enable = lib.mkOption {
 39      type = lib.types.bool;
 40      default = hasInput "bug";
 41      description = "Add the `bug` CLI (set false if the project ships its own wrapper).";
 42    };
 43    local-code-review.enable = lib.mkOption {
 44      type = lib.types.bool;
 45      default = hasInput "local-code-review";
 46      description = "Add the `lcr` CLI.";
 47    };
 48    secrets.enable = lib.mkOption {
 49      type = lib.types.bool;
 50      default = hasInput "secrets";
 51      description = "Add the `secrets` CLI.";
 52    };
 53  };
 54
 55  config = lib.mkIf cfg.enable {
 56    packages = [
 57      # toolchain the interactive bash environment needs
 58      pkgs.bash
 59      pkgs.bash-completion
 60      pkgs.bashInteractive
 61      pkgs.jujutsu
 62    ]
 63    # tools; the inputs are declared by the consumer (see header), so only add
 64    # each one when it is present and not explicitly disabled.
 65    ++ lib.optional cfg.bug.enable (inputs.bug.packages.${pkgs.system}.bug)
 66    ++ lib.optional cfg.local-code-review.enable (inputs.local-code-review.packages.${pkgs.system}.default)
 67    ++ lib.optional cfg.secrets.enable (inputs.secrets.packages.${pkgs.system}.default);
 68
 69    # The customized bash environment. It is `types.lines`, so each project's
 70    # own enterShell is concatenated onto this.
 71    enterShell = ''
 72      # Interactive shells only: `devenv shell -- <cmd>` has no line editing,
 73      # and bind warns there.
 74      if [[ $- == *i* ]]; then
 75        # Configure bash with fish-like features
 76        bind 'set completion-ignore-case on'  # Case-insensitive completion
 77        bind 'set show-all-if-ambiguous on'   # Show all completions on first tab
 78        bind 'set menu-complete-display-prefix on'
 79        bind 'TAB:menu-complete'              # Tab cycles through completions
 80        bind '"\e[A":history-search-backward' # Up arrow searches history
 81        bind '"\e[B":history-search-forward'  # Down arrow searches history
 82        bind 'set colored-completion-prefix on'  # Color the completion prefix
 83        bind 'set colored-stats on'           # Color the completion stats
 84
 85        # Enable bash-completion if available
 86        if [ -f ${pkgs.bash-completion}/etc/profile.d/bash_completion.sh ]; then
 87          source ${pkgs.bash-completion}/etc/profile.d/bash_completion.sh
 88        fi
 89
 90        # Better directory navigation
 91        shopt -s autocd 2>/dev/null          # Type directory name to cd
 92        shopt -s dirspell 2>/dev/null        # Correct spelling of dir names
 93        shopt -s cdspell 2>/dev/null         # Correct spelling of cd args
 94
 95        # Enable ** globbing for recursive directory matching
 96        shopt -s globstar 2>/dev/null
 97      fi
 98    '';
 99  };
100}