#compdef launchctl
# macOS launchd completion.

_launchctl_domains() {
    local uid=$EUID
    local -a domains=(
        'system:system services'
        "user/${uid}:services for the current user"
        "gui/${uid}:services in the current graphical session"
    )
    _describe -t domains 'launchd domain' domains
}

_launchctl_service_targets() {
    local uid=$EUID label
    local -a targets=()

    while IFS=$'\t' read -r _ _ label; do
        [[ -n $label ]] && targets+=("gui/${uid}/${label}")
    done < <(launchctl list 2>/dev/null | tail -n +2)

    if (( ${#targets} )); then
        _describe -t services 'launchd service target' targets
    else
        _message 'launchd service target'
    fi
}

_launchctl() {
    local context state state_descr line
    typeset -A opt_args

    local -a commands=(
        'bootstrap:register services or directories in a domain'
        'bootout:unregister services or directories from a domain'
        'enable:enable a service'
        'disable:disable a service'
        'kickstart:run or restart a service'
        'kill:send a signal to a service'
        'print:show a domain or service'
        'print-disabled:show persistent enable and disable overrides'
        'list:list loaded services'
        'start:start a legacy service by label'
        'stop:stop a legacy service by label'
        'remove:remove a legacy service by label'
        'load:load legacy plist files'
        'unload:unload legacy plist files'
        'setenv:set an environment variable'
        'unsetenv:unset an environment variable'
        'getenv:get an environment variable'
        'limit:view or change resource limits'
        'config:set persistent launchd configuration'
        'dumpstate:dump launchd state'
        'reboot:reboot a launchd domain or the system'
        'version:show launchd version'
        'help:show launchctl help'
    )

    _arguments -C \
        '1:command:->command' \
        '*::argument:->args'

    case $state in
        command)
            _describe -t commands 'launchctl command' commands
            ;;
        args)
            case $words[2] in
                bootstrap)
                    if (( CURRENT == 3 )); then
                        _launchctl_domains
                    else
                        _files -g '*.plist(-.)'
                    fi
                    ;;
                bootout)
                    if (( CURRENT == 3 )); then
                        _launchctl_domains
                        _launchctl_service_targets
                    else
                        _files -g '*.plist(-.)'
                    fi
                    ;;
                enable|disable|kickstart)
                    _launchctl_service_targets
                    ;;
                print)
                    _launchctl_domains
                    _launchctl_service_targets
                    ;;
                print-disabled)
                    _launchctl_domains
                    ;;
                load|unload)
                    _files -g '*.plist(-.)'
                    ;;
                start|stop|remove)
                    local -a labels
                    labels=(${${(f)"$(launchctl list 2>/dev/null)"}[2,-1]##*$'\t'})
                    _describe -t services 'service label' labels
                    ;;
                kill)
                    if (( CURRENT == 3 )); then
                        _signals
                    else
                        _launchctl_service_targets
                    fi
                    ;;
                setenv)
                    if (( CURRENT == 3 )); then
                        _parameters
                    else
                        _message 'value'
                    fi
                    ;;
                getenv|unsetenv)
                    _parameters
                    ;;
                *)
                    _message 'argument'
                    ;;
            esac
            ;;
    esac
}

_launchctl "$@"
