Bash Script with User Defined Functions in Autocomplete

Bash script with user defined functions in autocomplete

This workaround should do the trick.

    #!/bin/bash

func1() {
echo "You are in func1: $@"
}

func2() {
echo "You are in func2: $@"
}

myFunc1() {
echo "You are in myFunc1: $@"
}

# usage: autocomplete "word1 word2 ..."
autocomplete() {
# try to autocomplete the last word, and
# keep a record of the rest of the input
OTHER_WORDS="${READLINE_LINE% *} "
if [[ ${#OTHER_WORDS} -ge ${#READLINE_LINE} ]]; then
# if there is only 1 word...
OTHER_WORDS=""
fi

# the -W flag tells compgen to read autocomplete
# from the 1st argument provided, then we
# evaluate the last word of the current line
# through compgen
AUTOCOMPLETE=($(compgen -W $1 "${READLINE_LINE##* }"))
if [[ ${#AUTOCOMPLETE[@]} == 1 ]]; then
# if there is only 1 match, substitute it
READLINE_LINE="$OTHER_WORDS${AUTOCOMPLETE[0]} "
# position the cursor at the end of the word
READLINE_POINT=${#READLINE_LINE}
else
#...otherwise print the possibilities
echo -e "cmd> $READLINE_LINE\n${AUTOCOMPLETE[@]}"
fi
}

# list the values to be autocompleted
MYFUNC="func1 func2 myFunc1"
# enable line editing
set -o emacs
# call autocomplete when TAB is pressed
bind -x '"\t":"autocomplete \$MYFUNC"';
while read -ep "cmd> "; do
# history is just a nice bonus
history -s $REPLY
eval ${REPLY}
done

To try it :

    ]$ ./mybash.sh
cmd> my<tab>
cmd> myFunc1

cmd> func<tab>
func1 func2

cmd> func1 hello, world!
You are in func2: hello, world!

cmd> func1 my<tab>
cmd> func1 myFunc1

As mentioned in my previous comment, have a look at this question. It uses a nice trick to auto detect all inner functions in order to use it as auto-complete values.

Bash: how to simplify autocompletion of custom created functions by using the already available bash-completion functions?

Git completion is quite easy to add to your own bash functions actually, for example, this little script autocompletes your git branches:

my_func () { return; }
source /usr/share/bash-completion/completions/git
__git_complete my_func __git_complete_refs

Now my_func has autocompletion for branch names.

Or like this you can have an alias g to git with working auto completion:

source /usr/share/bash-completion/completions/git
alias g=git
__git_complete g __git_main

Look in the /usr/share/bash-completion/completions/git file for all completions possible. The original file in the source code: https://github.com/git/git/blob/master/contrib/completion/git-completion.bash

There are a bunch of default complete functions, but they might not always do what you want, because they are made specially for git commands. In some cases you might want to make a custom auto complete function. Looking in the source code of the git-completion.bash you can figure stuff out. For example this auto complete function only completes local branch names:

source /usr/share/bash-completion/completions/git
git_local_branches () {
__gitcomp_direct "$(__git_heads "" "$cur" " ")"
}
my_func () { return; }
__git_complete my_func git_local_branches

Also see this answer for more info on how general bash completion works. Normally you would use the complete command, but Git created its own complete function __git_complete, which you should use for git completion.

Autocomplete function argument in shell function

It does matter very much which shell you're using.

First, let me mention that you can add often used directories to a "hotlist" that you can then use with cd. For instance, you could do this:

cdpath=(~/Development/Personal ~/Development/Work)

and then, at any point (and from any directory), you should be able to type cd blog. Tab completion will work as well.

If you still want to have your own functions for cd and add tab completion for them, here's a very informative article about how to write your own completion functions.

In a nutshell, you create a file in the zsh completion directory, called _dp, and add something like this to it:

#compdef dp

compadd $(command ls -1 $HOME/Development/Personal 2>/dev/null --color=none | sed -e 's/ /\\ /g')

How to configure bash autocomplete for file search and custom search?

You can use complete's -o default option (Usually I'd use both -o default and -o bashdefault):

complete -o default -F _test_complete remote

According to man bash:

  • bashdefault

    Perform the rest of the default bash completions if the compspec generates no matches.

  • default

    Use readline's default filename completion if the compspec generates no matches.

Git autocomplete for custom bash functions

Manually-crafted bash completion is as simple as this:

# our handler that returns choices by populating Bash array COMPREPLY
# (filtered by the currently entered word ($2) via compgen builtin)
_gitpull_complete() {
branches=$(git branch -l | cut -c3-)
COMPREPLY=($(compgen -W "$branches" -- "$2"))
}

# we now register our handler to provide completion hints for the "gitpull" command
complete -F _gitpull_complete gitpull

After sourcing the above commands:

$ gitpull <TAB>
asd master qwe zxc
$ gitpull m<TAB>
$ gitpull master

The ultimate reference on bash completion is (of course) the section on Programmable Completion in the bash manual, but a nice introduction is given on "Debian Administration" page (part 1 and a more important part 2).

autocomplete in bash script

Actually you can borrow quite a bit of code from geirha's answer:

# this is a custom function that provides matches for the bash autocompletion
_repo_complete() {
local file
# iterate all files in a directory that start with our search string
for file in ~/Desktop/_REPOS/"$2"*; do
# If the glob doesn't match, we'll get the glob itself, so make sure
# we have an existing file. This check also skips entries
# that are not a directory
[[ -d $file ]] || continue

# add the file without the ~/Desktop/_REPOS/ prefix to the list of
# autocomplete suggestions
COMPREPLY+=( $(basename "$file") )
done
}

# this line registers our custom autocompletion function to be invoked
# when completing arguments to the repo command
complete -F _repo_complete repo

The for loop iterates all files in a directory that start with the string given as second argument to the _repo_complete function (this is the string to be autocompleted).

Add the code to your .bashrc and it should work!

Enable autocomplete for parsed arguments in getopts

First I copied your script snippet in a file called auto.sh and set the execution permission on it:

#!/bin/bash

while getopts 'l:r:m:?h' c
do
case $c in
l)
library=$OPTARG
;;
r)
rename_config=$OPTARG
;;
m)
align_mm=$OPTARG
;;
h|?) usage
;;
esac
done

if [ $library = "bassik" ];
then
read_mod="clip"
clip_seq="GTTTAAGAGCTAAGCTGGAAACAGCATAGCAA"
echo "Bassik library selected"
elif [ $library = "moffat_tko1" ];
then
read_mod="trim"
sg_length=20
echo "Moffat TKO1 library selected"
elif [ $library = "sabatini" ];
then
read_mod="trim"
sg_length=20
echo "Sabatini library selected"
fi

Then, to set up an auto-completion for the -l option, you can begin with those basics steps (this can be future enhanced):

1. Create a completion script (e.g. ./auto-complete.sh) which contains the libs function to be called upon completion request (-F parameter of complete command). The function triggers the display of the library names (content of COMPREPLY array variable) if -l option is the word preceding the completion place ($3 argument):

function libs()
{
# $1 is the name of the command
# $2 is the word being completed
# $3 is the word preceding the word being completed

case $3 in
-l) COMPREPLY+=("bassi")
COMPREPLY+=("moffat_tko1")
COMPREPLY+=("sabatini");;
esac
}

complete -F libs auto.sh

2. Source the script in your local shell:

$ source ./auto-complete.sh

3. Launch the shell script and type TAB key twice after a space behind the -l option:

$ ./auto.sh -l <tab><tab>
bassik moffat_tko1 sabatini
$ ./auto.sh -l bassik
Bassik library selected

4. The preceding systematically lists all the choices when you type TAB key. To have a more accurate completion when typing the first letters, the completion script can be enhanced to use compgen command:

function libs()
{
# $1 is the name of the command
# $2 is the word being completed
# $3 is the word preceding the word being completed

case $3 in
-l) COMPREPLY=($(compgen -W "bassik moffat_tko1 sabatini" "${COMP_WORDS[$COMP_CWORD]}"));;
esac
}

complete -F libs auto.sh

How to pass a function with arguments to another function

The -F option is supposed to be followed by just a function name. If you want to execute a command with options, you need to use -C. But the command is required to print the completions to standard output, not set COMPREPLY. So change the function to:

_autocomplete() {
COMPREPLY=( $(compgen -W "$1" -- "${COMP_WORDS[COMP_CWORD]}") )
for reply in "${COMPREPLY[@]}"
do
printf '%s\n' "$reply"
done
return 0
}

complete -C "_autocomplete example_param" some_function

How to make a custom BASH function to cd into a certain directory with autocomplete

You could consider CDPATH. You can export CDPATH=~/Documents to have all the directories under ~/Documents added for autocompletion. You can have a function or alias for this export command and set & unset CDPATH as and when you need.

Hope this helps!



Related Topics



Leave a reply



Submit