fzf icon indicating copy to clipboard operation
fzf copied to clipboard

[Feat] Allow adjustment of output formatting

Open ferguscollins opened this issue 9 months ago • 5 comments

Checklist

  • [x] I have read through the manual page (man fzf)
  • [x] I have searched through the existing issues
  • [ ] For bug reports, I have checked if the bug is reproducible in the latest version of fzf

Output of fzf --version

0.60.3 (0012183e)

OS

  • [ ] Linux
  • [ ] macOS
  • [x] Windows
  • [ ] Etc.

Shell

  • [ ] bash
  • [ ] zsh
  • [ ] fish

Problem / Steps to reproduce

Right now using {n} outputs the field in double quotes. In nix I can easily trim this but in Windows this becomes a hassle and requires post processing of the fzf output outside of the fzf call itself.

Could an option be added to define what the wrapping character is? Or just a toggle to remove it?

Example:

$ type file.csv
test

$ type file.csv | fzf --bind "enter:accept"
test

$ type file.csv | fzf --bind "enter:execute(echo {})+abort"
"test"

This is a minimum example to showcase the output difference, I am aware that the function in the example is no different to the regular fzf output.

ferguscollins avatar Mar 21 '25 10:03 ferguscollins

Have you tested --accept-nth?

junegunn avatar Mar 22 '25 00:03 junegunn

I have, it does not change the quote wrapping between accept and echoing the output.

ferguscollins avatar Mar 22 '25 07:03 ferguscollins

Can you test again? --accept-nth doesn't produce quotes.

$ echo foo bar | fzf --accept-nth 2
bar

junegunn avatar Mar 22 '25 10:03 junegunn

Apologies I wasn't clear in which part produces quotes, I am specifically talking about using {n} to output either part or all of the selected row.

$ echo test | fzf --accept-nth 1
test

$ echo test | fzf --accept-nth 1 --bind "enter:execute(echo {1})+abort"
"test"

$ echo test | fzf --accept-nth 1 --bind "enter:execute(echo {})+abort"
"test"

This is always formatted differently to the output of accept and needs to be handled differently between accept and {} if the quotes need to be trimmed (apologies for the word vomit of a sentence, I am not sure how else to describe the caveat). If multiple combinations need to be selectable then using --accept-nth is not an option as it can only be used for a single combination.

In the below examples, selecting a value with enter will yield the first two fields formatted without quotes, and selecting with f1 or f2 will yield the first and last fields with different kinds of quotation. In a single call of fzf the logical option is to never use --accept-nth if multiple output options are required as then you will be forced to account for different kinds of output formatting as opposed to only having to deal with quotes when using {n}.

$ echo foo bar baz | fzf --accept-nth 1,2 
foo bar

$ echo foo bar baz | fzf --bind "f1:execute(echo {1,3})+abort"
"foo baz"

$ echo foo bar baz | fzf --bind "f2:execute(echo {1} {3})+abort"
"foo" "baz"

On Linux this isn't a problem as the formatting of {n} and accept are the same. All of my post processing scripts that rely on consistent output formatting would need to have handling added for use in Windows, it makes portability between OSes more difficult.

I would argue that all of the outputs should be formatted consistently, and that that format should be without quotes for all options as it is when using fzf on Linux. This may impact legacy implementations on Windows however hence the feature request instead of a bug report.

I should have included all of this detail in the initial post, I realise it is not as clear as it was in my head.

ferguscollins avatar Mar 23 '25 11:03 ferguscollins

We need to clarify a few things.


A placeholder expression is designed to be evaluated to a quoted string, so that it can be safely passed as an argument to an external program. It was first introduced to be used with --preview option.

fzf --preview 'cat {}'

However, it looks like echo of Windows, unlike in Linux, behaves differently and does not recognize single quotes as quoting characters. So I guess this automatic quoting may not be desirable on Windows. Related #4330.


Another thing.

echo test | fzf --accept-nth 1 --bind "enter:execute(echo {1})+abort"

FWIW, this strategy will not work on non-Windows binaries since 0.53.0.

  • Process started by execute action now directly writes to and reads from /dev/tty. Manual /dev/tty redirection for interactive programs is no longer required.
    # Vim will work fine without /dev/tty redirection
    ls | fzf --bind 'space:execute:vim {}' > selected
    

The output of execute is directed to /dev/tty and you can't capture it.

echo test | fzf --bind 'enter:execute(echo {1})+abort' | wc
# test
#        0       0       0

You're supposed to use become action instead.

echo test | fzf --bind "enter:become(echo {1})" | wc
       1       1       5

become also works on Windows, so you should use it instead of the old execute way.


If multiple combinations need to be selectable then using --accept-nth is not an option as it can only be used for a single combination.

You can specify a template if you need multiple placeholders.

echo foo bar baz | fzf --accept-nth '[template example] {1} // {1,3,2} // {1} {3} {2} // {-1}'
    # [template example] foo // foo bazbar // foo baz bar // baz
  • Note that the output of each placeholder expression is not quoted. That's because when you use --accept-nth, it's not executing an external program, but it's just expanding the template string. So no quoting for argument passing.
  • Also note that {1,3,2} and {1} {3} {2} give different results.
  • You can read more about the template in https://junegunn.github.io/fzf/releases/0.60.0/

format should be without quotes for all options as it is when using fzf on Linux

As noted above, each placeholder expression is "always" quoted and properly escaped to be passed as an argument on Linux. Say you have a file named it's mine and you want to preview the file. If {} isn't quoted, it's unnecessarily tricky to handle it correctly.

fzf --preview 'cat {}'

becomes cat it's mine, and you'll get unexpected EOF while looking for matching ' error.

Manual quoting doesn't work either.

fzf --preview "cat '{}'"

becomes cat 'it's mine', and you get the same error. So, fzf quotes it for you, escaping single quotes in it, so cat {} "just works".


fzf also does quoting on Windows, but using a different set of rules.

https://github.com/junegunn/fzf/blob/ba6d1b8772ce5e75ff999dcca21c0fadb689d7bf/src/util/util_windows.go#L142-L165

Coming up with the rule was painful due to many edge cases, but I guess it's still not perfect. See #2609 and #3651.

junegunn avatar Mar 29 '25 06:03 junegunn