# bash completion for xrandr                               -*- shell-script -*-

_comp_cmd_xrandr_outputs()
{
    "$1" -q 2>/dev/null | awk '/connected/ {print $1}'
}

_comp_cmd_xrandr_monitors()
{
    "$1" --listmonitors 2>/dev/null |
        command sed -ne 's/.* [0-9]*: [+\*]*\([^ ]*\).*/\1/p'
}

_comp_cmd_xrandr_providers()
{
    "$1" --listproviders 2>/dev/null |
        command sed -ne "s/.*cap:.*$2.* name:\([^ ]*\).*/\1/p"
}

_comp_cmd_xrandr_modes()
{
    "$1" -q 2>/dev/null | command sed \
        -e "1,/^$2 / d" \
        -e '/connected/,$ d' \
        -e '/^[[:space:]]*h: / d' \
        -e '/^[[:space:]]*v: / d' \
        -e 's/\([^[:space:]]\)[[:space:]].*/\1/'
}

_comp_cmd_xrandr_all_modes()
{
    "$1" -q 2>/dev/null | command sed \
        -e '/^[^[:space:]].*/ d' \
        -e '/^[[:space:]]*h: / d' \
        -e '/^[[:space:]]*v: / d' \
        -e 's/[[:space:]]*\([^[:space:]]*\)[[:space:]].*/\1/'
}

_comp_cmd_xrandr_help()
{
    "$1" --help 2>/dev/null
}

_xrandr()
{
    local cur prev words cword
    _init_completion || return

    local i output
    for ((i = cword - 1; i > 0; i--)); do
        if [[ ${words[i]} == --output ]]; then
            output=${words[i + 1]}
            break
        fi
    done

    case "$prev" in
        -display | -d | -s | --size | -r | --rate | --refresh | --screen | \
            --fb | --fbmm | --pos | --set | --scale | --transform | --crtc | \
            --panning | --gamma | --newmode | --rmmode | --setmonitor)
            return
            ;;
        --output | --addmode | --delmode | --dpi)
            local outputs=$(_comp_cmd_xrandr_outputs "$1")
            COMPREPLY=($(compgen -W "$outputs" -- "$cur"))
            return
            ;;
        --left-of | --right-of | --above | --below | --same-as)
            if [[ -v output ]]; then
                local outputs=$(_comp_cmd_xrandr_outputs "$1")
                COMPREPLY=($(compgen -W "$outputs" -- "$cur"))
            fi
            return
            ;;
        --mode)
            if [[ -v output ]]; then
                local modes=$(_comp_cmd_xrandr_modes "$1" "$output")
                COMPREPLY=($(compgen -W "$modes" -- "$cur"))
            fi
            return
            ;;
        -o | --orientation)
            COMPREPLY=($(
                compgen -W 'normal inverted left right 0 1 2 3' -- "$cur"
            ))
            return
            ;;
        --reflect)
            if [[ -v output ]]; then
                COMPREPLY=($(compgen -W 'normal x y xy' -- "$cur"))
            fi
            return
            ;;
        --rotate)
            if [[ -v output ]]; then
                COMPREPLY=($(compgen -W 'normal inverted left right' -- "$cur"))
            fi
            return
            ;;
        --filter)
            if [[ -v output ]]; then
                COMPREPLY=($(compgen -W 'bilinear nearest' -- "$cur"))
            fi
            return
            ;;
        --setprovideroutputsource)
            local providers=$(_comp_cmd_xrandr_providers "$1" "Sink Output")
            COMPREPLY=($(compgen -W "$providers" -- "$cur"))
            return
            ;;
        --setprovideroffloadsink)
            local providers=$(_comp_cmd_xrandr_providers "$1" "Source Offload")
            COMPREPLY=($(compgen -W "$providers" -- "$cur"))
            return
            ;;
        --delmonitor)
            local monitors=$(_comp_cmd_xrandr_monitors "$1")
            COMPREPLY=($(compgen -W "$monitors" -- "$cur"))
            return
            ;;
    esac

    # second arguments
    if ((cword >= 2)); then
        case "${words[cword - 2]}" in
            --set)
                return
                ;;
            --addmode)
                local modes=$(_comp_cmd_xrandr_all_modes "$1")
                COMPREPLY=($(compgen -W "$modes" -- "$cur"))
                return
                ;;
            --delmode)
                local modes=$(_comp_cmd_xrandr_modes "$1" "${words[cword - 1]}")
                COMPREPLY=($(compgen -W "$modes" -- "$cur"))
                return
                ;;
            --setmonitor)
                COMPREPLY=($(compgen -W 'auto' -- "$cur"))
                return
                ;;
            --setprovideroutputsource)
                local providers=$(
                    _comp_cmd_xrandr_providers "$1" "Source Output"
                )
                COMPREPLY=($(compgen -W "0x0 $providers" -- "$cur"))
                return
                ;;
            --setprovideroffloadsink)
                local providers=$(
                    _comp_cmd_xrandr_providers "$1" "Sink Offload"
                )
                COMPREPLY=($(compgen -W "0x0 $providers" -- "$cur"))
                return
                ;;
        esac
    fi

    # third arguments
    if ((cword >= 3)); then
        case "${words[cword - 3]}" in
            --setmonitor)
                local outputs=$(_comp_cmd_xrandr_outputs "$1")
                COMPREPLY=($(compgen -W "none $outputs" -- "$cur"))
                # TODO: the third argument is actually a comma-separated list
                return
                ;;
        esac
    fi

    local options
    if [[ -v output ]]; then
        options=$(
            _comp_cmd_xrandr_help "$1" |
                command sed -e 's/ or /\n  /g' -e 's/<[^>]*>]//g' |
                _parse_help -
        )
    else
        # if no output is specified, remove per-output options
        options=$(
            _comp_cmd_xrandr_help "$1" |
                command sed -e '/^  -/!d' -e 's/ or /\n  /g' \
                    -e 's/<[^>]*>]//g' | _parse_help -
        )
    fi

    COMPREPLY=($(compgen -W "$options" -- "$cur"))
} &&
    complete -F _xrandr xrandr

# ex: filetype=sh
