# Common funcitons of Bash auto-completion in Gnuastro. For more details on
# completion, see the "autocomplete feature" section under the "Developing"
# chapter of Gnuastro's manual and the comments below.
#
# This script contains generic functions that can be used by all the
# programs. Each program also has its own '*-complete.bash' file that will
# use the generic functions here and define all the internal variables that
# these functions take as input/output. During the installation, all those
# '*-complete.bash' files will be appended to this (and installed as one
# file to be loaded into the user's '.bashrc').
#
# Because the combined file is loaded into the user's Bash environment
# every time, we don't want to complicate the user's environment with
# global environment variables. As a result, all the functions used in the
# Bash auto-completion should be 'local' (to that particular function and
# the functions it calls).
#
# To debug/test this script, you can take these steps after building
# Gnuastro in the program's 'bin/progname/astprogname-complete.bash'
# file. Building Gnuastro is necessary because one of the files
#
#    1. Uncomment the two 'source' lines in the program's completion
#       script.
#    2. Correct the un-commented locations. Note that the second is an
#       automatically built file (it is not under version control or in the
#       source directory). So in case you have defined a separate build
#       directory, give that directory. If you are building within your
#       source (which is generally a bad idea!), it will be the same
#       directory.
#    3. Give a value to the 'gnuastro_prefix' variable within
#       '_gnuastro_autocomplete_astprogname'. This is the location that
#       Gnuastro is installed in your OS (usually '/usr/local/bin').
#    4. Activate the program's script with this command in the terminal you
#       are testing: 'source bin/progname/astprogname-complete.bash' (here
#       assuming you are in the top Gnuastro source directory, you can run
#       it from anywhere, just correct the locatation).
#
# Original author:
#     Pedram Ashofteh-Ardakani <pedramardakani@pm.me>
# Contributing author(s):
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/licenses/>.





#######################################################################
############      Options and general operating mode       ############
#######################################################################

# Basic initialization.
_gnuastro_autocomplete_initialize(){

    # Initialize the completion response with null
    COMPREPLY=();

    # Variable "current", is the current word being completed. "$2" is the
    # default value for the current word in completion scripts. But we are
    # using the longer form: "${COMP_WORDS[COMP_CWORD]}" for clarity.
    current="${COMP_WORDS[COMP_CWORD]}"
    if [ "$current" = "=" ]; then

        # The equal sign '=' raises complexities when filling suggestions
        # for long options. Things will work out fine when they are simply
        # ignored.
        current=""

    fi

    # Variable "prev", is one word before the one being completed. By
    # default, this is set as "$3" in completion scripts. But we are using
    # the longer form: "${COMP_WORDS[COMP_CWORD-1]}" to avoid confusions
    # with the arguments of our internal functions. Note that Bash will
    # return the '=' sign as a separate component of the line, so in that
    # case, we want the second-last word.
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    if [ "$prev" = "=" ]; then

        # While a user is writing a long option's argument, the previous
        # word will be the equal sign '='. This is not helpful at all. But
        # looking at a word just before '=' helps us understand which long
        # option is being called upon.
        prev="${COMP_WORDS[COMP_CWORD-2]}"

    fi
}





# List all the options of the given program (an '=' is kept for the options
# that need a value). In the output of '--help', option lines have these
# properties:
#
#   - The full line starts with two empty spaces.
#   - The first non-white character is a '-'.
#   - It contains a long option formated like '--XXXX'.
#
# But some options have a short version (which we ignore in
# autocompletion), so if the first word ends with a ',' the option name we
# want to show is the second word.
_gnuastro_autocomplete_option_list(){
    options_all=$("${COMP_WORDS[0]}" --help \
                      | awk '/^  / && $1 ~ /^-/ && /--+[a-zA-Z0-9]*/ { \
                              if($1 ~ /,$/) name=$2; \
                              else          name=$1; \
                              print name}' \
                      | sed -e's|=.*|=|');
}





# Return successfully if the previous token (specified as first argument)
# is an option that requires a value and store the option name if it is.
#
#   INPUT:
#     1) [as argument] String to search for.
#     *) [as variable] 'options_all' (in case the list of options is
#                      already read)
_gnuastro_autocomplete_string_is_valued_option(){

    # For easy reading.
    local string=$1

    # If the first character of the string isn't a '-', then its not an
    # option and there is no need to do any futher checks (and slow down
    # the output) so we can safely return failure.
    if [ ${string:0:1} != "-" ]; then return 1; fi

    # List of option names (with an '=' after those that need a value.
    if [ x"$options_all" = x ]; then
        _gnuastro_autocomplete_option_list
    fi

    # Go over the option list and see if they match the '$1'.
    for option in $options_all; do
        if [[ $option = $string=* ]]; then return 0; fi
    done

    # If control reaches here, then return failure (1).
    return 1
}





# See if the current word is an argument or option value.
_gnuastro_autocomplete_mode_arg_optval(){

    # If the previous token is the first token, then this is an
    # argument, no need for any further checks.
    if [ $prev = "${COMP_WORDS[0]}" ]; then
        argument=$current

    # If the previous token is an option that needs a value, then this is
    # an option value, this function will set 'option_name' and
    # 'option_name_complete' if necessary.
    elif _gnuastro_autocomplete_string_is_valued_option $prev; then
        option_name=$prev
        option_value=$current
        option_name_complete=1

    # The previous token wasn't an option that required a value, so this is
    # an argument.
    else
        argument=$current
    fi
}





# See if this is an argument, option name or option value. This function
# will fill 'argument', 'option_name' and 'option_value' (they should be
# initialized to an empty string before it).
#
#  option_value=FULL:            We are busy completing an option value.
#  option_name=FULL:             Can mean different meanings.
#    {
#      option_name_complete==0:  We are still filling the option name.
#      option_name_complete==1:  We are starting the option values.
#    }
#  argument=FULL:                We are busy filling an argument.
#  argument=EMPTY:               We haven't started writing an argument yet.
_gnuastro_autocomplete_mode(){

    # Local variable necessary only in this function.
    local namevalue=""

    # If the current word is empty, it may be an argument, or value of an
    # option (in case a value-required option is given before).
    if [ x$current = x ]; then
        _gnuastro_autocomplete_mode_arg_optval

    # The current word isn't empty.
    else

        # If the current word starts with a '-', it is an option name or
        # 'name=value' pair.
        if [ ${current:0:1} = "-" ]; then

            # If there is an equal sign, then we should separate the option
            # name from the value and keep
            if [[ $current = *=* ]]; then

                # By setting the "internal field separator" (IFS) to '='
                # and using 'read', we can separate the strings before and
                # after the equal sign.
                IFS="=" read -ra namevalue <<< $current
                option_name=${namevalue[0]}
                option_name_complete=1

                # If the value isn't written yet, (for example '--hdu='),
                # then the second string will just be an '='. But no value
                # is given yet, so 'option_value' should be empty.
                option_value=${namevalue[1]}
                if [ x$option_value = x"\=" ]; then option_value=""; fi
            else
                option_name=$current
                option_name_complete=0
            fi

        # The current word didn't start with a '-', so it may be an
        # argument or option value.
        else
            # Bash may separate the '=' in 'name=value' tokens. In this
            # scenario, when the user only gives 'name=' and presses TAB,
            # then 'current' will be '='. In this case, we should just set
            # it to empty.
            if [ $current = "=" ]; then current=""; fi

            # Check to see if its an argument or option value.
            _gnuastro_autocomplete_mode_arg_optval
        fi

    fi
}




# Given a certain option (as first argument), find the value that the user
# has given for it.
#
# OUTPUT:
#   read_option_value
_gnuastro_autocomplete_read_option_value(){

    # Inputs:
    local read_option_name=$1

    # Initialize the output (defined as 'local' before this).
    read_option_value=""

    # Parse through the given command-line and find the value.
    local option_found=0
    for word in ${COMP_WORDS[*]}; do

        # Ignore the program name (first word), current (last) word and any
        # '=' signs.
        if [ x$word = x${COMP_WORDS[0]} ] \
               || [ x$word = x$current ] \
               || [ x$word = x"=" ]; then
            local just_a_place_holder=1
        else
            # If the 'option_found' flag is set, this is the answer, set it
            # and return (this has to be *before* the place that we set
            # 'option_found').
            if [ $option_found = 1 ]; then
                read_option_value="$word";
                return 0
            fi

            # If this word is the desired option, set the 'option_found'
            # flag so the next word is taken as the value.
            if [ x$word = x$read_option_name ]; then option_found=1; fi
        fi
    done
}




















#######################################################################
############                     Files                     ############
#######################################################################

# Check if the given file is a FITS file (that can actually be
# opened). Note that FITS files have many possible extensions (see the
# 'gal_fits_name_is_fits' function in 'lib/fits.c').
_gnuastro_autocomplete_is_fits(){
    if "$gnuastro_prefix"/astfits "$1" &> /dev/null; then return 0;
    else                                                  return 1;
    fi
}





# Return successfully if argument (a FITS file) has a image HDU.
_gnuastro_autocomplete_fits_has_image(){
    if _gnuastro_autocomplete_is_fits "$1"; then
        if [ $("$gnuastro_prefix"/astfits "$1" --hasimagehdu) = 1 ]; then
            return 0
        fi
    fi
    return 1
}





# Return successfully if argument (a FITS file) has a table HDU.
_gnuastro_autocomplete_fits_has_table(){
    if _gnuastro_autocomplete_is_fits "$1"; then
        if [ $("$gnuastro_prefix"/astfits "$1" --hastablehdu) = 1 ]; then
            return 0
        fi
    fi
    return 1
}





# Return successfully if first argument is plain-text (not binary).
_gnuastro_autocomplete_is_plaintext(){
    if file "$1" | grep 'executable\|binary' &> /dev/null; then return 1;
    else                                                        return 0;
    fi
}





# Return successfully (with 0) if the given non-FITS file is a table.
_gnuastro_autocomplete_is_plaintext_table(){

    # Only do the check if the file exists.
    if [ -f "$1" ]; then

        # If the file is not plain-text, it will contain an 'executable' or
        # 'binary' in the output of the 'file' command.
        if _gnuastro_autocomplete_is_plaintext "$1"; then

            # The file is plain-text. Extract the first non-commented or
            # empty line and feed it to 'asttable' to see if it can be
            # interpretted properly. We don't want to bother with the other
            # lines, because we don't want to waste computational power
            # here.
            if awk '!/^#/ && NF>0 {print; exit 0}' "$1" \
                    | "$gnuastro_prefix"/asttable &> /dev/null; then
                return 0
            else
                return 1
            fi

            # The file was binary
        else return 1
        fi

    # The file didn't exist.
    else return 1
    fi
}





# Return successfully if the first argument is a table.
_gnuastro_autocomplete_is_table(){
    if   _gnuastro_autocomplete_fits_has_table     "$1"; then return 0
    elif _gnuastro_autocomplete_is_plaintext_table "$1"; then return 0
    else                                                      return 1
    fi
}





# If a certain file (image, table, or certain other files) is already given
# in the previous tokens, return successfully (with zero), and will put its
# name in 'given_file'. Otherwise, return a failure (1) and 'given_file'
# will be untouched.
_gnuastro_autocomplete_first_in_arguments(){

    # Inputs
    local mode=$1

    # Local variables (that are only for this function).
    local word=""
    local previous=""

    # Initialize outputs
    given_file=""

    # Go over all the words/tokens given until now.
    for word in ${COMP_WORDS[*]}; do

        # Ignore the program name (first word), current (last) word, any
        # directories or '=', or any word that starts with a '-' (which is
        # an option).
        if [ x$word = x${COMP_WORDS[0]} ] \
               || [ x$word = x$current ] \
               || [ ${word:0:1} = "-" ] \
               || [ x$word = x"=" ] \
               || [ -d $word ]; then
            local just_a_place_holder=1
        else
            # If the previous word is a valued option, then it shouldn't be
            # checked.
            if _gnuastro_autocomplete_string_is_valued_option $previous; then
                local just_a_place_holder=1

            # Previous word was not a valued option, do the operation based
            # on the mode.
            else
                case "$mode" in
                    fits)
                        if _gnuastro_autocomplete_is_fits "$word"; then
                            given_file="$word"
                        fi
                        ;;
                    image)
                        if _gnuastro_autocomplete_fits_has_image "$word"; then
                            given_file="$word"
                            return 0;
                        fi
                        ;;
                    table)
                        if _gnuastro_autocomplete_is_table "$word"; then
                            given_file="$word"
                            return 0;
                        fi
                        ;;
                    source_c)
                        if $(echo "$word" | grep "\.c$" &> /dev/null) \
                                && [ -f "$word" ]; then
                            given_file="$word"
                            return 0;
                        fi
                        ;;
                esac
            fi
        fi

        # If this word isn't an '=', put it in 'previous' and go onto the
        # next word.
        if [ $word != "=" ]; then
            previous=$word
        fi
    done

    # If control reached here, then there weren't any tables on the
    # command-line until now.
    return 1;
}





# Find the requested file from the existing tokens on the command-line.
#
# INPUT ARGUMENTS:
#    1) Mode of file ('table', 'image', 'fits').
#    2) Name of option containing file names.
#
# WRITTEN VARIABLES (should be defined before this function).
#     given_file: file name of given table.
_gnuastro_autocomplete_given_file(){

    # Set inputs (for each readability).
    local mode="$1"
    local name="$2"
    local read_option_value=""

    # If 'name' is emtpy, we should look in the arguments, otherwise, we
    # should look into the options.
    if [ x"$name" = x ]; then
        if _gnuastro_autocomplete_first_in_arguments $mode; then
            # given_file is written by the function as a side-effect.
            local just_a_place_holder=1
        fi

    # We are looking for a certain option.
    else
        # Read the given option's value.
        _gnuastro_autocomplete_read_option_value "$name"

        # If we are in image-mode, and the found file has an image, then
        # put the name in 'given_file' (final output). Same for tables.
        case $mode in
            fits)
                if _gnuastro_autocomplete_is_fits "$read_option_value"; then
                    given_file="$read_option_value"
                fi
                ;;
            image)
                if _gnuastro_autocomplete_fits_has_image \
                       "$read_option_value"; then
                    given_file="$read_option_value"
                fi
                ;;
            table)
                if _gnuastro_autocomplete_is_table \
                       "$read_option_value"; then
                    given_file="$read_option_value"
                fi
                ;;
        esac
    fi

}





# Find the requested filename and HDU within the already entered
# command-line. This option needs three arguments:
#
# INPUT ARGUMENTS
#    1) Mode of file ('table' or 'image').
#    2) The filename option (if empty string, 1st argument).
#    3) The HDU option (only necessary if the file is FITS).
#
# WRITTEN VARIABLES (should be defined before this function).
#    given_file: file name of given table/image.
#    given_hdu:  HDU of given table/table.
_gnuastro_autocomplete_given_file_and_hdu(){

    # Set inputs (for each readability).
    local mode=$1
    local name=$2
    local hduoption=$3

    # Internal variables.
    local read_option_value=""

    # Initialize the outputs (defined before this).
    given_hdu=""
    given_file=""

    # First, confirm the table file name. If requested table is in an
    # argument, 'name' will be empty.
    _gnuastro_autocomplete_given_file $mode $name

    # If a file name existed and it is a FITS file, find the HDU given in
    # the option.
    if [ x"$given_file" != x ] \
           && _gnuastro_autocomplete_is_fits "$given_file"; then
        _gnuastro_autocomplete_read_option_value $hduoption
        given_hdu="$read_option_value"
    fi
}




















#######################################################################
############               Completion replies              ############
#######################################################################
# Given a set of strings, select the one that matches the first argument
_gnuastro_autocomplete_compreply_from_string(){

    # Internal variables (for easy reading).
    local string="$1"
    local match="$2"

    # When there isn't any match string, just add everything.
    if [ x"$match" = x ]; then
        for v in $string; do COMPREPLY+=("$v"); done

    # When there is a match, limit it. We aren't using 'grep' because it
    # can confuse a possible '--XXX', with its own options on some systems
    # (and placing a '--' before the search string may not be portable).
    else
        for v in $(echo $string \
                       | awk '{for(i=1;i<=NF;++i) \
                                 if($i ~ /^'$match'/) print $i}'); do
            COMPREPLY+=("$v");
        done
    fi
}




# Some options take multiple values, separated by a comma (for example
# '--option=A,B,C'). Once the possible solutions have been found by the
# caller function, this function will decide how to print the suggestions:
# add a comma or not.
_gnuastro_autocomplete_compreply_comma_when_matched(){

    # Input arguments:
    local replies="$1"
    local tomatch="$2"
    local fullmatch="$3"
    local continuematch="$4"

    # Add the completion replies.
    if [ x"$continuematch" = x ]; then
        for c in $replies; do COMPREPLY+=("$c"); done
    else
        # If there is only one match, include the previously specified
        # replies in the final filled value and append an ',' to let the
        # user specify more values to the option.
        if [ $(echo $replies | wc -w) = 1 ]; then

            # In the continue-mode we don't want the final value to be
            # appended with a space.
            compopt -o nospace

            # When 'fullmatch' and 'tomatch' are the same, this was the
            # first requested reply, so we can safely just print it with a
            # comma.
            if [ x"$fullmatch" = x"$tomatch" ]; then
                COMPREPLY+=("$replies,")

            # This was not the first reply, so we need to add the old ones
            # as a prefix. But we first need to remove any possible start
            # of the current reply.
            else
                local oldreps=$(echo "$fullmatch" | sed -e's|'$tomatch'$||')
                COMPREPLY+=("$oldreps$replies,")
            fi

        # There was more than one matching reply, so continue suggesting
        # with only the column names.
        else
            local oldreps=$(echo "$fullmatch" | sed -e's|'$tomatch'$||')
            for c in $replies; do COMPREPLY+=("$oldreps$c"); done
        fi
    fi
}





# Add completion replies for the values to '--searchin'.
_gnuastro_autocomplete_compreply_searchin(){
    _gnuastro_autocomplete_compreply_from_string \
        "name unit comment" "$1"
}





# Add completion replies for the values to '--searchin'.
_gnuastro_autocomplete_compreply_tableformat(){
    _gnuastro_autocomplete_compreply_from_string \
        "fits-ascii fits-binary txt" "$1"
}





# Add completion replies for the values to '--numthreads'.
_gnuastro_autocomplete_compreply_numthreads(){
    if nproc &> /dev/null; then
        local numthreads="$(seq $(nproc))"
        _gnuastro_autocomplete_compreply_from_string \
            "$numthreads" "$1"
    fi
}





# Values to the common '--interpmetric' option.
_gnuastro_autocomplete_compreply_interpmetric(){
    _gnuastro_autocomplete_compreply_from_string \
        "radial manhattan" "$1"
}





# Values to the common '--type' option.
_gnuastro_autocomplete_compreply_numbertype(){
    _gnuastro_autocomplete_compreply_from_string \
        "uint8 int8 uint16 int16 uint32 int32 uint64 int64 float32 float64" \
        "$1"
}





# Values to the common '--wcslinearmatrix' option.
_gnuastro_autocomplete_compreply_wcslinearmatrix(){
    _gnuastro_autocomplete_compreply_from_string \
        "cd pc" "$1"
}





# Add matching options to the completion replies.
_gnuastro_autocomplete_compreply_options_all(){

    # Variable only necessary here.
    local options_match=""

    # Get the list of option names (with an '=' after those that need a
    # value (if 'options_all' isn't already set)
    if [ x"$options_all" = x ]; then
        _gnuastro_autocomplete_option_list
    fi

    # Limit the options to those that start with the already given portion.
    if [ x$1 = x ]; then
        options_match="$options_all"
    else
        # We aren't using 'grep' because it can confuse the '--XXX' with
        # its own options on some systems (and placing a '--' before the
        # search string may not be portable).
        options_match=$(echo "$options_all" | awk '/^'$1'/')
    fi

    # Add the list of options.
    for f in $options_match; do COMPREPLY+=("$f"); done

    # Disable the extra space on the command-line after the match, only for
    # this run (only relevant when we have found the match).
    compopt -o nospace
}





# Add a file into the completion replies. The main point is to remove the
# fixed directory name prefix of the file (that is appended by 'ls').
#
# It takes two arguments:
#
#   1. Base string (that was fed into 'ls' to find the full string).
#      This string CAN BE EMPTY.
#   2. Full string.
#
# If the first is a full directory, then it will remove it from the full
# string before saving string (which is standard in autocomplete (the user
# has already given it and it is just annoying!).
_gnuastro_autocomplete_compreply_file(){

    # For some reason, when there are multiple matches in a sub-directory,
    # removing the directory removes the whole thing that the user has
    # already typed! So the part below (which was the main purpose of this
    # function is currently commented). Until that bug is fixed, we'll just
    # return the full file name. Here is how you can reproduce the problem
    # (with the MAIN FUNCTION below uncommented and the WORK AROUND
    # commented):
    #
    #    $ ls
    #    image.fits
    #    $ mkdir subdir
    #    $ mv image.fits subdir/ab-123.fits
    #    $ cp subdir/ab-123.fits subdir/ab-456.fits
    #    $ astcrop subdir/ab-[TAB]

    # MAIN FUNCTION
    #if [ x$1 != x ] && [ -d $1 ]; then COMPREPLY+=("${2#$1}")
    #else                               COMPREPLY+=("$2")
    #fi

    # WORK AROUND
    COMPREPLY+=("$2")
}





# Add all the HDUs that contain a table/image in the first argument (a FITS
# file) into the completion replies.
#
# INPUT ARGUMENTS
#    1) Mode of file ('table', 'image', or 'all').
#    2) Name of file.
#    3) Existing argument.
_gnuastro_autocomplete_compreply_hdus(){

    # Local variables (for easy reading)
    local mode="$1"
    local given_file="$2"
    local matchstr="$3"

    if _gnuastro_autocomplete_is_fits "$given_file"; then

        # Get list of the file's HDUs.
        hdus=$("$gnuastro_prefix"/astfits "$given_file" \
                                 --list"$mode"hdus)

        # Add the matching ones into COMPREPLY.
        _gnuastro_autocomplete_compreply_from_string \
            "$hdus" "$matchstr"
    fi
}





# Add all the keywords in current HDU to the replies.
#
# INPUT ARGUMENTS:
#    1) FITS file name.
#    2) HDU within the FITS file.
#    3) Existing argument (to match).
#    4) If a comma should be appended in case of match.
_gnuastro_autocomplete_compreply_keys(){

    # Input arguments.
    local given_file="$1"
    local given_hdu="$2"
    local fullmatch="$3"
    local continuematch="$4"

    # Local variables.
    local keys=""
    local tomatch=""

    # Keywords can sometimes be given in series (for example
    # '--keyvalue=A,B,C'). In this case, the caller will give a non-empty
    # value to the fourth argument ('continuematch'). We therefore need to
    # will take the last component of the comma-separated list for the
    # matching of the next element.
    if [ x"$continuematch" = x ]; then
        tomatch="$fullmatch"
    else
        tomatch=$(echo $fullmatch | awk 'BEGIN{FS=","} {print $NF}')
    fi

    # Get list of keywords.
    keys=$("$gnuastro_prefix"/astfits "$given_file" \
                             --hdu="$given_hdu" \
                             --printkeynames \
               | grep ^$tomatch)

    _gnuastro_autocomplete_compreply_comma_when_matched \
        "$keys" "$tomatch" "$fullmatch" "$continuematch"
}





# Fill the replies with certain files.
_gnuastro_autocomplete_compreply_directories(){

    # For easy reading.
    local arg=$1

    # Get the list of directories (all ending with '/', with '-d' we are
    # telling 'ls' to not go into sub-directories).
    local directs=($(ls -d "$arg"*/ 2> /dev/null))

    # If a directory exists at all.
    if [ x"${directs[0]}" != x ]; then

        # If there is only one match.
        if [ x"${directs[1]}" = x ]; then

            # If there are sub-directories, then keep the ending '/' and
            # don't add space (the user may want to add sub-directories).
            if $(ls -d "${directs[0]}"/*/ &> /dev/null); then
                COMPREPLY+=("$d")
                compopt -o nospace

            # There are no sub-directories. In this case, remove the ending
            # '/' and let Bash add a space after the matched name.
            else
                COMPREPLY+=($(echo "${directs[0]}" | sed -e's|/$||'))
            fi

        # More than one match: go over all the matches and add them. we
        # should avoid printing a space (so the sub-directories continue in
        # the same token). Also RECALL THAT '$d' ALREADY ENDS WITH A '/'
        # HERE.
        else
            for d in ${directs[*]}; do
                COMPREPLY+=("$d")
                compopt -o nospace
            done
        fi
    fi
}





# Fill the replies with all image formats (note that the 'image' of
# '_gnuastro_autocomplete_compreply_files_certain' is only FITS files)
_gnuastro_autocomplete_compreply_images_all(){

    # Local variables to be filled by functions.
    local arg="$1"
    local ls_in=""
    local files=""
    local suffixes_jpeg=""
    local suffixes_tiff=""

    # Get the FITS images.
    _gnuastro_autocomplete_compreply_files_certain image "$arg"

    # If the given name doesn't have a suffix, then search for desired
    # suffixes.
    if [ x"$arg" = x"$(echo $arg | cut -d. -f1)" ]; then

        # Since the other formats are checked by suffix and there are many
        # suffixes, its easier to just call 'ls' once.
        _gnuastro_autocomplete_compreply_suffixes_jpeg
        _gnuastro_autocomplete_compreply_suffixes_tiff
        for s in $suffixes_jpeg $suffixes_tiff; do
            ls_in="$ls_in "$arg"*$s"
        done

    # The given argument already contains a suffix. So you can safely
    # ignore the matched suffixes.
    else
        ls_in=$arg"*"
    fi

    # Find the matching files and add them to the replies.
    files=($(ls -d $ls_in 2> /dev/null))
    for f in ${files[*]}; do
        if [ -d "$f" ]; then
            COMPREPLY+=("$f/")
            compopt -o nospace
        else
            _gnuastro_autocomplete_compreply_file "$arg" "$f"
        fi
    done
}




# Fill the replies with certain files.
_gnuastro_autocomplete_compreply_files_certain(){

    # For easy reading.
    local arg=$2
    local mode=$1

    # Get list of matching files (with '-d' we are telling 'ls' to not go
    # into sub-directories).
    local files=($(ls -d "$arg"* 2> /dev/null))

    # Parse the list of files and add it when it is a directory or it can
    # be read as a table.
    for f in ${files[*]}; do
        if [ -d "$f" ]; then
            COMPREPLY+=("$f/")
            compopt -o nospace
        else
            case "$mode" in
                fits)
                    if _gnuastro_autocomplete_is_fits "$f"; then
                        _gnuastro_autocomplete_compreply_file "$arg" "$f"
                    fi
                    ;;
                image)
                    if _gnuastro_autocomplete_fits_has_image "$f"; then
                        _gnuastro_autocomplete_compreply_file "$arg" "$f"
                    fi
                    ;;
                table)
                    if _gnuastro_autocomplete_is_table "$f"; then
                        _gnuastro_autocomplete_compreply_file "$arg" "$f"
                    fi
                    ;;
                source_c)
                    if $(echo $f | grep "\.c$" &> /dev/null); then
                        _gnuastro_autocomplete_compreply_file "$arg" "$f"
                    fi
                    ;;
                source_la)
                    if $(echo $f | grep "\.la$" &> /dev/null); then
                        _gnuastro_autocomplete_compreply_file "$arg" "$f"
                    fi
                    ;;
            esac
        fi
    done
}





# Add all table columns in given file (possibly with HDU) that start with
# the given string into the completion replies.
_gnuastro_autocomplete_compreply_table_columns(){

    # Inputs
    local table_file="$1"
    local table_hdu="$2"
    local fullmatch="$3"
    local continuematch="$4"

    # Internal
    local tomatch=""
    local columns=""
    local hdu_option=""

    # If no file has been given, don't set anything, just return.
    if [ x"$table_file" = x ]; then return 0; fi

    # If a HDU is given, then add it to the options.
    if [ x"$table_hdu" != x ]; then hdu_option="--hdu=$table_hdu"; fi

    # Columns can usually be given in series (for example
    # '--column=A,B,C'). In this case, the caller will give a non-empty
    # value to the fourth argument ('continuematch'). We therefore need to
    # will take the last component of the comma-separated list for the
    # matching of the next element.
    if [ x"$continuematch" = x ]; then
        tomatch="$fullmatch"
    else
        tomatch=$(echo $fullmatch | awk 'BEGIN{FS=","} {print $NF}')
    fi

    # Get the list of columns from the output of '--information': the
    # column names are the second column of the lines that start with a
    # number. If there is no column name, print the column number.
    #
    # We are forcing 'awk' to read after the second line of 'asttable'
    # output, because the second line contains the filename. The filename
    # might start with numbers. If so, there will be an unwanted '(hdu:'
    # printed in the results. Here, 'awk' will print the second column in
    # lines that start with a number.
    columns=$("$gnuastro_prefix"/asttable --information \
                                "$table_file" $hdu_option \
                  | awk 'NR>2 && /^[0-9]/ { \
                            if($2=="n/a") print $1; else print $2 \
                         }' \
                  | grep ^$tomatch)

    # Add the necessary columns in a comma-separated manner.
    _gnuastro_autocomplete_compreply_comma_when_matched \
        "$columns" "$tomatch" "$fullmatch" "$continuematch"
}

_gnuastro_autocomplete_compreply_arithmetic_lib(){
arithmetic_lib_operators=" + - x / % lt le gt ge eq ne and or not isblank isnotblank where bitand bitor bitxor lshift rshift bitnot abs pow sqrt log log10 sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh atan2 ra-to-degree dec-to-degree degree-to-ra degree-to-dec counts-to-mag mag-to-counts sb-to-mag mag-to-sb counts-to-sb sb-to-counts counts-to-jy jy-to-counts counts-to-nanomaggy nanomaggy-to-counts mag-to-jy jy-to-mag au-to-pc pc-to-au ly-to-pc pc-to-ly ly-to-au au-to-ly minvalue maxvalue numbervalue sumvalue meanvalue stdvalue medianvalue unique noblank min max number sum mean std median quantile sigclip-number sigclip-median sigclip-mean sigclip-number mknoise-sigma mknoise-sigma-from-mean mknoise-poisson mknoise-uniform random-from-hist random-from-hist-raw stitch uchar char ushort short uint int ulong long float32 float64 e pi c G h au ly avogadro fine-structure box-around-ellipse vertices-on-sphere size makenew index counter indexonly counteronly swap constant pool-max pool-min pool-sum pool-mean pool-median GAL_ARITHMETIC_OP_EQB1950_TO_EQJ2000: GAL_ARITHMETIC_OP_EQB1950_TO_ECB1950: GAL_ARITHMETIC_OP_EQB1950_TO_ECJ2000: GAL_ARITHMETIC_OP_EQB1950_TO_GALACTIC: GAL_ARITHMETIC_OP_EQB1950_TO_SUPERGALACTIC: GAL_ARITHMETIC_OP_EQJ2000_TO_EQB1950: GAL_ARITHMETIC_OP_EQJ2000_TO_ECB1950: GAL_ARITHMETIC_OP_EQJ2000_TO_ECJ2000: GAL_ARITHMETIC_OP_EQJ2000_TO_GALACTIC: GAL_ARITHMETIC_OP_EQJ2000_TO_SUPERGALACTIC: GAL_ARITHMETIC_OP_ECB1950_TO_EQB1950: GAL_ARITHMETIC_OP_ECB1950_TO_EQJ2000: GAL_ARITHMETIC_OP_ECB1950_TO_ECJ2000: GAL_ARITHMETIC_OP_ECB1950_TO_GALACTIC: GAL_ARITHMETIC_OP_ECB1950_TO_SUPERGALACTIC: GAL_ARITHMETIC_OP_ECJ2000_TO_EQB1950: GAL_ARITHMETIC_OP_ECJ2000_TO_EQJ2000: GAL_ARITHMETIC_OP_ECJ2000_TO_ECB1950: GAL_ARITHMETIC_OP_ECJ2000_TO_GALACTIC: GAL_ARITHMETIC_OP_ECJ2000_TO_SUPERGALACTIC: GAL_ARITHMETIC_OP_GALACTIC_TO_EQB1950: GAL_ARITHMETIC_OP_GALACTIC_TO_EQJ2000: GAL_ARITHMETIC_OP_GALACTIC_TO_ECB1950: GAL_ARITHMETIC_OP_GALACTIC_TO_ECJ2000: GAL_ARITHMETIC_OP_GALACTIC_TO_SUPERGALACTIC: GAL_ARITHMETIC_OP_SUPERGALACTIC_TO_EQB1950: GAL_ARITHMETIC_OP_SUPERGALACTIC_TO_EQJ2000: GAL_ARITHMETIC_OP_SUPERGALACTIC_TO_ECB1950: GAL_ARITHMETIC_OP_SUPERGALACTIC_TO_ECJ2000: GAL_ARITHMETIC_OP_SUPERGALACTIC_TO_GALACTIC:"
}

_gnuastro_autocomplete_compreply_arithmetic_prog(){
arithmetic_prog_operators=" filter-mean filter-median filter-sigclip-mean filter-sigclip-median erode dilate number-neighbors connected-components fill-holes invert interpolate-minngb interpolate-maxngb interpolate-meanngb interpolate-medianngb interpolate-minofregion interpolate-maxofregion collapse-sum collapse-min collapse-max collapse-mean collapse-number collapse-median collapse-sigclip-std collapse-sigclip-mean collapse-sigclip-median collapse-sigclip-number add-dimension-slow add-dimension-fast repeat"
}

_gnuastro_autocomplete_compreply_suffixes_jpeg(){
suffixes_jpeg=" jpg JPG jpeg JPEG jpe jif jfif jfi"
}

_gnuastro_autocomplete_compreply_suffixes_tiff(){
suffixes_tiff=" tif TIF tiff TIFF"
}

_gnuastro_autocomplete_compreply_convertt_colormap(){
convertt_colormaps=" hsv)) sls)) viridis)){ccode=COLOR_VIRIDIS; gray) sls-inverse))"
}

_gnuastro_autocomplete_compreply_specline_names(){
specline_names=" Ne-VIII-770 Ne-VIII-780 Ly-epsilon Ly-delta Ly-gamma C-III-977 N-III-989 N-III-991.51 N-III-991.57 Ly-beta O-VI-1031 O-VI-1037 Ar-I-1066 Ly-alpha N-V-1238 N-V-1242 Si-II-1260 Si_II-1302 O-I-1302 C-II-1334 C-II-1335 Si-IV-1393 O-IV-1397 O-IV-1399 Si-IV-1402 N-IV-1486 C-IV-1548 C-IV-1550 He-II-1640 O-III-1660 O-III-1666 N-III-1746 N-III-1748 Al-III-1854 Al-III-1862 Si-III C-III-1908 N-II-2142 O-III-2320 C-II-2323 C-II-2324 Fe-XI-2648 He-II-2733 Mg-V-2782 Mg-II-2795 Mg-II-2802 Fe-IV-2829 Fe-IV-2835 Ar-IV-2853 Ar-IV-2868 Mg-V-2928 He-I-2945 O-III-3132 He-I-3187 He-II-3203 O-III-3312 Ne-V-3345 Ne-V-3425 O-III-3444 N-I-3466-4 N-I-3466-5 He-I-3487 Fe-VII-3586 Fe-VI-3662 H-19 H-18 H-17 H-16 H-15 H-14 O-II-3726 O-II-3728 H-13 H-12 Fe-VII-3758 H-11 H-10 H-9 Fe-V-3839 Ne-III-3868 He-I-3888 H-8 Fe-V-3891 Fe-V-3911 Ne-III-3967 H-epsilon He-I-4026 S-II-4068 Fe-V-4071 S-II-4076 H-delta He-I-4143 Fe-II-4178 Fe-V-4180 Fe-II-4233 Fe-V-4227 Fe-II-4287 Fe-II-4304 O-II-4317 H-gamma O-III-4363 Ar-XIV O-II-4414 Fe-II-4416 Fe-II-4452 He-I-4471 Fe-II-4489 Fe-II-4491 N-III-4510 Fe-II-4522 Fe-II-4555 Fe-II-4582 Fe-II-4583 Fe-II-4629 N-III-4634 N-III-4640 N-III-4641 C-III-4647 C-III-4650 C-III-5651 Fe-III-4658 He-II-4685 Ar-IV-4711 Ar-IV-4740 H-beta Fe-VII-4893 Fe-IV-4903 Fe-II-4923 O-III-4958 O-III-5006 Fe-II-5018 Fe-III-5084 Fe-VI-5145 Fe-VII-5158 Fe-II-5169 Fe-VI-5176 Fe-II-5197 N-I-5200 Fe-II-5234 Fe-IV-5236 Fe-III-5270 Fe-II-5276 Fe-VII-5276 Fe-XIV Ca-V Fe-II-5316-6 Fe-II-5316-7 Fe-VI-5335 Fe-VI-5424 Cl-III-5517 Cl-III-5537 Fe-VI-5637 Fe-VI-5677 C-III-5697 Fe-VII-5720 N-II-5754 C-IV-5801 C-IV-5811 He-I-5875 O-I-6046 Fe-VII-6087 O-I-6300 S-III-6312 Si-II-6347 O-I-6363 Fe-II-6369 Fe-X Fe-II-6516 N-II-6548 H-alpha N-II-6583 S-II-6716 S-II-6730 O-I-7002 Ar-V He-I-7065 Ar-III-7135 Fe-II-7155 Ar-IV-7170 Fe-II-7172 C-II-7236 Ar-IV-7237 O-I-7254 Ar-IV-7262 He-I-7281 O-II-7319 O-II-7330 Ni-II-7377 Ni-II-7411 Fe-II-7452 N-I-7468 S-XII Ar-III-7751 He-I-7816 Ar-I-7868 Ni-III Fe-XI-7891 He-II-8236 Pa-20 Pa-19 Pa-18 O-I-8446 Pa-17 Ca-II-8498 Pa-16 Ca-II-8542 Pa-15 Cl-II Pa-14 Fe-II-8616 Ca-II-8662 Pa-13 N-I-8680 N-I-8703 N-I-8711 Pa-12 Pa-11 Fe-II-8891 Pa-10 S-III-9068 Pa-9 S-III-9531 Pa-epsilon C-I-9824 C-I-9850 S-VIII He-I-10027 He-I-10031 Pa-delta S-II-10286 S-II-10320 S-II-10336 Fe-XIII He-I-10830 Pa-gamma Ly-limit H-limit Pa-limit"
}

_gnuastro_autocomplete_compreply_wcs_coordsys(){
wcs_coordsys=""
}
# Bash autocompletion to Gnuastro's Arithmetic program. See the comments
# above 'bin/completion.bash.in' for more.
#
# Original author:
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Contributing author(s):
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/





# For debugging
#
# See the description in 'bin/completion.bash.in'.
#source /PATH/TO/GNUASTRO/SRC/bin/completion.bash.in
#source /PATH/TO/GNUASTRO/BUILD/bin/completion.bash.built





#######################################################################
############       Only for Arithmetic (this program)      ############
#######################################################################

# Dealing with arguments: Arithmetic only takes array/image files.
_gnuastro_autocomplete_astarithmetic_arguments(){

    # Local variables to be filled by functions.
    local arithmetic_lib_operators=""
    local arithmetic_prog_operators=""

    # Print all accessible images.
    _gnuastro_autocomplete_compreply_files_certain image "$argument"

    # If atleast one image has already been given, also print the
    # arithmetic operators with the file names.
    if _gnuastro_autocomplete_first_in_arguments image; then

        # Fill the variables.
        _gnuastro_autocomplete_compreply_arithmetic_lib
        _gnuastro_autocomplete_compreply_arithmetic_prog

        # Add them to COMPREPLY
        _gnuastro_autocomplete_compreply_from_string \
            "$arithmetic_lib_operators $arithmetic_prog_operators" \
            "$argument"
    fi
}





# Fill option value (depends on option).
_gnuastro_autocomplete_astarithmetic_option_value(){

    # Internal variables.
    local fits_file=""
    local given_hdu=""
    local given_file=""

    # Keep this in the same order as the output of '--help', for options
    # with similar operations, keep the order within the '|'s.
    case "$option_name" in

        -h|--hdu|-g|--globalhdu|-w|--wcshdu)
            _gnuastro_autocomplete_given_file image ""
            _gnuastro_autocomplete_compreply_hdus \
                image "$given_file" "$current"
            ;;

        -w|--wcsfile)
            _gnuastro_autocomplete_compreply_files_certain image "$current"
            ;;

        --interpmetric)
            for v in radial manhattan; do COMPREPLY+=("$v"); done
            ;;

        --tableformat)
            _gnuastro_autocomplete_compreply_tableformat "$current"
            ;;

        --wcslinearmatrix)
            _gnuastro_autocomplete_compreply_wcslinearmatrix "$current"
            ;;

        --numthreads)
            _gnuastro_autocomplete_compreply_numthreads "$current"
            ;;

    esac
}





_gnuastro_autocomplete_astarithmetic(){

    # The installation directory of Gnuastro. The '/opt/local/bin' part will be
    # replaced automatically during 'make install', with the user's given
    # requested installation directory. If you are debugging, please
    # correct it yourself (usually to '/usr/local/bin', but don't commit
    # this particular change).
    local gnuastro_prefix="/opt/local/bin"

    # Basic initialization. The variables we want to remain inside this
    # function are given a 'local' here and set inside the 'initialize'
    # function. The variables are defined above the function that gives
    # them a value.
    local prev=""
    local current=""
    local argument=""
    _gnuastro_autocomplete_initialize

    # For a check
    #echo
    #echo "prev:     $prev"
    #echo "current:  $current"
    #echo "argument: $argument"

    # Extract the current mode (if the user is giving an argument, option
    # name, or option value). See the description above this function on
    # how the mode is set.
    local options_all=""
    local option_name=""
    local option_value=""
    local option_name_complete=0
    _gnuastro_autocomplete_mode

    # For a check
    #echo
    #echo "argument:             $argument"
    #echo "option_name:          $option_name"
    #echo "option_name_complete: $option_name_complete"
    #echo "option_value:         $option_value"

    # If 'option_name_complete==1', then we are busy filling in the option
    # value.
    if [ $option_name_complete = 1 ]; then
        _gnuastro_autocomplete_astarithmetic_option_value

    # When 'option_name' is not empty (and not yet complete), we are busy
    # filling in the option name.
    elif [ x$option_name != x ]; then
        _gnuastro_autocomplete_compreply_options_all "$option_name"

    # In the case of "none-of-the-above", it is an argument.
    else
        _gnuastro_autocomplete_astarithmetic_arguments
    fi
}





# Define the completion specification, or COMPSPEC: -o bashdefault: Use
# Bash default completions if nothing is found.  -F function: Use this
# 'function' to generate the given program's completion.
complete -o bashdefault -F _gnuastro_autocomplete_astarithmetic astarithmetic
# Bash autocompletion to Gnuastro's BuildProgram. See the comments above
# 'bin/completion.bash.in' for more.
#
# Original author:
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Contributing author(s):
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/





# For debugging
#
# See the description in 'bin/completion.bash.in'.
#source /PATH/TO/GNUASTRO/SRC/bin/completion.bash.in
#source /PATH/TO/GNUASTRO/BUILD/bin/completion.bash.built





#######################################################################
############     Only for BuildProgram (this program)      ############
#######################################################################

# Fill the replies with available C compilers
_gnuastro_autocomplete_compreply_c_compiler(){
    for f in gcc clang cc $CC; do
        if which $f &> /dev/null; then COMPREPLY+=("$f"); fi
    done
}





# Dealing with arguments: BuildProgram currently only takes C source files.
_gnuastro_autocomplete_astbuildprog_arguments(){
    local given_file=""
    if _gnuastro_autocomplete_first_in_arguments source_c; then
        _gnuastro_autocomplete_compreply_options_all ""
    else
        _gnuastro_autocomplete_compreply_files_certain source_c "$argument"
    fi
}





# Fill option value (depends on option).
_gnuastro_autocomplete_astbuildprog_option_value(){

    # Internal variables.
    local junk=1
    local fits_file=""
    local given_hdu=""
    local given_file=""

    # Keep this in the same order as the output of '--help', for options
    # with similar operations, keep the order within the '|'s.
    case "$option_name" in

        -a|--la)
            _gnuastro_autocomplete_compreply_files_certain source_la "$current"
            ;;

        -c|--cc)
            _gnuastro_autocomplete_compreply_c_compiler
            ;;

        -I|--includedir|-L|--linkdir)
            _gnuastro_autocomplete_compreply_directories "$current"
            ;;

        -l|--linklib|-t|--tag|-W|--warning)
            # There is no easy way to guess which libraries the user wants
            # to link with, or the tag, or the warning level.
            junk=1
            ;;

        -O|--optimize)
            for f in $(printf "0\n1\n2\n3" | grep ^"$current"); do
                COMPREPLY+=("$f");
            done
            ;;

    esac
}





_gnuastro_autocomplete_astbuildprog(){

    # The installation directory of Gnuastro. The '/opt/local/bin' part will be
    # replaced automatically during 'make install', with the user's given
    # requested installation directory. If you are debugging, please
    # correct it yourself (usually to '/usr/local/bin', but don't commit
    # this particular change).
    local gnuastro_prefix="/opt/local/bin"

    # Basic initialization. The variables we want to remain inside this
    # function are given a 'local' here and set inside the 'initialize'
    # function. The variables are defined above the function that gives
    # them a value.
    local prev=""
    local current=""
    local argument=""
    _gnuastro_autocomplete_initialize

    # For a check
    #echo
    #echo "prev:     $prev"
    #echo "current:  $current"
    #echo "argument: $argument"

    # Extract the current mode (if the user is giving an argument, option
    # name, or option value). See the description above this function on
    # how the mode is set.
    local options_all=""
    local option_name=""
    local option_value=""
    local option_name_complete=0
    _gnuastro_autocomplete_mode

    # For a check
    #echo
    #echo "argument:             $argument"
    #echo "option_name:          $option_name"
    #echo "option_name_complete: $option_name_complete"
    #echo "option_value:         $option_value"

    # If 'option_name_complete==1', then we are busy filling in the option
    # value.
    if [ $option_name_complete = 1 ]; then
        _gnuastro_autocomplete_astbuildprog_option_value

    # When 'option_name' is not empty (and not yet complete), we are busy
    # filling in the option name.
    elif [ x$option_name != x ]; then
        _gnuastro_autocomplete_compreply_options_all "$option_name"

    # In the case of "none-of-the-above", it is an argument.
    else
        _gnuastro_autocomplete_astbuildprog_arguments
    fi
}





# Define the completion specification, or COMPSPEC: -o bashdefault: Use
# Bash default completions if nothing is found.  -F function: Use this
# 'function' to generate the given program's completion.
complete -o bashdefault -F _gnuastro_autocomplete_astbuildprog astbuildprog
# Bash autocompletion to Gnuastro's ConvertType. See the comments above
# 'bin/completion.bash.in' for more.
#
# Original author:
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Contributing author(s):
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/





# For debugging
#
# See the description in 'bin/completion.bash.in'.
#source /PATH/TO/GNUASTRO/SRC/bin/completion.bash.in
#source /PATH/TO/GNUASTRO/BUILD/bin/completion.bash.built





#######################################################################
############      Only for ConvertType (this program)      ############
#######################################################################

# Dealing with arguments: ConvertType can take multiple images as arguments
# (so unlike other programs, there is no option to print options). One way
# would be to calculate how many color channels there are in each input and
# look at the desired output format and its necessary color channels. But
# that is too complicated for now.
_gnuastro_autocomplete_astconvertt_arguments(){
    _gnuastro_autocomplete_compreply_images_all "$argument"
}





# Fill option value (depends on option).
_gnuastro_autocomplete_astconvertt_option_value(){

    # Internal variables.
    local fits_file=""
    local given_hdu=""
    local given_file=""
    local convertt_colormaps=""

    # Keep this in the same order as the output of '--help', for options
    # with similar operations, keep the order within the '|'s.
    case "$option_name" in

        -h|--hdu|-g|--globalhdu)
            _gnuastro_autocomplete_given_file image ""
            _gnuastro_autocomplete_compreply_hdus \
                image "$given_file" "$current"
            ;;

        --colormap)
            _gnuastro_autocomplete_compreply_convertt_colormap
            _gnuastro_autocomplete_compreply_from_string \
                "$convertt_colormaps" "$current"
            ;;

        -u|--quality)
            _gnuastro_autocomplete_compreply_from_string \
                "$(seq 100)" "$current"
            ;;

        --wcslinearmatrix)
            _gnuastro_autocomplete_compreply_wcslinearmatrix "$current"
            ;;

        --numthreads)
            _gnuastro_autocomplete_compreply_numthreads "$current"
            ;;


    esac
}





_gnuastro_autocomplete_astconvertt(){

    # The installation directory of Gnuastro. The '/opt/local/bin' part will be
    # replaced automatically during 'make install', with the user's given
    # requested installation directory. If you are debugging, please
    # correct it yourself (usually to '/usr/local/bin', but don't commit
    # this particular change).
    local gnuastro_prefix="/opt/local/bin"

    # Basic initialization. The variables we want to remain inside this
    # function are given a 'local' here and set inside the 'initialize'
    # function. The variables are defined above the function that gives
    # them a value.
    local prev=""
    local current=""
    local argument=""
    _gnuastro_autocomplete_initialize

    # For a check
    #echo
    #echo "prev:     $prev"
    #echo "current:  $current"
    #echo "argument: $argument"

    # Extract the current mode (if the user is giving an argument, option
    # name, or option value). See the description above this function on
    # how the mode is set.
    local options_all=""
    local option_name=""
    local option_value=""
    local option_name_complete=0
    _gnuastro_autocomplete_mode

    # For a check
    #echo
    #echo "argument:             $argument"
    #echo "option_name:          $option_name"
    #echo "option_name_complete: $option_name_complete"
    #echo "option_value:         $option_value"

    # If 'option_name_complete==1', then we are busy filling in the option
    # value.
    if [ $option_name_complete = 1 ]; then
        _gnuastro_autocomplete_astconvertt_option_value

    # When 'option_name' is not empty (and not yet complete), we are busy
    # filling in the option name.
    elif [ x$option_name != x ]; then
        _gnuastro_autocomplete_compreply_options_all "$option_name"

    # In the case of "none-of-the-above", it is an argument.
    else
        _gnuastro_autocomplete_astconvertt_arguments
    fi
}





# Define the completion specification, or COMPSPEC: -o bashdefault: Use
# Bash default completions if nothing is found.  -F function: Use this
# 'function' to generate the given program's completion.
complete -o bashdefault -F _gnuastro_autocomplete_astconvertt astconvertt
# Bash autocompletion to Gnuastro's CosmicCalculator program. See the
# comments above 'bin/completion.bash.in' for more.
#
# Original author:
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Contributing author(s):
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/





# For debugging
#
# See the description in 'bin/completion.bash.in'.
#source /PATH/TO/GNUASTRO/SRC/bin/completion.bash.in
#source /PATH/TO/GNUASTRO/BUILD/bin/completion.bash.built





#######################################################################
############    Only for CosmicCalculator (this program)   ############
#######################################################################

# Dealing with arguments: CosmicCalculator doesn't take any arguments, so
# show the use the list of options immediately.
_gnuastro_autocomplete_astcosmiccal_arguments(){
    _gnuastro_autocomplete_compreply_options_all ""
}





# Fill option value (depends on option).
_gnuastro_autocomplete_astcosmiccal_option_value(){

    # Internal variables.
    local specline_names=""

    # Keep this in the same order as the output of '--help', for options
    # with similar operations, keep the order within the '|'s.
    case "$option_name" in

        --obsline)
            # Put the list of spectral lines in 'specline_names'.
            _gnuastro_autocomplete_compreply_specline_names

            # Add them to the replies.
            _gnuastro_autocomplete_compreply_from_string \
                "$specline_names" "$current"

            # If this is the only suggestion, then add a ',' (to let the
            # user easily type-in their observed value at this line.
            if [        x"${COMPREPLY[0]}" != x ] \
                   && [ x"${COMPREPLY[1]}"  = x ]; then
                COMPREPLY[0]="${COMPREPLY[0]},";
                compopt -o nospace
            fi
            ;;

        --lineatz)
            _gnuastro_autocomplete_compreply_specline_names
            _gnuastro_autocomplete_compreply_from_string \
                "$specline_names" "$current"
            ;;
    esac
}





_gnuastro_autocomplete_astcosmiccal(){

    # The installation directory of Gnuastro. The '/opt/local/bin' part will be
    # replaced automatically during 'make install', with the user's given
    # requested installation directory. If you are debugging, please
    # correct it yourself (usually to '/usr/local/bin', but don't commit
    # this particular change).
    local gnuastro_prefix="/opt/local/bin"

    # Basic initialization. The variables we want to remain inside this
    # function are given a 'local' here and set inside the 'initialize'
    # function. The variables are defined above the function that gives
    # them a value.
    local prev=""
    local current=""
    local argument=""
    _gnuastro_autocomplete_initialize

    # For a check
    #echo
    #echo "prev:     $prev"
    #echo "current:  $current"
    #echo "argument: $argument"

    # Extract the current mode (if the user is giving an argument, option
    # name, or option value). See the description above this function on
    # how the mode is set.
    local options_all=""
    local option_name=""
    local option_value=""
    local option_name_complete=0
    _gnuastro_autocomplete_mode

    # For a check
    #echo
    #echo "argument:             $argument"
    #echo "option_name:          $option_name"
    #echo "option_name_complete: $option_name_complete"
    #echo "option_value:         $option_value"

    # If 'option_name_complete==1', then we are busy filling in the option
    # value.
    if [ $option_name_complete = 1 ]; then
        _gnuastro_autocomplete_astcosmiccal_option_value

    # When 'option_name' is not empty (and not yet complete), we are busy
    # filling in the option name.
    elif [ x$option_name != x ]; then
        _gnuastro_autocomplete_compreply_options_all "$option_name"

    # In the case of "none-of-the-above", it is an argument.
    else
        _gnuastro_autocomplete_astcosmiccal_arguments
    fi
}





# Define the completion specification, or COMPSPEC: -o bashdefault: Use
# Bash default completions if nothing is found.  -F function: Use this
# 'function' to generate the given program's completion.
complete -o bashdefault -F _gnuastro_autocomplete_astcosmiccal astcosmiccal
# Bash autocompletion to Gnuastro's Crop program. See the comments above
# 'bin/completion.bash.in' for more.
#
# Original author:
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Contributing author(s):
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/





# For debugging
#
# See the description in 'bin/completion.bash.in'.
#source /PATH/TO/GNUASTRO/SRC/bin/completion.bash.in
#source /PATH/TO/GNUASTRO/BUILD/bin/completion.bash.built





#######################################################################
############          Only for Crop (this program)         ############
#######################################################################

# Dealing with arguments: Crop can take any number of images, so don't
# suggest options
_gnuastro_autocomplete_astcrop_arguments(){
    _gnuastro_autocomplete_compreply_files_certain image "$argument"
}





# Fill option value (depends on option).
_gnuastro_autocomplete_astcrop_option_value(){

    # Internal variables.
    local fits_file=""
    local given_hdu=""
    local given_file=""

    # Keep this in the same order as the output of '--help', for options
    # with similar operations, keep the order within the '|'s.
    case "$option_name" in

        -h|--hdu)
            _gnuastro_autocomplete_given_file image ""
            _gnuastro_autocomplete_compreply_hdus \
                image "$given_file" "$current"
            ;;

        -O|--mode)
            _gnuastro_autocomplete_compreply_from_string \
                "img wcs" "$current"
            ;;

        -T|--type)
            _gnuastro_autocomplete_compreply_numbertype "$current"
            ;;

        --wcslinearmatrix)
            _gnuastro_autocomplete_compreply_wcslinearmatrix "$current"
            ;;

        --cathdu)
            _gnuastro_autocomplete_given_file table "--catalog"
            _gnuastro_autocomplete_compreply_hdus \
                table "$given_file" "$current"
            ;;

        --catalog)
            _gnuastro_autocomplete_compreply_files_certain table "$current"
            ;;

        --namecol|--coordcol)
            _gnuastro_autocomplete_given_file_and_hdu \
                table "--catalog" "--hdu"
            _gnuastro_autocomplete_compreply_table_columns \
                "$given_file" "$given_hdu" "$current"
            ;;

        --numthreads)
            _gnuastro_autocomplete_compreply_numthreads "$current"
            ;;

    esac
}





_gnuastro_autocomplete_astcrop(){

    # The installation directory of Gnuastro. The '/opt/local/bin' part will be
    # replaced automatically during 'make install', with the user's given
    # requested installation directory. If you are debugging, please
    # correct it yourself (usually to '/usr/local/bin', but don't commit
    # this particular change).
    local gnuastro_prefix="/opt/local/bin"

    # Basic initialization. The variables we want to remain inside this
    # function are given a 'local' here and set inside the 'initialize'
    # function. The variables are defined above the function that gives
    # them a value.
    local prev=""
    local current=""
    local argument=""
    _gnuastro_autocomplete_initialize

    # For a check
    #echo
    #echo "prev:     $prev"
    #echo "current:  $current"
    #echo "argument: $argument"

    # Extract the current mode (if the user is giving an argument, option
    # name, or option value). See the description above this function on
    # how the mode is set.
    local options_all=""
    local option_name=""
    local option_value=""
    local option_name_complete=0
    _gnuastro_autocomplete_mode

    # For a check
    #echo
    #echo "argument:             $argument"
    #echo "option_name:          $option_name"
    #echo "option_name_complete: $option_name_complete"
    #echo "option_value:         $option_value"

    # If 'option_name_complete==1', then we are busy filling in the option
    # value.
    if [ $option_name_complete = 1 ]; then
        _gnuastro_autocomplete_astcrop_option_value

    # When 'option_name' is not empty (and not yet complete), we are busy
    # filling in the option name.
    elif [ x$option_name != x ]; then
        _gnuastro_autocomplete_compreply_options_all "$option_name"

    # In the case of "none-of-the-above", it is an argument.
    else
        _gnuastro_autocomplete_astcrop_arguments
    fi
}





# Define the completion specification, or COMPSPEC: -o bashdefault: Use
# Bash default completions if nothing is found.  -F function: Use this
# 'function' to generate the given program's completion.
complete -o bashdefault -F _gnuastro_autocomplete_astcrop astcrop
# Bash autocompletion to Gnuastro's Fits program. See the comments above
# 'bin/completion.bash.in' for more.
#
# Original author:
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Contributing author(s):
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/





# For debugging
#
# See the description in 'bin/completion.bash.in'.
#source /PATH/TO/GNUASTRO/SRC/bin/completion.bash.in
#source /PATH/TO/GNUASTRO/BUILD/bin/completion.bash.built





#######################################################################
############          Only for Fits (this program)         ############
#######################################################################

# Dealing with arguments: Fits can take any number of images, so don't
# suggest options
_gnuastro_autocomplete_astfits_arguments(){
    _gnuastro_autocomplete_compreply_files_certain fits "$argument"
}





# Fill option value (depends on option).
_gnuastro_autocomplete_astfits_option_value(){

    # Internal variables.
    local fits_file=""
    local given_hdu=""
    local given_file=""
    local wcs_coordsys=""

    # Keep this in the same order as the output of '--help', for options
    # with similar operations, keep the order within the '|'s.
    case "$option_name" in

        --hdu|--copy|--cut|--remove)
            _gnuastro_autocomplete_given_file fits ""
            _gnuastro_autocomplete_compreply_hdus \
                all "$given_file" "$current"
            ;;

        --outhdu)
            _gnuastro_autocomplete_given_file fits "--output"
            _gnuastro_autocomplete_compreply_hdus \
                all "$given_file" "$current"
            ;;

        --output)
            _gnuastro_autocomplete_compreply_files_certain fits "$current"
            ;;

        --tableformat)
            _gnuastro_autocomplete_compreply_tableformat "$current"
            ;;

        --delete|--datetosec)
            _gnuastro_autocomplete_given_file_and_hdu fits "" "--hdu"
            _gnuastro_autocomplete_compreply_keys "$given_file" \
                                                  "$given_hdu" "$current"
            ;;

        --keyvalue)
            _gnuastro_autocomplete_given_file_and_hdu fits "" "--hdu"
            _gnuastro_autocomplete_compreply_keys "$given_file" \
                                                  "$given_hdu" "$current" \
                                                  "yes"
            ;;

        --rename|--update)
            # Find the match.
            _gnuastro_autocomplete_given_file_and_hdu fits "" "--hdu"
            _gnuastro_autocomplete_compreply_keys "$given_file" \
                                                  "$given_hdu" "$current"

            # If there is the only one suggestion, then add a ',' (to let
            # the user easily type-in the new name.
            if [        x"${COMPREPLY[0]}" != x ] \
                   && [ x"${COMPREPLY[1]}"  = x ]; then
                COMPREPLY[0]="${COMPREPLY[0]},";
                compopt -o nospace
            fi
            ;;

        --wcscoordsys)
            _gnuastro_autocomplete_compreply_wcs_coordsys
            _gnuastro_autocomplete_compreply_from_string \
                "$wcs_coordsys" "$current"
            ;;

        --wcsdistortion)
            _gnuastro_autocomplete_compreply_from_string \
                "SIP TPV" "$current"
            ;;
    esac
}





_gnuastro_autocomplete_astfits(){

    # The installation directory of Gnuastro. The '/opt/local/bin' part will be
    # replaced automatically during 'make install', with the user's given
    # requested installation directory. If you are debugging, please
    # correct it yourself (usually to '/usr/local/bin', but don't commit
    # this particular change).
    local gnuastro_prefix="/opt/local/bin"

    # Basic initialization. The variables we want to remain inside this
    # function are given a 'local' here and set inside the 'initialize'
    # function. The variables are defined above the function that gives
    # them a value.
    local prev=""
    local current=""
    local argument=""
    _gnuastro_autocomplete_initialize

    # For a check
    #echo
    #echo "prev:     $prev"
    #echo "current:  $current"
    #echo "argument: $argument"

    # Extract the current mode (if the user is giving an argument, option
    # name, or option value). See the description above this function on
    # how the mode is set.
    local options_all=""
    local option_name=""
    local option_value=""
    local option_name_complete=0
    _gnuastro_autocomplete_mode

    # For a check
    #echo
    #echo "argument:             $argument"
    #echo "option_name:          $option_name"
    #echo "option_name_complete: $option_name_complete"
    #echo "option_value:         $option_value"

    # If 'option_name_complete==1', then we are busy filling in the option
    # value.
    if [ $option_name_complete = 1 ]; then
        _gnuastro_autocomplete_astfits_option_value

    # When 'option_name' is not empty (and not yet complete), we are busy
    # filling in the option name.
    elif [ x$option_name != x ]; then
        _gnuastro_autocomplete_compreply_options_all "$option_name"

    # In the case of "none-of-the-above", it is an argument.
    else
        _gnuastro_autocomplete_astfits_arguments
    fi
}





# Define the completion specification, or COMPSPEC: -o bashdefault: Use
# Bash default completions if nothing is found.  -F function: Use this
# 'function' to generate the given program's completion.
complete -o bashdefault -F _gnuastro_autocomplete_astfits astfits
# Bash autocompletion to Gnuastro's Table program. See the comments above
# 'bin/completion.bash.in' for more.
#
# Original author:
#     Pedram Ashofteh-Ardakani <pedramardakani@pm.me>
# Contributing author(s):
#     Mohammad Akhlaghi <mohammad@akhlaghi.org>
# Copyright (C) 2021-2023 Free Software Foundation, Inc.
#
# Gnuastro is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Gnuastro is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Gnuastro. If not, see <http://www.gnu.org/





# For debugging
#
# See the description in 'bin/completion.bash.in'.
#source /PATH/TO/GNUASTRO/SRC/bin/completion.bash.in
#source /PATH/TO/GNUASTRO/BUILD/bin/completion.bash.built





#######################################################################
############         Only for Table (this program)         ############
#######################################################################

# Dealing with arguments: Table only takes one argument/file. So if a table
# has been previously given on the command-line only print option names.
_gnuastro_autocomplete_asttable_arguments(){
    local given_file=""
    if _gnuastro_autocomplete_first_in_arguments table; then
        _gnuastro_autocomplete_compreply_options_all ""
    else
        _gnuastro_autocomplete_compreply_files_certain table "$argument"
    fi
}





# Fill option value (depends on option).
_gnuastro_autocomplete_asttable_option_value(){

    # Internal variables.
    local fits_file=""
    local given_hdu=""
    local given_file=""

    # Keep this in the same order as the output of '--help', for options
    # with similar operations, keep the order within the '|'s.
    case "$option_name" in

        # Options that take a columns from the main argument.
        --column|--noblank|--noblankend|--inpolygon|--outpolygon|--colmetadata|--equal|--notequal)

            # The '--column' and '--noblank' options can (and usually
            # will!) take more than one column name as value.
            local continuematch=""
            case "$option_name" in
                --column|--noblank|--noblankend) continuematch=yes;;
            esac

            # Find the suggestions.
            _gnuastro_autocomplete_given_file_and_hdu table "" --hdu
            _gnuastro_autocomplete_compreply_table_columns \
                "$given_file" "$given_hdu" "$current" "$continuematch"

            # These options take a column name as first value, and the user
            # should continue with other details. So when there is only one
            # match, we need to disable the extra space that is printed by
            # default and also add a ',' to prepare the user for entering
            # other points.
            case "$option_name" in
                --colmetadata|--equal|--notequal) compopt -o nospace;;
            esac
            ;;

        -C|--catcolumns)
            _gnuastro_autocomplete_given_file_and_hdu \
                table --catcolumnfile --catcolumnhdu
            _gnuastro_autocomplete_compreply_table_columns \
                "$given_file" "$given_hdu" "$current"
            ;;

        -h|--hdu)
            _gnuastro_autocomplete_given_file table ""
            _gnuastro_autocomplete_compreply_hdus \
                table "$given_file" "$current"
            ;;

        -L|--catcolumnfile)
            _gnuastro_autocomplete_compreply_files_certain table "$current"
            ;;

        --searchin)
            _gnuastro_autocomplete_compreply_searchin "$current"
            ;;

        -u|--catcolumnhdu)
            _gnuastro_autocomplete_given_file table --catcolumnfile
            _gnuastro_autocomplete_compreply_hdus \
                table "$given_file" "$current"
            ;;

        -w|--wcsfile)
            _gnuastro_autocomplete_compreply_files_certain image "$current"
            ;;

        -W|--wcshdu)
            _gnuastro_autocomplete_given_file image --wcsfile
            _gnuastro_autocomplete_compreply_hdus \
                image "$given_file" "$current"
            ;;

        --tableformat)
            _gnuastro_autocomplete_compreply_tableformat "$current"
            ;;

        --copy)
            ;;
    esac
}





_gnuastro_autocomplete_asttable(){

    # The installation directory of Gnuastro. The '/opt/local/bin' part will be
    # replaced automatically during 'make install', with the user's given
    # requested installation directory. If you are debugging, please
    # correct it yourself (usually to '/usr/local/bin', but don't commit
    # this particular change).
    local gnuastro_prefix="/opt/local/bin"

    # Basic initialization. The variables we want to remain inside this
    # function are given a 'local' here and set inside the 'initialize'
    # function. The variables are defined above the function that gives
    # them a value.
    local prev=""
    local current=""
    local argument=""
    _gnuastro_autocomplete_initialize

    # For a check
    #echo
    #echo "prev:     $prev"
    #echo "current:  $current"
    #echo "argument: $argument"

    # Extract the current mode (if the user is giving an argument, option
    # name, or option value). See the description above this function on
    # how the mode is set.
    local options_all=""
    local option_name=""
    local option_value=""
    local option_name_complete=0
    _gnuastro_autocomplete_mode

    # For a check
    #echo
    #echo "argument:             $argument"
    #echo "option_name:          $option_name"
    #echo "option_name_complete: $option_name_complete"
    #echo "option_value:         $option_value"

    # If 'option_name_complete==1', then we are busy filling in the option
    # value.
    if [ $option_name_complete = 1 ]; then
        _gnuastro_autocomplete_asttable_option_value

    # When 'option_name' is not empty (and not yet complete), we are busy
    # filling in the option name.
    elif [ x$option_name != x ]; then
        _gnuastro_autocomplete_compreply_options_all "$option_name"

    # In the case of "none-of-the-above", it is an argument.
    else
        _gnuastro_autocomplete_asttable_arguments
    fi
}





# Define the completion specification, or COMPSPEC: -o bashdefault: Use
# Bash default completions if nothing is found.  -F function: Use this
# 'function' to generate the given program's completion.
complete -o bashdefault -F _gnuastro_autocomplete_asttable asttable
