Terminal, Git and global search integrated in Neovim
- Published on
- ·5 min read
Never leave Neovim (seriously, almost never)
An editor is cool. A complete environment where you edit, search, commit, run commands - all without touching the mouse? That's the dream. In my Neovim config (roughly 1800 lines of Lua, 46 plugins where half are probably useless), four tools turn it into a real development cockpit. toggleterm for an integrated terminal. lazygit for Git. grug-far for massive search-and-replace. trouble.nvim for diagnostics. With this setup, I leave Neovim... basically never.
Integrated terminal with Toggleterm
Natural instinct when terminal working? Open another one. Toggleterm makes it seamless: `Ctrl-`` and a horizontal terminal pops up at the bottom. No juggling windows, no chaos. Just terminal toggling.
{
"akinsho/toggleterm.nvim",
version = "*",
opts = {
size = 15,
open_mapping = [[<c-`>]],
hide_numbers = true,
shade_terminals = true,
shading_factor = 2,
start_in_insert = true,
persist_size = true,
direction = "horizontal",
},
}
Why it actually works:
- Session persistence : Start
bun dev, hide it, edit code, come back. Server's still running. No nonsense restart. - Visual shading : Terminal is slightly darkened. You see instantly what's terminal and what's code.
- Multiple terminals : Open two, three, whatever. Each keeps its own state.
Real benefit: builds, tests, dev servers - without leaving Neovim. You never lose context.
Visual Git with Lazygit
I've been using Git from the command line for years, but for some operations -- interactive rebase, conflict resolution, cherry-pick -- a TUI (Terminal User Interface) is infinitely more efficient. Lazygit is that TUI, and it integrates perfectly into Neovim via toggleterm.
-- Lazygit as a floating terminal
local Terminal = require("toggleterm.terminal").Terminal
local lazygit = Terminal:new({
cmd = "lazygit",
dir = "git_dir",
direction = "float",
float_opts = {
border = "rounded",
},
on_open = function(term)
vim.cmd("startinsert!")
end,
on_close = function(_)
vim.cmd("startinsert!")
end,
})
-- Keymap: <leader>gg to open lazygit
vim.keymap.set("n", "<leader>gg", function()
lazygit:toggle()
end, { desc = "Lazygit" })
Hit <leader>gg and lazygit floats. Staging, commits, pushes, rebases, stash management, diffs. All the things you'd normally do with 10 chained git commands? Here it's arrows and enter.
Why lazygit beats raw git bash?
- Visual diff : You see line-by-line exactly what you're staging. No surprise commits.
- Interactive rebase : Reorder commits, squash them, edit one - arrows and enter.
- Conflict resolution : Side-by-side view. You pick one version or the other. No manual merging of text.
Global search and replace with Grug-far
Renaming a variable across an entire project, fixing a recurring pattern, migrating an API: these operations require a powerful search-and-replace tool. Grug-far, powered by ripgrep, fills that role.
{
"MagicDuck/grug-far.nvim",
opts = {
headerMaxWidth = 80,
},
cmd = "GrugFar",
keys = {
{
"<leader>S",
function()
local grug = require("grug-far")
local ext = vim.bo.buftype == "" and vim.fn.expand("%:e")
grug.open({
transient = true,
prefills = {
filesFilter = ext and ext ~= "" and "*." .. ext or nil,
},
})
end,
mode = { "n", "v" },
desc = "Search and Replace",
},
{
"<leader>sw",
function()
local grug = require("grug-far")
grug.open({
transient = true,
prefills = {
search = vim.fn.expand("<cword>"),
},
})
end,
desc = "Search word under cursor",
},
},
}
The keymaps:
<leader>S: Opens the search panel in a left vertical split, pre-filtered to current file extension. Handy.<leader>sw: Searches the word under the cursor directly.
What makes grug-far different from sed:
- Real-time preview : You see replacements before applying them. No disasters.
- File-by-file review : Accept or reject each change individually. Full control.
- Full regex : All of ripgrep. No restrictions.
- Exclusion patterns :
node_modules,.git,.next,dist, lock files, minified stuff - automatically ignored via config. (seriously, don't judge me for an hour spent debugging this)
Diagnostics navigation with Trouble.nvim
When the LSP reports errors or warnings, you need to browse them efficiently. Trouble.nvim provides a dedicated panel for navigating all project diagnostics.
{
"folke/trouble.nvim",
opts = {
use_diagnostic_signs = true,
},
cmd = "Trouble",
keys = {
{ "<leader>xx", "<cmd>Trouble diagnostics toggle<cr>", desc = "Diagnostics (Trouble)" },
{ "<leader>xX", "<cmd>Trouble diagnostics toggle filter.buf=0<cr>", desc = "Buffer diagnostics" },
{ "<leader>xq", "<cmd>Trouble qflist toggle<cr>", desc = "Quickfix list (Trouble)" },
{ "<leader>xl", "<cmd>Trouble loclist toggle<cr>", desc = "Location list (Trouble)" },
},
}
The keymaps:
<leader>xx: All project diagnostics. Errors, warnings, hints. Everything.<leader>xX: Filter to current file only. Useful when fixing one specific file, no distractions.<leader>xq: Quickfix list in Trouble. Way more readable than native quickfix.<leader>xl: Location list. Same concept.
LSP integration? Transparent. Every TypeScript error, every ESLint warning, every Python diagnostic navigable with normal Neovim keys.
The daily workflow (how it actually goes)
Typical session:
- Edit code - main buffer, window navigation (
C-h,C-j,C-k,C-l) and buffer switching (S-h,S-l) - Check diagnostics -
<leader>xxto make sure it compiles and passes linting - Big refactor? -
<leader>Sto open grug-far, make the replacement, validate - Commit -
<leader>ggfor lazygit, stage, write message, push. Done. - Run tests - `Ctrl-`` for the terminal
Zero mouse. Logical keymaps. You never leave Neovim. Save (<leader>w) and quit (<leader>q) complete the setup for 100% keyboard workflow.
That's it
Four plugins that turn Neovim from a text editor into a full development environment. Integrated terminal = no window chaos. Lazygit = Git becomes fast and visual. Grug-far = large-scale refactoring without stress. Trouble = all problems in one list. Once it's in muscle memory, you save massive amounts of time per session.
Neovim from scratch series — This article is part of a complete series on configuring Neovim from scratch.
Previous: Telescope, Treesitter and essential coding plugins for Neovim | Next: AI completion in Neovim: Codeium, Gemini and nvim-cmp