
source $SCRIPT_DIR/../modules/completion

function _cmd($ctx : Module, $t : [String], $c : Int) : Candidates? {
    if $t.size() == 1 || $c == 1{
        var actions = case $t[0] {
            'command' => ['-A', 'builtin', '-A', 'external']
            'exec' => ['-A', 'external']
            else => ['-A', 'command']
        }

        var prefix = $t.size() == 1 ? "" : $t.peek()
        if $prefix.contains('/') {
            $actions.add('-A').add('exec')
        }
        if $prefix.startsWith('~') {
            $actions.add('-A').add('tilde')
        }
        complete -q -m $ctx $actions $prefix
        return $COMPREPLY
    } else {
        $t.shift()
        return $compDelegate($ctx, $t, $c - 1)
    }
}

_extract_sub() {
    for $line in $STDIN {
        var matched = $/^      ([-a-z]+) +.+/.match($line)
        if let m = $matched {
            echo ${$m.group(1)!}
        }
    }
}

function _shctl($ctx : Module, $t : [String], $c : Int) : Candidates {
    if $c == 1 {
        var p = ""
        if $c < $t.size() {
            $p = $t.peek()
        }
        var ret : Candidates
        for line in <(help shctl | _extract_sub) {
            if $line.startsWith($p) {
                $ret.add($line)
            }
        }
        return $ret
    }
    assert $t.size() > 1
    case $t[1] {
    'set'|'unset' => {
        var p = ""
        if $c < $t.size() {
            $p = $t.peek()
        }
        var ret : Candidates
        for line in <(shctl set | cut -d ' ' -f 1) {
            if $line.startsWith($p) {
                $ret.add($line)
            }
        }
        return $ret
    }
    else => return new Candidates()
    }
}

source $SCRIPT_DIR/../modules/fzf as _fzf

function _kill($ctx : Module, $t : [String], $c : Int) : Candidates? {
    let size = $t.size()
    if $c < $size {
        var v = $t.peek()
        case $v {
            '-' => return new Candidates().add('-l').add('-s')
            else => if !$v.startsWith('-') {
                if $t.size() > 2 {
                    if $t[-2] == '-s' {
                        complete -q -A signal -- $v
                        return $COMPREPLY
                    } elif $t[-2] == '-l' {
                        return $none
                    }
                }
            }
        }
    } else {
        var v = $t.peek()
        case $v {
            '-s' => {
                complete -q -A signal ''
                return $COMPREPLY
            }
            else => if !$v.startsWith('-')  {
                return new Candidates().add($_fzf.fzf_proc_select().join(' '))
            }
        }
    }
    return new Candidates()
}

$compAdd("command", $_cmd)
$compAdd("call", $_cmd)
$compAdd("exec", $_cmd)
$compAdd('shctl', $_shctl)
$compAdd('kill', $_kill)


# defined by compdef

compdef --cmd help --arg-cmd "help | cut -d ' ' -f 1"
compdef --cmd help --short s --arg-cmd "help | cut -d ' ' -f 1"
compdef --cmd unsetenv --arg-action env
compdef --cmd cd --arg-action dir
compdef --cmd cd --short L --arg-action dir
compdef --cmd cd --short P --arg-action dir
compdef --cmd pwd --short L
compdef --cmd pwd --short P
compdef --cmd complete --short A \
        --arg-cmd "help complete | grep -E '^      [_a-z]+' | sed 's/^      //g' | cut -d ' ' -f 1"