shell-completions
shell-completions copied to clipboard
Execution of shell-completion causes change in console `IFS` value
Hello,
I have an example yaml and output bash script from running the appspec completion
command with the --bash
parameter.
Command run
Click to expand!
The bash script is sourced in my ~/.bash_profile
.
Example yaml file
Click to expand!
---
name: ica-context-switcher
title: Switch contexts
options:
- name: project-name
summary: |
Name of the project
type: string
completion:
command_string: |-
cat "$HOME/.ica-ica-lazy/tokens/tokens.json" | jq -r 'keys[]'
- name: scope
summary: |
The privilege level you'd like to associate with the token
type: string
enum: [ admin, read-only ]
Example bash completion script
Click to expand!
#!/usr/bin/env bash
# Generated with perl module App::Spec v0.013
_ica-context-switcher() {
COMPREPLY=()
local program=ica-context-switcher
local cur prev words cword
_init_completion -n : || return
declare -a FLAGS
declare -a OPTIONS
declare -a MYWORDS
local INDEX=`expr $cword - 1`
MYWORDS=("${words[@]:1:$cword}")
FLAGS=('--help' 'Show command help' '-h' 'Show command help')
OPTIONS=('--project-name' 'Name of the project
' '--scope' 'The privilege level you'"\\'"'d like to associate with the token
')
__ica-context-switcher_handle_options_flags
case ${MYWORDS[$INDEX-1]} in
--project-name)
_ica-context-switcher__option_project_name_completion
;;
--scope)
_ica-context-switcher_compreply "admin" "read-only"
return
;;
esac
case $INDEX in
*)
__comp_current_options || return
;;
esac
}
_ica-context-switcher_compreply() {
local prefix=""
cur="$(printf '%q' "$cur")"
IFS=$'\n' COMPREPLY=($(compgen -P "$prefix" -W "$*" -- "$cur"))
__ltrim_colon_completions "$prefix$cur"
# http://stackoverflow.com/questions/7267185/bash-autocompletion-add-description-for-possible-completions
if [[ ${#COMPREPLY[*]} -eq 1 ]]; then # Only one completion
COMPREPLY=( "${COMPREPLY[0]%% -- *}" ) # Remove ' -- ' and everything after
COMPREPLY=( "${COMPREPLY[0]%%+( )}" ) # Remove trailing spaces
fi
}
_ica-context-switcher__option_project_name_completion() {
local CURRENT_WORD="${words[$cword]}"
local param_project_name="$(cat "$HOME/.ica-ica-lazy/tokens/tokens.json" | jq -r 'keys[]')"
_ica-context-switcher_compreply "$param_project_name"
}
__ica-context-switcher_dynamic_comp() {
local argname="$1"
local arg="$2"
local name desc cols desclength formatted
local comp=()
local max=0
while read -r line; do
name="$line"
desc="$line"
name="${name%$'\t'*}"
if [[ "${#name}" -gt "$max" ]]; then
max="${#name}"
fi
done <<< "$arg"
while read -r line; do
name="$line"
desc="$line"
name="${name%$'\t'*}"
desc="${desc/*$'\t'}"
if [[ -n "$desc" && "$desc" != "$name" ]]; then
# TODO portable?
cols=`tput cols`
[[ -z $cols ]] && cols=80
desclength=`expr $cols - 4 - $max`
formatted=`printf "%-*s -- %-*s" "$max" "$name" "$desclength" "$desc"`
comp+=("$formatted")
else
comp+=("'$name'")
fi
done <<< "$arg"
_ica-context-switcher_compreply ${comp[@]}
}
function __ica-context-switcher_handle_options() {
local i j
declare -a copy
local last="${MYWORDS[$INDEX]}"
local max=`expr ${#MYWORDS[@]} - 1`
for ((i=0; i<$max; i++))
do
local word="${MYWORDS[$i]}"
local found=
for ((j=0; j<${#OPTIONS[@]}; j+=2))
do
local option="${OPTIONS[$j]}"
if [[ "$word" == "$option" ]]; then
found=1
i=`expr $i + 1`
break
fi
done
if [[ -n $found && $i -lt $max ]]; then
INDEX=`expr $INDEX - 2`
else
copy+=("$word")
fi
done
MYWORDS=("${copy[@]}" "$last")
}
function __ica-context-switcher_handle_flags() {
local i j
declare -a copy
local last="${MYWORDS[$INDEX]}"
local max=`expr ${#MYWORDS[@]} - 1`
for ((i=0; i<$max; i++))
do
local word="${MYWORDS[$i]}"
local found=
for ((j=0; j<${#FLAGS[@]}; j+=2))
do
local flag="${FLAGS[$j]}"
if [[ "$word" == "$flag" ]]; then
found=1
break
fi
done
if [[ -n $found ]]; then
INDEX=`expr $INDEX - 1`
else
copy+=("$word")
fi
done
MYWORDS=("${copy[@]}" "$last")
}
__ica-context-switcher_handle_options_flags() {
__ica-context-switcher_handle_options
__ica-context-switcher_handle_flags
}
__comp_current_options() {
local always="$1"
if [[ -n $always || ${MYWORDS[$INDEX]} =~ ^- ]]; then
local options_spec=''
local j=
for ((j=0; j<${#FLAGS[@]}; j+=2))
do
local name="${FLAGS[$j]}"
local desc="${FLAGS[$j+1]}"
options_spec+="$name"$'\t'"$desc"$'\n'
done
for ((j=0; j<${#OPTIONS[@]}; j+=2))
do
local name="${OPTIONS[$j]}"
local desc="${OPTIONS[$j+1]}"
options_spec+="$name"$'\t'"$desc"$'\n'
done
__ica-context-switcher_dynamic_comp 'options' "$options_spec"
return 1
else
return 0
fi
}
complete -o default -F _ica-context-switcher ica-context-switcher
If I run the following command on a new console:
$ IFS="$IFS" python -c "import os; print(repr(os.environ['IFS']))"
' \t\n'
But I then call the auto-completion script
ica-context-switcher --<tab><tab>
I get a different value when trying to get the IFS output
$ IFS="$IFS" python -c "import os; print(repr(os.environ['IFS']))"
'\n'
I am running through WSL2 and this hasn't caused me any troubles, however, any colleague that runs bash on MacOS and then installs autocompletion with brew install bash_completion@2
ends up with the following issue: https://github.com/scop/bash-completion/issues/515
Is there a way for IFS to be reset to the default after the completion script has been activated?
Work around has been to run brew install bash_completion@2 --HEAD
since https://github.com/scop/bash-completion/issues/515 has been resolved by https://github.com/scop/bash-completion/pull/519
Thanks for the bugreport. Indeed that shouldn't be the case, and hopefully I can just fix it by using local, too
Setting local works, but beware of autocompletions, other autocompletions may call. If they haven't been patched then this will still have the same issue.
So
_<name>_compreply() {
local prefix=""
cur="$(printf '%q' "$cur")"
IFS=$'\n' COMPREPLY=($(compgen -P "$prefix" -W "$*" -- "$cur"))
...
to
_<name>_compreply() {
local prefix=""
local IFS=$'\n'
cur="$(printf '%q' "$cur")"
IFS=$'\n' COMPREPLY=($(compgen -P "$prefix" -W "$*" -- "$cur"))
...
seems to work