[Bash-completion-commits] [bash-completion] 01/05: tar: rework the completion completely
Ville Skyttä
scop-guest at moszumanska.debian.org
Mon Jun 1 16:26:17 UTC 2015
This is an automated email from the git hooks/post-receive script.
scop-guest pushed a commit to branch master
in repository bash-completion.
commit 8b23c84cc2935b15b8cb2ac1a90d061b914229a6
Author: Pavel Raiskup <praiskup at redhat.com>
Date: Tue Mar 11 19:05:57 2014 +0100
tar: rework the completion completely
Use the parsed 'tar --help' output for completion, at least for
GNU tar. For non-GNU tars use the _posix_tar completion. Adjust
the testsuite to cover some improvements.
---
completions/bsdtar | 1 +
completions/star | 1 +
completions/tar | 768 ++++++++++++++++++++++++++++++++++-----
test/fixtures/tar/archive.tar.xz | Bin 0 -> 10240 bytes
test/fixtures/tar/dir/fileA | 0
test/fixtures/tar/dir/fileB | 0
test/fixtures/tar/dir/fileC | 0
test/fixtures/tar/dir/hello | 0
test/fixtures/tar/escape.tar | Bin 0 -> 10240 bytes
test/lib/completions/tar.exp | 111 +++++-
10 files changed, 790 insertions(+), 91 deletions(-)
diff --git a/completions/bsdtar b/completions/bsdtar
new file mode 120000
index 0000000..e1d18b0
--- /dev/null
+++ b/completions/bsdtar
@@ -0,0 +1 @@
+tar
\ No newline at end of file
diff --git a/completions/star b/completions/star
new file mode 120000
index 0000000..e1d18b0
--- /dev/null
+++ b/completions/star
@@ -0,0 +1 @@
+tar
\ No newline at end of file
diff --git a/completions/tar b/completions/tar
index 8d867d0..dc053a1 100644
--- a/completions/tar
+++ b/completions/tar
@@ -1,37 +1,455 @@
# bash completion for GNU tar -*- shell-script -*-
+#
+# General info
+# ============
+#
+# The "old" style arguments
+# -------------------------
+#
+# We don't "advice" the old tar option format by default for GNU tar, example:
+#
+# 'tar czfT /tmp/archive.tar patterns.txt'
+#
+# We rather advice the 'tar -czf /tmp/archive.tar -T patterns.txt' format of
+# arguments. Though, if user starts the 'first' tar argument without leading
+# dash, we treat the command line apropriately.
+#
+#
+# long/short options origin
+# -------------------------
+#
+# For GNU tar, everything is parsed from `tar --help` output so not so much
+# per-distribution work should be needed. The _parse_help does not seem to be
+# good enough so parsed here directly.
+#
+#
+# FIXME: --starting-file (-K) (should be matched for extraction only)
+# FIXME: handle already used (at least short) options
+# FIXME: Test-cases for make check.
+# - check for no global variable pollution
+# FIXME: why PS4='$BASH_SOURCE:$LINENO: ' shows sometimes negative lines?
+# FIXME: timeout on tarball listing
+# FIXME: cache 'tar --help' parsing results into global variables
+# FIXME: at least 'tar -<tab>' should show some helping text (apart from just
+# pure option advices)
+# FIXME: short option completion should be more intuitive
+# - verbose mode option should be adviced multiple times
+# - mode option should be adviced only once
+# - format option should be adviced only once
+# ...
-_tar()
+__gtar_parse_help_opt()
{
- local cur prev words cword split
- _init_completion -s || return
+ local opttype arg opt separator optvar
+ opttype=long
+ arg="$2"
+ opt="$1"
+ separator=" "
- local ext regex tar untar
+ case "$opt" in
+ --*)
+ ;;
+ -\?)
+ return ;;
+ -*)
+ opttype=short
+ opt=${opt##-}
+ separator=
+ ;;
+ *)
+ echo >&2 "not an option $opt"
+ return 1
+ ;;
+ esac
+
+ # Remove arguments.
+ opt=${opt//\[*/}
+ opt=${opt//=*/=}
+
+ # Basic sanity.
+ opt=${opt//\"*/}
+ opt=${opt//\'*/}
+ opt=${opt//\;*/}
+
+ optvar=$opttype'_arg_'$arg
+
+ eval "$optvar=\"\$$optvar$separator\"\"$opt\""
+}
- if [[ $cword -eq 1 ]]; then
- COMPREPLY=( $( compgen -W 'c t x u r d A' -- "$cur" ) )
+
+__gtar_parse_help_line()
+{
+ local i
+
+ for i in $1; do
+ case "$i" in
+ # regular options
+ --*|-*)
+ __gtar_parse_help_opt "$i" "$2"
+ ;;
+
+ # end once there is single non-option word
+ *)
+ break;
+ esac
+ done
+}
+
+
+__gnu_tar_parse_help()
+{
+ local str line arg
+ while IFS= read line; do
+ # Ok, this requires some comment probably. The GNU help output prints
+ # options on lines beginning with spaces. After that, there is one
+ # or more options separated by ', ' separator string. We are matching
+ # like this then: ^<spaces>(<separator>?<option>)+<whatever>$
+ if [[ "$line" =~ \
+ ^[[:blank:]]{1,10}(((,[[:blank:]])?(--?([\]\[a-zA-Z0-9?-=]+))(,[[:space:]])?)+).*$ ]]; then
+
+ line=${BASH_REMATCH[1]}
+ str="${line//,/ }"
+
+ # Detect that all options on this line accept arguments (and whether
+ # the arguments are required or not). Note that only long option
+ # description in GNU help output mentions arguments. So the $line
+ # variable may contain e.g. '-X, --XXX[=NAME], -XXX2[=NAME]'.
+ arg=none
+ if [[ "$line" =~ --[A-Za-z0-9-]+(\[?)= ]]; then
+ test -n "${BASH_REMATCH[1]}" && arg=opt || arg=req
+ fi
+
+ __gtar_parse_help_line "$str" "$arg"
+ fi
+ done <<<"$(tar --help)"
+
+ long_opts="\
+ $long_arg_none\
+ $long_arg_opt\
+ $long_arg_req"
+
+ short_opts="$short_arg_none$short_arg_opt$short_arg_req"
+}
+
+
+# Hack: parse --warning keywords from tar's error output
+__gtar_parse_warnings()
+{
+ while IFS= read line; do
+ if [[ $line =~ ^[[:blank:]]*-[[:blank:]]*[\`\']([a-zA-Z0-9-]+)\'$ ]]; then
+ echo "${BASH_REMATCH[1]} no-${BASH_REMATCH[1]}"
+ fi
+ done <<<"$(LC_ALL=C tar --warning= 2>&1)"
+}
+
+
+# Helper to obtain last character of string.
+__tar_last_char()
+{
+ echo "${1: $(( ${#1} - 1))}"
+}
+
+
+__tar_parse_old_opt()
+{
+ local first_word char
+
+ # current word is the first word
+ test "$cword" -eq 1 -a -n "$cur" -a "${cur:0:1}" != '-' \
+ && old_opt_progress=1
+
+ # check that first argument does not begin with "-"
+ first_word=${words[1]}
+ test -n "$first_word" -a "${first_word:0:1}" != "-" \
+ && old_opt_used=1
+
+ # parse the old option (if present) contents to allow later code expect
+ # corresponding arguments
+ if test $old_opt_used -eq 1; then
+ char=${first_word:0:1}
+ while test -n "$char"; do
+ if __tar_is_argreq "$char"; then
+ old_opt_parsed+=("$char")
+ fi
+ first_word=${first_word##$char}
+ char=${first_word:0:1}
+ done
+ fi
+}
+
+
+# Make the analysis of whole command line.
+__tar_preparse_cmdline()
+{
+ local first_arg my_args tmparg i modes="ctxurdA"
+
+ shift # progname
+
+ __tar_parse_old_opt
+
+ first_arg=1
+ for i in "$@"; do
+ case "$i" in
+ --delete|--test-label)
+ tar_mode=${i:2:100}
+ tar_mode_arg=$i
+ break
+ ;;
+ --*)
+ # skip
+ ;;
+ -*[$modes]*)
+ tar_mode=${i//[^$modes]/}
+ tar_mode=${tar_mode:0:1}
+ tar_mode_arg=$i
+ break
+ ;;
+ *[$modes]*)
+ # Only the first arg may be "MODE" without leading dash
+ if test $first_arg -eq 1; then
+ tar_mode=${i//[^$modes]/}
+ tar_mode=${tar_mode:0:1}
+ tar_mode_arg=$i
+ fi
+ ;;
+ esac
+ first_arg=0
+ done
+}
+
+
+# Generate completions for -f/--file.
+__tar_file_option()
+{
+ local ext="$1"
+
+ case "$tar_mode" in
+ c)
+ # no need to advise user to re-write existing tarball
+ _filedir -d
+ ;;
+ *)
+ _filedir "$ext"
+ ;;
+ esac
+}
+
+
+# Returns truth if option requires argument. No equal sign must be pasted.
+# Accepts option in format: 'c', '-c', '--create'
+__tar_is_argreq()
+{
+ local opt
+ opt=$1
+ case "$opt" in
+ -[A-Za-z0-9?])
+ [[ "$short_arg_req" =~ ${opt##-} ]] && return 0
+ ;;
+ [A-Za-z0-9?])
+ [[ "$short_arg_req" =~ ${opt} ]] && return 0
+ ;;
+ --*)
+ [[ "$long_arg_req" =~ [[:blank:]]$opt=[[:blank:]] ]] && return 0
+ ;;
+ esac
+
+ return 1
+}
+
+
+# Called only for short parameter
+__tar_complete_mode()
+{
+ local short_modes has_mode rawopt generated \
+ allshort_raw_unused allshort_raw \
+ filler i
+
+ short_modes="ctx"
+ test x"$basic_tar" = x && short_modes="ctxurdA"
+
+ # Remove prefix when needed
+ rawopt=${cur#-}
+
+ # -c -z -x ... => czx
+ allshort_raw=${short_opts//[- ]/}
+
+ # init the 'mode' option if no option is in ${cur}
+ if test "$tar_mode" = none; then
+
+ # when user passed something like 'tar cf' do not put the '-' before
+ filler=
+ if test -z "$cur" && test x"$basic_tar" = x; then
+ filler=-
+ fi
+
+ generated=""
+ for (( i=0 ; 1; i++ )); do
+ local c="${short_modes:$i:1}"
+ test -z "$c" && break
+ generated+=" $filler$cur$c"
+ done
+
+ COMPREPLY=( $(compgen -W "$generated" ) )
return 0
fi
+ # The last short option requires argument, like '-cf<TAB>'. Cut the
+ # completion here to enforce argument processing.
+ if test "$old_opt_progress" -eq 0 \
+ && __tar_is_argreq "$(__tar_last_char "$cur")"; then
+ COMPREPLY=( "$cur" ) && return 0
+ fi
+
+ allshort_raw_unused=${allshort_raw//[$rawopt]/}
+ if test "$tar_mode" != none; then
+ allshort_raw_unused=${allshort_raw_unused//[$short_modes]}
+ fi
+
+ generated=
+ for (( i=0 ; 1; i++ )); do
+ local c="${allshort_raw_unused:$i:1}"
+ test -z "$c" && break
+ generated+=" $cur$c"
+ done
+
+ COMPREPLY=( $( compgen -W "$generated" ) )
+
+ return 0
+}
+
+
+__gtar_complete_lopts()
+{
+ local rv
+ COMPREPLY=( $( compgen -W "$long_opts" -- "$cur" ) )
+ rv=$?
+ [[ $COMPREPLY == *= ]] && compopt -o nospace
+ return $rv
+}
+
+
+__gtar_complete_sopts()
+{
+ local generated short_mode_opts i c
+ short_mode_opts="ctxurdA"
+ generated=${short_opts//[$short_mode_opts]/}
+
+ for (( i=0 ; 1; i++ )); do
+ c="${allshort_raw_unused:$i:1}"
+ test -z "$c" && break
+ generated+=" $cur$c"
+ done
+
+ COMPREPLY=( $( compgen -W "$generated" -- "$cur" ) )
+}
+
+
+__tar_try_mode()
+{
+ case "$cur" in
+ --*)
+ # posix tar does not support long opts
+ test -n "$basic_tar" && return 0
+ __gtar_complete_lopts
+ return $?
+ ;;
+
+ -*)
+ # posix tar does not support short optios
+ test -n "$basic_tar" && return 0
+
+ __tar_complete_mode && return 0
+ ;;
+
+ *)
+ if test "$cword" -eq 1 || test "$tar_mode" = none; then
+ __tar_complete_mode && return 0
+ fi
+ ;;
+ esac
+ return 1
+}
+
+
+__tar_adjust_PREV_from_old_option()
+{
+ # deal with old style arguments here
+ # $ tar cfTC # expects this sequence of arguments:
+ # $ tar cfTC ARCHIVE_FILE PATTERNS_FILE CHANGE_DIR
+ if test "$old_opt_used" -eq 1 \
+ -a "$cword" -gt 1 \
+ -a "$cword" -lt $(( ${#old_opt_parsed[@]} + 2 ));
+ then
+ # make e.g. 'C' option from 'cffCT'
+ prev="-${old_opt_parsed[ $cword - 2 ]}"
+ fi
+}
+
+
+__tar_extract_like_mode()
+{
+ local i
+ for i in x d t delete; do
+ test "$tar_mode" = "$i" && return 0
+ done
+ return 1
+}
+
+
+__tar_try_list_archive()
+{
+ local tarball tarbin untar
+
+ __tar_extract_like_mode || return 1
+
+ # This all is just to approach directory completion from "virtual"
+ # directory structure in tarbal (for which the _filedir is unusable)
+
+ set -- "${words[@]}"
+ tarbin=$1
+ untar="tf"
+ shift
+
+ read tarball <<<"$(printf -- '%s\n' "$@" \
+ | sed -n "/^.\{1,\}$regex\$/p" | tee /tmp/jetel)"
+ if test -n "$tarball"; then
+ local IFS=$'\n'
+ COMPREPLY=($(compgen -o filenames -W "$(
+ while read line; do
+ printf "%q\n" "$(printf %q"\n" "$line")"
+ done <<<"$($tarbin $untar "$tarball" 2>/dev/null)"
+ )" -- "$(printf "%q\n" "$cur")"))
+ return 0
+ fi
+}
+
+__tar_cleanup_prev()
+{
+ if [[ "$prev" =~ ^-[a-zA-Z0-9?]*$ ]]; then
+ # transformate '-caf' ~> '-f'
+ prev="-$(__tar_last_char "$prev")"
+ fi
+}
+
+__tar_detect_ext()
+{
local tars='@(@(tar|gem|spkg)?(.@(Z|[bgx]z|bz2|lz?(ma)))|t@([abglx]z|b?(z)2))'
+ ext="$tars"
+ regex='\(\(tar\|gem\|spkg\)\(\.\(Z\|[bgx]z\|bz2\|lz\(ma\)\?\)\)\?\|t\([abglx]z\|bz\?2\)\)'
- case ${words[1]} in
+ case "$tar_mode_arg" in
--*)
+ # Should never happen?
;;
?(-)*[cr]*f)
- if [[ $cword -eq 2 ]]; then
- ext='@(tar|gem|spkg)'
- case ${words[1]} in
- *a*) ext="$tars" ;;
- *z*) ext='t?(ar.)gz' ;;
- *Z*) ext='ta@(r.Z|z)' ;;
- *[jy]*) ext='t@(?(ar.)bz?(2)|b2)' ;;
- *J*) ext='t?(ar.)xz' ;;
- esac
- _filedir "$ext"
- else
- _filedir
- fi
- return 0
+ ext='@(tar|gem|spkg)'
+ case ${words[1]} in
+ *a*) ext="$tars" ;;
+ *z*) ext='t?(ar.)gz' ;;
+ *Z*) ext='ta@(r.Z|z)' ;;
+ *[jy]*) ext='t@(?(ar.)bz?(2)|b2)' ;;
+ *J*) ext='t?(ar.)xz' ;;
+ esac
;;
+([^ZzJjy])f)
ext="$tars"
@@ -49,84 +467,258 @@ _tar()
ext='@(@(tar|gem|spkg).@(lzma|xz)|t[lx]z)'
regex='\(\(tar\|gem\|spkg\)\.\(lzma\|xz\)\|t[lx]z\)'
;;
- *)
- _filedir
- return 0
- ;;
esac
+}
- case $prev in
- *${ext:-$tars})
- # complete on files in tar file
- #
- # get name of tar file from command line
- tar=$( sed -e 's/^.* \([^ ]*'$regex'\) .*$/\1/' <<<"${words[@]}" )
- # devise how to untar and list it
- untar=t${words[1]//[^Jzjyf]/}
-
- local IFS=$'\n'
- COMPREPLY=( $( compgen -W "$( printf '%s\n' $( tar $untar $tar \
- 2>/dev/null ) )" -- "$cur" ) )
- return 0
- ;;
- -C|--directory)
- _filedir -d
- return 0
- ;;
- --atime-preserve)
- COMPREPLY=( $( compgen -W 'replace system' -- "$cur" ) )
- return 0
- ;;
- --group)
- COMPREPLY=( $( compgen -g -- "$cur" ) )
- return 0
- ;;
- --owner)
- COMPREPLY=( $( compgen -u -- "$cur" ) )
- return 0
- ;;
- -F|--info-script|--new-volume-script|--rmt-command|--rsh-command|\
- -I|--use-compress-program)
- compopt -o filenames
- COMPREPLY=( $( compgen -c -- "$cur" ) )
- return 0
- ;;
- --volno-file|--add-file|-T|--files-from|-X|--exclude-from|--index-file)
+
+_gtar()
+{
+ local long_opts short_opts \
+ long_arg_none long_arg_opt long_arg_req \
+ short_arg_none short_arg_opt short_arg_req \
+ tar_mode tar_mode_arg old_opt_progress=0 \
+ old_opt_used=0 old_opt_parsed=()
+
+ # Main mode, e.g. -x or -c (extract/creation)
+ local tar_mode=none
+
+ # The mode argument, e.g. -cpf or -c
+ # FIXME: handle long options
+ local tar_mode_arg=
+
+ if test "$_TAR_OPT_DEBUG" = 1; then
+ set -x
+ PS4="\$BASH_SOURCE:\$LINENO: "
+ fi
+
+ local cur prev words cword split
+
+ _init_completion -s || return
+
+ # Fill the {long,short}_{opts,arg*}
+ __gnu_tar_parse_help
+
+ __tar_preparse_cmdline "${words[@]}"
+
+ local ext regex tar untar
+
+ __tar_detect_ext
+
+ while true; do # just-for-easy-break while, not looping
+ __tar_adjust_PREV_from_old_option
+ __tar_posix_prev_handle && break
+ __tar_cleanup_prev
+
+ # Handle all options *REQUIRING* argument. Optional arguments are up to
+ # user (TODO: is there any sane way to deal with this?). This case
+ # statement successes only if there already is PREV.
+ case $prev in
+ -C|--directory)
+ _filedir -d
+ break
+ ;;
+ --atime-preserve)
+ COMPREPLY=( $( compgen -W 'replace system' -- "$cur" ) )
+ break
+ ;;
+ --group)
+ COMPREPLY=( $( compgen -g -- "$cur" ) )
+ break
+ ;;
+ --owner)
+ COMPREPLY=( $( compgen -u -- "$cur" ) )
+ break
+ ;;
+ -F|--info-script|--new-volume-script|--rmt-command|--rsh-command|\
+ -I|--use-compress-program)
+ compopt -o filenames
+ COMPREPLY=( $( compgen -c -- "$cur" ) )
+ break
+ ;;
+ --volno-file|--add-file|-T|--files-from|-X|--exclude-from|\
+ --index-file|--listed-incremental|-g)
+ _filedir
+ break
+ ;;
+ -H|--format)
+ COMPREPLY=( $( compgen -W 'gnu oldgnu pax posix ustar v7' \
+ -- "$cur" ) )
+ break
+ ;;
+ --quoting-style)
+ COMPREPLY=( $( compgen -W 'literal shell shell-always c c-maybe
+ escape locale clocale' -- "$cur" ) )
+ break
+ ;;
+ --totals)
+ COMPREPLY=( $( compgen -W 'SIGHUP SIGQUIT SIGINT SIGUSR1 SIGUSR2' \
+ -- "$cur" ) )
+ break
+ ;;
+ --warning)
+ COMPREPLY=( $( compgen -W "$(__gtar_parse_warnings)" -- "$cur" ) )
+ break
+ ;;
+ --file|-f|-!(-*)f)
+ __tar_file_option "$ext"
+ break
+ ;;
+ --*)
+ # parameter with required argument but no completion yet
+ [[ " $long_arg_req " =~ \ $prev=\ ]] && break
+
+ # parameter with optional argument passed with =, something like
+ # --ocurrence=*<TAB> which is not handled above
+ [[ " $long_arg_opt " =~ \ $prev\ ]] && break
+
+ # if there is some unknown option with '=', for example
+ # (literally) user does --nonexistent=<TAB>, we do not want
+ # continue also
+ $split && break
+
+ # Most probably, when code goes here, the PREV varibale contains
+ # some string from "$long_arg_none" and we want continue.
+ ;;
+ -[a-zA-Z0-9?])
+ # argument required but no completion yet
+ [[ "$short_arg_req" =~ ${prev##-} ]] && break
+ ;;
+ esac
+
+ # safety belts
+ case "$cur" in
+ -[a-zA-Z0-9]=*)
+ # e.g. 'tar -c -f=sth' does not what user could expect
+ break
+ ;;
+ esac
+
+ # Handle the main operational mode of tar. We should do it as soon as
+ # possible.
+ __tar_try_mode && break
+
+ # handle others
+ case "$cur" in
+ --*)
+ __gtar_complete_lopts
+ break
+ ;;
+ -*)
+ # called only if it is *not* first parameter
+ __gtar_complete_sopts
+ break
+ ;;
+ esac
+
+ # the first argument must be "mode" argument or --param, if any of those
+ # was truth - the 'break' statement would have been already called
+ test "$cword" -eq 1 && break
+
+ __tar_try_list_archive && break
+
+ # file completion on relevant files
+ if test $tar_mode != none; then
_filedir
+ fi
+
+ break
+ done # just-for-easy-break while
+
+ if test "$_TAR_OPT_DEBUG" = 1; then
+ set +x
+ unset PS4
+ fi
+
+ return 0
+}
+
+
+__tar_posix_prev_handle()
+{
+ case "$prev" in
+ -f)
+ __tar_file_option "$ext"
return 0
;;
- -H|--format)
- COMPREPLY=( $( compgen -W 'gnu oldgnu pax posix ustar v7' \
- -- "$cur" ) )
- return 0
- ;;
- --quoting-style)
- COMPREPLY=( $( compgen -W 'literal shell shell-always c c-maybe
- escape locale clocale' -- "$cur" ) )
- return 0
- ;;
- --totals)
- COMPREPLY=( $( compgen -W 'SIGHUP SIGQUIT SIGINT SIGUSR1 SIGUSR2' \
- -- "$cur" ) )
- return 0
- ;;
- --occurrence|--sparse-version|--to-command|--mode|--mtime|\
- --tape-length|-b|--blocking-factor|--record-size|-V|--text|--backup|\
- --exclude|--exclude-tag*|-K|--starting-file|-N|--newer|--after-date|\
- --suffix|--strip-components|--transform|--xform|--checkpoint|\
- --checkpoint-action|--no-quote-chars|--quote-chars|--warnings)
+ -b)
return 0
- ;;
esac
- $split && return 0
+ return 1
+}
+
+
+_posix_tar()
+{
+ local long_opts short_opts basic_tar \
+ long_arg_none long_arg_opt long_arg_req \
+ short_arg_none short_arg_opt short_arg_req \
+ tar_mode tar_mode_arg old_opt_progress=0 \
+ old_opt_used=1 old_opt_parsed=()
+
+ # Main mode, e.g. -x or -c (extract/creation)
+ local tar_mode=none
+
+ # The mode argument, e.g. -cpf or -c
+ local tar_mode_arg=
+
+ local cur prev words cword split
+
+ _init_completion -s || return
+
+ basic_tar=yes
+ tar_mode=none
+
+ # relatively compatible modes are {c,t,x}
+ # relatively compatible options {b,f,m,v,w}
+ short_arg_req="fb"
+ short_arg_none="wmv"
+ short_opts="$short_arg_req$short_arg_none"
+
+ __tar_preparse_cmdline "${words[@]}"
+
+ local ext regex tar untar
+
+ __tar_detect_ext
+
+ __tar_adjust_PREV_from_old_option
+
+ __tar_posix_prev_handle && return 0
+
+ __tar_try_mode && return
+
+ __tar_try_list_archive && return
# file completion on relevant files
- _filedir "$ext"
+ _filedir
+}
- return 0
+
+_tar()
+{
+ local cmd=${COMP_WORDS[0]} output line
+ read line <<<"$($cmd --version)"
+ case "$line" in
+ *GNU*)
+ _gtar "$@"
+ ;;
+ *)
+ _posix_tar "$@"
+ ;;
+ esac
}
-[ -n "${COMP_TAR_INTERNAL_PATHS:-}" ] && complete -F _tar -o dirnames tar ||
- complete -F _tar tar
+
+
+if [ -n "${COMP_TAR_INTERNAL_PATHS:-}" ]; then
+ complete -F _tar -o dirnames tar
+ complete -F _gtar -o dirnames gtar
+ complete -F _posix_tar -o dirnames bsdtar
+ complete -F _posix_tar -o dirnames star
+else
+ complete -F _tar tar
+ complete -F _gtar gtar
+ complete -F _posix_tar bsdtar
+ complete -F _posix_tar star
+fi
# ex: ts=4 sw=4 et filetype=sh
diff --git a/test/fixtures/tar/archive.tar.xz b/test/fixtures/tar/archive.tar.xz
new file mode 100644
index 0000000..c8d2725
Binary files /dev/null and b/test/fixtures/tar/archive.tar.xz differ
diff --git a/test/fixtures/tar/dir/fileA b/test/fixtures/tar/dir/fileA
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/tar/dir/fileB b/test/fixtures/tar/dir/fileB
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/tar/dir/fileC b/test/fixtures/tar/dir/fileC
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/tar/dir/hello b/test/fixtures/tar/dir/hello
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/tar/escape.tar b/test/fixtures/tar/escape.tar
new file mode 100644
index 0000000..7af7e9f
Binary files /dev/null and b/test/fixtures/tar/escape.tar differ
diff --git a/test/lib/completions/tar.exp b/test/lib/completions/tar.exp
index 37f1ae4..70e38d0 100644
--- a/test/lib/completions/tar.exp
+++ b/test/lib/completions/tar.exp
@@ -2,19 +2,124 @@ proc setup {} {
save_env
}
-
proc teardown {} {
- assert_env_unmodified
+ assert_env_unmodified {/OLDPWD=/d}
}
-
setup
+# Detect whether system's tar is GNU tar
+set cmd "tar --version"
+send "$cmd\r"
+expect "^$cmd\r\n"
+expect {
+ -re "GNU\[^\n\]*\n" {
+ set tar_version gnu
+ }
+ -re ".*\n" {
+ set tar_version unknown
+ }
+}
+sync_after_int
+
+
+set test "old option: list escaped chars"
+assert_complete_dir "a/b\\'c/" "tar tf escape.tar a/b\\\'" $::srcdir/fixtures/tar $test
+sync_after_int
+
+# TODO: "tar tf escape.tar a/b"
+set test "check that any completion done"
assert_complete_any "tar "
+sync_after_int
+
+# Use bsdtar as the it completes to only 'zc zt zx' ('tar' can be GNU tar and it
+# can would have more options)
+set test "old option: mode is not on first place"
+assert_complete {zc zt zx} "bsdtar z" $test
+sync_after_int
+
+set test "old option: test 'f' when mode is not as a first option"
+assert_complete_dir "dir/ dir2/" "tar zfc " $::srcdir/fixtures/tar
+sync_after_int
+
+set test "old option: creating archive and 'f' option"
+assert_complete_dir "dir/ dir2/" "tar cf " $::srcdir/fixtures/tar
+sync_after_int
+
+set test "old option: archive listing"
+assert_complete_dir "dir/fileA dir/fileB dir/fileC" "tar tf archive.tar.xz dir/file" $::srcdir/fixtures/tar
+sync_after_int
+set test "old option: check _second_ option in \"old\" argument"
+assert_complete_dir "dir/ dir2/" "bsdtar cbfvv NOT_EXISTS " $::srcdir/fixtures/tar
+sync_after_int
+set test "old option: create and members"
+assert_complete_dir "dir/ dir2/ archive.tar.xz escape.tar" "tar cTfvv NOT_EXISTS DONT_CREATE.tar " $::srcdir/fixtures/tar
sync_after_int
+if { "$tar_version" == "gnu" } {
+ set test "check short options"
+ assert_complete_any "tar -c"
+ sync_after_int
+
+ set test "mode not as a first option"
+ assert_complete_dir "dir/ dir2/" "tar -zcf " $::srcdir/fixtures/tar
+ sync_after_int
+
+ # Only directories should be completed.
+ set test "check that we do not suggest re-writing existing archive"
+ assert_complete_dir "dir/ dir2/" "tar -cf " $::srcdir/fixtures/tar
+ sync_after_int
+
+ set test "check --file option"
+ assert_complete_dir "dir/ dir2/" "tar -c --file " $::srcdir/fixtures/tar
+ sync_after_int
+
+ set test "check --file option #2"
+ assert_complete_dir "dir/ dir2/" "tar -cvv --file " $::srcdir/fixtures/tar
+ sync_after_int
+
+ set test "archive listing"
+ assert_complete_dir "dir/fileA dir/fileB dir/fileC" "tar -tf archive.tar.xz dir/file" $::srcdir/fixtures/tar
+ sync_after_int
+
+ set test "archive listing with --file"
+ assert_complete_dir "dir/fileA dir/fileB dir/fileC" "tar -t --file archive.tar.xz dir/file" $::srcdir/fixtures/tar
+ sync_after_int
+
+ # Some random options should work:
+ set test "test random tar's long option #1"
+ assert_complete "--blocking-factor= --block-number" "tar --block" $test
+ sync_after_int
+
+ set test "test random tar's long option #2"
+ assert_complete "--owner=" "tar --own" $test -nospace
+ sync_after_int
+
+ set test "test random tar's long option #3"
+ assert_complete "--posix" "tar -cf /dev/null --posi" $test
+ sync_after_int
+
+ # --owner
+ set users [exec bash -c "compgen -A user"]
+ set test "test --owner option"
+ assert_complete $users "tar --owner=" $test
+ sync_after_int
+
+ # --group
+ set groups [exec bash -c "compgen -A group"]
+ set test "test --group option"
+ assert_complete $groups "tar --group=" $test
+ sync_after_int
+
+ # use -b for this as -b is still not handled by tar's completion
+ set test "short opt -XXXb <TAB> (arg required)"
+ assert_no_complete "tar -cvvfb " $test
+ sync_after_int
+
+ # TODO: how to test that 'tar -cf<TAB>' completes to 'tar -cf '
+}
teardown
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/bash-completion/bash-completion.git
More information about the Bash-completion-commits
mailing list