diff --git a/shell/key-bindings.fish b/shell/key-bindings.fish index 03b543ea33c..803d0a937df 100644 --- a/shell/key-bindings.fish +++ b/shell/key-bindings.fish @@ -4,14 +4,9 @@ function fzf_key_bindings # Store current token in $dir as root for the 'find' command function fzf-file-widget -d "List files and folders" - set -l dir (commandline -t) - # The commandline token might be escaped, we need to unescape it. - set dir (eval "printf '%s' $dir") - if [ ! -d "$dir" ] - set dir . - end - # Some 'find' versions print undesired duplicated slashes if the path ends with slashes. - set dir (string replace --regex '(.)/+$' '$1' "$dir") + set -l commandline (__fzf_parse_commandline) + set -l dir $commandline[1] + set -l fzf_query $commandline[2] # "-path \$dir'*/\\.*'" matches hidden files/folders inside $dir but not # $dir itself, even if hidden. @@ -24,7 +19,7 @@ function fzf_key_bindings set -q FZF_TMUX_HEIGHT; or set FZF_TMUX_HEIGHT 40% begin set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS" - eval "$FZF_CTRL_T_COMMAND | "(__fzfcmd)" -m" | while read -l r; set result $result $r; end + eval "$FZF_CTRL_T_COMMAND | "(__fzfcmd)' -m --query "'$fzf_query'"' | while read -l r; set result $result $r; end end if [ -z "$result" ] commandline -f repaint @@ -51,15 +46,26 @@ function fzf_key_bindings end function fzf-cd-widget -d "Change directory" + set -l commandline (__fzf_parse_commandline) + set -l dir $commandline[1] + set -l fzf_query $commandline[2] + set -q FZF_ALT_C_COMMAND; or set -l FZF_ALT_C_COMMAND " - command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \ - -o -type d -print 2> /dev/null | cut -b3-" + command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \ + -o -type d -print 2> /dev/null | sed 's@^\./@@'" set -q FZF_TMUX_HEIGHT; or set FZF_TMUX_HEIGHT 40% begin set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" - eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)" +m" | read -l result - [ "$result" ]; and cd $result + eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)' +m --query "'$fzf_query'"' | read -l result + + if [ -n "$result" ] + cd $result + + # Remove last token from commandline. + commandline -t "" + end end + commandline -f repaint end @@ -82,4 +88,47 @@ function fzf_key_bindings bind -M insert \cr fzf-history-widget bind -M insert \ec fzf-cd-widget end + + function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath and rest of token' + # eval is used to do shell expansion on paths + set -l commandline (eval "printf '%s' "(commandline -t)) + + if [ -z $commandline ] + # Default to current directory with no --query + set dir '.' + set fzf_query '' + else + set dir (__fzf_get_dir $commandline) + + if [ "$dir" = "." -a (string sub -l 1 $commandline) != '.' ] + # if $dir is "." but commandline is not a relative path, this means no file path found + set fzf_query $commandline + else + # Also remove trailing slash after dir, to "split" input properly + set fzf_query (string replace -r "^$dir/?" '' "$commandline") + end + end + + echo $dir + echo $fzf_query + end + + function __fzf_get_dir -d 'Find the longest existing filepath from input string' + set dir $argv + + # Strip all trailing slashes. Ignore if $dir is root dir (/) + if [ (string length $dir) -gt 1 ] + set dir (string replace -r '/*$' '' $dir) + end + + # Iteratively check if dir exists and strip tail end of path + while [ ! -d "$dir" ] + # If path is absolute, this can keep going until ends up at / + # If path is relative, this can keep going until entire input is consumed, dirname returns "." + set dir (dirname "$dir") + end + + echo $dir + end + end