# bash completion for ug and ugrep
# recommended: add the following lines to ~/.inputrc
# set colored-stats on
# set colored-completion-prefix on

if ! declare -F _init_completion >/dev/null 2>&1; then
    return
fi

_comp_cmd_ugrep()
{
    local IFS=$' \t\n'
    local cur prev words cword
    _init_completion -s || return

    if [[ $cword -eq 1 && "${words[1]}" == "" ]]; then
        _comp_cmd_ugrep_usage
        return
    fi

    local i
    for i in "${!words[@]}"; do
        if [ "${words[$i]}" = "--" ]; then
            if [ $cword -gt $i ]; then
                _filedir
                return
            fi
            words=( "${words[@]:0:$i}" )
            break
        fi
    done

    case $prev in
    -D)
        # complete devices parameter
        COMPREPLY=( $(compgen -W "read skip" -- $cur) )
        compopt +o nospace
        return
        ;;
    -d)
        # complete directories parameter
        COMPREPLY=( $(compgen -W "read recurse skip" -- $cur) )
        compopt +o nospace
        return
        ;;
    -t)
        # complete a file type by generating the option values
        _comp_cmd_ugrep_file_type
        return
        ;;
    -Z)
        # suggest fuzzy parameters
        COMPREPLY=( $(compgen -W "1 +1 -1 ~1 +-1 +~1 +-~1 -~1 best1 best+1 best-1 best~1 best+-1 best+~1 best+-~1 best-~1" -- $cur) )
        return
        ;;
    esac

    case "${words[$cword]}" in
    --binary-files=*)
        # complete binary-files parameter
        COMPREPLY=( $(compgen -W "binary hex text with-hex without-match" -- $cur) )
        compopt +o nospace
        return
        ;;
    --color=* | --colour=*)
        # complete color and pretty parameter
        COMPREPLY=( $(compgen -W "always auto never" -- $cur) )
        compopt +o nospace
        return
        ;;
    --colors=* | --colours=* | --file-magic=*)
        # add an opening quote to quote the long option argument when recommended
        COMPREPLY=( "'" )
        return
        ;;
    --devices=*)
        # complete devices parameter
        COMPREPLY=( $(compgen -W "read skip" -- $cur) )
        compopt +o nospace
        return
        ;;
    --directories=*)
        # complete directories parameter
        COMPREPLY=( $(compgen -W "read recurse skip" -- $cur) )
        compopt +o nospace
        return
        ;;
    --encoding=*)
        # complete encoding format by generating the option values
        _comp_cmd_ugrep_encoding
        return
        ;;
    --hexdump=*)
        # suggest hexdump parameters
        COMPREPLY=( $(compgen -W "1a 2a 4ah 6ah 8ah 1aC1 2aC1 4ahC1 6ahC1 8ahC1" -- $cur) )
        return
        ;;
    --hyperlink=)
        # suggest hyperlinking line and column numbers
        COMPREPLY=( "+" )
        compopt +o nospace
        return
        ;;
    --sort=*)
        # complete sort key
        COMPREPLY=( $(compgen -W "best changed created name size used rbest rchanged rcreated rname rsize rused" -- $cur) )
        compopt +o nospace
        return
        ;;
    --file-type=*)
        # complete a file type by generating the option values
        _comp_cmd_ugrep_file_type
        return
        ;;
    --fuzzy=*)
        # suggest fuzzy parameters
        COMPREPLY=( $(compgen -W "1 +1 -1 ~1 +-1 +~1 +-~1 -~1 best1 best+1 best-1 best~1 best+-1 best+~1 best+-~1 best-~1" -- $cur) )
        return
        ;;
    esac

    case $cur in
    -A | -B | -C)
        # suggest a context
        COMPREPLY=( $(compgen -W "-A3 -B3 -C3" -- $cur) )
        return
        ;;
    -D*)
        # complete devices parameter
        COMPREPLY=( $(compgen -W "-Dread -Dskip" -- $cur) )
        compopt +o nospace
        return
        ;;
    -d*)
        # complete directories parameter
        COMPREPLY=( $(compgen -W "-dread -drecurse -dskip" -- $cur) )
        compopt +o nospace
        return
        ;;
    -e | -g | -M | -N | --and | --andnot | --not)
        # add an opening quote to quote the option argument when recommended
        COMPREPLY=( "${cur} '" )
        return
        ;;
    --colors | --colours)
        # add an opening quote to quote color arguments (recommended)
        COMPREPLY=( "${cur}='" )
        return
        ;;
    -K)
        # suggest a line range
        COMPREPLY=( "-K1,10" )
        return
        ;;
    -m*)
        # suggest a match count range
        COMPREPLY=( $(compgen -W "-m1 -m1, -m1,10" -- $cur) )
        return
        ;;
    -t*)
        # complete a file type by generating the option values
        _comp_cmd_ugrep_file_type_t
        return
        ;;
    -Z*)
        # suggest fuzzy parameters
        COMPREPLY=( $(compgen -W "-Z -Z1 -Z+1 -Z-1 -Z~1 -Z+-1 -Z+~1 -Z+-~1 -Z-~1 -Zbest1 -Zbest+1 -Zbest-1 -Zbest~1 -Zbest+-1 -Zbest+~1 -Zbest+-~1 -Zbest-~1" -- $cur) )
        return
        ;;
    --*)
        # complete long options by generating them
        COMPREPLY=( $(compgen -W "$(_parse_help _comp_cmd_ugrep_help)" -- $cur) )
        if [[ ! "${COMPREPLY[@]}" =~ "=" ]]; then
            # add space after long options that do not end with a =
            compopt +o nospace
        fi
        return
        ;;
    -?*)
        # add space after short option(s)
        COMPREPLY=( $cur )
        compopt +o nospace
        return
        ;;
    -)
        _comp_cmd_ugrep_usage
        return
        ;;
    esac

    _filedir
} &&
    complete -o nospace -F _comp_cmd_ugrep ug ug+ ugrep ugrep+

_comp_cmd_ugrep_usage()
{
    local -a usage=()
    local line i=0
    case $COMP_TYPE in
    33|63|64)
        # generate list of options, concat the first sentence to them
        usage[0]="Usage:"
        while read -r line; do
            # truncate to screen width
            (( ++i ))
            usage[$i]=${line:0:$COLUMNS}
        done < <(_comp_cmd_ugrep_help)
        ;;
    37)
        # generate list of options
        while read -r line; do
            # keep initial option only, remove the rest
            usage[$i]=${line%%[[, ]*}
            (( ++i ))
        done < <(_comp_cmd_ugrep_help)
        ;;
    esac
    COMPREPLY=( "${usage[@]}" )
    compopt -o nosort
}

_comp_cmd_ugrep_help()
{
cat <<'END'
-A NUM, --after-context=NUM Output NUM lines of trailing context after matching lines.
-a, --text Process a binary file as if it were text.
--all, -@ Search all files except hidden: cancel previous file and directory search restrictions and cancel --ignore-binary and --ignore-files when specified.
--and [-e] PATTERN Specify additional PATTERN that must match.
--andnot [-e] PATTERN Combines --and --not.
-B NUM, --before-context=NUM Output NUM lines of leading context before matching lines.
-b, --byte-offset The offset in bytes of a pattern match is displayed in front of the respective matched line.
--binary-files=TYPE Controls searching and reporting pattern matches in binary files.
--bool, -%, -%% Specifies Boolean query patterns.
--break Adds a line break between results from different files.
-C NUM, --context=NUM Output NUM lines of leading and trailing context surrounding each matching line.
-c, --count Only a count of selected lines is written to standard output.
--color[=WHEN], --colour[=WHEN] Mark up the matching text with the colors specified with option --colors or the GREP_COLOR or GREP_COLORS environment variable.
--colors=COLORS, --colours=COLORS Use COLORS to mark up text.
--config[=FILE], ---[FILE] Use configuration FILE.
--no-config Do not automatically load the default .ugrep configuration file.
--no-confirm Do not confirm actions in -Q query TUI.
--cpp Output file matches in C++.
--csv Output file matches in CSV.
-D ACTION, --devices=ACTION If an input file is a device, FIFO or socket, use ACTION to process it.
-d ACTION, --directories=ACTION If an input file is a directory, use ACTION to process it.
--delay=DELAY Set the default -Q key response delay.
--depth=[MIN,][MAX], -1, -2, -3, ... -9, -10, -11, ... Restrict recursive searches from MIN to MAX directory levels deep, where -1 (--depth=1) searches the specified path without recursing into subdirectories.
--dotall Dot . in regular expressions matches anything, including newline.
-E, --extended-regexp Interpret patterns as extended regular expressions (EREs).
-e PATTERN, --regexp=PATTERN Specify a PATTERN to search the input.
--encoding=ENCODING The encoding format of the input.
--exclude=GLOB Exclude files whose name matches GLOB, same as -g ^GLOB.
--exclude-dir=GLOB Exclude directories whose name matches GLOB from recursive searches, same as -g ^GLOB/.
--exclude-from=FILE Read the globs from FILE and skip files and directories whose name matches one or more globs.
--exclude-fs=MOUNTS Exclude file systems specified by MOUNTS from recursive searches.
-F, --fixed-strings Interpret pattern as a set of fixed strings, separated by newlines, any of which is to be matched.
-f FILE, --file=FILE Read newline-separated patterns from FILE.
--filter=COMMANDS Filter files through the specified COMMANDS first before searching.
--filter-magic-label=[+]LABEL:MAGIC Associate LABEL with files whose signature "magic bytes" match the MAGIC regex pattern.
--format=FORMAT Output FORMAT-formatted matches.
--free-space Spacing (blanks and tabs) in regular expressions are ignored.
--from=FILE Read additional pathnames of files to search from FILE.
-G, --basic-regexp Interpret patterns as basic regular expressions (BREs).
-g GLOBS, --glob=GLOBS, --iglob=GLOBS Only search files whose name matches the specified comma-separated list of GLOBS, same as --include=glob for each glob in GLOBS.
--glob-ignore-case Perform case-insensitive glob matching in general.
--group-separator[=SEP] Use SEP as a group separator for context options -A, -B and -C.
--no-group-separator Removes the group separator line from the output for context options -A, -B and -C.
-H, --with-filename Always print the filename with output lines.
-h, --no-filename Never print filenames with output lines.
--heading, -+ Group matches per file.
--help [WHAT], -? [WHAT] Display a help message on options related to WHAT when specified.
--hexdump[=[1-8][a][bch][A[NUM]][B[NUM]][C[NUM]]] Output matches in 1 to 8 columns of 8 hexadecimal octets.
--hidden, -. Search hidden files and directories (enabled by default in grep compatibility mode).
--hyperlink[=[PREFIX][+]] Hyperlinks are enabled for file names when colors are enabled.
-I, --ignore-binary Ignore matches in binary files.
-i, --ignore-case Perform case insensitive matching.
--ignore-files[=FILE] Ignore files and directories matching the globs in each FILE that is encountered in recursive searches.
--no-ignore-files Do not ignore files, i.e. cancel --ignore-files when specified.
--include=GLOB Only search files whose name matches GLOB, same as -g GLOB.
--include-dir=GLOB Only directories whose name matches GLOB are included in recursive searches, same as -g GLOB/.
--include-from=FILE Read the globs from FILE and search only files and directories whose name matches one or more globs.
--include-fs=MOUNTS Only file systems specified by MOUNTS are included in recursive searches.
--index Perform fast index-based recursive search.
-J NUM, --jobs=NUM Specifies the number of threads spawned to search files.
-j, --smart-case Perform case insensitive matching, unless a pattern is specified with a literal upper case letter.
--json Output file matches in JSON.
-K [MIN,][MAX], --range=[MIN,][MAX], --min-line=MIN, --max-line=MAX Start searching at line MIN, stop at line MAX when specified.
-k, --column-number The column number of a pattern match is displayed in front of the respective matched line, starting at column 1.
-L, --files-without-match Only the names of files not containing selected lines are written to standard output.
-l, --files-with-matches Only the names of files containing selected lines are written to standard output.
--label=LABEL Displays the LABEL value when input is read from standard input where a file name would normally be printed in the output.
--line-buffered Force output to be line buffered instead of block buffered.
--lines Boolean line matching mode for option --bool, the default mode.
-M MAGIC, --file-magic=MAGIC Only search files matching the magic signature pattern MAGIC.
-m [MIN,][MAX], --min-count=MIN, --max-count=MAX Require MIN matches, stop after MAX matches when specified.
--match Match all input.
--max-files=NUM Restrict the number of files matched to NUM.
--mmap[=MAX] Use memory maps to search files.
-N PATTERN, --neg-regexp=PATTERN Specify a negative PATTERN to reject specific -e PATTERN matches with a counter pattern.
-n, --line-number Each output line is preceded by its relative line number in the file, starting at line 1.
--not [-e] PATTERN Specifies that PATTERN should not match.
--null, -0 Output a zero byte after the file name.
--null-data, -00 Input and output are treated as sequences of lines with each line terminated by a zero byte instead of a newline; effectively swaps NUL with LF in the input and the output.
-O EXTENSIONS, --file-extension=EXTENSIONS Only search files whose filename extensions match the specified comma-separated list of EXTENSIONS, same as -g *.ext for each
-o, --only-matching Only the matching part of a pattern match is output.
--only-line-number Only the line number of a matching line is output.
--files, -%% Boolean file matching mode, the opposite of --lines.
-P, --perl-regexp Interpret PATTERN as a Perl regular expression using PCRE2.
-p, --no-dereference If -R or -r is specified, do not follow symbolic links, even when symbolic links are specified on the command line.
--pager[=COMMAND] When output is sent to the terminal, uses COMMAND to page through the output.
--pretty[=WHEN] When output is sent to a terminal, enables --color, --heading, -n, --sort, --tree and -T when not explicitly disabled.
-Q[=DELAY], --query[=DELAY] Query mode: start a TUI to perform interactive searches.
-q, --quiet, --silent Quiet mode: suppress all output.
-R, --dereference-recursive Recursively read all files under each directory, following symbolic links to files and directories, unlike -r.
-r, --recursive Recursively read all files under each directory, following symbolic links only if they are on the command line.
--replace=FORMAT Replace matching patterns in the output by FORMAT with % fields.
-S, --dereference-files When -r is specified, follow symbolic links to files, but not to directories.
-s, --no-messages Silent mode: nonexistent and unreadable files are ignored and their error messages and warnings are suppressed.
--save-config[=FILE] [OPTIONS] Save configuration FILE to include OPTIONS.
--separator[=SEP], --context-separator=SEP Use SEP as field separator between file name, line number, column number, byte offset and the matched line.
--split Split the -Q query TUI screen on startup.
--sort[=KEY] Displays matching files in the order specified by KEY in recursive searches.
--stats Output statistics on the number of files and directories searched and the inclusion and exclusion constraints applied.
-T, --initial-tab Add a tab space to separate the file name, line number, column number and byte offset with the matched line.
-t TYPES, --file-type=TYPES Search only files associated with TYPES, a comma-separated list of file types.
--tabs[=NUM] Set the tab size to NUM to expand tabs for option -k.
--tag[=TAG[,END]] Disables colors to mark up matches with TAG.
--tree, -^ Output directories with matching files in a tree-like format for option -c or --count, -l or --files-with-matches, -L or --files-without-match.
-U, --ascii, --binary Disables Unicode matching for ASCII and binary matching.
-u, --ungroup Do not group multiple pattern matches on the same matched line.
-V, --version Display version with linked libraries and exit.
-v, --invert-match Selected lines are those not matching any of the specified patterns.
--view[=COMMAND] Use COMMAND to view/edit a file in -Q query TUI by pressing CTRL-Y.
-W, --with-hex Output binary matches in hexadecimal, leaving text matches alone.
-w, --word-regexp The PATTERN is searched for as a word, such that the matching text is preceded by a non-word character and is followed by a non-word character.
--width[=NUM] Truncate the output to NUM visible characters per line.
-X, --hex Output matches and matching lines in hexadecimal.
-x, --line-regexp Select only those matches that exactly match the whole line, as if the patterns are surrounded by ^ and $.
--xml Output file matches in XML.
-Y, --empty Empty-matching patterns match all lines.
-y, --any-line, --passthru Any line is output (passthru).
-Z[best][+-~][MAX], --fuzzy[=[best][+-~][MAX]] Fuzzy mode: report approximate pattern matches within MAX errors.
-z, --decompress Search compressed files and archives.
--zmax=NUM When used with option -z or --decompress, searches the contents of compressed files and archives stored within archives by up to NUM expansion stages.
END
}

_comp_cmd_ugrep_file_type()
{
    COMPREPLY=( $(compgen -W "actionscript ada adoc asm asp aspx autoconf automake awk Awk basic batch bison c c++ clojure cpp csharp css csv dart Dart delphi elisp elixir erlang fortran gif Gif go groovy gsp haskell html jade java jpeg Jpeg js json jsp julia kotlin less lex lisp lua m4 make markdown matlab node Node objc objc++ ocaml parrot pascal pdf Pdf perl Perl php Php png Png prolog python Python r rpm Rpm rst rtf Rtf ruby Ruby rust scala scheme seed7 shell Shell smalltalk sql svg swift tcl tex text tiff Tiff tt typescript verilog vhdl vim xml Xml yacc yaml zig" -- $cur) )
    compopt +o nospace
}

_comp_cmd_ugrep_file_type_t()
{
    COMPREPLY=( $(compgen -W "-tactionscript -tada -tadoc -tasm -tasp -taspx -tautoconf -tautomake -tawk -tAwk -tbasic -tbatch -tbison -tc -tc++ -tclojure -tcpp -tcsharp -tcss -tcsv -tdart -tDart -tdelphi -telisp -telixir -terlang -tfortran -tgif -tGif -tgo -tgroovy -tgsp -thaskell -thtml -tjade -tjava -tjpeg -tJpeg -tjs -tjson -tjsp -tjulia -tkotlin -tless -tlex -tlisp -tlua -tm4 -tmake -tmarkdown -tmatlab -tnode -tNode -tobjc -tobjc++ -tocaml -tparrot -tpascal -tpdf -tPdf -tperl -tPerl -tphp -tPhp -tpng -tPng -tprolog -tpython -tPython -tr -trpm -tRpm -trst -trtf -tRtf -truby -tRuby -trust -tscala -tscheme -tseed7 -tshell -tShell -tsmalltalk -tsql -tsvg -tswift -ttcl -ttex -ttext -ttiff -tTiff -ttt -ttypescript -tverilog -tvhdl -tvim -txml -tXml -tyacc -tyaml -tzig" -- $cur) )
    compopt +o nospace
}

_comp_cmd_ugrep_encoding()
{
    COMPREPLY=( $(compgen -W "binary ASCII UTF-8 UTF-16 UTF-16BE UTF-16LE UTF-32 UTF-32BE UTF-32LE LATIN1 ISO-8859-1 ISO-8859-2 ISO-8859-3 ISO-8859-4 ISO-8859-5 ISO-8859-6 ISO-8859-7 ISO-8859-8 ISO-8859-9 ISO-8859-10 ISO-8859-11 ISO-8859-13 ISO-8859-14 ISO-8859-15 ISO-8859-16 MAC MACROMAN EBCDIC CP437 CP850 CP858 CP1250 CP1251 CP1252 CP1253 CP1254 CP1255 CP1256 CP1257 CP1258 KOI8-R KOI8-U KOI8-RU null-data" -- $cur) )
    compopt +o nospace
}

