diff --git a/playbooks/roles/arch/tasks/main.yml b/playbooks/roles/arch/tasks/main.yml index 4089e6a..b30f889 100644 --- a/playbooks/roles/arch/tasks/main.yml +++ b/playbooks/roles/arch/tasks/main.yml @@ -17,7 +17,7 @@ - tmux - gnupg - neovim - - skim + - fzf state: latest - name: Install Development Tools diff --git a/playbooks/roles/fedora/tasks/main.yml b/playbooks/roles/fedora/tasks/main.yml index 2d55598..0645967 100644 --- a/playbooks/roles/fedora/tasks/main.yml +++ b/playbooks/roles/fedora/tasks/main.yml @@ -17,8 +17,7 @@ - tmux - gpg - neovim - - hstr - - skim + - fzf state: latest - name: Install @development-tools diff --git a/playbooks/roles/opensuse/tasks/main.yml b/playbooks/roles/opensuse/tasks/main.yml index 508cee9..143513d 100644 --- a/playbooks/roles/opensuse/tasks/main.yml +++ b/playbooks/roles/opensuse/tasks/main.yml @@ -17,6 +17,7 @@ - tmux - gpg - neovim + - fzf state: latest - name: Install devel_* @@ -49,15 +50,3 @@ args: creates: /etc/zypp/repos.d/home_luke_nukem_rust_apps.repo -- name: Install skim - become: yes - become_method: sudo - zypper: - name: skim - state: latest - -- name: Put sk-tmux in ~/bin directory¬ - get_url: - url: https://raw.githubusercontent.com/lotabout/skim/v0.6.8/bin/sk-tmux - dest: ~/bin/sk-tmux - checksum: sha256:1dd67ed20f78c50bc7f9518a5908badd582117eaa67fa30c43e83dcc0b55afdb diff --git a/zsh/completions/_fzf b/zsh/completions/_fzf new file mode 100644 index 0000000..2096ad4 --- /dev/null +++ b/zsh/completions/_fzf @@ -0,0 +1,329 @@ +# ____ ____ +# / __/___ / __/ +# / /_/_ / / /_ +# / __/ / /_/ __/ +# /_/ /___/_/ completion.zsh +# +# - $FZF_TMUX (default: 0) +# - $FZF_TMUX_OPTS (default: '-d 40%') +# - $FZF_COMPLETION_TRIGGER (default: '**') +# - $FZF_COMPLETION_OPTS (default: empty) + +# Both branches of the following `if` do the same thing -- define +# __fzf_completion_options such that `eval $__fzf_completion_options` sets +# all options to the same values they currently have. We'll do just that at +# the bottom of the file after changing options to what we prefer. +# +# IMPORTANT: Until we get to the `emulate` line, all words that *can* be quoted +# *must* be quoted in order to prevent alias expansion. In addition, code must +# be written in a way works with any set of zsh options. This is very tricky, so +# careful when you change it. +# +# Start by loading the builtin zsh/parameter module. It provides `options` +# associative array that stores current shell options. +if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then + # This is the fast branch and it gets taken on virtually all Zsh installations. + # + # ${(kv)options[@]} expands to array of keys (option names) and values ("on" + # or "off"). The subsequent expansion# with (j: :) flag joins all elements + # together separated by spaces. __fzf_completion_options ends up with a value + # like this: "options=(shwordsplit off aliases on ...)". + __fzf_completion_options="options=(${(j: :)${(kv)options[@]}})" +else + # This branch is much slower because it forks to get the names of all + # zsh options. It's possible to eliminate this fork but it's not worth the + # trouble because this branch gets taken only on very ancient or broken + # zsh installations. + () { + # That `()` above defines an anonymous function. This is essentially a scope + # for local parameters. We use it to avoid polluting global scope. + 'local' '__fzf_opt' + __fzf_completion_options="setopt" + # `set -o` prints one line for every zsh option. Each line contains option + # name, some spaces, and then either "on" or "off". We just want option names. + # Expansion with (@f) flag splits a string into lines. The outer expansion + # removes spaces and everything that follow them on every line. __fzf_opt + # ends up iterating over option names: shwordsplit, aliases, etc. + for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do + if [[ -o "$__fzf_opt" ]]; then + # Option $__fzf_opt is currently on, so remember to set it back on. + __fzf_completion_options+=" -o $__fzf_opt" + else + # Option $__fzf_opt is currently off, so remember to set it back off. + __fzf_completion_options+=" +o $__fzf_opt" + fi + done + # The value of __fzf_completion_options here looks like this: + # "setopt +o shwordsplit -o aliases ..." + } +fi + +# Enable the default zsh options (those marked with in `man zshoptions`) +# but without `aliases`. Aliases in functions are expanded when functions are +# defined, so if we disable aliases here, we'll be sure to have no pesky +# aliases in any of our functions. This way we won't need prefix every +# command with `command` or to quote every word to defend against global +# aliases. Note that `aliases` is not the only option that's important to +# control. There are several others that could wreck havoc if they are set +# to values we don't expect. With the following `emulate` command we +# sidestep this issue entirely. +'emulate' 'zsh' '-o' 'no_aliases' + +# This brace is the start of try-always block. The `always` part is like +# `finally` in lesser languages. We use it to *always* restore user options. +{ + +# Bail out if not interactive shell. +[[ -o interactive ]] || return 0 + +# To use custom commands instead of find, override _fzf_compgen_{path,dir} +if ! declare -f _fzf_compgen_path > /dev/null; then + _fzf_compgen_path() { + echo "$1" + command find -L "$1" \ + -name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \ + -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@' + } +fi + +if ! declare -f _fzf_compgen_dir > /dev/null; then + _fzf_compgen_dir() { + command find -L "$1" \ + -name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \ + -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@' + } +fi + +########################################################### + +__fzf_comprun() { + if [[ "$(type _fzf_comprun 2>&1)" =~ function ]]; then + _fzf_comprun "$@" + elif [ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; }; then + shift + if [ -n "$FZF_TMUX_OPTS" ]; then + fzf-tmux ${(Q)${(Z+n+)FZF_TMUX_OPTS}} -- "$@" + else + fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%} -- "$@" + fi + else + shift + fzf "$@" + fi +} + +# Extract the name of the command. e.g. foo=1 bar baz** +__fzf_extract_command() { + local token tokens + tokens=(${(z)1}) + for token in $tokens; do + token=${(Q)token} + if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then + echo "$token" + return + fi + done + echo "${tokens[1]}" +} + +__fzf_generic_path_completion() { + local base lbuf cmd compgen fzf_opts suffix tail dir leftover matches + base=$1 + lbuf=$2 + cmd=$(__fzf_extract_command "$lbuf") + compgen=$3 + fzf_opts=$4 + suffix=$5 + tail=$6 + + setopt localoptions nonomatch + eval "base=$base" + [[ $base = *"/"* ]] && dir="$base" + while [ 1 ]; do + if [[ -z "$dir" || -d ${dir} ]]; then + leftover=${base/#"$dir"} + leftover=${leftover/#\/} + [ -z "$dir" ] && dir='.' + [ "$dir" != "/" ] && dir="${dir/%\//}" + matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do + echo -n "${(q)item}$suffix " + done) + matches=${matches% } + if [ -n "$matches" ]; then + LBUFFER="$lbuf$matches$tail" + fi + zle reset-prompt + break + fi + dir=$(dirname "$dir") + dir=${dir%/}/ + done +} + +_fzf_path_completion() { + __fzf_generic_path_completion "$1" "$2" _fzf_compgen_path \ + "-m" "" " " +} + +_fzf_dir_completion() { + __fzf_generic_path_completion "$1" "$2" _fzf_compgen_dir \ + "" "/" "" +} + +_fzf_feed_fifo() ( + command rm -f "$1" + mkfifo "$1" + cat <&0 > "$1" & +) + +_fzf_complete() { + setopt localoptions ksh_arrays + # Split arguments around -- + local args rest str_arg i sep + args=("$@") + sep= + for i in {0..${#args[@]}}; do + if [[ "${args[$i]}" = -- ]]; then + sep=$i + break + fi + done + if [[ -n "$sep" ]]; then + str_arg= + rest=("${args[@]:$((sep + 1)):${#args[@]}}") + args=("${args[@]:0:$sep}") + else + str_arg=$1 + args=() + shift + rest=("$@") + fi + + local fifo lbuf cmd matches post + fifo="${TMPDIR:-/tmp}/fzf-complete-fifo-$$" + lbuf=${rest[0]} + cmd=$(__fzf_extract_command "$lbuf") + post="${funcstack[1]}_post" + type $post > /dev/null 2>&1 || post=cat + + _fzf_feed_fifo "$fifo" + matches=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $str_arg" __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ') + if [ -n "$matches" ]; then + LBUFFER="$lbuf$matches" + fi + zle reset-prompt + command rm -f "$fifo" +} + +_fzf_complete_telnet() { + _fzf_complete +m -- "$@" < <( + command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0' | + awk '{if (length($2) > 0) {print $2}}' | sort -u + ) +} + +_fzf_complete_ssh() { + _fzf_complete +m -- "$@" < <( + setopt localoptions nonomatch + command cat <(cat ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?]') \ + <(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \ + <(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') | + awk '{if (length($2) > 0) {print $2}}' | sort -u + ) +} + +_fzf_complete_export() { + _fzf_complete -m -- "$@" < <( + declare -xp | sed 's/=.*//' | sed 's/.* //' + ) +} + +_fzf_complete_unset() { + _fzf_complete -m -- "$@" < <( + declare -xp | sed 's/=.*//' | sed 's/.* //' + ) +} + +_fzf_complete_unalias() { + _fzf_complete +m -- "$@" < <( + alias | sed 's/=.*//' + ) +} + +_fzf_complete_kill() { + _fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <( + command ps -ef | sed 1d + ) +} + +_fzf_complete_kill_post() { + awk '{print $2}' +} + +fzf-completion() { + local tokens cmd prefix trigger tail matches lbuf d_cmds + setopt localoptions noshwordsplit noksh_arrays noposixbuiltins + + # http://zsh.sourceforge.net/FAQ/zshfaq03.html + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags + tokens=(${(z)LBUFFER}) + if [ ${#tokens} -lt 1 ]; then + zle ${fzf_default_completion:-expand-or-complete} + return + fi + + cmd=$(__fzf_extract_command "$LBUFFER") + + # Explicitly allow for empty trigger. + trigger=${FZF_COMPLETION_TRIGGER-'**'} + [ -z "$trigger" -a ${LBUFFER[-1]} = ' ' ] && tokens+=("") + + # When the trigger starts with ';', it becomes a separate token + if [[ ${LBUFFER} = *"${tokens[-2]}${tokens[-1]}" ]]; then + tokens[-2]="${tokens[-2]}${tokens[-1]}" + tokens=(${tokens[0,-2]}) + fi + + lbuf=$LBUFFER + tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))} + # Kill completion (do not require trigger sequence) + if [ "$cmd" = kill -a ${LBUFFER[-1]} = ' ' ]; then + tail=$trigger + tokens+=$trigger + lbuf="$lbuf$trigger" + fi + + # Trigger sequence given + if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then + d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}) + + [ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}} + [ -n "${tokens[-1]}" ] && lbuf=${lbuf:0:-${#tokens[-1]}} + + if eval "type _fzf_complete_${cmd} > /dev/null"; then + prefix="$prefix" eval _fzf_complete_${cmd} ${(q)lbuf} + elif [ ${d_cmds[(i)$cmd]} -le ${#d_cmds} ]; then + _fzf_dir_completion "$prefix" "$lbuf" + else + _fzf_path_completion "$prefix" "$lbuf" + fi + # Fall back to default completion + else + zle ${fzf_default_completion:-expand-or-complete} + fi +} + +[ -z "$fzf_default_completion" ] && { + binding=$(bindkey '^I') + [[ $binding =~ 'undefined-key' ]] || fzf_default_completion=$binding[(s: :w)2] + unset binding +} + +zle -N fzf-completion +bindkey '^I' fzf-completion + +} always { + # Restore the original options. + eval $__fzf_completion_options + 'unset' '__fzf_completion_options' +} diff --git a/zsh/completions/_rg b/zsh/completions/_rg new file mode 100644 index 0000000..828a6e6 --- /dev/null +++ b/zsh/completions/_rg @@ -0,0 +1,638 @@ +#compdef rg + +## +# zsh completion function for ripgrep +# +# Run ci/test-complete after building to ensure that the options supported by +# this function stay in synch with the `rg` binary. +# +# For convenience, a completion reference guide is included at the bottom of +# this file. +# +# Originally based on code from the zsh-users project — see copyright notice +# below. + +_rg() { + local curcontext=$curcontext no='!' descr ret=1 + local -a context line state state_descr args tmp suf + local -A opt_args + + # ripgrep has many options which negate the effect of a more common one — for + # example, `--no-column` to negate `--column`, and `--messages` to negate + # `--no-messages`. There are so many of these, and they're so infrequently + # used, that some users will probably find it irritating if they're completed + # indiscriminately, so let's not do that unless either the current prefix + # matches one of those negation options or the user has the `complete-all` + # style set. Note that this prefix check has to be updated manually to account + # for all of the potential negation options listed below! + if + # We also want to list all of these options during testing + [[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] || + # (--[imnp]* => --ignore*, --messages, --no-*, --pcre2-unicode) + [[ $PREFIX$SUFFIX == --[imnp]* ]] || + zstyle -t ":complete:$curcontext:*" complete-all + then + no= + fi + + # We make heavy use of argument groups here to prevent the option specs from + # growing unwieldy. These aren't supported in zsh <5.4, though, so we'll strip + # them out below if necessary. This makes the exclusions inaccurate on those + # older versions, but oh well — it's not that big a deal + args=( + + '(exclusive)' # Misc. fully exclusive options + '(: * -)'{-h,--help}'[display help information]' + '(: * -)'{-V,--version}'[display version information]' + '(: * -)'--pcre2-version'[print the version of PCRE2 used by ripgrep, if available]' + + + '(buffered)' # buffering options + '--line-buffered[force line buffering]' + $no"--no-line-buffered[don't force line buffering]" + '--block-buffered[force block buffering]' + $no"--no-block-buffered[don't force block buffering]" + + + '(case)' # Case-sensitivity options + {-i,--ignore-case}'[search case-insensitively]' + {-s,--case-sensitive}'[search case-sensitively]' + {-S,--smart-case}'[search case-insensitively if pattern is all lowercase]' + + + '(context-a)' # Context (after) options + '(context-c)'{-A+,--after-context=}'[specify lines to show after each match]:number of lines' + + + '(context-b)' # Context (before) options + '(context-c)'{-B+,--before-context=}'[specify lines to show before each match]:number of lines' + + + '(context-c)' # Context (combined) options + '(context-a context-b)'{-C+,--context=}'[specify lines to show before and after each match]:number of lines' + + + '(column)' # Column options + '--column[show column numbers for matches]' + $no"--no-column[don't show column numbers for matches]" + + + '(count)' # Counting options + {-c,--count}'[only show count of matching lines for each file]' + '--count-matches[only show count of individual matches for each file]' + '--include-zero[include files with zero matches in summary]' + + + '(encoding)' # Encoding options + {-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings' + $no'--no-encoding[use default text encoding]' + + + '(engine)' # Engine choice options + '--engine=[select which regex engine to use]:when:(( + default\:"use default engine" + pcre2\:"identical to --pcre2" + auto\:"identical to --auto-hybrid-regex" + ))' + + + file # File-input options + '(1)*'{-f+,--file=}'[specify file containing patterns to search for]: :_files' + + + '(file-match)' # Files with/without match options + '(stats)'{-l,--files-with-matches}'[only show names of files with matches]' + '(stats)--files-without-match[only show names of files without matches]' + + + '(file-name)' # File-name options + {-H,--with-filename}'[show file name for matches]' + {-I,--no-filename}"[don't show file name for matches]" + + + '(file-system)' # File system options + "--one-file-system[don't descend into directories on other file systems]" + $no'--no-one-file-system[descend into directories on other file systems]' + + + '(fixed)' # Fixed-string options + {-F,--fixed-strings}'[treat pattern as literal string instead of regular expression]' + $no"--no-fixed-strings[don't treat pattern as literal string]" + + + '(follow)' # Symlink-following options + {-L,--follow}'[follow symlinks]' + $no"--no-follow[don't follow symlinks]" + + + glob # File-glob options + '*'{-g+,--glob=}'[include/exclude files matching specified glob]:glob' + '*--iglob=[include/exclude files matching specified case-insensitive glob]:glob' + + + '(glob-case-insensitive)' # File-glob case sensitivity options + '--glob-case-insensitive[treat -g/--glob patterns case insensitively]' + $no'--no-glob-case-insensitive[treat -g/--glob patterns case sensitively]' + + + '(heading)' # Heading options + '(pretty-vimgrep)--heading[show matches grouped by file name]' + "(pretty-vimgrep)--no-heading[don't show matches grouped by file name]" + + + '(hidden)' # Hidden-file options + '--hidden[search hidden files and directories]' + $no"--no-hidden[don't search hidden files and directories]" + + + '(hybrid)' # hybrid regex options + '--auto-hybrid-regex[dynamically use PCRE2 if necessary]' + $no"--no-auto-hybrid-regex[don't dynamically use PCRE2 if necessary]" + + + '(ignore)' # Ignore-file options + "(--no-ignore-global --no-ignore-parent --no-ignore-vcs --no-ignore-dot)--no-ignore[don't respect ignore files]" + $no'(--ignore-global --ignore-parent --ignore-vcs --ignore-dot)--ignore[respect ignore files]' + + + '(ignore-file-case-insensitive)' # Ignore-file case sensitivity options + '--ignore-file-case-insensitive[process ignore files case insensitively]' + $no'--no-ignore-file-case-insensitive[process ignore files case sensitively]' + + + '(ignore-exclude)' # Local exclude (ignore)-file options + "--no-ignore-exclude[don't respect local exclude (ignore) files]" + $no'--ignore-exclude[respect local exclude (ignore) files]' + + + '(ignore-global)' # Global ignore-file options + "--no-ignore-global[don't respect global ignore files]" + $no'--ignore-global[respect global ignore files]' + + + '(ignore-parent)' # Parent ignore-file options + "--no-ignore-parent[don't respect ignore files in parent directories]" + $no'--ignore-parent[respect ignore files in parent directories]' + + + '(ignore-vcs)' # VCS ignore-file options + "--no-ignore-vcs[don't respect version control ignore files]" + $no'--ignore-vcs[respect version control ignore files]' + + + '(require-git)' # git specific settings + "--no-require-git[don't require git repository to respect gitignore rules]" + $no'--require-git[require git repository to respect gitignore rules]' + + + '(ignore-dot)' # .ignore options + "--no-ignore-dot[don't respect .ignore files]" + $no'--ignore-dot[respect .ignore files]' + + + '(ignore-files)' # custom global ignore file options + "--no-ignore-files[don't respect --ignore-file flags]" + $no'--ignore-files[respect --ignore-file files]' + + + '(json)' # JSON options + '--json[output results in JSON Lines format]' + $no"--no-json[don't output results in JSON Lines format]" + + + '(line-number)' # Line-number options + {-n,--line-number}'[show line numbers for matches]' + {-N,--no-line-number}"[don't show line numbers for matches]" + + + '(line-terminator)' # Line-terminator options + '--crlf[use CRLF as line terminator]' + $no"--no-crlf[don't use CRLF as line terminator]" + '(text)--null-data[use NUL as line terminator]' + + + '(max-columns-preview)' # max column preview options + '--max-columns-preview[show preview for long lines (with -M)]' + $no"--no-max-columns-preview[don't show preview for long lines (with -M)]" + + + '(max-depth)' # Directory-depth options + '--max-depth=[specify max number of directories to descend]:number of directories' + '!--maxdepth=:number of directories' + + + '(messages)' # Error-message options + '(--no-ignore-messages)--no-messages[suppress some error messages]' + $no"--messages[don't suppress error messages affected by --no-messages]" + + + '(messages-ignore)' # Ignore-error message options + "--no-ignore-messages[don't show ignore-file parse error messages]" + $no'--ignore-messages[show ignore-file parse error messages]' + + + '(mmap)' # mmap options + '--mmap[search using memory maps when possible]' + "--no-mmap[don't search using memory maps]" + + + '(multiline)' # Multiline options + {-U,--multiline}'[permit matching across multiple lines]' + $no'(multiline-dotall)--no-multiline[restrict matches to at most one line each]' + + + '(multiline-dotall)' # Multiline DOTALL options + '(--no-multiline)--multiline-dotall[allow "." to match newline (with -U)]' + $no"(--no-multiline)--no-multiline-dotall[don't allow \".\" to match newline (with -U)]" + + + '(only)' # Only-match options + {-o,--only-matching}'[show only matching part of each line]' + + + '(passthru)' # Pass-through options + '(--vimgrep)--passthru[show both matching and non-matching lines]' + '!(--vimgrep)--passthrough' + + + '(pcre2)' # PCRE2 options + {-P,--pcre2}'[enable matching with PCRE2]' + $no'(pcre2-unicode)--no-pcre2[disable matching with PCRE2]' + + + '(pcre2-unicode)' # PCRE2 Unicode options + $no'(--no-pcre2 --no-pcre2-unicode)--pcre2-unicode[enable PCRE2 Unicode mode (with -P)]' + '(--no-pcre2 --pcre2-unicode)--no-pcre2-unicode[disable PCRE2 Unicode mode (with -P)]' + + + '(pre)' # Preprocessing options + '(-z --search-zip)--pre=[specify preprocessor utility]:preprocessor utility:_command_names -e' + $no'--no-pre[disable preprocessor utility]' + + + pre-glob # Preprocessing glob options + '*--pre-glob[include/exclude files for preprocessing with --pre]' + + + '(pretty-vimgrep)' # Pretty/vimgrep display options + '(heading)'{-p,--pretty}'[alias for --color=always --heading -n]' + '(heading passthru)--vimgrep[show results in vim-compatible format]' + + + regexp # Explicit pattern options + '(1 file)*'{-e+,--regexp=}'[specify pattern]:pattern' + + + '(replace)' # Replacement options + {-r+,--replace=}'[specify string used to replace matches]:replace string' + + + '(sort)' # File-sorting options + '(threads)--sort=[sort results in ascending order (disables parallelism)]:sort method:(( + none\:"no sorting" + path\:"sort by file path" + modified\:"sort by last modified time" + accessed\:"sort by last accessed time" + created\:"sort by creation time" + ))' + '(threads)--sortr=[sort results in descending order (disables parallelism)]:sort method:(( + none\:"no sorting" + path\:"sort by file path" + modified\:"sort by last modified time" + accessed\:"sort by last accessed time" + created\:"sort by creation time" + ))' + '!(threads)--sort-files[sort results by file path (disables parallelism)]' + + + '(stats)' # Statistics options + '(--files file-match)--stats[show search statistics]' + $no"--no-stats[don't show search statistics]" + + + '(text)' # Binary-search options + {-a,--text}'[search binary files as if they were text]' + "--binary[search binary files, don't print binary data]" + $no"--no-binary[don't search binary files]" + $no"(--null-data)--no-text[don't search binary files as if they were text]" + + + '(threads)' # Thread-count options + '(sort)'{-j+,--threads=}'[specify approximate number of threads to use]:number of threads' + + + '(trim)' # Trim options + '--trim[trim any ASCII whitespace prefix from each line]' + $no"--no-trim[don't trim ASCII whitespace prefix from each line]" + + + type # Type options + '*'{-t+,--type=}'[only search files matching specified type]: :_rg_types' + '*--type-add=[add new glob for specified file type]: :->typespec' + '*--type-clear=[clear globs previously defined for specified file type]: :_rg_types' + # This should actually be exclusive with everything but other type options + '(: *)--type-list[show all supported file types and their associated globs]' + '*'{-T+,--type-not=}"[don't search files matching specified file type]: :_rg_types" + + + '(word-line)' # Whole-word/line match options + {-w,--word-regexp}'[only show matches surrounded by word boundaries]' + {-x,--line-regexp}'[only show matches surrounded by line boundaries]' + + + '(unicode)' # Unicode options + $no'--unicode[enable Unicode mode]' + '--no-unicode[disable Unicode mode]' + + + '(zip)' # Compression options + '(--pre)'{-z,--search-zip}'[search in compressed files]' + $no"--no-search-zip[don't search in compressed files]" + + + misc # Other options — no need to separate these at the moment + '(-b --byte-offset)'{-b,--byte-offset}'[show 0-based byte offset for each matching line]' + '--color=[specify when to use colors in output]:when:(( + never\:"never use colors" + auto\:"use colors or not based on stdout, TERM, etc." + always\:"always use colors" + ansi\:"always use ANSI colors (even on Windows)" + ))' + '*--colors=[specify color and style settings]: :->colorspec' + '--context-separator=[specify string used to separate non-continuous context lines in output]:separator' + $no"--no-context-separator[don't print context separators]" + '--debug[show debug messages]' + '--trace[show more verbose debug messages]' + '--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)' + "(1 stats)--files[show each file that would be searched (but don't search)]" + '*--ignore-file=[specify additional ignore file]:ignore file:_files' + '(-v --invert-match)'{-v,--invert-match}'[invert matching]' + '(-M --max-columns)'{-M+,--max-columns=}'[specify max length of lines to print]:number of bytes' + '(-m --max-count)'{-m+,--max-count=}'[specify max number of matches per file]:number of matches' + '--max-filesize=[specify size above which files should be ignored]:file size (bytes)' + "--no-config[don't load configuration files]" + '(-0 --null)'{-0,--null}'[print NUL byte after file names]' + '--path-separator=[specify path separator to use when printing file names]:separator' + '(-q --quiet)'{-q,--quiet}'[suppress normal output]' + '--regex-size-limit=[specify upper size limit of compiled regex]:regex size (bytes)' + '*'{-u,--unrestricted}'[reduce level of "smart" searching]' + + + operand # Operands + '(--files --type-list file regexp)1: :_guard "^-*" pattern' + '(--type-list)*: :_files' + ) + + # This is used with test-complete to verify that there are no options + # listed in the help output that aren't also defined here + [[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] && { + print -rl - $args + return 0 + } + + # Strip out argument groups where unsupported (see above) + [[ $ZSH_VERSION == (4|5.<0-3>)(.*)# ]] && + args=( ${(@)args:#(#i)(+|[a-z0-9][a-z0-9_-]#|\([a-z0-9][a-z0-9_-]#\))} ) + + _arguments -C -s -S : $args && ret=0 + + case $state in + colorspec) + if [[ ${IPREFIX#--*=}$PREFIX == [^:]# ]]; then + suf=( -qS: ) + tmp=( + 'column:specify coloring for column numbers' + 'line:specify coloring for line numbers' + 'match:specify coloring for match text' + 'path:specify coloring for file names' + ) + descr='color/style type' + elif [[ ${IPREFIX#--*=}$PREFIX == (column|line|match|path):[^:]# ]]; then + suf=( -qS: ) + tmp=( + 'none:clear color/style for type' + 'bg:specify background color' + 'fg:specify foreground color' + 'style:specify text style' + ) + descr='color/style attribute' + elif [[ ${IPREFIX#--*=}$PREFIX == [^:]##:(bg|fg):[^:]# ]]; then + tmp=( black blue green red cyan magenta yellow white ) + descr='color name or r,g,b' + elif [[ ${IPREFIX#--*=}$PREFIX == [^:]##:style:[^:]# ]]; then + tmp=( {,no}bold {,no}intense {,no}underline ) + descr='style name' + else + _message -e colorspec 'no more arguments' + fi + + (( $#tmp )) && { + compset -P '*:' + _describe -t colorspec $descr tmp $suf && ret=0 + } + ;; + + typespec) + if compset -P '[^:]##:include:'; then + _sequence -s , _rg_types && ret=0 + # @todo This bit in particular could be better, but it's a little + # complex, and attempting to solve it seems to run us up against a crash + # bug — zsh # 40362 + elif compset -P '[^:]##:'; then + _message 'glob or include directive' && ret=1 + elif [[ ! -prefix *:* ]]; then + _rg_types -qS : && ret=0 + fi + ;; + esac + + return ret +} + +# Complete encodings +_rg_encodings() { + local -a expl + local -aU _encodings + + # This is impossible to read, but these encodings rarely if ever change, so it + # probably doesn't matter. They are derived from the list given here: + # https://encoding.spec.whatwg.org/#concept-encoding-get + _encodings=( + {{,us-}ascii,arabic,chinese,cyrillic,greek{,8},hebrew,korean} + logical visual mac {,cs}macintosh x-mac-{cyrillic,roman,ukrainian} + 866 ibm{819,866} csibm866 + big5{,-hkscs} {cn-,cs}big5 x-x-big5 + cp{819,866,125{0..8}} x-cp125{0..8} + csiso2022{jp,kr} csiso8859{6,8}{e,i} + csisolatin{{1..6},9} csisolatin{arabic,cyrillic,greek,hebrew} + ecma-{114,118} asmo-708 elot_928 sun_eu_greek + euc-{jp,kr} x-euc-jp cseuckr cseucpkdfmtjapanese + {,x-}gbk csiso58gb231280 gb18030 {,cs}gb2312 gb_2312{,-80} hz-gb-2312 + iso-2022-{cn,cn-ext,jp,kr} + iso8859{,-}{{1..11},13,14,15} + iso-8859-{{1..11},{6,8}-{e,i},13,14,15,16} iso_8859-{{1..9},15} + iso_8859-{1,2,6,7}:1987 iso_8859-{3,4,5,8}:1988 iso_8859-9:1989 + iso-ir-{58,100,101,109,110,126,127,138,144,148,149,157} + koi{,8,8-r,8-ru,8-u,8_r} cskoi8r + ks_c_5601-{1987,1989} ksc{,_}5691 csksc56011987 + latin{1..6} l{{1..6},9} + shift{-,_}jis csshiftjis {,x-}sjis ms_kanji ms932 + utf{,-}8 utf-16{,be,le} unicode-1-1-utf-8 + windows-{31j,874,949,125{0..8}} dos-874 tis-620 ansi_x3.4-1968 + x-user-defined auto none + ) + + _wanted encodings expl encoding compadd -a "$@" - _encodings +} + +# Complete file types +_rg_types() { + local -a expl + local -aU _types + + _types=( ${(@)${(f)"$( _call_program types rg --type-list )"}%%:*} ) + + _wanted types expl 'file type' compadd -a "$@" - _types +} + +_rg "$@" + +################################################################################ +# ZSH COMPLETION REFERENCE +# +# For the convenience of developers who aren't especially familiar with zsh +# completion functions, a brief reference guide follows. This is in no way +# comprehensive; it covers just enough of the basic structure, syntax, and +# conventions to help someone make simple changes like adding new options. For +# more complete documentation regarding zsh completion functions, please see the +# following: +# +# * http://zsh.sourceforge.net/Doc/Release/Completion-System.html +# * https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide +# +# OVERVIEW +# +# Most zsh completion functions are defined in terms of `_arguments`, which is a +# shell function that takes a series of argument specifications. The specs for +# `rg` are stored in an array, which is common for more complex functions; the +# elements of the array are passed to `_arguments` on invocation. +# +# ARGUMENT-SPECIFICATION SYNTAX +# +# The following is a contrived example of the argument specs for a simple tool: +# +# '(: * -)'{-h,--help}'[display help information]' +# '(-q -v --quiet --verbose)'{-q,--quiet}'[decrease output verbosity]' +# '!(-q -v --quiet --verbose)--silent' +# '(-q -v --quiet --verbose)'{-v,--verbose}'[increase output verbosity]' +# '--color=[specify when to use colors]:when:(always never auto)' +# '*:example file:_files' +# +# Although there may appear to be six specs here, there are actually nine; we +# use brace expansion to combine specs for options that go by multiple names, +# like `-q` and `--quiet`. This is customary, and ties in with the fact that zsh +# merges completion possibilities together when they have the same description. +# +# The first line defines the option `-h`/`--help`. With most tools, it isn't +# useful to complete anything after `--help` because it effectively overrides +# all others; the `(: * -)` at the beginning of the spec tells zsh not to +# complete any other operands (`:` and `*`) or options (`-`) after this one has +# been used. The `[...]` at the end associates a description with `-h`/`--help`; +# as mentioned, zsh will see the identical descriptions and merge these options +# together when offering completion possibilities. +# +# The next line defines `-q`/`--quiet`. Here we don't want to suppress further +# completions entirely, but we don't want to offer `-q` if `--quiet` has been +# given (since they do the same thing), nor do we want to offer `-v` (since it +# doesn't make sense to be quiet and verbose at the same time). We don't need to +# tell zsh not to offer `--quiet` a second time, since that's the default +# behaviour, but since this line expands to two specs describing `-q` *and* +# `--quiet` we do need to explicitly list all of them here. +# +# The next line defines a hidden option `--silent` — maybe it's a deprecated +# synonym for `--quiet`. The leading `!` indicates that zsh shouldn't offer this +# option during completion. The benefit of providing a spec for an option that +# shouldn't be completed is that, if someone *does* use it, we can correctly +# suppress completion of other options afterwards. +# +# The next line defines `-v`/`--verbose`; this works just like `-q`/`--quiet`. +# +# The next line defines `--color`. In this example, `--color` doesn't have a +# corresponding short option, so we don't need to use brace expansion. Further, +# there are no other options it's exclusive with (just itself), so we don't need +# to define those at the beginning. However, it does take a mandatory argument. +# The `=` at the end of `--color=` indicates that the argument may appear either +# like `--color always` or like `--color=always`; this is how most GNU-style +# command-line tools work. The corresponding short option would normally use `+` +# — for example, `-c+` would allow either `-c always` or `-calways`. For this +# option, the arguments are known ahead of time, so we can simply list them in +# parentheses at the end (`when` is used as the description for the argument). +# +# The last line defines an operand (a non-option argument). In this example, the +# operand can be used any number of times (the leading `*`), and it should be a +# file path, so we tell zsh to call the `_files` function to complete it. The +# `example file` in the middle is the description to use for this operand; we +# could use a space instead to accept the default provided by `_files`. +# +# GROUPING ARGUMENT SPECIFICATIONS +# +# Newer versions of zsh support grouping argument specs together. All specs +# following a `+` and then a group name are considered to be members of the +# named group. Grouping is useful mostly for organisational purposes; it makes +# the relationship between different options more obvious, and makes it easier +# to specify exclusions. +# +# We could rewrite our example above using grouping as follows: +# +# '(: * -)'{-h,--help}'[display help information]' +# '--color=[specify when to use colors]:when:(always never auto)' +# '*:example file:_files' +# + '(verbosity)' +# {-q,--quiet}'[decrease output verbosity]' +# '!--silent' +# {-v,--verbose}'[increase output verbosity]' +# +# Here we take advantage of a useful feature of spec grouping — when the group +# name is surrounded by parentheses, as in `(verbosity)`, it tells zsh that all +# of the options in that group are exclusive with each other. As a result, we +# don't need to manually list out the exclusions at the beginning of each +# option. +# +# Groups can also be referred to by name in other argument specs; for example: +# +# '(xyz)--aaa' '*: :_files' +# + xyz --xxx --yyy --zzz +# +# Here we use the group name `xyz` to tell zsh that `--xxx`, `--yyy`, and +# `--zzz` are not to be completed after `--aaa`. This makes the exclusion list +# much more compact and reusable. +# +# CONVENTIONS +# +# zsh completion functions generally adhere to the following conventions: +# +# * Use two spaces for indentation +# * Combine specs for options with different names using brace expansion +# * In combined specs, list the short option first (as in `{-a,--text}`) +# * Use `+` or `=` as described above for options that take arguments +# * Provide a description for all options, option-arguments, and operands +# * Capitalise/punctuate argument descriptions as phrases, not complete +# sentences — 'display help information', never 'Display help information.' +# (but still capitalise acronyms and proper names) +# * Write argument descriptions as verb phrases — 'display x', 'enable y', +# 'use z' +# * Word descriptions to make it clear when an option expects an argument; +# usually this is done with the word 'specify', as in 'specify x' or +# 'use specified x') +# * Write argument descriptions as tersely as possible — for example, articles +# like 'a' and 'the' should be omitted unless it would be confusing +# +# Other conventions currently used by this function: +# +# * Order argument specs alphabetically by group name, then option name +# * Group options that are directly related, mutually exclusive, or frequently +# referenced by other argument specs +# * Use only characters in the set [a-z0-9_-] in group names +# * Order exclusion lists as follows: short options, long options, groups +# * Use American English in descriptions +# * Use 'don't' in descriptions instead of 'do not' +# * Word descriptions for related options as similarly as possible. For example, +# `--foo[enable foo]` and `--no-foo[disable foo]`, or `--foo[use foo]` and +# `--no-foo[don't use foo]` +# * Word descriptions to make it clear when an option only makes sense with +# another option, usually by adding '(with -x)' to the end +# * Don't quote strings or variables unnecessarily. When quotes are required, +# prefer single-quotes to double-quotes +# * Prefix option specs with `$no` when the option serves only to negate the +# behaviour of another option that must be provided explicitly by the user. +# This prevents rarely used options from cluttering up the completion menu +################################################################################ + +# ------------------------------------------------------------------------------ +# Copyright (c) 2011 Github zsh-users - http://github.com/zsh-users +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the zsh-users nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL ZSH-USERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ------------------------------------------------------------------------------ +# Description +# ----------- +# +# Completion script for ripgrep +# +# ------------------------------------------------------------------------------ +# Authors +# ------- +# +# * arcizan +# * MaskRay +# +# ------------------------------------------------------------------------------ + +# Local Variables: +# mode: shell-script +# coding: utf-8-unix +# indent-tabs-mode: nil +# sh-indentation: 2 +# sh-basic-offset: 2 +# End: +# vim: ft=zsh sw=2 ts=2 et diff --git a/zsh/funcs/fzf_bindings.zsh b/zsh/funcs/fzf_bindings.zsh new file mode 100644 index 0000000..74ce9b7 --- /dev/null +++ b/zsh/funcs/fzf_bindings.zsh @@ -0,0 +1,121 @@ +# ____ ____ +# / __/___ / __/ +# / /_/_ / / /_ +# / __/ / /_/ __/ +# /_/ /___/_/ key-bindings.zsh +# +# - $FZF_TMUX_OPTS +# - $FZF_CTRL_T_COMMAND +# - $FZF_CTRL_T_OPTS +# - $FZF_CTRL_R_OPTS +# - $FZF_ALT_C_COMMAND +# - $FZF_ALT_C_OPTS + +# Key bindings +# ------------ + +# The code at the top and the bottom of this file is the same as in completion.zsh. +# Refer to that file for explanation. +if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then + __fzf_key_bindings_options="options=(${(j: :)${(kv)options[@]}})" +else + () { + __fzf_key_bindings_options="setopt" + 'local' '__fzf_opt' + for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do + if [[ -o "$__fzf_opt" ]]; then + __fzf_key_bindings_options+=" -o $__fzf_opt" + else + __fzf_key_bindings_options+=" +o $__fzf_opt" + fi + done + } +fi + +'emulate' 'zsh' '-o' 'no_aliases' + +{ + +[[ -o interactive ]] || return 0 + +# CTRL-T - Paste the selected file path(s) into the command line +__fsel() { + local cmd="${FZF_CTRL_T_COMMAND:-"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-"}" + setopt localoptions pipefail no_aliases 2> /dev/null + eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS" $(__fzfcmd) -m "$@" | while read item; do + echo -n "${(q)item} " + done + local ret=$? + echo + return $ret +} + +__fzfcmd() { + [ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; } && + echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf" +} + +fzf-file-widget() { + LBUFFER="${LBUFFER}$(__fsel)" + local ret=$? + zle reset-prompt + return $ret +} +zle -N fzf-file-widget +bindkey '^T' fzf-file-widget + +# Ensure precmds are run after cd +fzf-redraw-prompt() { + local precmd + for precmd in $precmd_functions; do + $precmd + done + zle reset-prompt +} +zle -N fzf-redraw-prompt + +# ALT-C - cd into the selected directory +fzf-cd-widget() { + local cmd="${FZF_ALT_C_COMMAND:-"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-"}" + setopt localoptions pipefail no_aliases 2> /dev/null + local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m)" + if [[ -z "$dir" ]]; then + zle redisplay + return 0 + fi + cd "$dir" + unset dir # ensure this doesn't end up appearing in prompt expansion + local ret=$? + zle fzf-redraw-prompt + return $ret +} +zle -N fzf-cd-widget +bindkey '\ec' fzf-cd-widget + +# CTRL-R - Paste the selected command from history into the command line +fzf-history-widget() { + local selected num + setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null + selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\s+(.*)/, $1)}++' | + FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) ) + local ret=$? + if [ -n "$selected" ]; then + num=$selected[1] + if [ -n "$num" ]; then + zle vi-fetch-history -n $num + fi + fi + zle reset-prompt + return $ret +} +zle -N fzf-history-widget +bindkey '^R' fzf-history-widget + +} always { + eval $__fzf_key_bindings_options + 'unset' '__fzf_key_bindings_options' +} diff --git a/zsh/funcs/skim.funcs b/zsh/funcs/skim.funcs deleted file mode 100644 index 32a1d14..0000000 --- a/zsh/funcs/skim.funcs +++ /dev/null @@ -1,86 +0,0 @@ -# Key bindings -# ------------ -if [[ $- == *i* ]]; then - -# CTRL-T - Paste the selected file path(s) into the command line -__fsel() { - local cmd="${SKIM_CTRL_T_COMMAND:-"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-"}" - setopt localoptions pipefail no_aliases 2> /dev/null - eval "$cmd" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_CTRL_T_OPTS" $(__skimcmd) -m "$@" | while read item; do - echo -n "${(q)item} " - done - local ret=$? - echo - return $ret -} - -__skim_use_tmux__() { - [ -n "$TMUX_PANE" ] && [ "${SKIM_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ] -} - -__skimcmd() { - __skim_use_tmux__ && - echo "sk-tmux -d${SKIM_TMUX_HEIGHT:-40%}" || echo "sk" -} - -skim-file-widget() { - LBUFFER="${LBUFFER}$(__fsel)" - local ret=$? - zle reset-prompt - return $ret -} -zle -N skim-file-widget -bindkey '^T' skim-file-widget - -# Ensure precmds are run after cd -skim-redraw-prompt() { - local precmd - for precmd in $precmd_functions; do - $precmd - done - zle reset-prompt -} -zle -N skim-redraw-prompt - -# ALT-C - cd into the selected directory -skim-cd-widget() { - local cmd="${SKIM_ALT_C_COMMAND:-"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-"}" - setopt localoptions pipefail no_aliases 2> /dev/null - local dir="$(eval "$cmd" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_ALT_C_OPTS" $(__skimcmd) -m)" - if [[ -z "$dir" ]]; then - zle redisplay - return 0 - fi - cd "$dir" - unset dir # ensure this doesn't end up appearing in prompt expansion - local ret=$? - zle skim-redraw-prompt - return $ret -} -zle -N skim-cd-widget -bindkey '\ec' skim-cd-widget - -# CTRL-R - Paste the selected command from history into the command line -skim-history-widget() { - local selected num - setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null - selected=( $(fc -rl 1 | - SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} $SKIM_DEFAULT_OPTIONS -n2..,.. --tiebreak=score,index $SKIM_CTRL_R_OPTS --query=${(qqq)LBUFFER} -m" $(__skimcmd)) ) - local ret=$? - if [ -n "$selected" ]; then - num=$selected[1] - if [ -n "$num" ]; then - zle vi-fetch-history -n $num - fi - fi - zle reset-prompt - return $ret -} -zle -N skim-history-widget -bindkey '^R' skim-history-widget - -fi