Skip to content

NixOS Autocomplete

So you want to create a script that has tab completion, and you use home-manager?

pkgs.writeTextFile

I find just writing a standard tab completion file to disc the easiest way of accomplishing this.

let
  anyPackageName = pkgs.writeTextFile {
    name = "anyPackageName";
    destination = "/share/bash-completion/completions/script-name";
    text = ''
    Your tab completion script here
    '';
  };
in

If you ls ~/.nix-profile/share/bash-completion/completions your defined script-name inside destination will be located there now.

home.packages

Install your tab completion package with home.packages

  home.packages = [
    pkgs.anyPackageName
  ];

alias

Setting an alias is optional, the following code will create a script alias name of customApp that can be called from your terminal.

  programs.bash.shellAliases = {
    customApp = "~/.local/bin/your-script.sh";
  };
You will need to either source your .bashrc or reload your current shell to see these changes.

Complete

Here is an example of a tab completion script for a startup.sh that I use to manage a dev environment when working inside a project. The system creates a shell alias of punch-in so I can call punch-in app_start, or punch-in clean_db_start

Under the complete -F section, if using a alias, you can remove the all the lines besides complete -F _punch-in-startup punch-in

{ pkgs, ... }:

# Nix home-manager configuration file sets up a bash alias and tab completion for my punch-in startup.sh script

let
  punch-in-startup = pkgs.writeTextFile {
    name = "punch-in-startup";
    destination = "/share/bash-completion/completions/punch-in";
    text = ''
      _punch-in-startup() {
          local cur prev opts
          COMPREPLY=()
          cur="''${COMP_WORDS[COMP_CWORD]}"
          prev="''${COMP_WORDS[COMP_CWORD-1]}"

          # Available commands
          local commands="app_start app_stop clean_db_start db_create db_delete db_start db_stop logs"

          case "''${COMP_CWORD}" in
              1)
                  # First argument - show all commands
                  COMPREPLY=( $(compgen -W "''${commands}" -- ''${cur}) )
                  ;;
              *)
                  # No further completion needed for this script
                  COMPREPLY=()
                  ;;
          esac

          return 0
      }

      # Register completion for various ways to call the script
      complete -F _punch-in-startup startup.sh
      complete -F _punch-in-startup ./startup.sh
      complete -F _punch-in-startup ~/git/codeberg/punch-in/startup.sh

      # Register completion for the punch-in command/alias
      complete -F _punch-in-startup punch-in
      '';
  };

in

{
  ###
  # packages
  ###
  home.packages = [
    punch-in-startup
  ];

  ###
  # shell aliases
  ###
  programs.bash.shellAliases = {
    punch-in = "~/git/codeberg/punch-in/startup.sh";
  };
}