# (C) 2010 magicant

# Completion script for the "diff" command.
# Supports POSIX 2008, GNU diffutils 3.0, OpenBSD 4.8, SunOS 5.10, HP-UX 11i v3.

function completion/diff {

        case $("${WORDS[1]}" --version 2>/dev/null) in
                (*'diffutils'*) typeset type=GNU ;;
                (*)             typeset type="$(uname 2>/dev/null)" ;;
        esac
        case $type in
                (GNU) typeset long=true ;;
                (*)   typeset long= ;;
        esac

        typeset OPTIONS POSIXOPTIONS ADDOPTIONS ARGOPT PREFIX
        POSIXOPTIONS=( #>#
        "b ${long:+--ignore-space-change}; ignore changes in amount of whitespaces only"
        "C: ${long:+--context::}; output in copied context format with the specified number of context lines"
        "c; like -C 3"
        "e ${long:+--ed}; output in ed script format"
        "f ${long:+--forward-ed}; output in forward ed format"
        "r ${long:+--recursive}; recursively compare directories"
        "U: ${long:+--unified::}; output in unified context format with the specified number of context lines"
        "u; like -U 3"
        ) #<#

        ADDOPTIONS=()
        case $type in (GNU|*BSD|SunOS|HP-UX)
                ADDOPTIONS=("$ADDOPTIONS" #>#
                "D: ${long:+--ifdef:}; output in merged #ifdef format with the specified conditional macro name"
                "i ${long:+--ignore-case}; case-insensitive comparison"
                "l ${long:+--paginate}; output in long format thru the pr command"
                "n ${long:+--rcs}; output in rcsdiff format"
                "S: ${long:+--starting-file:}; restart directory comparison from the specified file"
                "s ${long:+--report-identical-files}; explicitly report identical files"
                "t ${long:+--expand-tabs}; expand tabs in output"
                "w ${long:+--ignore-all-space}; ignore whitespaces in comparison"
                "X: ${long:+--exclude-from:}; skip files whose names match a pattern in the specified file"
                "x: ${long:+--exclude:}; skip files whose names match the specified pattern"
                ) #<#
        esac
        case $type in (GNU|*BSD)
                ADDOPTIONS=("$ADDOPTIONS" #>#
                "a ${long:+--text}; assume all files are text"
                "d ${long:+--minimal}; make the output as small as possible"
                "I: ${long:+--ignore-matching-lines:}; don't output changes matching the specified regular expression"
                "L: ${long:+--label:}; specify the label used instead of the filename"
                "N ${long:+--new-file}; treat absent files as empty"
                "P ${long:+--unidirectional-new-file}; treat absent from-files as empty"
                "p ${long:+--show-c-function}; print the name of C function containing changes"
                "q ${long:+--brief}; just print the names of differing files"
                "T ${long:+--initial-tab}; prepend a tab to each output line to align text"
                ) #<#
        esac
        case $type in (GNU)
                ADDOPTIONS=("$ADDOPTIONS" #>#
                "B --ignore-blank-lines; ignore insertion/deletion of empty lines"
                "--binary; don't convert CR-LF into LF"
                "--changed-group-format:; specify the format of differing lines"
                "E --ignore-tab-expansion; ignore changes due to tab expansion"
                "F: --show-function-line:; specify a regular expression to find the name of the function containing the change"
                "--from-file:; specify a file to compare with each operand"
                "--horizon-lines:; don't discard the specified number of lines in the common prefix/suffix"
                "--ignore-file-name-case; case-insensitive filename comparison"
                "--left-column; print only the left column of two common lines (with -y)"
                "--line-format:; specify the --{old,new,unchanged}-line-format options at once"
                "--new-group-format:; specify the format of lines only in the second file"
                "--new-line-format:; specify the format of a line only in the second file"
                "--no-ignore-file-name-case; case-sensitive filename comparison"
                "--normal; output in normal format"
                "--old-group-format:; specify the format of lines only in the first file"
                "--old-line-format:; specify the format of a line only in the first file"
                "--speed-large-files; fast, half-hearted comparison"
                "--strip-trailing-cr; ignore carriage returns at the end of lines"
                "--suppress-blank-empty; don't end a line with a space unless there was one in the text"
                "--suppress-common-lines; don't print common lines (with -y)"
                "--tabsize:; specify how many spaces a tab stands for"
                "--to-file:; specify a file to compare each operand with"
                "--unchanged-group-format:; specify the format of lines common to the both files"
                "--unchanged-line-format:; specify the format of a line common to the both files"
                "v --version; print version info"
                "W: --width:; specify the max output width (with -y)"
                "y --side-by-side; output in side-by-side format"
                "--help"
                ) #<#
        esac
        case $type in (SunOS|HP-UX)
                ADDOPTIONS=("$ADDOPTIONS" #>#
                "h; fast, half-hearted comparison"
                ) #<#
        esac

        OPTIONS=("$POSIXOPTIONS" "$ADDOPTIONS")
        unset POSIXOPTIONS ADDOPTIONS

        command -f completion//parseoptions ${long:+-es}
        case $ARGOPT in
        (-)
                command -f completion//completeoptions
                ;;
        ([CUW]|--context|--unified|--horizon-lines|--tabsize|--width)
                ;;
        (D|--ifdef)
                if [ -r tags ]; then
                        complete -P "$PREFIX" -R "!_TAG_*" -- \
                                $(cut -f 1 tags 2>/dev/null)
                fi
                ;;
        (--*line-format)
                command -f completion/diff::line
                ;;
        (--*group-format)
                command -f completion/diff::group
                ;;
        (*)
                complete -P "$PREFIX" -f
                ;;
        esac

}

function completion/diff::line {

        typeset word="${TARGETWORD#"$PREFIX"}"
        word=${word//%%}
        case $word in (*%|*%[doxX])
                PREFIX=${TARGETWORD%\%*} #>>#
                complete -T -P "$PREFIX" -D "line contents, without newline" '%l'
                complete -T -P "$PREFIX" -D "line contents, with newline" '%L'
                complete -T -P "$PREFIX" -D "escape a following character enclosed in single-quotes" '%c'
                complete -T -P "$PREFIX" -D "line number in decimal" '%dn'
                complete -T -P "$PREFIX" -D "line number in octal" '%on'
                complete -T -P "$PREFIX" -D "line number in hexadecimal, lowercase" '%xn'
                complete -T -P "$PREFIX" -D "line number in hexadecimal, uppercase" '%Xn'
                complete -T -P "$PREFIX" -D "%" '%%'
                return 0 #<<#
                ;;
        esac

}

function completion/diff::group {

        typeset word="${TARGETWORD#"$PREFIX"}"
        word=${word//%%}
        case $word in
        (*%[doxX])
                PREFIX=${TARGETWORD%\%?}
                word=${TARGETWORD#"$PREFIX"} #>>#
                complete -T -P "$PREFIX" -D "line number just before the group in the first file" "${word}e"
                complete -T -P "$PREFIX" -D "line number just before the group in the second file" "${word}E"
                complete -T -P "$PREFIX" -D "line number of the first line in the group in the first file" "${word}f"
                complete -T -P "$PREFIX" -D "line number of the first line in the group in the second file" "${word}F"
                complete -T -P "$PREFIX" -D "line number of the last line in the group in the first file" "${word}l"
                complete -T -P "$PREFIX" -D "line number of the last line in the group in the second file" "${word}L"
                complete -T -P "$PREFIX" -D "line number just after the group in the first file" "${word}m"
                complete -T -P "$PREFIX" -D "line number just after the group in the second file" "${word}M"
                complete -T -P "$PREFIX" -D "number of lines in the group in the first file" "${word}n"
                complete -T -P "$PREFIX" -D "number of lines in the group in the second file" "${word}N"
                return 0 #<<#
                ;;
        (*%)
                PREFIX=${TARGETWORD%\%} #>>#
                complete -T -P "$PREFIX" -D "lines from the first file" '%<'
                complete -T -P "$PREFIX" -D "lines from the second file" '%>'
                complete -T -P "$PREFIX" -D "lines common to the both files" '%='
                complete -T -P "$PREFIX" -D "escape a following character enclosed in single-quotes" '%c'
                complete -T -P "$PREFIX" -D "format a decimal number" '%d'
                complete -T -P "$PREFIX" -D "format an octal number" '%o'
                complete -T -P "$PREFIX" -D "format a hexadecimal number in lowercase" '%x'
                complete -T -P "$PREFIX" -D "format a hexadecimal number in uppercase" '%X'
                complete -T -P "$PREFIX" -D "conditional expression" '%('
                complete -T -P "$PREFIX" -D "%" '%%'
                return 0 #<<#
                ;;
        esac

        return 1

}


# vim: set ft=sh ts=8 sts=8 sw=8 et:
