fzf: Using fzf in your program

Using fzf in your program #

While fzf is most commonly used in shell scripts, you can also use it in your programs written in different languages.

As a Go library #

fzf is written in Go, so you can use it as a library in your Go programs. However, the API is experimental and subject to change. I’ll try to keep this gist up-to-date with the latest changes.

In other languages #

Even if you’re not using Go, you can still use fzf in your programs as an external command. Here are some examples in different languages.

Ruby #

We write generic with_filter function that takes a command as the first argument and a block which produces the input to the command, and returns the selected entries as an array.

def with_filter(command)
  io = IO.popen(command, 'r+')
  begin
    stdout, $stdout = $stdout, io
    yield rescue nil
  ensure
    $stdout = stdout
  end
  io.close_write
  io.readlines.map(&:chomp)
end

result = with_filter('fzf -m') do
  1000.times do |n|
    puts n
    sleep 0.005
  end
end

pp result

Python #

Translated to Python.

import subprocess
import sys
import time

def with_filter(command, work):
    process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True, shell=True)
    original_stdout = sys.stdout
    sys.stdout = process.stdin
    try:
        work()
        process.stdin.close()
    except:
        pass
    finally:
        sys.stdout = original_stdout

    output = process.stdout.read().splitlines()
    process.stdout.close()
    return output

def work():
    for n in range(1000):
        print(n, flush=True)
        time.sleep(0.005)

print(with_filter('fzf -m', work))

Clojure #

We do the same with Clojure. The code here is a bit more involved, but it will give you a hint on how it can be done in other JVM languages.

(require '[clojure.java.io :as io])

(defmacro with-filter
  [command & forms]
  `(let [sh#  (or (System/getenv "SHELL") "sh")
         pb#  (ProcessBuilder. [sh# "-c" ~command])
         p#   (.start pb#)
         in#  (io/reader (.getInputStream p#))
         out# (io/writer (.getOutputStream p#))]
     (binding [*out* out#]
       (try ~@forms (.close out#) (catch Exception e#)))
     (take-while identity (repeatedly #(.readLine in#)))))

(let [result (with-filter "fzf -m"
               (dotimes [n 1000]
                 (println n)
                 (Thread/sleep 5)))]
  (println result))
Last modified: Jun 5, 2024
Copyright © 2024 Junegunn Choi