git.fiddlerwoaroof.com
Raw Blame History
#autoload

if [[ $_NIX_SHELL_COMPLETION_LOADED ]]; then
    # No point in re-defining these functions each time we do a completion
    return 0
fi

# Simple completion function to select a system
# List gathered from: https://github.com/NixOS/nixpkgs/blob/master/lib/platforms.nix
_nix_systems () {
    _values 'Systems' \
        i686-linux x86_64-linux \
        armv5tel-linux armv6l-linux armv7l-linux mips64el-linux \
        x86_64-darwin \
        i686-freebsd x86_64-freebsd \
        i686-openbsd x86_64-openbsd \
        i686-netbsd x86_64-netbsd \
        i686-cygwin x86_64-cygwin
}

# Completion function to select an angle-bracket expression from the nix path
# Assumptions: No '=' in the actual path components in NIX_PATH
# TODO: Complete files in /some/path for expressions like <nixpkgs/pkgs/...>
# IMPROVEMENT: Remove '<nixos-config>' since that seems rather useless(?)
_nix_shortcuts () {
    local nix_path=(${(s.:.)NIX_PATH})
    local named=(${(M)nix_path:#*=*})
    local dirs=(${nix_path:#*=*})
    local valid_dir_globs=($^dirs"/*/default.nix(N:h:t)")
    local valid_dirs=(${~valid_dir_globs})
    local names=(${named%%=*})
    _values shortcuts "<"${^valid_dirs}">" "<"${^names}">"
}

_nix_path() {
  _alternative \
    'nixpkgs:Nixpkgs:_nix_shortcuts' \
    'path:File Path:_nix_complete_dotnix_files'
}

_nix_complete_dotnix_files () {
    _path_files '-g' '*.nix(N) *(N-/)'
}

_nix_generations () {
    # List of package names with version numbers stripped
    local generations=($(nix-env --list-generations | awk '{print $1":"$2}'))
    _describe "Nix Generations" generations
}

_nix_installed_packages () {
    # List of package names with version numbers stripped
    local -a packages
    packages=($(nix-env -q | perl -pe 's/-[0-9.-].*$//'))
    _values "Nix Packages" $packages
}


# Generate nix code creating the default expression used by 'nix-env -iA'
_nix_gen_defexpr () {
    setopt local_options null_glob
    local -a result
    local -a queue=($1)
    while [[ ${#queue} > 0 ]]; do
        local current=$queue[1]
        shift queue
        if [[ -e $current/default.nix ]]; then
            result+=($current)
        else
            queue+=($current/*)
        fi
    done

    local nix_expr="{\n"
    for p in $result; do
        nix_expr+="$(basename $p) = import $p {};"
        nix_expr+="\n"
    done
    nix_expr+="}"

    echo $nix_expr
}


# Prints the attribute names (whitespace separated) of the given path
# Arguments: attribute_path [top_level_expr_path]
#   top_level_expr is interpreted as 'nix-env --file'
#   if top_level_expr is omitted it defaults to what 'nix-env -iA' uses
# Eg. _nix_attr_names nixos.python2Packages mypkgs.nix
_nix_attr_names () {
    setopt local_options pipefail

    local attr_path=top${1:+.$1}
    local defexpr_path=$2

    local defexpr
    if [[ -n $defexpr_path ]]; then
        if [[ -e $defexpr_path ]]; then
            # If the path exist use the absolute path to make sure import will
            # accept it.
            # (Otherwise the path is likely a <nixpkgs> notation)
            defexpr_path=${defexpr_path:a}
        fi
        defexpr="import $defexpr_path"
    elif [[ $command_name == nix-env ]]; then
        defexpr=$(_nix_gen_defexpr ~/.nix-defexpr)
    fi

    nix-instantiate --eval - \
          <<NIX_FILE | tr '[]"' ' '
                let
                  top_gen = $defexpr;
                  # --file arguments can be a lambda producing a record too
                  top = if builtins.typeOf top_gen == "lambda" then top_gen {} else top_gen ;
                in
                  builtins.attrNames $attr_path
NIX_FILE

    return $?
}


# Complete attribute paths
# NB: this function expects an optional argument so the user must make sure
#     zsh completion functions doesn't supply arguments. eg. when used in a
#     action spec to _arguments the function should be prefixed with a space:
#     `: _nix_attr_paths`
#     Without the space prefix _arguments will inject lots of arguments. These
#     are available(?) in the `expl` array anyway
_nix_attr_paths () {
    local attr_path=""
    if [[ $words[CURRENT] == *.* ]]; then
        attr_path=${words[CURRENT]%.*}
    fi

    local defexpr_path=$1
    if [[ -z $defexpr_path ]]; then
        if [[ $command_name == nix-env ]]; then
            defexpr_path=$opt_args[-f]
            if [[ -z $defexpr_path ]]; then
                defexpr_path=$opt_args[--file]
            fi
        else
            if [[ $line ]]; then
                defexpr_path=$line[1]
            elif [[ -e shell.nix && $command_name == nix-shell ]]; then
                defexpr_path=shell.nix
            elif [[ -e default.nix ]]; then
                defexpr_path=default.nix
            fi
        fi
    fi

    # Remove one level of shell quoting to make sure we see the same value as
    # the nix-* program will see.
    # ($opt_args and $line contain the verbatim string:
    #  eg. given `nix-shell '<nixpkgs>' -A ` $line[1] will be `'<nixpkgs>'` while
    #  nix-shell will see `<nixpkgs>`)
    defexpr_path=${(Q)defexpr_path}

    local -a result # must be on separate line to capture error code..
    result=( $(_nix_attr_names "$attr_path" $defexpr_path) ) 2>/dev/null

    if [[ $? > 0 ]]; then
        # Probably because of invalid attribute path or error in top-level expr
        return 1
    fi

    local prefix
    if [[ -n $attr_path ]]; then
        prefix=${attr_path}.
    fi

    _values -s . "Packages" ${prefix}${^result}
}

_nix_profiles () {
    local -a profiles
    profiles=($(find /nix/var/nix/profiles))
    _values "Nix Profiles" $profiles
}

# Used in: nix-build, nix-env, nix-instantiate, nix-shell, nixops
_nix_boilerplate_opts=(
  '(- *)--help[Print help message and exit]' \
  '(- *)--version[Print version number and exit]'
)

# Used in: nix-collect-garbage, nix-env, nix-store, nixops
_nix_dry_run='--dry-run[Show what would be done without doing it]'

# Used in: nix-collect-garbage, nix-store
_nix_gc_common=(
  '(- --print* --delete)--print-roots[Print roots used by garbage collector]' \
  '(- --print* --delete)--print-live[Print store paths reachable from roots]' \
  '(- --print* --delete)--print-dead[Print store paths not reachable from roots]' \
  '(- --print* --delete)--delete[Garbage collect all dead paths from the store]' \
)

# Used in: nixos-install, nix_common_opts
_nix_search_path_args=(
  '*-I+[Add path to Nix expression search path]:Include path:_nix_complete_dotnix_files'\
)

# Either true or false: useful for completing many Nix options
_nix_options_bool () {
    _values true false
}
# List gathered from: https://nixos.org/nix/manual/#sec-conf-file
# TODO: Complete the value as well, not just the key
_nix_options () {
    _values \
        'gc-keep-outputs' \
        'gc-keep-derivations' \
        'env-keep-derivations' \
        'build-max-jobs' \
        'build-cores' \
        'build-max-silent-time' \
        'build-timeout' \
        'build-max-log-size' \
        'build-users-group' \
        'build-use-chroot' \
        'build-chroot-dirs' \
        'build-extra-chroot-dirs' \
        'build-use-substitutes' \
        'build-fallback' \
        'build-cache-failure' \
        'build-keep-log' \
        'build-compress-log' \
        'use-binary-caches' \
        'binary-caches' \
        'binary-caches-files' \
        'trusted-binary-caches' \
        'extra-binary-caches' \
        'signed-binary-caches' \
        'binary-cache-public-keys' \
        'binary-caches-parallel-connections' \
        'verify-https-binary-caches' \
        'force-manifest' \
        'system' \
        'fsync-metadata' \
        'auto-optimise-store' \
        'connect-timeout' \
        'log-servers' \
        'trusted-users' \
        'allowed-users' \
        'restrict-eval' \
        'pre-build-hook'
}

_nix_repair='--repair[Fix corrupted or missing store paths by redownloading or rebuilding]';

# Misc Nix options accepted by nixos-rebuild
_nix_common_nixos_rebuild=(
  '(--verbose -v)*'{--verbose,-v}'[Increase verbosity of diagnostic messages]'\
  '(--no-build-output -Q)'{--no-build-output,-Q}'[Silence output to stdout and stderr]'\
  '(--max-jobs -j)'{--max-jobs,-j}'[Set the maximum number of build jobs that Nix will perform in parallel]'\
  '--cores[Set the parallelism of the individual builders (e.g. -j argument to make)]'\
  '(--keep-going -k)'{--keep-going,-k}'[Keep going in case of failed builds, to the greatest extent possible]'\
  '(--keep-failed -K)'{--keep-failed,-K}'[Do not delete the build directory if build fails]'\
  '--fallback[If binary download fails, fall back on building from source]'\
  '--show-trace[Print stack trace of evaluation errors]'\
  '--option[Set Nix configuration option]:Options:_nix_options:Value:( )'\
  $_nix_repair
  )

# Used in: nix-build, nix-env, nix-instantiate, nix-shell
_nix_common_opts=(
  $_nix_common_nixos_rebuild \
  $_nix_search_path_args \
  '(--attr -A)'{--attr,-A}'[Select an attribute from the top-level Nix expression being evaluated]:Packages: _nix_attr_paths'\
  '(--expr -E)'{--expr,-E}'[Interpret command line args as Nix expressions]:*:Files:_files'\
  '*--arg[Argument to pass to the Nix function]:Name:( ):Value:( )'\
  '--argstr[Like --arg, but the value is a string]: :'\
  '--max-silent-time[Builder times out after not producing stdout/stderr for x seconds]:Seconds:( )'\
  '--timeout[Timeout builder after given number of seconds]:Seconds:( )'\
  '--readonly-mode[Do not open Nix database]'\
  '--log-type[Configure how output is formatted]:Output format:((pretty\:"Default" escapes\:"Indicate nesting with escape codes" flat\:"Remove all nesting"))'\
)

_NIX_SHELL_COMPLETION_LOADED=1