Fzf: Bundling fzf as a library in a Go project

Created on 26 Jun 2020  路  6Comments  路  Source: junegunn/fzf

  • [x] I have read through the manual page (man fzf)
  • [x] I have the latest version of fzf
  • [x] I have searched through the existing issues

Info

  • OS

    • [x] Linux

    • [x] Mac OS X

    • [x] Windows

    • [x] Etc.

  • Shell

    • [x] bash

    • [x] zsh

    • [x] fish

Problem / Steps to reproduce

Hi, I'd love to use fzf in our Go project, but we would prefer to bundle it as a runtime module rather than shelling out to fzf which is not guaranteed to be present on a person's system. Here's a sketch of how we would use it (note that we currently shell out).

It looks like right now, fzf is not designed to run as a library, since most of the implementation is in a giant function Run() that invokes os.Exit upon completion, effectively shutting down the parent process. Furthermore, there doesn't seem to be a way to instantiate the options struct with arbitrary args instead of os.Args.

Would this project accept contributions that make it possible for fzf to be used as a library in addition to being its own executable? Thank you!

duplicate

Most helpful comment

And instead of calling os.Exit(code) in Run(), have it instead return the code, and then have main() exit with the return value of Run(). If this sounds workable I can prepare a PR this week (this is my first time looking at the codebase).

All 6 comments

This would be awesome! I just came here looking for the ability to do just this, and would also be interested in helping.

See:

I'm not particularly interested or motivated in designing and maintaining the API because fzf was strictly designed to be an individual program like many other programs in the Unix toolchain and I personally don't see myself needing it as a library. However, as long as we keep the API undocumented, which frees me from the future maintenance burden, I'm open to the suggestion.

I understand that you want to avoid shelling out, but I think shelling out is not such a bad idea. It gives your users more flexibility to

  • upgrade or modify fzf separately (e.g. using their own forks)
  • choose between alternative implementations of the same idea (peco, percol, fzy, selecta to name a few)
  • start fzf in a tmux popup window using fzf-tmux instead which is really great (https://github.com/junegunn/fzf/pull/1946)

And installing fzf as a dependency is trivial because more users these days use package managers such as Homebrew.

I'm not particularly interested or motivated in designing and maintaining the API because fzf was strictly designed to be an individual program like many other programs in the Unix toolchain and I personally don't see myself needing it as a library. However, as long as we keep the API undocumented, which frees me from the future maintenance burden, I'm open to the suggestion.

An undocumented API sounds like a fair compromise :)

@junegunn Thanks for chiming in! I see your point regarding maintenance. As a maintainer myself, I would definitely _not_ look forward to maintaining two separate APIs for this tool, especially if I don't ever use the 2nd one myself.

I also would not recommend breaking up the entire Run() function into discrete functions, since that would be risky and I don't even think I could pull it off, since I don't understand what most of it does 馃槄

The only thing I would try to accomplish in a fork would be to allow the code to accept inputs other than os.Args and os.Stdin, and to allow results other than to os.Stdout followed by an os.Exit(). This might be made possible without significant changes. If we come up with a set of changes that don't look overly risky, we might propose a PR to this project and see how you feel about it. In the meantime, feel free to close this issue as per others that were closed before this.

The only thing I would try to accomplish in a fork would be to allow the code to accept inputs other than os.Args and os.Stdin, and to allow results other than to os.Stdout followed by an os.Exit().

What about parsing arguments before invoking Run() and passing them in as an argument, in addition to stdin/stdout overrides?

And instead of calling os.Exit(code) in Run(), have it instead return the code, and then have main() exit with the return value of Run(). If this sounds workable I can prepare a PR this week (this is my first time looking at the codebase).

Was this page helpful?
0 / 5 - 0 ratings