junegunn / fzf

:cherry_blossom: A command-line fuzzy finder
https://junegunn.github.io/fzf/
MIT License
65.64k stars 2.41k forks source link

__fzf_cd__: initial backslash before ~ means alt-c chdir fails #1089

Closed jjkakakk closed 7 years ago

jjkakakk commented 7 years ago

On ALT-C chdir completion:

selecting the desired directory: in ~ directory folder structure ~/wibble wobble/foo

ALT-C wibb wob foo -> Enter

__fzf_cd__ $ cd \~/wibble\ wobble/foo -bash: cd: ~/wibble wobble/foo: Not a directory

the issue seems to be the initial escaping of the ~ character

junegunn commented 7 years ago

Do you use a custom FZF_ALT_C_COMMAND? The default command shouldn't print ~.

> cd ~
> mkdir -p "foo bar"/baz
> [ALT-C]
> cd foo\ bar/baz
/Users/jg/foo bar/baz
aurelg commented 7 years ago

I have the same problem on linux with bash when I use export FZF_ALT_C_COMMAND="cd ~/; bfs -type d -nohidden | sed s/^\./~/" , as described in FZF and RipGrep – Navigate with bash faster than ever before. It's like ~ is not expanded to $HOME anymore, and escaped. With zsh, no error is reported but the directory is not changed.

jjkakakk commented 7 years ago

same, can confirm that this change fixes it:

declare -x FZF_ALT_C_COMMAND="cd ~/; bfs -type d -nohidden | sed 's/^\\./\\/Users\\/me\\//'"

thanks

junegunn commented 7 years ago

The contract of FZF_ALT_C_COMMAND has been that it has to generate a list of unescaped paths (e.g. whitespaces, $, ~, !, etc.). Because most (as far as I know "all") directory traversal programs do not "shell-escape" paths.

$ mkdir /tmp/test
$ cd /tmp/test/
$ mkdir 'foo bar'
$ touch 'foo bar/$baz'

$ find .
.
./foo bar
./foo bar/$baz

$ rg --files
foo bar/$baz

$ ag -g ''
foo bar/$baz

$ git init
Initialized empty Git repository in /private/tmp/test/.git/
$ git add .
$ git ls-files
foo bar/$baz

And we have to escape the raw string before passing it to cd.

$ file foo bar/$baz
foo:  cannot open `foo' (No such file or directory)
bar/: cannot open `bar/' (No such file or directory)

$ file foo\ bar/\$baz
foo bar/$baz: empty

It's clear that the example in that blog post is not compatible with the current implementation of ALT-C. So you have three options:

  1. Do not use the example. Use commands that print relative paths to the current working directory. ALT-C was specifically designed for that purpose. To cd into a directory not under the current directory, use fuzzy cd completion.
cd **<tab>
cd ~/**<tab>
cd /tmp/**<tab>
  1. Replace ~ with the absolute path of your home directory as suggested above. I believe you can even hide the common prefix with the combination of --delimiter / and --with-nth 4..

  2. Write your own ALT-C implementation, and override the default version with it. It's actually trivial if you know how to write shell scripts. https://github.com/junegunn/fzf/blob/eaf6eb897879becff31ea9b27046c0eff9e1e646/shell/key-bindings.bash#L47-L52