3

Use case: I am trying to get source activate <env> to autocomplete the names of my conda environments (i.e. the list of directories in ~/anaconda3/envs/).

I've managed to get it to work if I didn't need the 'activate' in there using this code:

_source ()
{
    local cur

    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}

    COMPREPLY=($(ls ~/anaconda3/envs | xargs -I dirs bash -c "compgen -W dirs $cur"))

    return 0
}

complete -F _source source

I've tried setting the last argument of complete to source\ activate and 'source activate' but that's not working (it just autocompletes with local files).

The issue seems to be that because source activate is not a function, it doesn't pick it up.

The simple solution is, of course, to make a single-word bash script which just contains source activate $1. But I'd rather do it properly!

7
  • 1
    Defining a wrapper function, the supplying a completion for that, is the proper way. You don't want every call to source to complete its second argument based on the contents of ~/anaconda/envs. Commented Oct 6, 2016 at 16:30
  • I've never come across a case where I've wanted source activate to take anything else - I've only seen source used on its own. Do you have any examples? Commented Oct 6, 2016 at 16:58
  • 1
    source is a built-in shell command for executing an arbitrary shell script in the current shell rather than in a separate process. source activate is not a single command; it's just a call to source with activate as its first argument (the name of the script). Commented Oct 6, 2016 at 17:18
  • Got it, thanks. The issue I'm having now (with a wrapper function which is just source activate $1) is that the source doesn't seem to execute in the global scope - I get the expected messages telling me things are being taken off and added to my path, so it's working somewhere, but it doesn't change anything in the scope from which I called my wrapper script. Commented Oct 6, 2016 at 17:51
  • Ha... so the way to get it to execute in the global scope is, of course, source. Which makes my wrapper function the first argument, which means I can't use the autocompletion. Any way around this? Commented Oct 6, 2016 at 17:58

2 Answers 2

2

My solution was adapted from this conda issue.

It checks that the first argument is activate and then does the compgen using whatever the second word you're typing is.

#!/bin/bash
_complete_source_activate_conda(){
      if [ ${COMP_WORDS[COMP_CWORD-1]} != "activate" ]
      then
          return 0
      fi
      local cur=${COMP_WORDS[COMP_CWORD]}
      COMPREPLY=($(ls ~/anaconda3/envs | xargs -I dirs bash -c "compgen -W dirs $cur"))
      return 0
}

complete -F _complete_source_activate_conda source

Put that script in /etc/bash_completion.d/. Unfortunately it kills the first-word autocompletion - with some more fiddling it would probably be able to handle both.

Sign up to request clarification or add additional context in comments.

1 Comment

Getting the first-word autocompletion back would be a case of altering the if statement, and using this solution.
0

getting autocomplete to work for the second argument can be done with a case statement like this

_source()
{
    local cur prev opts
    case $COMP_CWORD in
        1) opts="activate";;
        2)  [ ${COMP_WORDS[COMP_CWORD-1]} = "activate" ] && opts=$(ls ~/anaconda3/envs | xargs -I dirs bash -c "compgen -W dirs $cur");;
        *);;
    esac
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    COMPREPLY=( $(compgen -W "$opts" -- ${cur}) )
    return 0
}
complete -F _source source

compgen is build in function of bash which you then give the options you want to complete for with $opts for the first argument it will authocomplete "activate" but that can be adapted to be a more existive list and for the second argument it first checks if the first argument is "activate" before attempting to complete

disclaimer i adapted this from a completion function i wrote for ubports-qa, i haven't been able to test it but it should just work

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.