Skip to content

Commit

Permalink
image: enable basic tab completion for bash
Browse files Browse the repository at this point in the history
  • Loading branch information
citrus-it committed Apr 19, 2024
1 parent f6248bd commit 9b5066f
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 1 deletion.
258 changes: 258 additions & 0 deletions image/templates/files/bash_completion
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# This file is derived from completion fragments at
# https://github.com/OpenIndiana/openindiana-completions
#
# Portions Copyright 2006 Yann Rouillard <[email protected]>
# Portions Copyright (c) 2013, Jonathan Perkin <[email protected]>
# Portions copyright 2013, Nexenta Systems, Inc.
# Portions Copyright (c) 2018, Michal Nowak <[email protected]>
# Portions Copyright 2024 Oxide Computer Company

_zlogin()
{
local cur prev line
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
line="${COMP_LINE}"

# zlogin [-dCEQ] [-e c] [-l username] zonename
# zlogin [-nEQS] [-e c] [-l username] zonename utility [argument]...
local opts="-E -Q -e -l"
local opts_interactive="-d -C"
local opts_util="-n -S"

if [[ "${cur}" == -* ]]
then
case "${line}" in
*\ -n\ *|*\ -S\ *)
COMPREPLY=( $(compgen -W "${opts} ${opts_util}" -- "${cur}") )
;;
*\ -d\ *|*\ -C\ *)
COMPREPLY=( $(compgen -W "${opts} ${opts_interactive}" -- "${cur}") )
;;
*)
COMPREPLY=( $(compgen -W "${opts} ${opts_util} ${opts_interactive}" -- "${cur}") )
;;
esac
else
# Provide running zone names
local zones=$(zoneadm list -n)
COMPREPLY=( $(compgen -W "${zones}" -- ${cur}) )
fi
}

_dash_z_zone()
{
local cur prev
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"

if [[ ${prev} =~ "-z" ]]; then
local zones="$(zoneadm list -n $*)"
COMPREPLY=( $(compgen -W "${zones}" -- ${cur}) )
fi
}

_dash_z_zone_running() { _dash_z_zone; }
_dash_z_zone_configured() { _dash_z_zone -c; }

_smf_complete_fmri()
{
local cur="$1" prefix="$2"
local cur_prefix fmri fmri_list=""
local exact_mode pattern

if [[ "$cur" == $prefix* ]]; then
[[ "$cur" == $prefix ]] && cur+="/"
pattern="$cur*"
exact_mode=1
else
pattern="$prefix*/$cur*"
fi

cur_prefix="${cur%"${cur##*/}"}"

for fmri in $(svcs -H -o FMRI "$pattern" 2>/dev/null); do
local fmri_part_list fmri_part
if [[ -z "$exact_mode" ]]; then
fmri=${fmri#$prefix/}

# We generate all possibles abbreviations for the FMRI
# no need to have a generic loop as we will have a finite
# number of components.
local OIFS="$IFS"; IFS="/"; set -- $fmri; IFS="$OIFS"
case $# in
1) fmri_part_list=" $1";;
2) fmri_part_list=" $2 $1/$2";;
3) fmri_part_list=" $3 $2/$3 $1/$2/$3";;
4) fmri_part_list=" $4 $3/$4 $2/$3/$4 $1/$2/$3/$4";;
esac
else
fmri_part_list="$fmri"
fi

# Here we make sure the completions begin with the pattern and
# we cut them at the first slash.
for fmri_part in $fmri_part_list; do
[[ "$fmri_part" == $cur* ]] || continue
local first_part=${fmri_part#$cur_prefix}
first_part=$cur_prefix${first_part%%/*}
[[ "$first_part" != "$fmri_part" ]] && first_part+="/"
fmri_list+=" $first_part"
done
done

COMPREPLY=( $fmri_list )

# Here we want to detect if there is only one completion proposed and that
# it ends with a slash. That means the user will still have to complete
# after, so we save him one tab keystroke by immediately proposing the
# next completion alternatives.
local i=${#COMPREPLY[*]}
if [[ $i -gt 0 ]] && [[ "${COMPREPLY[$((--i))]}" == */ ]]; then
# We have to iterate throught the list as we may have duplicates.
while [[ $i -ne 0 ]]; do
[[ "${COMPREPLY[$i]}" != "${COMPREPLY[$((i - 1))]}" ]] && break
((i--))
done
if [[ $i -eq 0 ]]; then
_smf_complete_fmri "${COMPREPLY[0]}" "$prefix"
return
fi
fi

# Work-around bash_completion issue where bash interprets a colon
# as a separator, borrowed from maven completion code which borrowed
# it from darcs completion code :).
local colonprefixes=${cur%"${cur##*:}"}
local i=${#COMPREPLY[*]}
while [ $((--i)) -ge 0 ]; do
COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"}
done
}

_svcadm()
{
local cur prev words cword line
line="${COMP_LINE}"
_init_completion -n : || return

local states="uninitialized offline online degraded maintenance disabled legacy-run"
local command_list="enable disable restart refresh clear mark milestone"
local command i

for (( i=1; i < $cword; i++ )); do
if [[ ${words[i]} == @(enable|disable|restart|refresh|clear|mark|milestone) ]]; then
command=${words[i]}
fi
done

if [[ -z "$command" ]]; then
# svcadm [-S state]...
if [[ ${prev} == -S ]]; then
COMPREPLY=( $(compgen -W "${states}" -- ${cur}) )
elif [[ ${cur} == -* ]]; then
if [[ "$(zonename)" == "global" ]]; then
zones="-Z -z"
fi
COMPREPLY=( $(compgen -W "-S -v ${zones}" -- ${cur}) )
else
# svcadm [-v] milestone [-d] milestone_FMRI
if [[ ${line} =~ -S ]]; then
command_list="$(echo ${command_list} | sed -e 's/milestone//')"
fi
COMPREPLY=( $(compgen -W "${command_list}" -- ${cur}) )
fi
else
if [[ ${cur} == -* ]]; then
case "$command" in
enable)
# enable [-rst]
COMPREPLY=( $(compgen -W "-r -s -t" -- ${cur}) );;
disable)
# disable [-st]
COMPREPLY=( $(compgen -W "-s -t" -- ${cur}) );;
mark)
# mark [-It]
COMPREPLY=( $(compgen -W "-I -t" -- ${cur}) );;
milestone)
# milestone [-d]
COMPREPLY=( $(compgen -W "-d" -- ${cur}) );;
esac
else
if [[ "$command" == "mark" ]] && [[ "$prev" != @(degraded|maintenance) ]]; then
COMPREPLY=( $(compgen -W "degraded maintenance" -- ${cur}) )
elif [[ "$command" == "milestone" ]]; then
_smf_complete_fmri "${cur}" "svc:/milestone"
else
_smf_complete_fmri "${cur}" "svc:"
fi
fi
fi

_dash_z_zone_running
}

_svcs()
{
local cur prev
local svcs_cols="ctid desc fmri inst nsta nstate scope svc sta state stime"

cur=${COMP_WORDS[COMP_CWORD]}
prev="${COMP_WORDS[COMP_CWORD-1]}"

case "$prev" in
-o|-s|-S)
# -o col[,col]... -s col -S col
COMPREPLY=($(compgen -W "$svcs_cols" -- "${cur##*,}"))
local existing_opts=$(expr "$cur" : '\(.*,\)')
if [[ -n "$existing_opts" ]]; then
COMPREPLY=( "${COMPREPLY[@]/#/${existing_opts}}" )
fi
if [[ ${prev} == -o ]]; then
compopt -o nospace
fi
return
;;
esac

if [[ $cur == -* ]]; then
# zone options are usable only in global zone
if [[ "$(zonename)" == "global" ]]; then
zones="-Z -z"
fi
COMPREPLY=( $(compgen -W "-? -a -H -p -o -s -S -d -D -R -l -L -v -x $zones" -- "${cur}") )
else
_smf_complete_fmri "${cur}" "svc:"
fi

_dash_z_zone_running
}

complete -F _svcadm svcadm
complete -F _svcs svcs
complete -F _zlogin zlogin

# Many illumos utilities are zone-aware through the -z option
#
complete -F _dash_z_zone_running allocate
complete -F _dash_z_zone_running deallocate
complete -F _dash_z_zone_running ipfs
complete -F _dash_z_zone_running ipfstat
complete -F _dash_z_zone_running ipmon
complete -F _dash_z_zone_running ipnat
complete -F _dash_z_zone_running ippool
complete -F _dash_z_zone_running pgrep
complete -F _dash_z_zone_running pkill
complete -F _dash_z_zone_running ps
complete -F _dash_z_zone_running psrset
complete -F _dash_z_zone_running ptree
complete -F _dash_z_zone_running svccfg
complete -F _dash_z_zone_running svcprop
complete -F _dash_z_zone_running wall

complete -F _dash_z_zone_configured auditreduce
complete -F _dash_z_zone_configured zoneadm
complete -F _dash_z_zone_configured zonecfg

# ex: filetype=sh
# vim: tabstop=2 shiftwidth=2 expandtab
4 changes: 4 additions & 0 deletions image/templates/files/bashrc
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,17 @@ pathdirs=(
'/opt/ooce/bin'
'/opt/oxide/opte/bin'
'/opt/oxide/mg-ddm'
'/opt/oxide/oxlog'
'/usr/sbin'
'/usr/bin'
'/bin'
'/sbin'
)
export PATH=$(IFS=':'; printf '%s' "${pathdirs[*]}")

. /usr/share/bash-completion/bash_completion
. /usr/share/bash-completion/oxide

#
# Bracketed paste in bash is a deeply questionable facility, and on a serial
# console where one may reset the system at any time it leaves the terminal in
Expand Down
8 changes: 7 additions & 1 deletion image/templates/gimlet/ramdisk-02-trim.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
{ "t": "remove_files", "dir": "/usr/demo" },
{ "t": "remove_files", "dir": "/usr/lib/help" },
{ "t": "remove_files", "dir": "/usr/share/doc" },
{ "t": "remove_files", "dir": "/usr/share/bash-completion" },
{ "t": "remove_files",
"dir": "/usr/share/bash-completion/completions" },
{ "t": "remove_files", "dir": "/usr/share/bash-completion/helpers" },

{ "t": "remove_files",
"dir": "/usr/perl5/5.36/man", "without": "recovery" },
Expand Down Expand Up @@ -106,6 +108,10 @@
"file": "/etc/motd",
"src": "motd",
"owner": "root", "group": "sys", "mode": "0644" },
{ "t": "ensure_file",
"file": "/usr/share/bash-completion/oxide",
"src": "bash_completion",
"owner": "root", "group": "root", "mode": "0644" },

{ "t": "ensure_file",
"file": "/etc/system.d/zfs:dbuf",
Expand Down

0 comments on commit 9b5066f

Please sign in to comment.