Skip to content

Fuzzy finder

Johannes Altmanninger edited this page Feb 23, 2019 · 21 revisions

Find

def find -params 1 -shell-script-candidates %{ find -type f } %{ edit %arg{1} }

Recursive file search under %opt{path} option

This command replicates Vim behavior when path option contains ** item. find will search for file recursively, and if several files found it will prompt you a list of files to choose. This is smart function, so it tries to find match as fast as possible before going full recursive.

define-command -docstring \
"find <filename>: search for file recusively under path option: %opt{path}" \
find -params 1 %{ evaluate-commands %sh{
    file=$1
    eval "set -- $kak_buflist"
    while [ $# -gt 0 ]; do            # Check if buffer with this
        if [ "$file" = "$1" ]; then   # file already exists. Basically
            printf "%s\n" "buffer $1" # emulating what edit command does
            exit
        fi
        shift
    done
    if [ -e "$file" ]; then                     # Test if file exists under
        printf "%s\n" "edit -existing %{$file}" # servers' working directory
        exit                                    # this is last resort until
    fi                                          # we start recursive searchimg

    # if everthing  above fails - search for file under path
    eval "set -- $kak_opt_path"
    while [ $# -gt 0 ]; do
        case $1 in                        # Since we want to check fewer places
            ./) path=${kak_buffile%/*} ;; # I've swapped ./ and %/ because
            %/) path=$PWD ;;              # %/ usually has smaller scope. So
            *)  path=$1 ;;                # this trick is a speedi-up hack.
        esac
        if [ -z "${file##*/*}" ]; then # test if filename contains path
            if [ -e "$path/$file" ]; then
                printf "%s\n" "edit -existing %{$path/$file}"
                exit
            fi
        else # build list of candidates or automatically select if only one found
            for candidate in $(find -L $path -mount -type f -name "$file"); do
                if [ -n "$candidate" ]; then
                    candidates="$candidates %{$candidate} %{evaluate-commands %{edit -existing %{$candidate}}}"
                fi
            done
            if [ -n "$candidates" ]; then
                printf "%s\n" "menu -auto-single $candidates"
                exit
            fi
        fi
        shift
    done
    printf "%s\n" "echo -markup %{{Error}unable to find file '$file'}"
}}

This command can also be mapped to gf keeping old behavior with gAlt+f:

map -docstring "file non-recursive" global goto '<a-f>' '<esc>gf'
map -docstring "file" global goto 'f' '<esc>: find %val{selection}<ret>'

Git

def git-edit -params 1 -shell-script-candidates %{ git ls-files } %{ edit %arg{1} }

FZF

fzf is a basic fuzzy finder tool used to interactively filter large lists of data in a shell.

In the following snippets, a tmux pane is opened with fzf ready to filter a list of files and a list of current buffers.

Other kakoune lists could be filtered this way, taking fzf.vim as inspiration.

define-command -docstring 'Invoke fzf to open a file' -params 0 fzf-edit %{
    evaluate-commands %sh{
        if [ -z "${kak_client_env_TMUX}" ]; then
            printf 'fail "client was not started under tmux"\n'
        else
            file="$(find . -type f |TMUX="${kak_client_env_TMUX}" fzf-tmux -d 15)"
            if [ -n "$file" ]; then
                printf 'edit "%s"\n' "$file"
            fi
        fi
    }
}

# the original version no longer works since kak_buflist is no longer ":" separated.
# this one works even you have single quote or newline in file names.

define-command -docstring 'Invoke fzf to select a buffer' fzf-buffer %{
    evaluate-commands %sh{
        BUFFER=$(
            (
                eval "set -- $kak_buflist"
                while [ $# -gt 0 ]; do
                    printf "%s\0" "$1"
                    shift
                done
            ) |
            fzf-tmux -d 15 --read0
        )
        BUFFER=${BUFFER/\'/\'\'}
        if [ -n "$BUFFER" ]; then
            printf "buffer '%s'" "${BUFFER}"
        fi
    }
}

fzf.kak

There's also a fzf.kak plugin, that includes such features:

  • Supports both x11 and tmux
  • Opening files with find, fd, rg, ag
  • Previewing file contents with syntax highlighting, backed by bat, coderay, highlight, rogue
  • Switching buffers
  • Automatic detection of your VCS to list project files. Supports:
    • Git
    • GNU Bazaar
    • Subversion
    • Mercurial
  • Searching tags with universal-ctags
    • Filtering tags by kinds for all ctags supported languages
  • Searching current buffer contents
  • Changing server's working directory

Rofi

Select an open buffer using Rofi

define-command rofi-buffers \
-docstring 'Select an open buffer using Rofi' %{ evaluate-commands %sh{
    BUFFER=$(printf "%s\n" "${kak_buflist}" | tr " " "\n" | rofi -dmenu | tr -d \')
    if [ -n "$BUFFER" ]; then
        printf "%s\n" "buffer ${BUFFER}"
    fi
} }

Using Ag + Rofi to select files in your project directory.

define-command rofi-files \
-docstring 'Select files in project using Ag and Rofi' %{nop %sh{
    FILE=$(ag -g "" | rofi -dmenu)
    if [ -n "$FILE" ]; then
        printf 'eval -client %%{%s} edit %%{%s}\n' "${kak_client}" "${FILE}" | kak -p "${kak_session}"
    fi
} }

Fast file finder: fasd integration

Add function k () kak `fasd -f $1` to your .zshrc to open frecent files with k filename

You can’t perform that action at this time.