mirror of
https://github.com/XNM1/linux-nixos-hyprland-config-dotfiles.git
synced 2025-09-15 09:45:58 +03:00

Add fzf key bindings function file with support for: - File search widget (Ctrl+T) - Command history search (Ctrl+R) (replaced by custom implementation) - Directory navigation (Alt+C) (replaced by custom implementation) Bindings work in both normal and insert modes, providing fuzzy search capabilities for fish shell navigation and command history.
232 lines
9.9 KiB
Fish
232 lines
9.9 KiB
Fish
### key-bindings.fish ###
|
|
# ____ ____
|
|
# / __/___ / __/
|
|
# / /_/_ / / /_
|
|
# / __/ / /_/ __/
|
|
# /_/ /___/_/ key-bindings.fish
|
|
#
|
|
# - $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 oldest supported fish version is 3.1b1. To maintain compatibility, the
|
|
# command substitution syntax $(cmd) should never be used, even behind a version
|
|
# check, otherwise the source command will fail on fish versions older than 3.4.0.
|
|
function fzf_key_bindings
|
|
|
|
# Check fish version
|
|
set -l fish_ver (string match -r '^(\d+).(\d+)' $version 2> /dev/null; or echo 0\n0\n0)
|
|
if test \( "$fish_ver[2]" -lt 3 \) -o \( "$fish_ver[2]" -eq 3 -a "$fish_ver[3]" -lt 1 \)
|
|
echo "This script requires fish version 3.1b1 or newer." >&2
|
|
return 1
|
|
else if not type -q fzf
|
|
echo "fzf was not found in path." >&2
|
|
return 1
|
|
end
|
|
|
|
function __fzf_defaults
|
|
# $argv[1]: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
|
# $argv[2..]: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
|
test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40%
|
|
string join ' ' -- \
|
|
"--height $FZF_TMUX_HEIGHT --min-height=20+ --bind=ctrl-z:ignore" $argv[1] \
|
|
(test -r "$FZF_DEFAULT_OPTS_FILE"; and string join -- ' ' <$FZF_DEFAULT_OPTS_FILE) \
|
|
$FZF_DEFAULT_OPTS $argv[2..-1]
|
|
end
|
|
|
|
function __fzfcmd
|
|
test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40%
|
|
if test -n "$FZF_TMUX_OPTS"
|
|
echo "fzf-tmux $FZF_TMUX_OPTS -- "
|
|
else if test "$FZF_TMUX" = 1
|
|
echo "fzf-tmux -d$FZF_TMUX_HEIGHT -- "
|
|
else
|
|
echo fzf
|
|
end
|
|
end
|
|
|
|
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
|
|
set -l fzf_query ''
|
|
set -l prefix ''
|
|
set -l dir '.'
|
|
|
|
# Set variables containing the major and minor fish version numbers, using
|
|
# a method compatible with all supported fish versions.
|
|
set -l -- fish_major (string match -r -- '^\d+' $version)
|
|
set -l -- fish_minor (string match -r -- '^\d+\.(\d+)' $version)[2]
|
|
|
|
# fish v3.3.0 and newer: Don't use option prefix if " -- " is preceded.
|
|
set -l -- match_regex '(?<fzf_query>[\s\S]*?(?=\n?$)$)'
|
|
set -l -- prefix_regex '^-[^\s=]+=|^-(?!-)\S'
|
|
if test "$fish_major" -eq 3 -a "$fish_minor" -lt 3
|
|
or string match -q -v -- '* -- *' (string sub -l (commandline -Cp) -- (commandline -p))
|
|
set -- match_regex "(?<prefix>$prefix_regex)?$match_regex"
|
|
end
|
|
|
|
# Set $prefix and expanded $fzf_query with preserved trailing newlines.
|
|
if test "$fish_major" -ge 4
|
|
# fish v4.0.0 and newer
|
|
string match -q -r -- $match_regex (commandline --current-token --tokens-expanded | string collect -N)
|
|
else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
|
|
# fish v3.2.0 - v3.7.1 (last v3)
|
|
string match -q -r -- $match_regex (commandline --current-token --tokenize | string collect -N)
|
|
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)' '')
|
|
else
|
|
# fish older than v3.2.0 (v3.1b1 - v3.1.2)
|
|
set -l -- cl_token (commandline --current-token --tokenize | string collect -N)
|
|
set -- prefix (string match -r -- $prefix_regex $cl_token)
|
|
set -- fzf_query (string replace -- "$prefix" '' $cl_token | string collect -N)
|
|
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)|\\\n\\\n$' '')
|
|
end
|
|
|
|
if test -n "$fzf_query"
|
|
# Normalize path in $fzf_query, set $dir to the longest existing directory.
|
|
if test \( "$fish_major" -ge 4 \) -o \( "$fish_major" -eq 3 -a "$fish_minor" -ge 5 \)
|
|
# fish v3.5.0 and newer
|
|
set -- fzf_query (path normalize -- $fzf_query)
|
|
set -- dir $fzf_query
|
|
while not path is -d $dir
|
|
set -- dir (path dirname $dir)
|
|
end
|
|
else
|
|
# fish older than v3.5.0 (v3.1b1 - v3.4.1)
|
|
if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
|
|
# fish v3.2.0 - v3.4.1
|
|
string match -q -r -- '(?<fzf_query>^[\s\S]*?(?=\n?$)$)' \
|
|
(string replace -r -a -- '(?<=/)/|(?<!^)/+(?!\n)$' '' $fzf_query | string collect -N)
|
|
else
|
|
# fish v3.1b1 - v3.1.2
|
|
set -- fzf_query (string replace -r -a -- '(?<=/)/|(?<!^)/+(?!\n)$' '' $fzf_query | string collect -N)
|
|
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r '\\\n$' '')
|
|
end
|
|
set -- dir $fzf_query
|
|
while not test -d "$dir"
|
|
set -- dir (dirname -z -- "$dir" | string split0)
|
|
end
|
|
end
|
|
|
|
if not string match -q -- '.' $dir; or string match -q -r -- '^\./|^\.$' $fzf_query
|
|
# Strip $dir from $fzf_query - preserve trailing newlines.
|
|
if test "$fish_major" -ge 4
|
|
# fish v4.0.0 and newer
|
|
string match -q -r -- '^'(string escape --style=regex -- $dir)'/?(?<fzf_query>[\s\S]*)' $fzf_query
|
|
else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
|
|
# fish v3.2.0 - v3.7.1 (last v3)
|
|
string match -q -r -- '^/?(?<fzf_query>[\s\S]*?(?=\n?$)$)' \
|
|
(string replace -- "$dir" '' $fzf_query | string collect -N)
|
|
else
|
|
# fish older than v3.2.0 (v3.1b1 - v3.1.2)
|
|
set -- fzf_query (string replace -- "$dir" '' $fzf_query | string collect -N)
|
|
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^/?|\\\n$' '')
|
|
end
|
|
end
|
|
end
|
|
|
|
string escape -n -- "$dir" "$fzf_query" "$prefix"
|
|
end
|
|
|
|
# Store current token in $dir as root for the 'find' command
|
|
function fzf-file-widget -d "List files and folders"
|
|
set -l commandline (__fzf_parse_commandline)
|
|
set -lx dir $commandline[1]
|
|
set -l fzf_query $commandline[2]
|
|
set -l prefix $commandline[3]
|
|
|
|
set -lx FZF_DEFAULT_OPTS (__fzf_defaults \
|
|
"--reverse --walker=file,dir,follow,hidden --scheme=path" \
|
|
"$FZF_CTRL_T_OPTS --multi --print0")
|
|
|
|
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
|
|
set -lx FZF_DEFAULT_OPTS_FILE
|
|
|
|
set -l result (eval (__fzfcmd) --walker-root=$dir --query=$fzf_query | string split0)
|
|
and commandline -rt -- (string join -- ' ' $prefix(string escape -- $result))' '
|
|
|
|
commandline -f repaint
|
|
end
|
|
|
|
function fzf-history-widget -d "Show command history"
|
|
set -l -- command_line (commandline)
|
|
set -l -- current_line (commandline -L)
|
|
set -l -- total_lines (count $command_line)
|
|
set -l -- fzf_query (string escape -- $command_line[$current_line])
|
|
|
|
set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \
|
|
'--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \
|
|
'--bind=\'shift-delete:execute-silent(eval history delete --exact --case-sensitive -- (string escape -n -- {+} | string replace -r -a "^\d*\\\\\\t|(?<=\\\\\\n)\\\\\\t" ""))+reload(eval $FZF_DEFAULT_COMMAND)\'' \
|
|
"--bind=ctrl-r:toggle-sort --highlight-line $FZF_CTRL_R_OPTS" \
|
|
'--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c)
|
|
|
|
set -lx FZF_DEFAULT_OPTS_FILE
|
|
set -lx FZF_DEFAULT_COMMAND
|
|
|
|
if type -q perl
|
|
set -a FZF_DEFAULT_OPTS --tac
|
|
set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\''
|
|
else
|
|
set FZF_DEFAULT_COMMAND \
|
|
'set -l h (builtin history -z --reverse | string split0);' \
|
|
'for i in (seq (count $h) -1 1);' \
|
|
'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \
|
|
end
|
|
end
|
|
|
|
# Merge history from other sessions before searching
|
|
test -z "$fish_private_mode"; and builtin history merge
|
|
|
|
if set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query | string split0)
|
|
if test "$total_lines" -eq 1
|
|
commandline -- (string replace -a -- \n\t \n $result)
|
|
else
|
|
set -l a (math $current_line - 1)
|
|
set -l b (math $current_line + 1)
|
|
commandline -- $command_line[1..$a] (string replace -a -- \n\t \n $result)
|
|
commandline -a -- '' $command_line[$b..-1]
|
|
end
|
|
end
|
|
|
|
commandline -f repaint
|
|
end
|
|
|
|
function fzf-cd-widget -d "Change directory"
|
|
set -l commandline (__fzf_parse_commandline)
|
|
set -lx dir $commandline[1]
|
|
set -l fzf_query $commandline[2]
|
|
set -l prefix $commandline[3]
|
|
|
|
set -lx FZF_DEFAULT_OPTS (__fzf_defaults \
|
|
"--reverse --walker=dir,follow,hidden --scheme=path" \
|
|
"$FZF_ALT_C_OPTS --no-multi --print0")
|
|
|
|
set -lx FZF_DEFAULT_OPTS_FILE
|
|
set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND"
|
|
|
|
if set -l result (eval (__fzfcmd) --query=$fzf_query --walker-root=$dir | string split0)
|
|
cd -- $result
|
|
commandline -rt -- $prefix
|
|
end
|
|
|
|
commandline -f repaint
|
|
end
|
|
|
|
bind \cr fzf-history-widget
|
|
bind -M insert \cr fzf-history-widget
|
|
|
|
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
|
bind \ct fzf-file-widget
|
|
bind -M insert \ct fzf-file-widget
|
|
end
|
|
|
|
if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND"
|
|
bind \ec fzf-cd-widget
|
|
bind -M insert \ec fzf-cd-widget
|
|
end
|
|
|
|
end
|
|
### end: key-bindings.fish ###
|