Belajar Neovim - Integrated Terminal & Task Management (toggleterm.nvim)
Episode 19 of 28

Belajar Neovim - Integrated Terminal & Task Management (toggleterm.nvim)

Di episode ini kita akan membangun terminal terintegrasi di dalam Neovim menggunakan toggleterm.nvim, menjalankan LazyGit di dalam floating window, serta menyiapkan task runner untuk menjalankan test dan build tanpa harus berpindah keluar dari editor.

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

Pendahuluan

Setelah di episode 18 sebelumnya kita membahas integrasi Git di dalam Neovim melalui gitsigns.nvim dan diffview.nvim, pada episode kali ini kita akan menyempurnakan alur kerja sehari-hari dengan kemampuan yang selama ini menjadi keunggulan IDE tradisional: terminal terintegrasi dan manajemen task. Kita akan menggunakan toggleterm.nvim untuk membuka terminal langsung di dalam editor, menjalankan TUI LazyGit di dalam floating window, serta membuat task runner untuk menjalankan test dan build tanpa meninggalkan Neovim.

Kenapa topik ini begitu penting di dunia kerja nyata? Coba ingat pola kerja seorang DevOps yang mengelola microservices: dia mengedit konfigurasi, menjalankan test, melihat output log, lalu memperbaiki kesalahan — semua dalam siklus yang cepat dan berulang. Setiap kali kalian harus Alt+Tab keluar editor untuk menjalankan perintah di terminal terpisah, kalian kehilangan konteks dan momentum. Sebaliknya, ketika terminal dan editor berada di tempat yang sama, siklus edit → run → debug menjadi satu gerakan mulus. Inilah yang disebut integrated development environment secara harfiah: lingkungan di mana semua tool kerja saling terhubung.

Perlu digarisbawahi bahwa Neovim sebenarnya sudah punya terminal bawaan (:terminal), namun ia masih terasa "mentah" untuk penggunaan harian: tidak ada cara cepat untuk toggle, tidak ada mode floating, dan integrasi antar-buffer terbatas. Di sinilah toggleterm.nvim hadir sebagai penyempurna. Mari kita mulai.

Pembahasan Utama

Konsep: Kenapa :terminal Bawaan Kurang Memadai?

Sebelum masuk ke konfigurasi, penting untuk memahami why. Neovim sudah mendukung built-in terminal melalui :terminal sejak versi 0.2, namun ia memiliki beberapa keterbatasan:

  1. Tidak ada toggle cepat — kalian harus ingat nomor buffer terminal lalu membukanya kembali secara manual.
  2. Terminal "nyangkut" di layout — jika kalian membuka terminal di dalam split, terminal itu ikut tersimpan di tab dan menempati ruang kerja secara permanen.
  3. Kontrol keyboard tidak konsisten — untuk mengirim escape ke terminal, kalian harus menekan Ctrl+\ Ctrl+n terlebih dahulu, yang terasa janggal bagi pengguna yang terbiasa dengan alur Ctrl+\.

toggleterm.nvim mengatasi semua ini dengan memberikan satu abstraksi: sebuah terminal yang bisa di-toggle. Saat tidak dipakai, terminal sepenuhnya hilang dari pandangan; saat dibutuhkan, ia muncul dalam satu penekanan tombol. Ini persis seperti integrated terminal di VS Code, namun dengan kontrol penuh ala Neovim.

Memasang toggleterm.nvim dengan lazy.nvim

Karena kita sudah membangun fondasi plugin manager lazy.nvim di episode 9, memasang plugin ini cukup dengan satu spec:

lua/plugins/terminal.lua
return {
  {
    "akinsho/toggleterm.nvim",
    version = "*",
    keys = {
      { "\\", desc = "Toggle terminal (bottom split)" },
      { "<C-\\>", desc = "Toggle terminal (floating)" },
      { "<C-t>", "<cmd>ToggleTerm direction=float<CR>", desc = "Floating terminal" },
    },
    config = function()
      require("toggleterm").setup({
        size = 12,
        open_mapping = [[<C-\>]],
        direction = "horizontal",
        close_on_exit = true,
        shading_factor = 2,
        float_opts = {
          border = "curved",
          width = 0.9,
          height = 0.85,
          winblend = 3,
        },
      })
    end,
  },
}

Beberapa opsi penting yang perlu dipahami:

OpsiNilaiFungsi
size12Tinggi default terminal dalam baris saat memakai mode horizontal/vertical
open_mapping<C-\>Tombol utama untuk men-toggle terminal
direction"horizontal"Arah default terminal muncul (bisa vertical atau float)
close_on_exittrueOtomatis menutup window saat proses di terminal selesai (misal menjalankan exit)
shading_factor2Tingkat darken background terminal agar menonjol dari editor
float_opts.border"curved"Gaya border floating window (pilihan: single, double, rounded, curved)

Note

Perhatikan penulisan keys pada spec di atas. Pada lazy.nvim, entri keys dengan format { "\\", desc = "..." } dianggap sebagai keymap yang belum di-mapping, sehingga lazy.nvim akan meng-install pluginnya terlebih dahulu saat tombol \ pertama kali ditekan — inilah esensi lazy-loading by key yang sudah kita pelajari di episode 23 nanti. Baris open_mapping di dalam setup() berfungsi ganda sebagai keymap aktual untuk Ctrl+\.

Workflow Dasar: Floating Terminal & Bottom Split

Setelah spec di atas di-load, kalian memiliki tiga cara membuka terminal:

  1. Ctrl+\ — men-toggle terminal horizontal di bagian bawah (default).
  2. \ — alternatif toggle yang juga memicu lazy-loading plugin.
  3. Ctrl+t — membuka floating terminal langsung.

Coba bayangkan skenario ini: kalian sedang mengerjakan sebuah bug di file handler.go, lalu ingin cepat-cepat menjalankan go build ./... tanpa menutup file tersebut. Kalian tinggal tekan Ctrl+\, ketik perintahnya, lihat hasilnya, lalu tekan Ctrl+\ lagi untuk menyembunyikannya. File yang sedang diedit tetap di tempatnya, konteks tidak hilang, dan seluruh proses hanya memakan dua penekanan tombol.

Terminal di toggleterm.nvim sebenarnya adalah buffer biasa. Itu artinya kalian bisa menavigasinya seperti buffer lain: buka file log dari output terminal dengan gf, menyalin teksnya dengan mode visual, bahkan membuka lebih dari satu terminal dengan nama berbeda:

Membuat terminal bernama (contoh untuk docker compose)
local Terminal = require("toggleterm.terminal").Terminal
local dockerlogs = Terminal:new({ cmd = "docker compose logs -f", hidden = true })
 
vim.keymap.set("n", "<leader>tl", function()
  dockerlogs:toggle()
end, { desc = "Toggle Docker compose logs" })

Tip

Terminologi yang harus dibedakan: Ctrl+\ (tanpa n) mengirim sinyal toggle ke Neovim untuk membuka/menutup terminal, sedangkan Ctrl+\ Ctrl+n adalah kombinasi untuk keluar dari mode terminal dan kembali ke normal mode di dalam Neovim. Banyak pemula yang bingung membedakan keduanya — kita akan bahas lebih dalam di bagian kesalahan umum.

Integrasi LazyGit: Git TUI di Dalam Floating Window

Di episode 18 kita sudah membahas integrasi Git di dalam buffer dengan gitsigns dan diffview. Namun untuk operasi Git yang kompleks — seperti rebase interaktif, mengelola branch, atau menyusun commit yang rapi — tampilan text-based user interface (TUI) seperti LazyGit jauh lebih produktif. LazyGit adalah aplikasi terminal untuk Git yang menampilkan status, log, stash, dan branch dalam satu layar, lengkap dengan shortcut keyboard.

Integrasi yang natural: jalankan LazyGit di dalam floating terminal toggleterm yang besar. Tampilannya seperti membuka aplikasi Git GUI, tapi berjalan di dalam Neovim:

lua/plugins/terminal.lua (tambahan)
local Terminal = require("toggleterm.terminal").Terminal
 
local lazygit = Terminal:new({
  cmd = "lazygit",
  dir = "git_dir",
  direction = "float",
  float_opts = {
    border = "rounded",
    width = 0.95,
    height = 0.95,
  },
  on_open = function(term)
    vim.cmd("startinsert!")
  end,
  on_close = function()
    vim.cmd("normal! <C-w>=")
  end,
})
 
vim.keymap.set("n", "<leader>gg", function()
  lazygit:toggle()
end, { desc = "Open LazyGit (floating)" })
Instalasi LazyGit (Linux/macOS)
brew install lazygit
# atau
sudo pacman -S lazygit
# atau via binary release dari GitHub releases

Important

Kode dir = "git_dir" pada contoh di atas adalah penanda agar LazyGit mendeteksi akar repository Git secara otomatis dari buffer aktif. Jika kalian tidak menambahkan dir, terminal akan membuka di direktori kerja Neovim saat dijalankan (:pwd), yang bisa jadi bukan lokasi repo yang sedang dikerjakan — sumber kebingungan klasik yang sudah kita kenali di episode 11 saat membahas lokasi file.

Dengan pengaturan ini, alur kerja Git kalian menjadi: tekan <leader>gg → LazyGit muncul memenuhi layar → lihat perubahan di panel staging, susun commit, push → tekan <leader>gg lagi untuk menutupnya → kembali ke kode. Tidak perlu pernah keluar dari Neovim untuk urusan Git.

Task Runner & Make: Menjalankan Test/Build ke Quickfix

Sekarang kita masuk ke bagian yang paling relevan dengan pekerjaan DevOps: menjalankan task seperti build atau test tanpa meninggalkan editor. Konsepnya sederhana — eksekusi sebuah perintah shell yang hasilnya ditangkap dan ditampilkan di dalam quickfix list atau terminal — namun dampaknya besar: kalian bisa langsung menavigasi error menggunakan :cnext / :cprev karena baris error di-parse dan di-link ke lokasi file.

Pendekatan 1: Task Runner Sederhana dengan vim.fn.system (Sinkron)

Untuk task cepat yang hasilnya ringkas, kita bisa menggunakan vim.fn.system yang menjalankan perintah secara sinkron:

lua/config/tasks.lua
local function run(cmd)
  vim.cmd("copen")
  vim.fn.setqflist({}, " ", { title = cmd })
  local output = vim.fn.system(cmd)
  local lines = vim.split(output, "\n", { trimempty = false })
  vim.fn.setqflist({}, " ", { lines = lines })
  vim.cmd("wincmd p")
end
 
vim.keymap.set("n", "<leader>tt", function()
  run("go test ./...")
end, { desc = "Run Go tests" })
 
vim.keymap.set("n", "<leader>tb", function()
  run("go build ./...")
end, { desc = "Run Go build" })

Setelah perintah selesai, hasilnya muncul di quickfix, dan dengan setqflist Neovim secara otomatis akan mencoba me-resolve baris yang terlihat seperti file:line:pesan menjadi lompatan ke file. Tekan Enter di quickfix untuk langsung loncat ke lokasi error.

Pendekatan 2: Task Asinkron dengan Plenary job

vim.fn.system bersifat blocking: editor membeku selama perintah berjalan. Untuk test suite yang memakan waktu puluhan detik, ini bukan pengalaman yang baik. Solusinya adalah menjalankan task secara asinkron menggunakan plenary.job, yang sudah menjadi dependency standar di ekosistem plugin Neovim:

lua/config/tasks.lua (asinkron)
local Job = require("plenary.job")
 
local function run_async(cmd, args)
  vim.cmd("copen")
  vim.fn.setqflist({}, " ", { title = cmd })
  Job:new({
    command = cmd,
    args = args,
    on_exit = function(job, code)
      local result = job:result()
      vim.schedule(function()
        vim.fn.setqflist({}, " ", { lines = result })
        vim.api.nvim_echo({ { "Task selesai dengan exit code " .. code, "DiagnosticInfo" } }, false, {})
      end)
    end,
  }):start()
end
 
vim.keymap.set("n", "<leader>tt", function()
  run_async("go", { "test", "./..." })
end, { desc = "Run Go tests (async)" })

Tip

Perhatikan pemanggilan vim.schedule. Job berjalan di luar event loop utama Neovim (ini yang membuatnya asinkron), sehingga API Neovim tidak boleh dipanggil langsung dari dalam callback on_exit. vim.schedule menunda eksekusi sampai kembali ke loop utama — ini pola wajib yang harus kalian kuasai saat menulis kode yang berinteraksi dengan proses eksternal.

Pendekatan 3: Integrasi dengan make

Terakhir, Neovim sudah memiliki dukungan first-class untuk make (:make), yang menjalankan make di direktori dan otomatis mengisi quickfix list dari output gcc/go/tsc. Kalian bisa memetakan <leader>tm untuk itu:

lua
vim.keymap.set("n", "<leader>tm", "<cmd>make<CR>", { desc = "Run make" })
vim.keymap.set("n", "<leader>te", "<cmd>copen<CR>", { desc = "Open quickfix" })
vim.keymap.set("n", "<leader>tn", "<cmd>cnext<CR>", { desc = "Next error" })
vim.keymap.set("n", "<leader>tp", "<cmd>cprev<CR>", { desc = "Previous error" })

Salah satu kekuatan :make adalah dukungan makeprg dan errorformat. Jika proyek kalian memakai Makefile dengan target yang bermacam-macam, :make test atau :make lint akan langsung bekerja tanpa plugin tambahan — cukup sesuaikan errorformat agar error parser memahami format output tool kalian.

Tabel Ringkasan Keymap

KeymapModeAksi
Ctrl+\InsertToggle terminal horizontal (default)
\NormalToggle terminal (lazy-loaded)
Ctrl+tNormal/InsertToggle floating terminal
<leader>ggNormalBuka LazyGit di floating window
<leader>ttNormalJalankan go test ./... ke quickfix
<leader>tbNormalJalankan go build ./... ke quickfix
<leader>tmNormalJalankan :make
<leader>tn / <leader>tpNormalNavigasi error quickfix berikutnya/sebelumnya

Kesalahan Umum (Common Pitfalls)

KesalahanGejalaSolusi
Bingung Ctrl+\ vs Ctrl+\ Ctrl+nTerminal tidak mau kembali ke normal mode, atau malah toggle menutup terminalIngat: Ctrl+\ sendirian = toggle; Ctrl+\ Ctrl+n = keluar ke normal mode di dalam buffer terminal
Keybinding terminal menabrak mapping lainTekan Ctrl+\ tapi terminal tidak munculCek :verbose imap <C-\> — mungkin plugin lain (misal LazyVim extras) sudah me-mapping Ctrl+\ lebih dulu
Floating window kelewat kecil / kebesaranTerminal floating tidak nyaman dipakaiSesuaikan float_opts.width/height, atau aktifkan wrap dan winblend yang lebih tinggi
Task blocking membuat editor bekuUI macet saat test berjalanGanti vim.fn.system dengan plenary.job atau vim.system yang asinkron
LazyGit membuka di direktori salahRepo yang muncul bukan repo projectSet dir = "git_dir" pada Terminal:new
Quickfix tidak me-link errorOutput muncul tapi tidak bisa loncat ke filePastikan format output sesuai errorformat; terkadang perlu :set errorformat khusus per-tool

Caution

Jika kalian memakai LazyGit, jangan pernah menekan Ctrl+\ Ctrl+n di dalam window LazyGit dengan harapan kembali ke editor — karena LazyGit sendiri juga menggunakan Ctrl+\ sebagai shortcut menuju panel tertentu. Biasanya lebih aman men-toggle floating window dengan keymap <leader>gg yang sudah kalian buat, bukan dengan Ctrl+\ global.

Penutup

Pada episode 19 ini kita telah membangun tiga kemampuan inti yang menjadikan Neovim layaknya IDE modern: terminal terintegrasi dengan toggleterm.nvim dalam berbagai mode (horizontal, floating), integrasi LazyGit di dalam floating window untuk alur kerja Git yang cepat, serta task runner untuk menjalankan test dan build dengan output yang langsung masuk ke quickfix list. Kita juga membahas perbedaan mendasar antara eksekusi sinkron dan asinkron, lengkap dengan pola vim.schedule yang wajib dipahami.

Dengan kemampuan ini, siklus edit → test → debug tidak lagi memaksa kalian berpindah aplikasi. Neovim sudah menjadi ruang kerja tunggal.

Namun, editor yang cepat belum lengkap tanpa gerakan editing yang cerdas. Di episode 20 selanjutnya, kita akan membahas Code Editing Productivity Boosters — plugin yang mengotomatiskan penutupan kurung dan tag, manipulasi surround text, komentar cepat, serta popup bantuan shortcut which-key. Pastikan tetap semangat!

Belajar Neovim - Integrated Terminal & Task Management (toggleterm.nvim) | Belajar Neovim