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.

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.
: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:
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.
toggleterm.nvim dengan lazy.nvimKarena kita sudah membangun fondasi plugin manager lazy.nvim di episode 9, memasang plugin ini cukup dengan satu spec:
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:
| Opsi | Nilai | Fungsi |
|---|---|---|
size | 12 | Tinggi 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_exit | true | Otomatis menutup window saat proses di terminal selesai (misal menjalankan exit) |
shading_factor | 2 | Tingkat 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+\.
Setelah spec di atas di-load, kalian memiliki tiga cara membuka terminal:
Ctrl+\ — men-toggle terminal horizontal di bagian bawah (default).\ — alternatif toggle yang juga memicu lazy-loading plugin.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:
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.
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:
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)" })brew install lazygit
# atau
sudo pacman -S lazygit
# atau via binary release dari GitHub releasesImportant
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.
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.
vim.fn.system (Sinkron)Untuk task cepat yang hasilnya ringkas, kita bisa menggunakan vim.fn.system yang menjalankan perintah secara sinkron:
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.
jobvim.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:
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.
makeTerakhir, 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:
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.
| Keymap | Mode | Aksi |
|---|---|---|
Ctrl+\ | Insert | Toggle terminal horizontal (default) |
\ | Normal | Toggle terminal (lazy-loaded) |
Ctrl+t | Normal/Insert | Toggle floating terminal |
<leader>gg | Normal | Buka LazyGit di floating window |
<leader>tt | Normal | Jalankan go test ./... ke quickfix |
<leader>tb | Normal | Jalankan go build ./... ke quickfix |
<leader>tm | Normal | Jalankan :make |
<leader>tn / <leader>tp | Normal | Navigasi error quickfix berikutnya/sebelumnya |
| Kesalahan | Gejala | Solusi |
|---|---|---|
Bingung Ctrl+\ vs Ctrl+\ Ctrl+n | Terminal tidak mau kembali ke normal mode, atau malah toggle menutup terminal | Ingat: Ctrl+\ sendirian = toggle; Ctrl+\ Ctrl+n = keluar ke normal mode di dalam buffer terminal |
| Keybinding terminal menabrak mapping lain | Tekan Ctrl+\ tapi terminal tidak muncul | Cek :verbose imap <C-\> — mungkin plugin lain (misal LazyVim extras) sudah me-mapping Ctrl+\ lebih dulu |
| Floating window kelewat kecil / kebesaran | Terminal floating tidak nyaman dipakai | Sesuaikan float_opts.width/height, atau aktifkan wrap dan winblend yang lebih tinggi |
| Task blocking membuat editor beku | UI macet saat test berjalan | Ganti vim.fn.system dengan plenary.job atau vim.system yang asinkron |
| LazyGit membuka di direktori salah | Repo yang muncul bukan repo project | Set dir = "git_dir" pada Terminal:new |
| Quickfix tidak me-link error | Output muncul tapi tidak bisa loncat ke file | Pastikan 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.
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!