guix/etc/completion/bash/guix

359 lines
9.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GNU Guix --- Functional package management for GNU
# Copyright © 2015-2022 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2021 Tobias Geerinck-Rice <me@tobias.gr>
#
# This file is part of GNU Guix.
#
# GNU Guix is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or (at
# your option) any later version.
#
# GNU Guix is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
# Bash completion for Guix commands.
declare _guix_available_packages
declare _guix_commands
_guix_complete_command ()
{
local word_at_point="${COMP_WORDS[$COMP_CWORD]}"
if [ -z "$_guix_commands" ]
then
# Cache the list of commands to speed things up.
_guix_commands="$(${COMP_WORDS[0]} --help 2> /dev/null \
| grep '^ ' \
| sed '-es/^ *\([a-z-]\+\).*$/\1/g')"
fi
COMPREPLY+=($(compgen -W "$_guix_commands" -- "$word_at_point"))
}
_guix_complete_subcommand ()
{
local command="${COMP_WORDS[1]}"
local subcommands="$(${COMP_WORDS[0]} $command --help 2> /dev/null \
| grep '^ [a-z]' \
| sed -e's/^ \+\([a-z-]\+\).*$/\1/g')"
COMPREPLY+=($(compgen -W "$subcommands" -- "${COMP_WORDS[$COMP_CWORD]}"))
}
_guix_complete_available_package ()
{
local prefix="$1"
if [ -z "$_guix_available_packages" ]
then
# Cache the complete list because it rarely changes and makes
# completion much faster.
_guix_available_packages="$(${COMP_WORDS[0]} package -A 2> /dev/null \
| cut -f1)"
fi
COMPREPLY+=($(compgen -W "$_guix_available_packages" -- "$prefix"))
}
_guix_complete_installed_package ()
{
# Here we do not cache the list of installed packages because that
# may change over time and the list is relatively small anyway.
local prefix="$1"
local packages="$(${COMP_WORDS[0]} package -I "^$prefix" 2> /dev/null \
| cut -f1)"
COMPREPLY+=($(compgen -W "$packages" -- "$prefix"))
}
_guix_complete_option ()
{
local command="${COMP_WORDS[$1]}"
local subcommand="${COMP_WORDS[$(($1 + 1))]}"
if [ $1 -eq 0 ]
then
command=""
subcommand=""
elif _guix_is_option "$subcommand"
then
subcommand=""
fi
local options="$(${COMP_WORDS[0]} $command $subcommand --help 2> /dev/null \
| grep '^ \+-' \
| sed -e's/^.*--\([a-zA-Z0-9_-]\+\)\(=\?\).*/--\1\2/g')"
compopt -o nospace
COMPREPLY+=($(compgen -W "$options" -- "$2"))
}
_guix_is_option ()
{
case "$1" in
-*)
true
;;
*)
false
;;
esac
}
_guix_is_removing ()
{
local word
local result="false"
for word in ${COMP_WORDS[*]}
do
case "$word" in
--remove|--remove=*|-r)
result=true
break
;;
esac
done
$result
}
_guix_is_short_option ()
{
case "${COMP_WORDS[$COMP_CWORD - 1]}" in
--*) false;;
-*$1) true ;;
*) false ;;
esac
}
_guix_is_long_option ()
{
# Don't handle (non-GNU?) --long-option VALUE, as Guix doesn't either.
case "${COMP_WORDS[$COMP_CWORD]}" in
--$1=*) true ;;
*) false ;;
esac
}
_guix_is_dash_f ()
{
_guix_is_short_option f ||
_guix_is_long_option file ||
_guix_is_long_option install-from-file ||
_guix_is_long_option whole-file
}
_guix_is_dash_l ()
{
_guix_is_short_option l ||
_guix_is_long_option load
}
_guix_is_dash_L ()
{
_guix_is_short_option L ||
_guix_is_long_option load-path
}
_guix_is_dash_m ()
{
_guix_is_short_option m ||
_guix_is_long_option manifest
}
_guix_is_dash_C ()
{
_guix_is_short_option C ||
_guix_is_long_option channels
}
_guix_is_dash_p ()
{
_guix_is_short_option p ||
_guix_is_long_option profile
}
_guix_complete_file ()
{
# Let Readline complete file names.
compopt -o default
COMPREPLY=()
}
_guix_complete_available_package_or_store_file ()
{
_guix_complete_available_package "$@"
# The current _guix_complete_file implementation doesn't compose (append to
# COMPREPLY), so we suggest file names only if no package names matched.
if [[ -z "$COMPREPLY" ]]
then
_guix_complete_file # TODO: restrict to store files
fi
}
_guix_complete_pid ()
{
local pids="$(cd /proc; echo [0-9]*)"
COMPREPLY+=($(compgen -W "$pids" -- "$1"))
}
_guix_complete ()
{
local word_count=${#COMP_WORDS[*]}
local word_at_point="${COMP_WORDS[$COMP_CWORD]}"
# Find the innermost command at point, e.g. "build" in the case of
# "guix time-machine OPTIONS -- build<Tab>" -- but "time-machine" if
# point is moved before "build".
local command_index=0
local command
local word_index=0
local word
local expect_command="true"
while [[ $((++word_index)) -le COMP_CWORD ]]
do
word="${COMP_WORDS[$word_index]}"
if $expect_command
then
command_index=$word_index
command="$word"
expect_command="false"
continue
fi
if [[ "$word" = "--" ]]
then
case "$command" in
environment|shell)
break
;;
time-machine)
expect_command="true"
;;
esac
fi
done
case $COMP_CWORD in
$command_index)
_guix_complete_command
_guix_complete_option 0 "$word_at_point"
;;
*)
if [[ "$command" = "package" ]]
then
if _guix_is_dash_L || _guix_is_dash_m || _guix_is_dash_p || _guix_is_dash_f
then
_guix_complete_file
elif _guix_is_removing
then
_guix_complete_installed_package "$word_at_point"
else
_guix_complete_available_package "$word_at_point"
fi
elif [[ "$command" = "install" ]]
then
if _guix_is_dash_L || _guix_is_dash_m || _guix_is_dash_p
then
_guix_complete_file
else
_guix_complete_available_package "$word_at_point"
fi
elif [[ "$command" = "upgrade" || "$command" = "remove" ]]
then
if _guix_is_dash_L || _guix_is_dash_m || _guix_is_dash_p
then
_guix_complete_file
else
_guix_complete_installed_package "$word_at_point"
fi
elif [[ "$command" = "build" ]]
then
if _guix_is_dash_L || _guix_is_dash_m || _guix_is_dash_f
then
_guix_complete_file
else
_guix_complete_available_package_or_store_file "$word_at_point"
fi
elif [[ "$command" = "environment" || "$command" = "shell" ]]
then
if _guix_is_dash_f && [[ "$command" = "shell" ]]
then
# The otherwise identical guix environment lacks the -f option.
_guix_complete_file
elif _guix_is_dash_L || _guix_is_dash_m || _guix_is_dash_p || _guix_is_dash_l
then
_guix_complete_file
elif _guix_is_option "$word_at_point"
then
_guix_complete_option "$command_index" "$word_at_point"
else
_guix_complete_available_package "$word_at_point"
fi
elif [[ "$command" = "download" || "$command" = "gc" || "$command" = "hash" ]]
then
_guix_complete_file
elif [[ "$command" = "size" ]]
then
_guix_complete_available_package_or_store_file "$word_at_point"
elif [[ "$command" = "system" || "$command" = "home" ]]
then
case $((COMP_CWORD - command_index)) in
1) _guix_complete_subcommand;;
*) _guix_complete_file;; # TODO: restrict to *.scm
esac
elif [[ "$command" = "pull" ]]
then
if _guix_is_dash_C || _guix_is_dash_p
then
_guix_complete_file
fi
elif [[ "$command" = "time-machine" ]]
then
if _guix_is_dash_C
then
_guix_complete_file
else
_guix_complete_option "$command_index" "$word_at_point"
fi
elif [[ "$command" = "container" ]]
then
case $((COMP_CWORD - command_index)) in
1) _guix_complete_subcommand;;
2) _guix_complete_pid "$word_at_point";;
*) _guix_complete_file;;
esac
elif [[ "$command" = "import" ]]
then
_guix_complete_subcommand
elif [[ "$command" = "weather" ]]
then
if _guix_is_dash_m
then
_guix_complete_file
else
_guix_complete_available_package "$word_at_point"
fi
elif [[ "$command" = "style" ]]
then
if _guix_is_dash_f
then
_guix_complete_file
else
_guix_complete_available_package "$word_at_point"
fi
else
_guix_complete_available_package "$word_at_point"
fi
;;
esac
if [[ -z "$COMPREPLY" && COMP_CWORD -gt command_index ]] &&
_guix_is_option "$word_at_point"
then
_guix_complete_option "$command_index" "$word_at_point"
fi
}
complete -F _guix_complete guix