LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   bash completion "complete -f" not working (https://www.linuxquestions.org/questions/linux-software-2/bash-completion-complete-f-not-working-635918/)

iamback 04-17-2008 03:37 AM

bash completion "complete -f" not working
 
Hello all,
Code:

complete -d cd rmdir
works perfectly fine and when I type cd only directories appear
BUT
Code:

complete -f cat
does not work. It displays all the contents be it a file or a directory.
e.g.
Code:

complete -f -X '!*k' evince
This also displays all the files and directories that end at k.
So in essence the question is that why is -f not working.
These are the actual lines that might be interesting for someone.
Code:

shopt -s extglob progcomp cdspell cdable_vars
complete -d cd mkdir rmdir
complete -f cat less
complete -f -X '!*.@(cc|cpp)' g++

I also tried:
Code:

complete -A file cat less
But to no avail
I'll be really thankful for a help.
By the way, the following works in bash the way it should, yes for .bashrc and no for Desktop because .bashrc is a file and Desktop is a directory. So -f seems ok..
Code:

if [ -f .bashrc ] ; then echo yes; else echo no; fi
if [ -f Desktop ] ; then echo yes; else echo no; fi

Thanks and regards,
cad

klo_2k 05-21-2008 11:43 PM

(Note: The stuff below is highly experimental and I haven't tested it beyond with a few limited filenames, as I realized on completion this is too restrictive (I come across this post searching for solutions to the same problem...) - I'll explain see why later.)

Escape function - nothing special, just escapes the spaces and other special characters, I've probably missed some out...:
Code:

_escape () {
        local argv=$1
        local out
       
        if (( $(echo $argv|grep -cE "[ ()!$|]|'\''|[|]")==1 )); then        # Same as the sed expression below - sed needs to be escaped.
                out=$(echo "$argv"|sed -e 's/\([ ()!$|]\|'\''\|\[\|\]\)/\\\1/g')
        else
                out=$argv
        fi
        echo $out        # So caller can set it to a variable
        return 0
}


File completion - get the entire directory listing then select the files only:
Code:

_fcomp () {
        local argv=$2
        local listing
        local i j
        local IFS=$'\n'        # We want to ignore spaces and use \n only - or use $'\x0a'.

        listing=( $(compgen -f $argv) )
        for ((i=0, j=0; i<${#listing[*]}; i++)); do
                if [ -f ${listing[i]} ]; then
                        COMPREPLY[j]=$(_escape "${listing[i]}")        # Possible bottleneck in "_escape"?
                        ((j++))        # Only incrase if it's a file
                fi
        done
}


Assign the above 2 functions using something like below, for the various editors:
complete -F _fcomp gedit less mousepad vi vim


The main problem with this implementation is that:
1 - You cannot access a file in another directory...
2 - Performance - Enumerating an entire directory and picking off the bits you want is rather slow. Best to just use quoted escape instead - something like: compgen -f -P '"' -S '"' "$searchString" - I only coded the escape function like this for self education...

Hope this give you some idea...


All times are GMT -5. The time now is 12:12 AM.