junegunn / fzf

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

--with-nth option appends extra delimiter when using a custom delimiter #2154

Open polijan opened 4 years ago

polijan commented 4 years ago

Info

Problem / Steps to reproduce

When using fzf with --with-nth and 1) specifying a custom delimiter (non space) and 2) selecting a single field (which isn't the last field), then an extra delimiter is being appended to the selected field.

Example:

echo '1:2:3:4' | fzf -d : --with-nth 2

expected in the finder: 2 what's being displayed: 2:

vejkse commented 4 years ago

This seems to be the same issue as #1792.

polijan commented 4 years ago

Ok, yes, it's similar to #1792 (I didn't see it, but now I can also see many more instances where people are puzzled by fzf's "fields" #1253 #2048 #2099 #1440 etc... ).

It's just extremely confusing:

echo '1:2:3' | fzf -d ':' --with-nth 1,3,2   => '1:32:'
# ^-- so, fields include a delimiter, but last field does not?
echo '1 2 3' | fzf -d ' ' --with-nth 1,3,2   => '1 32'
# ^-- now, why is there some special treatment for trailing ' ' "field" ?
echo '1.2.3' | fzf -d '.' --with-nth 1,3,2    => '12.'
# ^-- I really cannot understand what's going on here !!??!

Is that really the desired behavior? It's unsuitable for CSV files, or files like /etc/passwd, or any "fields" as generally understood by cut, awk, and every unix tool out there. If in fzf a "field" is by design totally different than anything else, at the very minimum it should be clear in the manpage (which instead explicitly refers to awk tool). My humble suggestion is still to align what a field means to the common concept (by awk, cut, etc.) as it would open up more possibilities when piping fzf with those tools.

junegunn commented 4 years ago

I'm not going to argue with what you think, I'll just try to explain why the examples work that way.

echo '1:2:3' | fzf -d ':' --with-nth 1,3,2   => '1:32:'
# ^-- so, fields include a delimiter, but last field does not?

In this case, the last field does not have a delimiter. One thing you should note is that -d option takes a regular expression rather than a plain string (see man fzf).

echo '1:2:;3' | fzf -d '[:;]+' --with-nth 1,3,2
# > 1:32:;

What character should fzf append after 3?


echo '1.2.3' | fzf -d '.' --with-nth 1,3,2    => '12.'

. is recognized as a regular expression matching any character. So each character becomes a field of its own. If you want to use literal . as a delimiter, you should escape it with a backslash.

echo '1.2.3.' | fzf -d '\.' --with-nth 1,3,2
# > 1.3.2.

As I mentioned in the previous issues, --with-nth option was primarily designed for simpler use cases,

# Hiding long, unreadable identifier
fzf --with-nth 2 << EOF | awk '{print $1}'
f1d2d2f924e986ac86fdf7b36c94bcdf32beec15  foo
e242ed3bffccdf271b7fbaf34ed72d089537b42f  bar
EOF

and it's really not a replacement for proper text processors you mentioned. I would suggest that you preprocess input text with a program that you're comfortable with and use --with-nth of fzf only to hide one or two fields.

polijan commented 4 years ago

thanks for the explanation

vovcacik commented 2 years ago

I have also run into this:

echo foobar > test.txt
rg --no-heading foobar | fzf --delimiter ":" --with-nth 1

Fzf then displays test.txt: and query of txt$ won't work as intended, since then colon is part of the match. I think ripgrep can be configured with custom separator, so I could use the whitespace workaround (#1792), but that seems like a stretch. Also my data can contain any whitespace character.

vovcacik commented 2 years ago

I have got fix for this. It changes the item string as follows:

echo 1:2:3:| fzf -d ":" --with-nth 1,3,2
"1:3:2:" (current)
"1:3:2" (new)

echo 1 2 3 | fzf -d " " --with-nth 1,3,2
"1 3 2"
"1 3 2"

echo 1.2.3.| fzf -d "." --with-nth 1,3,2
"12."
"12"

echo 1.2.3| fzf -d "." --with-nth 1,3,2
"12."
"12"

echo 1.2.3.| fzf -d "\." --with-nth 1,3,2
"1.3.2."
"1.3.2"

echo 1.2.3.| fzf -d "\." --with-nth 1,3,2
"1.32."
"1.32"

echo 1:2:;3;| fzf -d "[:;]+" --with-nth 1,3,2
"1:3;2:;"
"1:3;2"

echo 1:2:;3| fzf -d "[:;]+" --with-nth 1,3,2
"1:32:;"
"1:32"

It works fine for the reasonable examples.