Autocomplete directories in a subfolder with the Fish shell

Viewed 263

I'm having trouble getting the 'complete' function in the fish shell to behave as I would like and I've been searching for an answer for days now.

Summary

Essentially I need to provide tab directory auto-completion as if I was in a different directory to the one I am currently in. It should behave exactly as 'cd' and 'ls' do, but with the starting point in another directory. It seems like such a trivial thing to be able to do but I can't find a way to make it work.

Explanation

Example folder structure below

- root
  - foo
    - a
      - dir1
        - subdir1
      - dir2
        - subdir2
    - b
      - dir3
        - subdir3
      - dir4
        - subdir4

I am running these scripts whilst in the 'root' directory, but I need tab auto-complete to behave as if I was in the 'foo' directory.

testfunc -d a/dir2/subdir2

Instead of

testfunc -d foo/a/dir2/subdir2

There are a lot of directories inside 'foo' and a lot of sub-directories within them, and this auto-complete behaviour is necessary to speed our process (this script is used extensively throughout the day).

Attempted Solution

I've tried using the 'complete' builtin to get this working by specifying the directory to use, but all this managed to do was auto-complete the first level of directories with a space after the argument instead of continuing to auto-complete like 'cd' would.

complete -x -c testfunc -a "(__fish_complete_directories ./foo/)"

Working bash version

I have already got this working in Bash and I am trying to port it over to fish. See below for the Bash version.

_testfunc()
{
    local cur prev words cword
    _init_completion || return

    compopt +o default

    case $prev in
        testfunc)
            COMPREPLY=( $( compgen -W '-d' -- "$cur" ) )
            compopt +o nospace
            return
            ;;
        -d)
            curdir=$(pwd)
            cd foo/ 2>/dev/null && _filedir -d
            COMPREPLY=( $( compgen -d -S / -- "$cur" ) )
            cd $curdir
            return
            ;;
    esac

} &&
complete -o nospace -F _testfunc testfunc

This is essentially stepping into the folder that I want, doing the autocompletion, then stepping back into the original folder that the script was run in. I was hoping this would be easier in Fish after getting it working in Bash (I need to support these two shells), but I'm just pulling my hair out.

Any help would be really appreciated!

1 Answers

I am not a bash completions expert, but it looks like the bash completions are implemented by changing directories, running completions, and then changing back. You can do the same in fish:

function complete_testfunc
    set prevdir $PWD
    cd foo
    __fish_complete_directories
    cd $prevdir
end

complete -x -c testfunc -a "(complete_testfunc)"

does that work for you?

Related