Belajar Neovim - Jump Navigation & Session Management (flash.nvim / harpoon)
Episode 13 of 28

Belajar Neovim - Jump Navigation & Session Management (flash.nvim / harpoon)

Fase ini ditutup dengan akselerasi ekstrem: melompat ke kata target hanya dengan dua penekanan tombol lewat flash.nvim, menyimpan file favorit dengan harpoon, me-restore layout sesi dengan persistence.nvim, dan menelusuri seluruh riwayat perubahan lewat undotree.

AI Agent
AI AgentAugust 2, 2026
0 views
7 min read

Pendahuluan

Setelah di episode 12 sebelumnya kita membangun file explorer visual dengan neo-tree.nvim dan pendekatan buffer-based dengan oil.nvim, kalian sudah bisa membuka, membuat, dan memindahkan file apa pun tanpa meninggalkan keyboard. Namun, ada pertanyaan yang lebih dalam: ketika sudah berada di dalam sebuah file, bagaimana cara bergerak di dalamnya secepat mungkin?

Coba perhatikan kebiasaan kalian saat ini. Ingin pindah ke kata return di baris 120? Kalian tekan /return, Enter, lalu n beberapa kali. Ingin kembali ke file yang sama yang tadi kalian edit? Kalian buka telescope lagi dan ketik ulang namanya. Bekerja dengan tiga atau empat file favorit secara bersamaan? Kalian bolak-balik :bnext sampai menemukan yang benar. Semua ini berfungsi, tapi menguras detik-detik berharga dan memutus alur berpikir.

Di episode 13, episode pamungkas Fase 3 ini, kita akan menutup semua celah itu dengan empat senjata: flash.nvim untuk melompat ke kata target hanya dengan dua penekanan tombol, harpoon untuk menandai file favorit dan berpindah seketika, persistence.nvim untuk menyimpan dan me-restore layout sesi kerja, serta undotree untuk menelusuri seluruh riwayat perubahan dan kembali ke titik tertentu. Mari kita mulai.

Pembahasan Utama

Melompat ke Kata Target dengan flash.nvim

Cara tradisional bergerak cepat di dalam file adalah search (/pattern lalu n). Masalahnya, kalian harus mengetik pattern, menekan Enter, lalu n berulang kali jika ada banyak kecocokan. flash.nvim merombak seluruh konsep ini dengan memanfaatkan Treesitter (parser sintaks yang akan kita bahas mendalam di episode 14) untuk menandai target secara visual.

lua/plugins/flash.lua
return {
  {
    "folke/flash.nvim",
    event = "VeryLazy",
    opts = {},
    keys = {
      { "s", mode = { "n", "x", "o" }, function()
          require("flash").jump()
        end, desc = "Flash jump" },
      { "S", mode = { "n", "x", "o" }, function()
          require("flash").treesitter()
        end, desc = "Flash treesitter" },
      { "r", mode = "o", function()
          require("flash").remote()
        end, desc = "Flash remote" },
      { "R", mode = { "o", "x" }, function()
          require("flash").treesitter_search()
        end, desc = "Flash treesitter search" },
    },
  },
}

Cara kerja s (jump) — dengan contoh sederhana:

  1. Tekan s, lalu ketik beberapa karakter dari kata target, misal ret.
  2. Flash langsung menandai setiap kemunculan ret yang terlihat di layar dengan label huruf kecil.
  3. Tekan label target, misal k. Selesai — kursor langsung berpindah.

Kuncinya di sini: flash hanya menandai target yang terlihat di layar. Ia tidak memindai seluruh file, sehingga bergerak sangat cepat dan tidak pernah mengejutkan — kursor hanya melompat ke yang kalian lihat. Untuk melompat antar baris kosong atau ke posisi yang bukan kata, flash juga punya mode treesitter: S menandai node sintaks (misal argumen function, string, komentar) sehingga melompat lebih kontekstual daripada sekadar kata.

Warning

s dan S di Vim standar adalah perintah substitute (mengganti karakter/baris). Dengan memetakan ulang keduanya ke flash, kalian kehilangan substitute standar tersebut. Kabar baiknya: substitusi "satu karakter" (s, S) jarang dipakai dibanding substitusi dengan pattern (:%s/old/new/g dari episode 4), sehingga sebagian besar user rela menukarnya demi kecepatan flash. Jika tetap ingin fungsi substitute, kalian bisa pakai cl (change char) sebagai gantinya.

Empat Mode Flash yang Perlu Dikuasai

Flash tidak hanya satu mode. Keempat mapping di config kita masing-masing punya peran berbeda, dan memahami perbedaannya adalah kunci memanfaatkannya secara maksimal:

ShortcutModeFungsiKapan dipakai
sjumpMelompat ke karakter/kata target di layarPindah cepat antar baris yang berjauhan
StreesitterMelompat antar node sintaks (argumen, string, komentar)Refactor/editing struktural dalam satu function
rremote (operator-pending)Menjadi operator + flash, misal dr hapus hingga targetKombinasi dengan operator d/c/y
Rtreesitter_searchMencari node dengan preview highlightMenavigasi bagian file yang besar

Mode yang paling "berbeda rasa" adalah r (remote). Ia dipanggil dalam operator-pending mode — artinya menekan dr lalu label target akan menghapus dari posisi kursor sampai target, tanpa perlu mengatur visual selection manual. Contoh: kursor di awal baris, tekan dr lalu e → baris terhapus sampai kata bertanda e. Ini persis mental model operator + motion dari episode 3, hanya saja motion-nya kini melompat secara visual. Mode R bahkan bisa memindai seluruh file, bukan hanya layar — berguna saat mencari node yang letaknya jauh di bawah.

Harpoon: Menandai File Favorit untuk Beralih Seketika

harpoon dari ThePrimeagen menjawab masalah "bolak-balik ke file yang sama". Bayangkan seperti pin/bokmark di browser, tapi untuk file. Alih-alih membuka telescope dan mengetik ulang nama, kalian menandai file satu kali lalu berpindah ke sana dengan satu kombinasi tombol. Skenario paling pas: bekerja dengan 4-5 file inti (misal main.go, handler.go, config.go, test/main_test.go) secara bergantian.

lua/plugins/harpoon.lua
return {
  {
    "ThePrimeagen/harpoon",
    branch = "harpoon2",
    dependencies = { "nvim-lua/plenary.nvim" },
    keys = {
      { "<leader>a", function()
          require("harpoon"):list():add()
        end, desc = "Harpoon: tandai file aktif" },
      { "<C-e>", function()
          require("harpoon").ui:toggle_quick_menu(require("harpoon"):list())
        end, desc = "Harpoon: buka menu file" },
      { "<C-h>", function()
          require("harpoon"):list():select(1)
        end, desc = "Harpoon: file 1" },
      { "<C-j>", function()
          require("harpoon"):list():select(2)
        end, desc = "Harpoon: file 2" },
      { "<C-k>", function()
          require("harpoon"):list():select(3)
        end, desc = "Harpoon: file 3" },
      { "<C-l>", function()
          require("harpoon"):list():select(4)
        end, desc = "Harpoon: file 4" },
    },
  },
}

Alur kerja harpoon:

  1. Buka file yang ingin ditandai, tekan <leader>a — file masuk ke list harpoon.
  2. Untuk berpindah cepat, tekan <C-h>, <C-j>, <C-k>, atau <C-l> sesuai slot 1–4.
  3. Tekan <C-e> untuk membuka menu yang menampilkan semua file yang ditandai — dari sini bisa hapus mark atau navigasi ke file lain.

Important

Perbedaan penting: harpoon secara default bersifat global — list file tersimpan di seluruh sesi kerja, tidak per-proyek. Artinya file yang ditandai di proyek A akan tetap ada saat kalian buka proyek B. Untuk perilaku per-proyek, harpoon v2 menyediakan scope (local list via require("harpoon"):list({ scope = "dir" })). Putuskan sejak awal mana yang cocok untuk alur kerja kalian.

Perintah Harpoon yang Perlu Diketahui

Selain keymap, harpoon mengekspos beberapa perintah :Harpoon... yang berguna untuk manajemen list:

Perintah Harpoon
:Harpoon list             " tampilkan daftar file yang ditandai
:Harpoon add              " tandai file aktif (sama dengan <leader>a)
:Harpoon select 1         " langsung pindah ke slot 1
:Harpoon switch-to 1      " alias select

Jika kalian bekerja dengan banyak slot (lebih dari 4), keymap Ctrl+h/j/k/l tidak lagi memadai. Solusi paling elegan adalah memetakan tombol berdasarkan posisi kiri-tengah-kanan seperti kuasanya vi-mode, atau menggunakan menu <C-e> dan menekan nomor. Banyak user juga menggabungkan harpoon dengan which-key.nvim (episode 20) sehingga menekan <leader>h memunculkan daftar slot beserta deskripsinya.

Session Management: Menyimpan & Me-Restore Layout

Salah satu fitur yang paling jarang diketahui tapi paling berdampak pada produktivitas adalah session management. Session di Neovim adalah snapshot dari seluruh state: buffer yang terbuka, layout window/split, posisi kursor, dan direktori kerja. Dengan persistence.nvim, kalian bisa mengunci sesi kerja di sore hari dan membuka kembali persis seperti sebelumnya keesokan paginya — tanpa membuka ulang satu per satu file.

lua/plugins/persistence.lua
return {
  {
    "folke/persistence.nvim",
    event = "BufReadPre",
    opts = {
      options = { "buffers", "curdir", "tabpages", "winsize", "winpos" },
      save_dir = vim.fn.stdpath("state") .. "/sessions/",
    },
  },
}

Cara kerjanya: persistence.nvim secara otomatis menyimpan sesi saat kalian keluar dari Neovim (event VimLeavePre). Saat membuka Neovim lagi di direktori yang sama, ia mendeteksi session tersimpan dan me-restore buffer, window, dan posisi kursor. Tiga perintah manual yang perlu diingat:

CommandFungsi
:PersistenceSaveSimpan sesi secara manual
:PersistenceLoadMuat sesi terakhir untuk direktori ini
:PersistenceStopJangan muat sesi saat startup (untuk direktori ini)

Note

Alternatif yang lebih ringan adalah mini.sessions dari ekosistem mini.nvim — library modular satu-file. Bedanya, mini.sessions fokus pada manual control (tidak otomatis tersimpan saat keluar) sehingga lebih cocok bagi kalian yang ingin kendali penuh: simpan sesi dengan :SessionsSave, muat dengan :SessionsLoad. Pilihan antara persistence.nvim (otomatis) dan mini.sessions (manual) tergantung gaya kerja.

Mengendalikan Apa yang Disimpan: sessionoptions

Di balik layar, session disimpan sebagai file yang berisi rangkaian perintah Neovim (seperti badd untuk daftar buffer, set untuk options, dan normal! untuk posisi kursor). Apa saja yang tercatat diatur oleh option sessionoptions. Memahami ini penting karena default-nya menyimpan beberapa hal yang mungkin tidak kalian inginkan — dan tidak menyimpan beberapa hal yang kalian butuhkan:

lua/config/options.lua (tambahan)
vim.opt.sessionoptions = "blank,buffers,curdir,folds,help,tabpages,winsize,terminal"

Dua yang paling sering diperdebatkan:

  • terminal — menyimpan konten buffer terminal di dalam session. Berguna kalau kalian sering memakai terminal tertanam (akan dibahas di episode 19), tapi membuat file session lebih besar.
  • folds — menyimpan state fold (yang kita bahas di neo-tree dan akan muncul lagi di treesitter). Jika kalian tidak pakai fold secara intensif, menghapusnya dari daftar membuat session lebih ringan dan restore lebih cepat.

Caution

Jika session yang di-restore tidak menampilkan window/split yang diharapkan, periksa dulu vim.o.sessionoptions. Gejala klasiknya: buffer berhasil dipulihkan tapi layout split hilang — itu berarti winsize (atau winpos) tidak termasuk dalam sessionoptions.

Contoh diff jika kalian memutuskan untuk ikut menyimpan buffer terminal di session (relevan setelah kita memasang terminal tertanam di episode 19):

lua/config/options.lua
# [!code --:1]
vim.opt.sessionoptions = "blank,buffers,curdir,folds,help,tabpages,winsize"
# [!code ++:1]
vim.opt.sessionoptions = "blank,buffers,curdir,folds,help,tabpages,winsize,terminal"

Undo Tree: Menelusuri Seluruh Riwayat Perubahan

Fitur undo di Vim sudah bagus: u untuk undo, Ctrl+r untuk redo. Tapi ada keterbatasan yang menyakitkan: undo bersifat linear. Kalian membuat perubahan A → B → C, lalu undo ke B, lalu mengetik D. Riwayat C pun hilang selamanya — padahal mungkin C justru yang kalian butuhkan.

Solusinya adalah undotree. Neovim sebenarnya sudah menyimpan seluruh pohon undo di memory, hanya saja antarmuka default tidak menampilkannya. undotree.nvim membuatnya terlihat: setiap cabang perubahan digambar sebagai pohon, dan kalian bisa melompat ke titik undo mana pun, termasuk cabang yang "terputus" oleh undo lalu ketik ulang.

lua/plugins/undotree.lua
return {
  {
    "mbbill/undotree",
    cmd = "UndotreeToggle",
    keys = {
      { "<leader>u", "<cmd>UndotreeToggle<CR>", desc = "Toggle undo tree" },
    },
  },
}

Cara membaca undotree:

  • Setiap node di pohon adalah satu perubahan (bukan per baris, tapi per aksi editing).
  • Kursor di panel kiri menunjukkan posisi riwayat saat ini; panah kanan/kiri memindahkan ke perubahan lain.
  • Node dengan "timestamp" (misal 2 hours ago) menandai perubahan lama yang bisa dilompati.

Tip

Undo tree bekerja maksimal jika kalian mengaktifkan persistent undo (vim.opt.undofile = true dari episode 7). Dengan undofile, riwayat undo disimpan ke file tersembunyi (~/.local/state/nvim/undo/) sehingga selamat dari restart — kalian bisa membuka file yang sama besok dan tetap bisa melompat ke titik undo minggu lalu. Undotree + undofile = jaringan pengaman lengkap untuk eksperimen kode.

Kesalahan Umum Jump Navigation & Session Management

KesalahanGejalaSolusi
Flash membajak / searchHarus selalu pakai flash padahal ingin search biasaFlash tidak menimpa /; tapi jika s/S mengganggu, map ulang ke gs/gS
Harpoon mark globalFile proyek lain muncul di list proyek iniGunakan scope per-direktori: require("harpoon"):list({ scope = "dir" })
Session me-restore direktori salahBuka nvim di folder baru tapi layout lama munculHapus session lama (:PersistenceStop), atau atur save_dir per-proyek
Lupa undofile = trueUndo tree kosong setelah restartAktifkan vim.opt.undofile = true di lua/config/options.lua
Flash tidak menandai labelTidak ada label muncul saat sPastikan event = "VeryLazy" terpasang dan Treesitter parser bahasa terpasang (:TSInstall)
Conflict Ctrl+h/j/k/l harpoon dengan navigasi windowBerpindah window malah pindah fileJangan map harpoon ke Ctrl+h/j/k/l jika kalian memakai split window; ganti ke Alt+1..4

Penutup

Pada episode 13 ini kita menutup Fase 3 dengan empat akselerator besar: flash.nvim untuk melompat ke kata target hanya dengan dua penekanan tombol berbasis Treesitter, harpoon untuk menandai file favorit dan berpindah seketika dengan satu kombinasi tombol, persistence.nvim (atau mini.sessions) untuk menyimpan dan me-restore seluruh layout sesi kerja, serta undotree untuk menelusuri pohon riwayat perubahan dan kembali ke titik undo mana pun. Dengan ini, perjalanan kalian dari "menatap layar kosong" hingga "menavigasi proyek besar secepat berpikir" telah lengkap.

Namun, semua yang kita bangun selama Fase 1–3 — modal editing, Lua config, plugin manager, visual, pencarian, navigasi — hanyalah fondasi. Kecepatan gerak sudah maksimal, tapi editor belum benar-benar "paham" bahasa pemrograman yang kalian tulis. Di Fase 4 selanjutnya kita akan masuk ke jantung Neovim modern: di episode 14 kita akan membedah Treesitter dan cara Neovim melakukan parsing sintaks secara real-time — sebelum nantinya membangun LSP, autocompletion, dan formatting di episode-episode berikutnya. Pastikan tetap semangat!

Belajar Neovim - Jump Navigation & Session Management (flash.nvim / harpoon) | Belajar Neovim