Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:luc14n0
nix
nix-bash-completions.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File nix-bash-completions.obscpio of Package nix
07070100000000000081A40000000000000000000000015E406D36000005EE000000000000000000000000000000000000001D00000000nix-bash-completions/LICENSEBSD 3-Clause License Copyright (c) 2017, Tor Hedin Brønner All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 07070100000001000081A40000000000000000000000015E406D3600001EDD000000000000000000000000000000000000001F00000000nix-bash-completions/README.md# nix-bash-completions Bash completion for the [Nix](https://nixos.org/nix/) and [NixOS](https://nixos.org/) command line tools. The aim is full completion support for every argument, option and option argument, as long as everything that's needed is available locally. For instance when accessing a nixpkgs repo through an url, and it has been previously downloaded, completion should be offered using the local copy. Any behavior which doesn't agree with the actual execution of the command is considered a bug. Issues are very welcome as I primarily use zsh and therefor won't catch that many bugs through daily usage. A thank you goes out to [Spencer Whitt](https://github.com/spwhitt) who started [nix-zsh-completions](https://github.com/spwhitt/nix-zsh-completions), as a lot of the boilerplate (options etc.) is taken from there. ## Usage For quick testing just source the `_nix` file: `. _nix`, and start tabbing. Some arguments support several types of input, but due to bash's limited completion system only exposes one type at a time. For instance `nix eval <tab>` will give you the default completion which is attribute paths, but `nix eval ./<tab>` will give you file completion (as store paths are valid input). If you aren't getting file completion on an option or argument which support it when starting off with `./`, `~/` or `/` please report it in an issue and it should be fixed promptly. Another example is `nix run --file channel:<tab>` which will complete channel names instead of files. ### Completing attribute paths to packages The preferred way to reference a package in Nix is by attribute path, not by name. Attribute paths look like this `nixos.mplayer` or `nixos.gnome.gedit`, where `nixos` is a collection of all packages. If `<tab>` results in eg. something like `nixos` you'll need to manually add a `.` to access the packages available in `nixos`. When using `nix-env` it's best to always add the `--attr` or `-A` flag as `nix-env` defaults to looking up packages by name which aren't completed fully (this is a legacy problem, the new `nix` command only works on attribute paths by default). Completion of attribute paths is context aware, so eg. `nix-env -i -f some/path/ -A <tab>` complete paths in `./some/path/default.nix`. It will also pick up `default.nix` or `shell.nix` in the current directory for `nix-build -A` and `nix-shell -A`. Things like `nix-shell -I nixpkgs=. -p <tab>` is also supported. ## Installation and dependencies ### NixOS 18.09 or newer Completion should work out of the box from 18.09 and onwards. If it's not working make sure that `programs.bash.enableCompletion` isn't set to false in `/etc/nixos/configuration.nix`. ### Other distros You need [bash-completion](https://github.com/scop/bash-completion) setup correctly. Installing the `bash-completion` package with the native package manager should probably do the trick. Then you can install `nix-bash-completions` from the cloned git repo with `nix-env -i -f default.nix`, or from nixpkgs eg. `nix-env -f '<nixpkgs> -iA nix-bash-completions'`. Make sure that `$XDG_DATA_DIRS` includes `~/.nix-profile/share`, which will tell `bash-completion` where to find the script when completion is done. Be careful though: make sure that `$XDG_DATA_DIRS` also includes your distribution's defaults (like `/usr/local/share/:/usr/share/`), or you may not be able to launch some applications from the console. Adding this to your `.bashrc` should work in general: ```bash export XDG_DATA_DIRS="$HOME/.nix-profile/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" ``` ### macOS In addition to setting up [bash-completion](https://github.com/scop/bash-completion) and installing `nix-bash-completions` through nix-env, you'll need a newer version of Bash (version 4 or greater) as [Apple refuses to ship GPL v3 licensed software](http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/). You might also need to copy or link the installed files in `~/.nix-profile/share/bash-completion/completions/` to `~/.local/share/bash-completion/completions/` so `bash-completion` will know where to look for the completion script. Though I don't know if it's necessary or that it will work, as I don't have a mac. If someone is using this successfully on macOS and would like to share the necessary steps then I'll happily add it to the readme. ## Implementation The script runs on top of `_parse` which is a bare bones implementation of zsh's [`_arguments`](http://zsh.sourceforge.net/Doc/Release/Completion-System.html#index-_005farguments) with some minor modifications to the syntax, and a bunch of stuff not implemented. A brief description of the `_parse` syntax follows, for anyone interested in reading the code, or using `_parse` for other completion scripts. ### `_parse` syntax `_parse` takes as arguments specifications of options and normal arguments. The spec looks like this at the moment (`[]` denotes optional syntax): Argument spec: - `:action` Argument specs tell `_parse` how to handle normal arguments (arguments not required by options). The first argument will be handled by the first `:action` passed to `_parse`, the second by the second argument spec passed, and so on. Actions starting with a `*` will handle all further arguments. `_parse` puts all the encountered normal arguments in the array `$line` for easy lookup when handling further completion. There's two types of actions: - `[*]->string` - `[*]_function` When completing an argument with a `->string` action `_parse` will set `$state` to `string`, return `1` and hand over control to the calling function which then need to handle the actual completion. The `[*]_function_` spec causes `_function` to be called, making it handle completion. At the moment this isn't that useful as passing options to `_function` isn't supported. `->string` actions together with a case statement is much more flexible. An example using the different actions: ```shell local state local -a line local -A opt_args opts _parse ':_known_hosts' ':*->FILE' && return case "$state" in FILE) COMPREPLY=($(compgen -f $cur)) esac ``` Here the function `_known_hosts` will handle completion for the first argument and then all further arguments will complete files through the `$state` case. The options spec have a few more pieces on top of actions: - `[(pattern|pattern ...)][*]--option[:action[:action2] ... ]` The simplest case just being: - `--option` Which tells `_parse` to add `--option` when completing options. If the option is present on the command line further option completion will exclude options matching any of the `pattern`s. By default `--option` will exclude itself. If we want an option to be repeatable we add the `*` prefix to the option. Adding actions to an option spec tells `_parse` that the option takes arguments. These actions are specified in the exact same way as the argument spec. Option arguments can later be looked up in the `$opt_args` associative array using the option as a key. The presence of __any__ option can be checked with `${opts[option]}`. A reduced version of `nix-shell` spec: ```shell local state local -a line local -A opt_args opts _parse ':*->FILE' '(--attr|-A)'{--attr,-A}':->ATTR_PATH' \ '(--packages|-p|shell)'{--packages,-p}'' '':*->FILE-OR-PACKAGE') \ && return case "$state" FILE-OR-PACKAGE) if [[ "${opts[--packages]}" || "${opts[-p]}" ]]; #Complete packages else COMPREPLY=($(compgen -f $cur)) fi esac ``` At the moment `_parse` only understands long options, eg. `--option`, and stackable short options, eg. `-f`. Syntax like `-some-option` is not supported. ## Issues - Only the first short option is completed, but eg. `nix-env -iA` is recognized, and `-i` won't be offered on any new option completion. Completing stacked options is probably not easily doable in bash. 07070100000002000081A40000000000000000000000015E406D360000D3CE000000000000000000000000000000000000001A00000000nix-bash-completions/_nix#!/usr/bin/env bash # Include this to get shell-script-mode to detect bash function _nix_print () { return 0 # Comment out to turn on print debugging while [[ "$1" ]]; do echo "$1" >> ~/log/nix shift done } function _nix_attr_paths () { local cur=${cur#@(\'|\")} cur=${cur%@(\'|\")} # Starting with '.' means we want files, not attribute names if [[ "$cur" == .* ]]; then return fi # The unnamed top context to look up attribute names local defexpr="$1" # The known valid part of the attribute path, eg. 'nixpkgs', if the # currently typed word is 'nixpkgs.mp' local attr_path="" if [[ -z ${cur/*.*/} ]]; then attr_path=${cur%.*} fi # attr1.attr3 -> ("attr1" "attr2") local -a paths=(${attr_path//./ }) paths=(${paths[*]/%/\"}) paths=(${paths[*]/#/\"}) # Auto call any functions in the attribute path. This isn't a language # feature, but done by nix when passing attributes on the command line. local -a packages=($(_nix_eval_stdin <<NIX_FILE let autocall = setOrLambda: if builtins.isFunction setOrLambda then setOrLambda {} else setOrLambda; top = autocall ($defexpr); names = [ ${paths[*]} ]; # Returns attr.name calling it if it's a function reducer = set: name: autocall (builtins.getAttr name set); result = builtins.foldl' reducer top names; in if builtins.isAttrs result then builtins.attrNames result else "" NIX_FILE )) # Don't insert space as we'll too often have to backspace and add a '.' compopt -o nospace # Generate the completion list prefixed with $attr_path and match against # the current word COMPREPLY=( $(compgen -P "${attr_path:+${attr_path}.}" -W "${packages[*]}" \ -- "${cur##*.}")) } function _nix_eval_stdin () { # Build up a modified NIX_PATH using -I and --include local i override="" for ((i=1; i < ${#words[*]}; i++)); do case "${words[i]}" in -I|--include) override+=${override:+:}${words[$((i+1))]} ;; esac done override+=${override:+:}${NIX_PATH} # Resolve channel: syntax while [[ "$override" == *@(=|:)channel:* ]]; do local channel=${override#*channel:} channel="channel:"${channel%%:*} local url="https://nixos.org/channels/"${channel:8}"/nixexprs.tar.xz" override=${override/"$channel"/"$url"} done # Resolve any url to a cache, else we might trigger a blocking download while [[ "$override" == *https://* ]]; do # Find the first url local url=${override#*https://} # Strip everything starting with the first colon url="https://"${url%%:*} local cache=$(_nix_resolve_url "$url") # Replace the url with the cache override=${override/"$url"/"$cache"} done # Eval stdin NIX_PATH=$override nix-instantiate --eval - 2> /dev/null | tr '"[]' ' ' } # Resolve any urls ourselves, as nix will start downloading and block # interaction if it's left to its own devices function _nix_resolve_url () { local url=$1 local version="$(${words[0]} --version)" local input if [[ "${version##* }" == 1.11.* ]]; then # works for nix 1.11 input="$url" else # works for nix 1.12 input="${url##*/}\0$url" fi local sha sha=$(nix-hash --flat --base32 --type sha256 <(printf "$input")) local cache=${XDG_CACHE_HOME:-~/.cache}/nix/tarballs local link="$cache"/"$sha"-file if [[ -e "$link" ]]; then echo "$cache/$(basename $(readlink $link))-unpacked" fi } # Get the correct file like argument from the command line function _nix_get_file_arg () { local file="" if [[ "${words[0]}" == @(nix-env|nix) ]]; then local i # Extract the last seen -f/--file argument for ((i=1; i < ${#words[*]}; i++)); do case "${words[i]}" in --file|-f) file=${words[$((i+1))]} ;; esac done elif [[ ${line[1]} ]]; then file="${line[1]}" elif [[ -e shell.nix && "${words[0]}" == nix-shell ]]; then file="shell.nix" elif [[ -e default.nix ]]; then file="default.nix" fi # Resolve files and urls if [[ "$file" ]]; then # Expand channel: syntax if [[ "$file" == channel:* ]]; then file="https://nixos.org/channels/"${file:8}"/nixexprs.tar.xz" fi # dequote file=$(dequote "$file") __expand_tilde_by_ref file if [[ -e "$file" ]]; then file=$(realpath "$file" 2>/dev/null) elif [[ "$file" == https://* ]]; then # Check the cache to resolve urls file=$(_nix_resolve_url "$file") fi fi printf -- "$file" } function _parse () { # Takes in `spec ...` and parses the command line using it # See README.md for more in depth explanation of the syntax ## Spec # :action -- A regular normal argument # :*action -- Repeating normal argument ## option spec # simple case: '-o' # [(pattern|pattern|...)][*]-f[:action[:[*]action ...]] # patterns to exclude from completion when option is typed ## action spec # ->string # set $state to 'string' # _function, function to run (isn't actually used though, so might be buggy) local -A options=() local -a arguments=("command") # Parse the spec local spec="$1" local -A groups local cur_group="" local split group excludes while [[ "$spec" ]]; do group="" excludes="" # check for an exclusion group # Strip it from $spec if found if [[ "$spec" == \(* ]]; then excludes=${spec%%\)*} excludes=${excludes:1}"#" spec="${spec#*\)}" fi case "$spec" in +) shift cur_group="$1" ;; -*) # exclude the option from itself by default local -a split=(${spec/:/ }) local flag=${split[0]} excludes=${flag}${excludes:+\|}${excludes:-\#} ;& \*-*) # Split on first : spec="${spec#\*}" # Strip possible star prefix local -a split=(${spec/:/ }) local flag=${split[0]} if [[ "$cur_group" ]]; then # Add the flag to the glob group groups[$cur_group]+=${groups[$cur_group]:+|}$flag fi # Internal representation [group#][excludes#]; options[$flag]="$excludes:${split[1]}" ;; :*) arguments+=("$spec") ;; esac shift spec="$1" done _nix_print " --**--" "-- Finished parsing spec" _nix_print "arguments:" "${arguments[*]}" _nix_print "options" "${!options[*]}" # _nix_print groups: ${!groups[*]} ${groups[*]} _nix_print "-- Parse words" # Use the parsed spec to handle the input # opt_arg queue local -a opt_queue=() local -a used_options=() local current_option="" local excluded_options="" # The list of completors corresponding to each word in words local completors=() # Reset all output variables line=() opts=() opt_args=() state="" local word="" i for ((i=0; i < ${#words[*]}; i++)); do word=${words[$i]} if [[ "${opt_queue[*]}" ]]; then # Consume an option argument _nix_print "consume option queue: $word ${opt_queue[0]}" local separator=${opt_args["$current_option"]:+:} opt_args["$current_option"]+=$separator${word//:/\\:} local action="${opt_queue[0]}" if [[ "$action" == \** ]]; then completors+=(${action#\*}) else completors+=(${action}) opt_queue=(${opt_queue[*]:1}) fi elif [[ "$word" == -* ]]; then # Handle options _nix_print "Consume option[s]: $word ${options[$word]}" completors+=("$word") # Reset flags local -a flags=() if [[ "$word" == --* ]]; then flags=("$word") else local letters=${word#-} j for ((j=0; j < ${#letters}; j++)); do flags+=(-${letters:j:1}) done fi local flag="" for flag in ${flags[*]}; do local spec=${options["$flag"]} local -a actions=(${spec//:/ }) # Register the flag being on the command line [[ "$spec" ]] && opts[${flag}]=1 # Check if actions contains an exclusion pattern if [[ ${actions[0]} == *\# ]]; then local prefix="${excluded_options:+|}" [[ "$cword" != "$i" || $flag == -? ]] \ && excluded_options+="$prefix${actions[0]:0:-1}" _nix_print "$flag's exclusion group:" "$prefix${actions[0]:0:-1}" actions=(${actions[*]:1}) fi # Add any option arguments to the queue if [[ "${actions[*]}" ]]; then current_option="$flag" # Add to the option argument queue _nix_print "option arguments: ${actions[*]}" opt_queue=(${actions[*]}) _nix_print "option queue: ${opt_queue[*]}" fi done else # Consume a regular argument _nix_print "Consume a regular argument: $word" line+=("$word") _nix_print "Adding completor: ${arguments[0]}" # Always add argument completors, even if empty local action="${arguments[0]}" _nix_print "action: $action" if [[ "$action" == :\** ]]; then completors+=("${action#:\*}") # Don't shift $arguments when the action is repeatable else completors+=("${action#:}") arguments=(${arguments[*]:1}) _nix_print "rest of arguments: ${arguments[*]}" fi fi done _nix_print "-- Finished parsing words: ${completors[*]}" local completor=${completors[$cword]} _nix_print "completor: $completor" case "$completor" in -\>*) state="${completor#->}" return 1 ;; -*) _nix_print "excluded_options $excluded_options" COMPREPLY=($(compgen -W "${!options[*]}" -X "*($excluded_options)" -- "$cur")) return 0 ;; _*) $completor return 0 ;; "") COMPREPLY=($(compgen -W "${!options[*]}" -X "*($excluded_options)" -- "$cur")) return 0 ;; esac } # Completions for all nix commands function _nix_completion () { local cur prev words cword # Setup current word, previous word, words and index of current word in # words (cword) _init_completion -n =: || return _nix_print "command line: ${words[*]}" _nix_print "number ${#words[*]}" _nix_print "cword $cword" local -a nix_boilerplate_opts=('--help' '--version') local nix_repair='--repair'; local nix_search_path_args='*-I:->option-INCLUDE' # Misc Nix options accepted by nixos-rebuild local -a nix_common_nixos_rebuild=( ${nix_search_path_args} '(--verbose|-v)'{--verbose,-v} '(--no-build-output|-Q)'{--no-build-output,-Q} '(--max-jobs|-j)'{--max-jobs,-j}':->empty' '--cores' '(--keep-going|-k)'{--keep-going,-k} '(--keep-failed|-K)'{--keep-failed,-K} '--fallback' '--show-trace' ${nix_repair}) # Used for all the nix-* commands, but not nixos-* commands # Introduced in 2.0 local -a nix_new_opts=( '*--include:->option-INCLUDE' "*--option:->nixoption:->nixoptionvalue" ) # Used in: nix-build, nix-env, nix-instantiate, nix-shell local -a nix_common_opts=( ${nix_common_nixos_rebuild[*]} ${nix_new_opts[*]} '*'{--attr,-A}':->attr_path' '*--arg:->function-arg:->empty' '*--argstr:->function-arg:->empty' '--max-silent-time:->empty' '--timeout:->empty' '--readonly-mode' '--log-type:->log-type') local nix_dry_run='--dry-run' local -a nix_gc_common=( '(- --print* --delete)--print-roots' '(-|--print*|--delete)--print-live' '(-|--print*|--delete)--print-dead' '(-|--print*|--delete)--delete' ) local state context word opt local -a line local -A opt_args local -A opts # Handle the different nix* commands # # The basic idea is making a spec to pass to _parse then # handle any possibly argument completion based on the resulting $state. # # For some commands like nix-env the spec depends on the flags already # typed on the command line. # # So in general there's three phases: # 1. Create the spec, possibly checking for existing flags and commands # 2. Pass the spec to parse and let it do its job # 3. Generating completions based on the resulting $state local -a main_commands=() case "${words[0]}" in nix-build) local -a nix_build_opts=( '--drv-link:->empty' '--add-drv-link' '(--expr|-E)'{--expr,-E} '--no-out-link' {--out-link,-o}':->empty') _parse ':*->file-or-expr' ${nix_common_opts[*]} \ ${nix_boilerplate_opts[*]} \ ${nix_build_opts[*]} && return 0 ;; nix-shell) local -a nix_shell_opts=( '--command:->option-COMMAND' '--exclude:->regex' '--pure' # nix-shell only takes one -A, so override the default "(--attr|-A)"{--attr,-A}':->attr_path' '(--packages|-p|--expr|-E)'{--expr,-E} '(--packages|-p|--expr|-E)'{--packages,-p}) _parse ':*->package_attr_path' ${nix_common_opts[*]} \ + boiler \ ${nix_boilerplate_opts[*]} \ ${nix_shell_opts[*]} && return 0 if [[ "$state" == package_attr_path ]]; then if [[ "${opts[--packages]}" || "${opts[-p]}" ]]; then _nix_attr_paths "import <nixpkgs>" return 0 else state=file-or-expr fi fi ;; nix-env) local -a main_options=( {--install,-i} {--upgrade,-u} {--uninstall,-e} --set-flag {--query,-q} {--switch-profile,-S} --list-generations --delete-generations {--switch-generation,-G} --rollback) local ex_group="${main_options[*]}" ex_group="(${ex_group// /|})" local -a main_spec=( "$ex_group"{--install,-i} "$ex_group"{--upgrade,-u} "$ex_group"{--uninstall,-e} "$ex_group"--set-flag":->flag_name:->flag_value" "$ex_group"{--query,-q} "$ex_group"{--switch-profile,-S} "$ex_group"--list-generations "$ex_group"--delete-generations "$ex_group"{--switch-generation,-G} "$ex_group"--rollback ) local -a nix_env_common_opts=( ${nix_common_opts[*]} '(--profile|-p)'{--profile,-p}':->profile' $nix_dry_run '--system-filter:->nix-system') local -a nix_env_b=('(--prebuilt-only|-b)'{--prebuilt-only,-b}) local nix_env_from_profile='--from-profile:->profile' local -a command_options for word in ${words[*]:1}; do case "$word" in --install|-*([a-zA-Z])i*([a-zA-Z])) command_options=( ${nix_env_common_opts[*]} ${nix_env_b[*]} $nix_env_from_profile '(--preserve-installed|-P)'{--preserve-installed,-P} '(--remove-all|-r)'{--remove-all,-r} '(-A|--attr)'{-A,--attr} ':*->installed_packages') break ;; --upgrade|-*([a-zA-Z])u*([a-zA-Z])) command_options=( ${nix_env_common_opts[*]} ${nix_env_b[*]} ${nix_env_from_profile[*]} '(-lt|-leq|-eq|--always)--lt' '(-lt|-leq|-eq|--always)--leq' '(-lt|-leq|-eq|--always)--eq' '(-lt|-leq|-eq|--always)--always' ':*->installed_packages') break ;; --uninstall|-*([a-zA-Z])e*([a-zA-Z])) command_options=(${nix_env_common_opts[*]} ':*->installed_packages') break ;; --set-flag) command_options=(${nix_env_common_opts[*]}) break ;; --query|-*([a-zA-Z])q*([a-zA-Z])) command_options=( ${nix_env_common_opts[*]} ${nix_env_b[*]} '(--available|-a)'{--available,-a} '(--status|-s)'{--status,-s} '(--attr-path|-P)'{--attr-path,-P} '(--compare-versions|-c)'{--compare-versions,-c} '--no-name' '--system' '--drv-path' '--out-path' '--description' '--xml' '--json' '--meta') break ;; --switch-profile|-*([a-zA-Z])S*([a-zA-Z])) command_options=(${nix_env_common_opts[*]} ':->profile') break ;; --delete-generations) command_options=(${nix_env_common_opts[*]} ':*->nix_generation') break ;; --switch-generation|-*([a-zA-Z])G*([a-zA-Z])) command_options=(${nix_env_common_opts[*]} ':->nix_generation') break ;; --list-generations) command_options=(${nix_env_common_opts[*]}) break ;; esac done _parse ${command_options[*]} \ '*'{--file,-f}':->option-FILE' \ ${nix_boilerplate_opts} ${main_spec[*]} && return 0 case "$state" in installed_packages) if [[ (${opts[-i]} || ${opts[--install]}) \ && (${opts[-A]} || ${opts[--attr]}) ]]; then # -iA means we should complete attribute paths state=attr_path elif [[ "$cur" == @("./"*|/*|\~*) ]]; then # Complete files and return if we're entering files with # absolute file syntax that nix will understand state=file else local -a packages=($(nix-env -q)) packages=(${packages[*]%%-[0-9]*}) COMPREPLY=($(compgen -W "${packages[*]}" -- "$cur")) return fi ;; nix_generation) local -a generations=($(nix-env --list-generations | \ sed -E \ -e 's= ([0-9]+) .*=\1=')) COMPREPLY=($(compgen -W "${generations[*]}" -- "$cur")) return ;; flag_name) COMPREPLY=($(compgen -W "priority keep active" -- "$cur")) return ;; flag_value) local flag_name=$prev case $flag_name in priority) return 0 ;; keep|active) COMPREPLY=($(compgen -W "true false" -- "$cur")) return 0 ;; esac ;; esac ;; nix-store) local -a main_options=( {--realise,-r} '--gc' '--delete' {--query,-q} '--add' '--verify' '--verify-path' '--repair-path' '--dump' '--restore' '--export' '--import' '--optimise' {--read-log,-l} '--dump-db' '--load-db' '--print-env' '--query-failed-paths' '--clear-failed-paths') local ex_group="${main_options[*]}" ex_group="(${ex_group// /|})" local -a main_spec=(${main_options[*]/#/$ex_group}) local -a command_options=() for word in ${words[*]:1}; do case "$word" in --realise|-*([a-zA-Z])r*([a-zA-Z])) command_options=( ${nix_dry_run[*]} '--add-root:->gc-root' '--indirect' '--ignore-unknown' ':*->file') break ;; --gc) command_options=( ${nix_gc_common[*]} '--max-freed:->empty') break ;; --delete) command_options=('--ignore-liveness' ':*->file') break ;; --query|-*([a-zA-Z])q*([a-zA-Z])) local -a queries=( '--outputs' {--requisites,-R} '--references' '--referrers' '--referrers-closure' '--deriver' '--graph' '--tree' '--binding' '--hash' '--size' '--roots') local query_group="${queries[*]}" query_group="(${query_group// /|})" local -a query_spec=(${queries[*]/#/$query_group}) local -a query_common=( '(--use-output|-u)'{--use-output,-u} '(--force-realise|-f)'{--force-realise,-f}) local -a requisite_options=() for opt in ${words[*]:1}; do case "$opt" in --requisites|-*([a-zA-Z])R*([a-zA-Z])) requisite_options=('--include-outputs') ;; esac done command_options=(${query_spec[*]} ${query_common[*]} {requisite_options[*]} ":*->file") break ;; --verify) command_options=('--check-contents' '--repair') break ;; --dump-db|--load-db|--query-failed-paths) # Nothing to complete break ;; *) command_options=(':*->file') break ;; esac done _parse ${nix_boilerplate_opts[*]} ${command_options[*]} \ ${nix_new_opts[*]} \ ${main_spec[*]} && return 0 ;; nix-channel) # nix-channel handling _parse \ ${nix_boilerplate_opts[*]} \ ${nix_new_opts[*]} \ '(-*)--add:->url:->channel_name' \ '(-*)--remove:->nix_channels' \ '(-*)--list' \ '(-*)--update:->nix_channels'\ '(-*)--rollback' && return 0 case "$state" in nix_channels) channels=($(nix-channel --list \ | sed -E \ -e 's/ .*//')) COMPREPLY=($(compgen -W "${channels[*]}" -- "$cur")) return 0 ;; esac ;; nix-copy-closure) _parse \ ${nix_boilerplate_opts[*]} \ ${nix_new_opts[*]} \ '(--from)--to' '(--to)--from' '--sign' '--gzip' \ '--include-outputs' '(--use-substitutes -s)'{--use-substitutes,-s} \ ':_user_at_host' ':*->file' && return 0 ;; nix-collect-garbage) _parse \ ${nix_boilerplate_opts[*]} \ ${nix_new_opts[*]} \ '(--delete-old|-d)'{--delete-old,-d} \ '--delete-older-than:->empty' \ ${nix_dry_run[*]} && return 0 ;; nix-hash) local ig='--to-base16|--to-base32' _parse \ ${nix_boilerplate_opts[*]} \ ${nix_new_opts[*]} \ '(-*)--to-base16:->hash' \ '(-*)--to-base32:->hash' \ "($ig)--flat" \ "($ig)--base32" \ "($ig)--truncate" \ "($ig)--type:->option-TYPE" \ ":*->file" && return 0 # TODO: Don't add file completion if we're using anything in $ig ;; nix-instantiate) _parse \ ${nix_boilerplate_opts[*]} '(--expr|-E)'{--expr,-E} \ ${nix_common_opts[*]} '--xml' '--json' '--add-root:->gc-root' \ '--indirect' '--parse' '--eval' "(-*)--find-file:*->nix-path-file"\ '--strict' '--read-write-mode' ':*->file-or-expr' && return 0 ;; nix-install-package) _parse \ ${nix_boilerplate_opts[*]} \ '--non-interactive' \ '(--profile|-p)'{--profile,-p}':->nix_profile' \ '--set' \ '--url:->url' \ ':->file' && return 0 # TODO: make --url and :->file mutually exclusive ;; nix-prefetch-url) _parse '--type:->option-TYPE' ':->option-FILE' ':->empty'\ '*'{--attr,-A}':->attr_path' '--unpack' \ '--name:->store-name' '--print-path' \ && return 0 ;; nix-push) _parse \ ${nix_boilerplate_opts[*]} \ '--dest:->directory' '(--none)--bzip2'\ '(--bzip2)--none' '--force' '--link'\ '(--manifest-path)--manifest'\ '(--manifest)--manifest-path:->file'\ '--url-prefix:->url'\ ':*->file' && return 0 ;; nixos-option) _parse \ $nix_search_path_args '--xml' \ ':->nixos_options' && return 0 if [[ "$state" == nixos_options ]]; then _nix_attr_paths ' with import <nixpkgs/lib>; filterAttrsRecursive (k: _: substring 0 1 k != "_") (evalModules { modules = import <nixpkgs/nixos/modules/module-list.nix>; }).options ' return 0 fi ;; nixos-rebuild) main_commands=( 'switch' 'boot' 'test' 'build' 'dry-build' 'dry-activate' 'edit' 'build-vm' 'build-vm-with-bootloader') _parse \ ${nix_boilerplate_opts[*]} \ ${nix_common_nixos_rebuild[*]} \ "*--option:->nixoption:->nixoptionvalue" \ '--upgrade' '--install-grub' "--no-build-nix" \ '--fast' '--rollback' \ '(--profile-name|-p)'{--profile-name,-p}':->profile-name' \ ':->main_command' && return 0 ;; nixos-install) _parse \ ${nix_boilerplate_opts[*]} \ $nix_search_path_args '--root:->directory'\ '--show-trace' '--chroot' && return 0 ;; nixos-generate-config) _parse ${nix_boilerplate_opts[*]} \ '--no-filesystems' '--show-hardware-config' '--force'\ '--root:->directory' '--dir:->directory' && return 0 ;; nixos-version) _parse ${nix_boilerplate_opts[*]} \ '(-*)'{--hash,--revision} && return 0 ;; nixos-container) main_commands=( 'list' 'create' 'destroy' 'start' 'stop' 'status' 'update' 'login' 'root-login' 'run' 'show-ip' 'show-host-key') local container_name=':->container'; local container_config='--config:->container_config'; local -a main_options=() for word in ${words[*]:1}; do case "$word" in create) main_options=( $container_name $container_config '--config-file:->file' '--system-path:->file' '--ensure-unique-name' '--auto-start') break ;; run) main_options=($container_name) break ;; update) main_options=($container_name $container_config) break ;; destroy|start|stop|status|login|root-login|show-ip|show-host-key) main_options=($container_name) break ;; esac done _parse '--help' ':->main_command' ${main_options[*]} && return 0 case "$state" in container) local -a containers=($(nixos-container list)) COMPREPLY=($(compgen -W "${containers[*]}" -- "$cur")) return 0 ;; esac ;; nixos-build-vms) _parse '--show-trace' "--no-out-link" \ ':->nix_file' '--help'\ && return 0 ;; nixops) main_commands=( list create modify clone delete info check set-args deploy send-keys destroy stop start reboot show-physical ssh ssh-for-each scp rename backup backup-status remove-backup clean-backups restore show-option list-generations rollback delete-generation show-console-output dump-nix-paths export import edit) # Options valid for every command local -a nixops_common_arguments=( '(--state|-s)'{--state,-s}':->file' '(--deployment|-d)'{--deployment,-d} '--confirm' '--debug') local -a nixops_include_exclude=( '--include:_known_hosts' '--exclude:_known_hosts') local -a nixops_search_path_args=('-I:->option-INCLUDE') local -a command_options=() for word in ${words[*]:1}; do case "$word" in create) main_options=( ${nixops_search_path_args[*]} ':*->nix_file') break ;; modify) main_options=( ${nixops_search_path_args[*]} '(--name|-n)'{--name,-n}':->empty' ':*->nix_file') break ;; clone) main_options=('(--name|-n)'{--name,-n}':->empty') break ;; delete) main_options=('--all' '--force') break ;; deploy) main_options=( '(--kill-obsolete|-k)'{--kill-obsolete,-k} ${nix_dry_run[*]} ${nix_repair[*]} '--create-only' '--build-only' '--copy-only' '--check' '--allow-reboot' '--force-reboot' '--allow-recreate' ${nixops_include_exclude[*]} ${nixops_search_path_args[*]} '--max-concurrent-copy:->number') break ;; destroy) main_options=( '--all' ${nixops_include_exclude[*]}) break ;; stop|start|backp) main_options=(${nixops_include_exclude[*]}) break ;; info) main_options=('--all' '--plain' '--no-eval') break ;; check|ssh) break ;; ssh-for-each) main_options=( '(--parallel|-p)'{--parallel,-p} ${nixops_include_exclude[*]}) break ;; reboot) main_options=( ${nixops_include_exclude[*]} '--no-wait') break ;; restore) main_options=( ${nixops_include_exclude[*]} '--devices:->device_name' '--backup-id:->backup_id') break ;; show-option) main_options=( '--xml' ':_known_hosts' ':->nixops_option') break ;; set-args) main_options=( '*--arg:->arg_name:->arg_value' '*--argstring:->arg_name:->arg_value' '--unset:->empty') break ;; show-console-output) main_options=(':_known_hosts') break ;; export) break ;; import) main_options=( '--include-keys') break ;; esac done _parse ':->main_command' \ ${nixops_common_arguments[*]} \ ${main_options[*]} \ ${nix_boilerplate_opts[*]} && return 0 ;; nix) type nix &> /dev/null || return local -a common_options common_options=("(--debug)"--debug "(-h|--help)"{-h,--help} "(--help-config)"--help-config "*--builders:->machine" "--store:->option-STORE-URI" "*--option:->nixoption:->nixoptionvalue" "(--quiet)--quiet" "*{-v,--verbose}" "(--version)"--version) # Extract the commands with descriptions # like ('command:some description' 'run:run some stuff') main_commands=( $(nix --help | sed -E \ -e '/^Available commands/,/^$/!d' \ -e '/^Available commands/d' \ -e '/^$/d' \ -e 's=^ +([0-9a-z-]*) +(.*)$=\1=')) # Add commands to an associative array for easy lookup local -A command_lookup local main_command for main_command in ${main_commands[*]}; do command_lookup[$main_command]=1 done local -a command_options=() local -a command_arguments=() # Setup the correct command_arguments and command_options depending # on which command we've typed local word for word in ${words[*]:1}; do # Check if we're in a valid command if [[ "${command_lookup[$word]}" == 1 ]]; then # Extract an array describing the possible arguments to the # command eg. (NAR PATH) for cat-nar or (INSTALLABLES) for # run local -a args=( $(nix $word --help | sed -E \ -e '2,$d' \ -e 's=^Usage.*<FLAGS>==' \ -e 's=\.|\?|<|>==g')) # And add the corresponding completors local arg for arg in ${args[*]}; do local plural="" [[ "$arg" == *S ]] && plural="*" command_arguments+=(":${plural}->arg-$arg") done # Extract the lines containing the option descriptions # Strip out the human descriptions local -a option_descriptions option_descriptions=( $(nix $word --help | sed -E \ -e '/^Flags:/,/^$/!d' \ -e "/^Flags:/d" \ -e 's/(.*) .*/\1/' \ -e 's/ //g' \ -e '/^$/d')) local option option_spec for option_spec in ${option_descriptions[*]}; do # Extract the options by stripping everything up from the # first '<', and any ',' local -a option_group=($(echo "$option_spec" \ | sed -E \ -e 's=,= =' \ -e 's=<.*==')) # Extract any arguments, by stripping the options, and # any '<' or '>' local -a option_args=( $(echo "$option_spec" \ | sed -E \ -e "s=.*${option_group[*]: -1}==" \ -e 's=[^<]*<==' \ -e 's=<|>= =g')) local ACTIONS="" for arg in ${option_args[*]}; do local plural="" [[ "$arg" == *S ]] && plural="*" ACTIONS+=":${plural}->option-$arg" done for option in ${option_group[*]}; do # Handle `run --keep/--unset` manually as they can be # repeated if [[ "$word" == run \ && "$option" == @(-k|--keep|-u|--unset) ]]; then command_options+=("*${option}:->option-PARAMS") elif [[ "$word" == add-to-store \ && "$option" == @(-n|--name) ]]; then # Another <NAME> ambiguity local exclusions="${option_group[*]}" command_options+=("(${exclusions// /|})${option}:->store-name") elif [[ "$option" == @(-I|--include) ]]; then # Special handling of --include due to type # ambiguity command_options+=("*${option}:->option-INCLUDE") elif [[ "$option" == @(--arg|--argstr|-f|--file) ]]; then # Repeatable options command_options+=("*${option}"$ACTIONS) else # Default to mutually exclusive non-repeatable # options local exclusions="${option_group[*]}" command_options+=("(${exclusions// /|})"$option$ACTIONS) fi done done break fi done _nix_print "command arguments: " _parse ':->main_command' \ ${command_arguments[*]} \ ${common_options[*]} \ ${command_options[*]} && return 0 ;; esac _nix_print "state: $state" _nix_print "line: ${line[*]}" _nix_print "opt_args: ${!opt_args[*]} ${opt_args[*]}" # Handle completion of different types of arguments while true; do case "$state" in main_command) COMPREPLY=($(compgen -W "${main_commands[*]}" -- "$cur")) return ;; arg-@(INSTALLABLES|INSTALLABLE|PACKAGE|DEPENDENCY)) if [[ "$cur" == @("./"*|/*|\~*) ]]; then # Complete files and return if we're entering files with # absolute file syntax that nix will understand compopt -o nospace COMPREPLY=($(compgen -f -- $cur)) return 0 fi # Continue with the shared attr_path handling ;& attr_path) # Handle all the various way commands expects the top level # expression being built local defexpr="" local file=$(_nix_get_file_arg) if [[ "$file" ]]; then # Extract --arg and --argstr into $args local i=1 args="" name="" value="" for ((i=1; i < ${#words[*]}; i++)); do case "${words[$i]}" in --arg) name=$(dequote "${words[$((i+1))]}") value=$(dequote "${words[$((i+2))]}") args+="$name = $value;" i=$((i+2)) ;; --argstr) name=$(dequote "${words[$((i+1))]}") value=$(dequote "${words[$((i+2))]}") args+="$name = \"$value\";" i=$((i+2)) ;; esac done args=${args:+\{$args\}} if [[ "${opts[--expr]}" || "${opts[-E]}" ]]; then defexpr="($file) $args" else defexpr="import $file $args" fi else # If there's no file input, generate the default top level # expressions for nix-env or nix if [[ "${words[0]}" == nix-env ]]; then # Generate nix code creating the default expression used by # 'nix-env -iA' local -a result local -a queue=(~/.nix-defexpr) while [[ ${#queue[*]} > 0 ]]; do local current="${queue[0]}" queue=(${queue[*]:1}) if [[ -e "$current/default.nix" ]]; then result+=($current) else local -a children=($(echo "$current"/*)) if [[ "$children" != *\* ]]; then queue+=(${children[*]}) fi fi done defexpr="{ " for p in ${result[*]}; do defexpr+="$(basename $p) = import $p; " done defexpr+="}" elif [[ "${words[0]}" == nix ]]; then # Fall back to completing available channels in the NIX_PATH # Extract the channels from NIX_PATH and -I/--include local -a channels=(${NIX_PATH[*]//:/ }) # The order doesn't matter as we're only using the names # This will also split eg. htttp://some/path, but we'll we'll # throw those elements away since they don't contain a '=' channels+=(${opt_args[-I]//:/ }) channels+=(${opt_args[--include]//:/ }) # Add the names in an associative array to avoid duplicates local -A names local channel name for channel in ${channels[*]}; do name=${channel%%=*} if [[ "$name" != "$channel" ]]; then # Only add paths with a name, not sure how they work names[$name]=1 fi done defexpr=$'{ ' for name in ${!names[*]}; do # nixos-config isn't useful or possible to complete [[ "$name" == nixos-config ]] && continue defexpr+="$name = import <${name}>; " done defexpr+=' }' fi fi _nix_print defexpr: "$defexpr" _nix_attr_paths "$defexpr" return 0 ;; function-arg|option-NAME) local file=$(_nix_get_file_arg) local func="" if [[ "${opts[--expr]}" || "${opts[-E]}" ]]; then func="$file" else func="import $file" fi local i exclude="" for ((i=1; i < ${#words[*]}; i++)); do case "${words[$i]}" in --arg|--argstr) # Don't add the name we're currently typing [[ $i == $((cword - 1)) ]] && continue exclude+=${exclude:+|}${words[$((i+1))]} ;; esac done local -a names=($(_nix_eval_stdin <<NIX_FILE let args = builtins.functionArgs ($func); in builtins.attrNames args NIX_FILE )) COMPREPLY=($(compgen -W "${names[*]}" -X "*($exclude)" -- "$cur")) return ;; file-or-expr) if [[ "${opts[--expr]}" || "${opts[-E]}" ]]; then state=expr else state=option-FILE fi continue ;; profile|option-PROFILE-DIR) compopt -o filenames if [[ "$cur" ]]; then COMPREPLY=($(compgen -d -- "$cur")) else local profiles=/nix/var/nix/profiles/ COMPREPLY=($(cd $profiles && compgen -P $profiles -d \ -- "${cur#$profiles}")) fi return ;; gc-root) compopt -o filenames if [[ "$cur" || "${opts[--indirect]}" ]]; then COMPREPLY=($(compgen -d -- $cur)) else local gcroot=/nix/var/nix/gcroots/ COMPREPLY=($(cd $gcroot && compgen -P $gcroot -d \ -- ${cur#$gcroot})) fi return ;; nix-system) local -a systems=( $(_nix_eval_stdin <<NIX_FILE (import <nixpkgs> {}).lib.systems.doubles.all NIX_FILE )) COMPREPLY=($(compgen -W "${systems[*]//@(\[|\])/}" -- "$cur")) return ;; arg-@(PATH|PATHS|NAR)) compopt -o filenames COMPREPLY=($(compgen -f -- $cur)) return ;; option-STORE-URI|directory) ## Not sure how to present alternatives here compopt -o filenames COMPREPLY=($(compgen -d -- $cur)) return ;; option-COMMAND) COMPREPLY=($(compgen -c -- $cur)) return ;; option-FILE|arg-FILES) if [[ "$cur" == channel:* ]]; then local -a channels=( nixos-13.10 nixos-16.09 nixos-14.04 nixos-16.09-small nixos-14.04-small nixos-17.03 nixos-14.12 nixos-17.03-small nixos-14.12-small nixos-17.09 nixos-15.09 nixos-17.09-small nixos-15.09-small nixos-unstable nixos-16.03 nixos-unstable-small nixos-16.03-small nixpkgs-17.09-darwin nixos-16.03-testing nixpkgs-unstable nixpkgs-18.03-darwin nixos-18.03 nixos-18.03-small ) COMPREPLY=($(compgen -W "${channels[*]}" -- "${cur#*:}")) return fi ;& arg-FILES|nix_file) compopt -o filenames COMPREPLY=($(compgen -d -- "$cur")) COMPREPLY+=($(compgen -X "!*.nix" -f -- "$cur")) return ;; option-FILES|option-PATH|file) compopt -o filenames COMPREPLY=($(compgen -f -- $cur)) return ;; option-TYPE) COMPREPLY=($(compgen -W "md5 sha1 sha256 sha512" -- "$cur")) return ;; option-PARAMS) COMPREPLY=($(compgen -v -- $cur)) return ;; option-INCLUDE) # --include <PATH> completion case "$cur" in /*|./*|~/*) compopt -o filenames COMPREPLY=($(compgen -d -- "$cur")) COMPREPLY+=($(compgen -X "!*.nix" -f -- "$cur")) ;; *=*) # This actually works due to bash's COMP_WORDBREAKS # weirdness compopt -o filenames COMPREPLY=($(compgen -d -- "${cur#*=}")) COMPREPLY+=($(compgen -X "!*.nix" -f -- "${cur#*=}")) ;; *) local -a nixpath=(${NIX_PATH//:/ }) local -a path_names local p for p in ${nixpath[*]}; do [[ "$p" == *=* ]] && path_names+=(${p%=*}) done compopt -o nospace COMPREPLY=($(compgen -S "=" -W "${path_names[*]}" -- "$cur")) ;; esac return ;; nixoption) local -a nix_options nix_options=($(nix --help-config | sed -E \ -e '/^$/,/^$/!d' \ -e '/^$/d' \ -e 's=^ +([0-9a-z-]*) +(.*)$=\1=')) COMPREPLY=($(compgen -W "${nix_options[*]}" -- $cur)) return ;; *|arg-REGEX|arg-STRINGS|option-NAME|option-EXPR|option-STRING) _nix_print "$state not implemented yet" # Fall back to file completion compopt -o filenames COMPREPLY+=($(compgen -f -- "$cur")) return ;; esac done return 1 } # Set up the completion for all relevant commands complete -F _nix_completion \ nix-build nix-shell nix-env nix-store \ nix-channel nix-copy-closure nix-collect-garbage \ nix-hash nix-instantiate \ nix-install-package nix-prefetch-url nix-push \ nixos-rebuild nixos-install nixos-version \ nixos-container nixos-generate-config nixos-build-vms \ nix nixos-option 07070100000003000081A40000000000000000000000015E406D3600000C8A000000000000000000000000000000000000002200000000nix-bash-completions/changelog.md# bash: v0.6, zsh: 0.3.6 The quest for an awesome completion system continues. The main bulk of changes apply to both ZSH and Bash, with explicit notes otherwise. ## -I/--include <PATH> support Attribute path completion now takes `-I` and `--include` into account. This makes completion work correctly when doing things like this: ```bash nix-shell -I nixpkgs=. --packages <tab> ``` When the completion system executes any nix code it will first resolve all URLS in the `NIX_PATH`, and in `-I` input, to a local store path if present. This protects against triggering an intrusive download while completing. `channel:` syntax is correctly translated to its `https://` form and resolved to a cache too. ZSH will tell you when it can't find a local cache of any URL. ## --arg and --argstr support Argument names are now offered as completions using `builtins.functionArgs`. Names already supplied on the command line is excluded from completions. Attribute path completion will also take --arg and --argstr into account, which means things like this work: ```bash nix-instantiate --eval default.nix --argstr bar foo -A <tab> ``` If the content of `default.nix` is `{bar}: {foo = bar;}` then completing will result in `foo`. ## --expr and -E support Attribute path completion now works for `--expr` input, including argument name completion. Note, URLs in the expression body is not yet resolved to a local cache so might trigger a download. This should ideally be fixed. In ZSH `--expr` now behaves properly, allowing completion of options after it has been entered (bash already did the correct thing here). ## Other small fixes and improvements - Most arguments which expects a `.nix` file will now only offer up those and directories, reducing clutter - `--file` will now complete more than once, the last one being used to generate attribute matches. In ZSH this allows aliasing `nix-env` to `nix-env -f '<nixpkgs>'` while still getting further `--file` completion which can be used to override the default. - nix-env now offer `--file` completion together with main operation completion by default. This is a compromise between discover-ability of main operations and the want to specify common options quickly. - `--add-root` will now off up `/nix/var/nix/gcroots/` by default, if `--indirect` is specified it will give normal directory completion. - Add missing `--help` and `--version` completion to many commands - nix-env: `--filter-system` will complete possible systems. - nix-instantiate: `--find-file` will no longer offer misleading file completion And a bunch of other small changes and fixes. # v0.4 Minor fixes: - Fix `nix-build -A nixUn` completion. - Fix `nix-build some/path -A`, the script didn't take realpath of `some/path` # v0.3 Some bug fixes and improvements: - All commands should now complete attribute paths when supplying `'<nixpkgs>` as file input - nix-env: `-A` only worked for `-i`/`--install`, now works for all main operations - nix-env will now only complete main operations until one has been supplied - nix-env --switch-generation will now complete generations - nix-channel: completes channel names properly now And a few other minor improvements. 07070100000004000081A40000000000000000000000015E406D3600000197000000000000000000000000000000000000002100000000nix-bash-completions/default.nixwith import <nixpkgs> {}; stdenv.mkDerivation rec { name = "nix-bash-completions"; src = ./.; installPhase = '' commands=$( function complete() { shift 2; echo "$@"; } shopt -s extglob source _nix ) install -Dm444 -t $out/share/bash-completion/completions _nix cd $out/share/bash-completion/completions for c in $commands; do ln -s _nix $c done ''; } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!134 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor