
# for fzf key binding

function _fzf_select(q : String, list : [String], opts : String) : String? {
    command -v fzf &>> /dev/null || return $none

    importenv FZF_DEFAULT_OPTS : ""
    var fzf_opt = "--height 40% --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS --bind=ctrl-r:toggle-sort $opts +m"
    let eaw = $EAW == 1 ? 0 : 1

    var arg = ['-q', $q]
    if $q.empty() { $arg.clear(); }
    var ret = "$(printf "%s\n" ${$list} | sort | uniq | FZF_DEFAULT_OPTS=$fzf_opt RUNEWIDTH_EASTASIAN=$eaw fzf $arg)"
    return $ret.empty() ? $none : $ret
}

function _fzf_search_hist(q : String, list : [String]?) : String? {
    $list || return $none

    importenv FZF_SEARCH_HIST_OPTS : ""
    return $_fzf_select($q, $list!, $FZF_SEARCH_HIST_OPTS)
}

function _fzf_select_files(q : String, list : [String]?) : String? {
    command -v fzf &>> /dev/null || return $none

    importenv FZF_DEFAULT_OPTS : ""
    importenv FZF_SELECT_FILES_OPTS : "--preview 'cat {}'"
    var fzf_opt = "--height 40% --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_SELECT_FILES_OPTS -m"
    let eaw = $EAW == 1 ? 0 : 1

    var ret = ""
    command find -L . -mindepth 1 \( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \) \
        -prune \
        -o -type f -print \
        -o -type d -print \
        -o -type l -print 2>> /dev/null | cut -b3- | FZF_DEFAULT_OPTS=$fzf_opt RUNEWIDTH_EASTASIAN=$eaw fzf | 
        for line in $STDIN {
            $ret += $line.quote()
            $ret += ' '
        }
    return $ret.empty() ? $none : $ret
}

function _fzf_cd(q : String, list : [String]?) : String? {
    command -v fzf &>> /dev/null || return $none

    importenv FZF_DEFAULT_OPTS : ""
    importenv FZF_CD_OPTS : ""
    var fzf_opt = "--height 40% --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_CD_OPTS +m"
    let eaw = $EAW == 1 ? 0 : 1

    var line = "$(command find -L . -mindepth 1 \( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \) \
        -prune \
        -o -type d -print 2>> /dev/null | cut -b3- | FZF_DEFAULT_OPTS=$fzf_opt RUNEWIDTH_EASTASIAN=$eaw fzf)"
    if $line.empty() {
        return $none
    }
    return "command cd -- ${$line.quote()}"
}

function _fzf_select_killring(q : String, list : [String]?) : String? {
    $list || return $none
    return $_fzf_select($q, $list!, "--height 20%")
}

# for completion
function fzf_proc_select() : [String] {
    command -v fzf &>> /dev/null || return new [String]()

    importenv FZF_DEFAULT_OPTS : ""
    var fzf_opt = "--height 40% --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS" + 
                  "-m --header-lines=1 --preview 'echo {}' --preview-window down:3:wrap --min-height 15"
    let eaw = $EAW == 1 ? 0 : 1
    var ret : [String]
    (command ps -eo user,pid,ppid,start,time,command 2> /dev/null ||
      command ps -eo user,pid,ppid,time,args) | FZF_DEFAULT_OPTS=$fzf_opt RUNEWIDTH_EASTASIAN=$eaw fzf | 
      for line in $STDIN {
        var r = $/^[^ ]+[ ]+([0-9]+)/.match($line) ?? continue
        $ret.add($r.group(1)!)
      }
    return $ret
}

# CTRL-R
$LINE_EDIT.action('fzf-search-hist', 'hist-select', $_fzf_search_hist)
$LINE_EDIT.bind("^R", 'fzf-search-hist')

# CTRL-T
$LINE_EDIT.action('fzf-select-files', 'insert', $_fzf_select_files)
$LINE_EDIT.bind('^T', 'fzf-select-files')

# ALT-C
$LINE_EDIT.action('fzf-cd', 'replace-whole-accept', $_fzf_cd)
$LINE_EDIT.bind('^[c', 'fzf-cd')

# ALT-K
$LINE_EDIT.action('fzf-kill-ring', 'kill-ring-select', $_fzf_select_killring)
$LINE_EDIT.bind('^[k', 'fzf-kill-ring')