Membedah model dasar fzf dari stdin ke filter ke stdout, cara kerja fuzzy matching berbasis subsequence dan skor relevansi, bahasa exit code, serta anatomi komponen utama antarmukanya.

Setelah di episode 1 kita memahami sejarah fzf — dari plugin Vim 2013 karya Junegunn Choi hingga standar de-facto dalam Go — sekarang saatnya membedah bagaimana fzf bekerja dari dalam. Episode ini adalah jembatan antara "kenapa fzf ada" dan "bagaimana memakainya dengan benar", jadi perhatikan alurnya baik-baik.
Banyak pengguna fzf memakainya seperti kotak ajaib: beri daftar, dapatkan pilihan. Padahal di balik itu ada model kerja yang sederhana dan bisa diprediksi. Memahami model ini — seperti membuka kap mesin sebelum menyetir — akan membuat kalian jauh lebih percaya diri saat hasilnya tidak sesuai harapan, dan lebih siap memanfaatkan opsi-opsi yang kita bahas di episode-episode berikutnya.
Jika harus mereduksi fzf menjadi satu kalimat: fzf membaca item dari stdin, menampilkannya secara interaktif, lalu mencetak item yang dipilih ke stdout.
stdin -> fzf (UI interaktif) -> stdoutAda tiga tahap dalam model ini, dan setiap tahap punya peran yang jelas:
ls, find, rg, git branch, atau bahkan cat.Enter, fzf mencetak item terpilih ke output standar, siap diteruskan ke perintah berikutnya dalam pipeline.Pola inilah yang membuat fzf begitu fleksibel: karena ia tidak peduli daftarnya berasal dari mana, ia bisa dipakai untuk memilih file, proses, branch, atau riwayat dengan cara yang sama persis.
printf "apple\nbanana\ncherry\n" | fzfJalankan perintah di atas, ketik ba, tekan Enter — fzf akan mencetak banana ke terminal. Sekarang tambahkan perintah lanjutan untuk membuktikan bahwa outputnya benar-benar terus mengalir ke pipeline:
printf "apple\nbanana\ncherry\n" | fzf | wc -lJika kalian memilih banana, perintah di atas mencetak 1 — fzf menghasilkan satu baris, dan wc -l menghitungnya. Inilah esensi arsitektur fzf: dia adalah filter, bukan tujuan akhir. Nilainya justru paling terasa ketika outputnya dipakai perintah lain.
Fuzzy matching di balik fzf bertumpu pada satu konsep: subsequence. Sekumpulan karakter dikatakan cocok dengan sebuah item jika karakter-karakter tersebut muncul di dalam item dengan urutan yang sama — meskipun tidak bersebelahan.
Ambil contoh query fzf dan item learn-fzf. Semua huruf f, z, f muncul berurutan di dalam item, jadi cocok. Sekarang query lrf terhadap item yang sama: l cocok, r cocok, f cocok — tetap berurutan, tetap cocok, hanya dengan celah di antaranya. Itulah kekuatan fuzzy matching: kalian tidak perlu mengetik item secara utuh.
printf "learn-fzf\nfzf\ntmux\nzellij\n" | fzfCoba ketik lz pada contoh di atas — kalian akan melihat hasil yang menarik: learn-fzf bisa cocok (huruf l dan z ada dan berurutan), begitu juga zellij. Di sinilah skor berperan.
Fzf tidak sekadar "cocok atau tidak" — ia menghitung skor relevansi untuk setiap item, lalu mengurutkan berdasarkan skor. Semakin baik kualitas kecocokan — misalnya karakter bersebelahan, berada di awal kata, atau membentuk awalan kata — semakin tinggi skornya. Item dengan skor tertinggi menempati posisi teratas, sehingga hasil yang paling relevan selalu mudah dijangkau. Inilah yang membedakan fzf dari pencocokan naif sederhana.
Setiap kali fzf selesai, ia "berbicara" melalui exit code — angka yang dikembalikan ke shell. Ini adalah sistem sinyal utama fzf untuk scripting, dan aturannya sederhana:
| Exit Code | Arti |
|---|---|
0 | Item dipilih dan dicetak ke stdout |
1 | Tidak ada item yang cocok, atau dibatalkan tanpa pilihan |
130 | Diinterupsi dengan Ctrl+C (SIGINT) |
printf "apple\nbanana\n" | fzf
echo $?Tekan Esc untuk membatalkan, lalu lihat $? — nilainya 1. Ini bukan error dalam arti buruk; ini informasi: tidak ada yang dipilih, lanjutkan sesuai logika. Di episode-episode selanjutnya, pola fzf || exit 1 akan sering dipakai di dalam script — bahasa exit code inilah kunci agar fzf bisa dipakai sebagai komponen yang andal.
Ketika fzf berjalan, layar kalian terbagi menjadi beberapa bagian dengan peran masing-masing:
belajar <- prompt: area mengetik query
learn-fzf.md <- list + pointer pada item aktif
2/10 <- info: posisi pointer dan total item>.Masing-masing komponen ini dikendalikan oleh opsi yang berbeda: --prompt mengatur teks prompt, --pointer mengatur simbol pointer, --info mengatur tampilan info, dan --preview mengatur window pratinjau. Kalian akan menyentuh semuanya mulai episode 4.
Selain antarmuka, fzf juga memiliki controlling options — opsi yang mengendalikan perilaku, bukan tampilan. Contoh paling berguna: --exit-0 yang membuat fzf langsung mencetak satu-satunya item tanpa menunggu interaksi, dan --filter yang menjalankan fzf tanpa antarmuka sama sekali — cocok untuk scripting non-interaktif. Keduanya akan menjadi teman setia di episode lanjutan.
Sebelum menutup episode ini, kenali dulu lima mode pencarian yang akan kalian pakai setiap hari:
| Mode | Contoh | Arti |
|---|---|---|
| Fuzzy (default) | fzf | Karakter berurutan, boleh berselang |
| Exact | 'fzf | Karakter persis, tidak boleh berselang |
| Prefix | ^learn | Item harus diawali learn |
| Suffix | .md$ | Item harus diakhiri .md |
| Extended | kombinasi di atas | Semua pola di atas aktif sekaligus |
Pada fzf modern, extended search aktif secara default — itulah mengapa pola-pola seperti ^learn atau 'build langsung bekerja tanpa konfigurasi. Detil setiap mode, termasuk cara menggabungkannya dan mengendalikan perilaku huruf besar/kecil, akan kita bedah tuntas di episode 3.
Pada episode 2 ini, kalian telah membedah arsitektur utama fzf: model stdin -> filter -> stdout yang menjadi jiwanya, cara kerja fuzzy matching berbasis subsequence dan skor relevansi, bahasa exit code (0, 1, 130), serta anatomi komponen antarmuka dan controlling options.
Inti yang harus dibawa pulang:
0 dipilih, 1 tidak ada yang dipilih, 130 diinterupsi.--exit-0 dan --filter.Di episode 3 selanjutnya, kita akan menguasai fuzzy matching dan search modes secara mendalam — pola pencarian, kontrol case, hingga algoritma skor v1 dan v2 yang menentukan urutan hasil. Sampai jumpa di episode 3!