From 0518a21b3419c53c2dc13753320a4b205ea5a493 Mon Sep 17 00:00:00 2001 From: Yedaya Katsman Date: Sun, 2 Jun 2024 22:07:19 +0300 Subject: [PATCH] feat(tar): use long option compression options Previously we only used single letter options to decide what file extensions to complete for extracting archives, make it also consider long options (gnu style). Co-Authored-By: Koichi Murase --- completions/tar | 90 +++++++++++++++++++++++++++++----------------- test/t/test_tar.py | 5 +++ 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/completions/tar b/completions/tar index 9c33ade1f60..26df2efcbd4 100644 --- a/completions/tar +++ b/completions/tar @@ -205,10 +205,15 @@ _comp_cmd_tar__preparse_cmdline() case "$i" in --delete | --test-label | --catenate | --concatenate | --extract | --get | --update | --list | --append | --create) tar_mode=${i:2:100} - # FIXME: We don't set $tar_mode_arg since it's used for combined - # single letter options, but that means we don't handle - # compression formats. - break + ;; + --bzip2 | --xz | --lzip | --lzma | --lzop | --zstd) + tar_compression_mode=${i:2:100} + ;; + --gzip | --gunzip | --ungzip) + tar_compression_mode="gzip" + ;; + --compress | --uncompress) + tar_compression_mode="compress" ;; --*) # skip @@ -439,10 +444,15 @@ _comp_cmd_tar__cleanup_prev() fi } +_comp_cmd_tar__is_bsdtar() +{ + [[ ${COMP_WORDS[0]} == ?(*/)bsdtar ]] +} + _comp_cmd_tar__detect_ext() { local tars='@(@(tar|spkg)?(.@(Z|[bgx]z|bz2|lz?(ma|o)|zst))|t@([abglx]z|b?(z)2|zst)|cbt|gem|xbps)' - if [[ ${COMP_WORDS[0]} == ?(*/)bsdtar ]]; then + if _comp_cmd_tar__is_bsdtar; then # https://github.com/libarchive/libarchive/wiki/LibarchiveFormats tars=${tars/%\)/|pax|cpio|iso|zip|@(j|x)ar|mtree|a|7z|warc} if _comp_cmd_tar__extract_like_mode; then @@ -455,33 +465,44 @@ _comp_cmd_tar__detect_ext() fi ext="$tars" - case "$tar_mode_arg" in - --*) - # FIXME: get correct extensions for long options (gnu style) - ;; - ?(-)*[cr]*f) + if ! _comp_cmd_tar__extract_like_mode; then + if ! _comp_cmd_tar__is_bsdtar; then ext='@(tar|gem|spkg|cbt|xpbs)' - 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) - # Pass through using defaults above - ;; - *[Zz]*f) - ext='@(@(t?(ar.)|spkg.)@(gz|Z)|taz)' - ;; - *[jy]*f) - ext='@(t?(ar.)bz?(2)|spkg|tb2)' - ;; - *[J]*f) - ext='@(@(tar|spkg).@(lzma|xz)|t[lx]z)' - ;; - esac + fi + case $tar_mode_arg:$tar_compression_mode in + *a*:none | *:auto-compress) + ext="$tars" + ;; + *z*:none | *:gzip) + ext='t?(ar.)gz' + ;; + *Z*:none | *:compress) + ext='ta@(r.Z|z)' + ;; + *[jy]*:none | *:bzip2) + ext='t@(?(ar.)bz?(2)|b2)' + ;; + *J*:none | *:xz) + ext='t?(ar.)xz' + ;; + esac + else + #TODO: lzip, lzma, lzop + case $tar_mode_arg:$tar_compression_mode in + *[Zz]*f:none | *:gzip | *:compress) + ext='@(@(t?(ar.)|spkg.)@(gz|Z)|taz)' + ;; + *[jy]*f:none | *:bzip2) + ext='@(t?(ar.)bz?(2)|spkg|tb2)' + ;; + *J*f:none | *:xz) + ext='@(@(tar|spkg).@(lzma|xz)|t[lx]z)' + ;; + *:zstd) + ext='t?(ar.)zst' + ;; + esac + fi } _comp_cmd_tar__gnu() @@ -496,9 +517,11 @@ _comp_cmd_tar__gnu() local tar_mode=none # The mode argument, e.g. -cpf or -c - # FIXME: handle long options local tar_mode_arg= + # Compression mode - from long options + local tar_compression_mode=none + if [[ -v _comp_cmd_tar__debug ]]; then set -x local PS4='$BASH_SOURCE:$LINENO: ' @@ -683,6 +706,9 @@ _comp_cmd_tar__posix() # The mode argument, e.g. -cpf or -c local tar_mode_arg= + # Compression mode - from long options + local tar_compression_mode=none + local cur prev words cword was_split comp_args _comp_initialize -s -- "$@" || return diff --git a/test/t/test_tar.py b/test/t/test_tar.py index a9c2f515e23..73db7c30905 100644 --- a/test/t/test_tar.py +++ b/test/t/test_tar.py @@ -127,4 +127,9 @@ def test_23(self, completion): def test_24(self, completion): assert completion == "archive.tar.xz dir/ dir2/".split() + # Test compression detection of gnu style options + @pytest.mark.complete("tar --extract --xz --file ", cwd="tar") + def test_25(self, completion): + assert completion == "archive.tar.xz dir/ dir2/".split() + # TODO: "tar tf escape.tar a/b"