installShellFiles: Enhance installShellCompletion
Teach installShellCompletion how to install completions from a named pipe. Also add a convenience flag `--cmd NAME` that synthesizes the name for each completion instead of requiring repeated `--name` flags. Usage looks something like installShellCompletion --cmd foobar \ --bash <($out/bin/foobar --bash-completion) \ --fish <($out/bin/foobar --fish-completion) \ --zsh <($out/bin/foobar --zsh-completion) Fixes #83284
This commit is contained in:
parent
506a936e5f
commit
7e1e8543fc
@ -2070,7 +2070,7 @@ nativeBuildInputs = [ breakpointHook ];
|
|||||||
The <literal>installManPage</literal> function takes one or more paths to manpages to install. The manpages must have a section suffix, and may optionally be compressed (with <literal>.gz</literal> suffix). This function will place them into the correct directory.
|
The <literal>installManPage</literal> function takes one or more paths to manpages to install. The manpages must have a section suffix, and may optionally be compressed (with <literal>.gz</literal> suffix). This function will place them into the correct directory.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The <literal>installShellCompletion</literal> function takes one or more paths to shell completion files. By default it will autodetect the shell type from the completion file extension, but you may also specify it by passing one of <literal>--bash</literal>, <literal>--fish</literal>, or <literal>--zsh</literal>. These flags apply to all paths listed after them (up until another shell flag is given). Each path may also have a custom installation name provided by providing a flag <literal>--name NAME</literal> before the path. If this flag is not provided, zsh completions will be renamed automatically such that <literal>foobar.zsh</literal> becomes <literal>_foobar</literal>.
|
The <literal>installShellCompletion</literal> function takes one or more paths to shell completion files. By default it will autodetect the shell type from the completion file extension, but you may also specify it by passing one of <literal>--bash</literal>, <literal>--fish</literal>, or <literal>--zsh</literal>. These flags apply to all paths listed after them (up until another shell flag is given). Each path may also have a custom installation name provided by providing a flag <literal>--name NAME</literal> before the path. If this flag is not provided, zsh completions will be renamed automatically such that <literal>foobar.zsh</literal> becomes <literal>_foobar</literal>. A root name may be provided for all paths using the flag <literal>--cmd NAME</literal>; this synthesizes the appropriate name depending on the shell (e.g. <literal>--cmd foo</literal> will synthesize the name <literal>foo.bash</literal> for bash and <literal>_foo</literal> for zsh). The path may also be a fifo or named fd (such as produced by <literal><(cmd)</literal>), in which case the shell and name must be provided.
|
||||||
<programlisting>
|
<programlisting>
|
||||||
nativeBuildInputs = [ installShellFiles ];
|
nativeBuildInputs = [ installShellFiles ];
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
@ -2081,6 +2081,11 @@ postInstall = ''
|
|||||||
installShellCompletion --zsh --name _foobar share/completions.zsh
|
installShellCompletion --zsh --name _foobar share/completions.zsh
|
||||||
# implicit behavior
|
# implicit behavior
|
||||||
installShellCompletion share/completions/foobar.{bash,fish,zsh}
|
installShellCompletion share/completions/foobar.{bash,fish,zsh}
|
||||||
|
# using named fd
|
||||||
|
installShellCompletion --cmd foobar \
|
||||||
|
--bash <($out/bin/foobar --bash-completion) \
|
||||||
|
--fish <($out/bin/foobar --fish-completion) \
|
||||||
|
--zsh <($out/bin/foobar --zsh-completion)
|
||||||
'';
|
'';
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
# shellcheck shell=bash
|
||||||
# Setup hook for the `installShellFiles` package.
|
# Setup hook for the `installShellFiles` package.
|
||||||
#
|
#
|
||||||
# Example usage in a derivation:
|
# Example usage in a derivation:
|
||||||
@ -49,7 +49,7 @@ installManPage() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# installShellCompletion [--bash|--fish|--zsh] ([--name <name>] <path>)...
|
# installShellCompletion [--cmd <name>] ([--bash|--fish|--zsh] [--name <name>] <path>)...
|
||||||
#
|
#
|
||||||
# Each path is installed into the appropriate directory for shell completions for the given shell.
|
# Each path is installed into the appropriate directory for shell completions for the given shell.
|
||||||
# If one of `--bash`, `--fish`, or `--zsh` is given the path is assumed to belong to that shell.
|
# If one of `--bash`, `--fish`, or `--zsh` is given the path is assumed to belong to that shell.
|
||||||
@ -61,9 +61,20 @@ installManPage() {
|
|||||||
# If the shell completion needs to be renamed before installing the optional `--name <name>` flag
|
# If the shell completion needs to be renamed before installing the optional `--name <name>` flag
|
||||||
# may be given. Any name provided with this flag only applies to the next path.
|
# may be given. Any name provided with this flag only applies to the next path.
|
||||||
#
|
#
|
||||||
|
# If all shell completions need to be renamed before installing the optional `--cmd <name>` flag
|
||||||
|
# may be given. This will synthesize a name for each file, unless overridden with an explicit
|
||||||
|
# `--name` flag. For example, `--cmd foobar` will synthesize the name `_foobar` for zsh and
|
||||||
|
# `foobar.bash` for bash.
|
||||||
|
#
|
||||||
# For zsh completions, if the `--name` flag is not given, the path will be automatically renamed
|
# For zsh completions, if the `--name` flag is not given, the path will be automatically renamed
|
||||||
# such that `foobar.zsh` becomes `_foobar`.
|
# such that `foobar.zsh` becomes `_foobar`.
|
||||||
#
|
#
|
||||||
|
# A path may be a named fd, such as produced by the bash construct `<(cmd)`. When using a named fd,
|
||||||
|
# the shell type flag must be provided, and either the `--name` or `--cmd` flag must be provided.
|
||||||
|
# This might look something like:
|
||||||
|
#
|
||||||
|
# installShellCompletion --zsh --name _foobar <($out/bin/foobar --zsh-completion)
|
||||||
|
#
|
||||||
# This command accepts multiple shell flags in conjunction with multiple paths if you wish to
|
# This command accepts multiple shell flags in conjunction with multiple paths if you wish to
|
||||||
# install them all in one command:
|
# install them all in one command:
|
||||||
#
|
#
|
||||||
@ -76,9 +87,16 @@ installManPage() {
|
|||||||
# installShellCompletion --fish --name foobar.fish share/completions.fish
|
# installShellCompletion --fish --name foobar.fish share/completions.fish
|
||||||
# installShellCompletion --zsh --name _foobar share/completions.zsh
|
# installShellCompletion --zsh --name _foobar share/completions.zsh
|
||||||
#
|
#
|
||||||
|
# Or to use shell newline escaping to split a single invocation across multiple lines:
|
||||||
|
#
|
||||||
|
# installShellCompletion --cmd foobar \
|
||||||
|
# --bash <($out/bin/foobar --bash-completion) \
|
||||||
|
# --fish <($out/bin/foobar --fish-completion) \
|
||||||
|
# --zsh <($out/bin/foobar --zsh-completion)
|
||||||
|
#
|
||||||
# If any argument is `--` the remaining arguments will be treated as paths.
|
# If any argument is `--` the remaining arguments will be treated as paths.
|
||||||
installShellCompletion() {
|
installShellCompletion() {
|
||||||
local shell='' name='' retval=0 parseArgs=1 arg
|
local shell='' name='' cmdname='' retval=0 parseArgs=1 arg
|
||||||
while { arg=$1; shift; }; do
|
while { arg=$1; shift; }; do
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
if (( parseArgs )); then
|
if (( parseArgs )); then
|
||||||
@ -97,6 +115,17 @@ installShellCompletion() {
|
|||||||
# treat `--name=foo` the same as `--name foo`
|
# treat `--name=foo` the same as `--name foo`
|
||||||
name=${arg#--name=}
|
name=${arg#--name=}
|
||||||
continue;;
|
continue;;
|
||||||
|
--cmd)
|
||||||
|
cmdname=$1
|
||||||
|
shift || {
|
||||||
|
echo 'installShellCompletion: error: --cmd flag expected an argument' >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
continue;;
|
||||||
|
--cmd=*)
|
||||||
|
# treat `--cmd=foo` the same as `--cmd foo`
|
||||||
|
cmdname=${arg#--cmd=}
|
||||||
|
continue;;
|
||||||
--?*)
|
--?*)
|
||||||
echo "installShellCompletion: warning: unknown flag ${arg%%=*}" >&2
|
echo "installShellCompletion: warning: unknown flag ${arg%%=*}" >&2
|
||||||
retval=2
|
retval=2
|
||||||
@ -110,39 +139,67 @@ installShellCompletion() {
|
|||||||
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
echo "installShellCompletion: installing $arg${name:+ as $name}"
|
echo "installShellCompletion: installing $arg${name:+ as $name}"
|
||||||
fi
|
fi
|
||||||
# if we get here, this is a path
|
# if we get here, this is a path or named pipe
|
||||||
# Identify shell
|
# Identify shell and output name
|
||||||
local basename
|
|
||||||
basename=$(stripHash "$arg")
|
|
||||||
local curShell=$shell
|
local curShell=$shell
|
||||||
if [[ -z "$curShell" ]]; then
|
local outName=''
|
||||||
# auto-detect the shell
|
if [[ -z "$arg" ]]; then
|
||||||
case "$basename" in
|
echo "installShellCompletion: error: empty path is not allowed" >&2
|
||||||
?*.bash) curShell=bash;;
|
return 1
|
||||||
?*.fish) curShell=fish;;
|
elif [[ -p "$arg" ]]; then
|
||||||
?*.zsh) curShell=zsh;;
|
# this is a named fd or fifo
|
||||||
*)
|
if [[ -z "$curShell" ]]; then
|
||||||
if [[ "$basename" = _* && "$basename" != *.* ]]; then
|
echo "installShellCompletion: error: named pipe requires one of --bash, --fish, or --zsh" >&2
|
||||||
# probably zsh
|
return 1
|
||||||
echo "installShellCompletion: warning: assuming path \`$arg' is zsh; please specify with --zsh" >&2
|
elif [[ -z "$name" && -z "$cmdname" ]]; then
|
||||||
curShell=zsh
|
echo "installShellCompletion: error: named pipe requires one of --cmd or --name" >&2
|
||||||
else
|
return 1
|
||||||
echo "installShellCompletion: warning: unknown shell for path: $arg" >&2
|
fi
|
||||||
retval=2
|
else
|
||||||
continue
|
# this is a path
|
||||||
fi;;
|
local argbase
|
||||||
esac
|
argbase=$(stripHash "$arg")
|
||||||
|
if [[ -z "$curShell" ]]; then
|
||||||
|
# auto-detect the shell
|
||||||
|
case "$argbase" in
|
||||||
|
?*.bash) curShell=bash;;
|
||||||
|
?*.fish) curShell=fish;;
|
||||||
|
?*.zsh) curShell=zsh;;
|
||||||
|
*)
|
||||||
|
if [[ "$argbase" = _* && "$argbase" != *.* ]]; then
|
||||||
|
# probably zsh
|
||||||
|
echo "installShellCompletion: warning: assuming path \`$arg' is zsh; please specify with --zsh" >&2
|
||||||
|
curShell=zsh
|
||||||
|
else
|
||||||
|
echo "installShellCompletion: warning: unknown shell for path: $arg" >&2
|
||||||
|
retval=2
|
||||||
|
continue
|
||||||
|
fi;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
outName=$argbase
|
||||||
fi
|
fi
|
||||||
# Identify output path
|
# Identify output path
|
||||||
local outName sharePath
|
if [[ -n "$name" ]]; then
|
||||||
outName=${name:-$basename}
|
outName=$name
|
||||||
|
elif [[ -n "$cmdname" ]]; then
|
||||||
|
case "$curShell" in
|
||||||
|
bash|fish) outName=$cmdname.$curShell;;
|
||||||
|
zsh) outName=_$cmdname;;
|
||||||
|
*)
|
||||||
|
# Our list of shells is out of sync with the flags we accept or extensions we detect.
|
||||||
|
echo 'installShellCompletion: internal error' >&2
|
||||||
|
return 1;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
local sharePath
|
||||||
case "$curShell" in
|
case "$curShell" in
|
||||||
bash) sharePath=bash-completion/completions;;
|
bash) sharePath=bash-completion/completions;;
|
||||||
fish) sharePath=fish/vendor_completions.d;;
|
fish) sharePath=fish/vendor_completions.d;;
|
||||||
zsh)
|
zsh)
|
||||||
sharePath=zsh/site-functions
|
sharePath=zsh/site-functions
|
||||||
# only apply automatic renaming if we didn't have a manual rename
|
# only apply automatic renaming if we didn't have a manual rename
|
||||||
if test -z "$name"; then
|
if [[ -z "$name" && -z "$cmdname" ]]; then
|
||||||
# convert a name like `foo.zsh` into `_foo`
|
# convert a name like `foo.zsh` into `_foo`
|
||||||
outName=${outName%.zsh}
|
outName=${outName%.zsh}
|
||||||
outName=_${outName#_}
|
outName=_${outName#_}
|
||||||
@ -153,8 +210,16 @@ installShellCompletion() {
|
|||||||
return 1;;
|
return 1;;
|
||||||
esac
|
esac
|
||||||
# Install file
|
# Install file
|
||||||
install -Dm644 -T "$arg" "${!outputBin:?}/share/$sharePath/$outName" || return
|
local outDir="${!outputBin:?}/share/$sharePath"
|
||||||
# Clear the name, it only applies to one path
|
local outPath="$outDir/$outName"
|
||||||
|
if [[ -p "$arg" ]]; then
|
||||||
|
# install handles named pipes on NixOS but not on macOS
|
||||||
|
mkdir -p "$outDir" \
|
||||||
|
&& cat "$arg" > "$outPath"
|
||||||
|
else
|
||||||
|
install -Dm644 -T "$arg" "$outPath"
|
||||||
|
fi || return
|
||||||
|
# Clear the per-path flags
|
||||||
name=
|
name=
|
||||||
done
|
done
|
||||||
if [[ -n "$name" ]]; then
|
if [[ -n "$name" ]]; then
|
||||||
|
Loading…
Reference in New Issue
Block a user