Terminal, Git and global search integrated in Neovim

Terminal, Git and global search integrated in Neovim

·5 min read·Updated on February 13, 2026

Never leaving Neovim

Four tools turn Neovim into a complete development cockpit: toggleterm for an integrated terminal, lazygit for Git, grug-far for bulk search-and-replace, trouble.nvim for diagnostics.

Integrated terminal with Toggleterm

`Ctrl-`` pops a horizontal terminal at the bottom: no overlapping windows, just a terminal that toggles in and out.

{
  "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",
  },
}

Three qualities that matter:

  • Persistence: start bun dev, close the terminal, edit code, reopen it — the server is still running.
  • Visual shading: the terminal is dimmed relative to the code, so the distinction is instant.
  • Multiple terminals: each with its own session, pwd and running processes.

Running a build, executing tests, starting a dev server: no reason to leave the editor, and no lost context.

Visual Git with Lazygit

For some operations — interactive rebase, conflict resolution, cherry-pick — a TUI is far more efficient than the command line. Lazygit plugs into Neovim through 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" })

<leader>gg opens a floating window: staging file by file or hunk by hunk, commit, push, pull, interactive rebase, stash, visual diffs.

What the TUI adds over command-line git:

  • Visual diff: you see line by line what you're staging, so no surprises at commit time.
  • Interactive rebase: reordering, squashing or editing commits is arrow keys and enter.
  • Conflict resolution: side-by-side view, pick one version or the other, no manual text merging.

Global search-and-replace with Grug-far

Renaming a variable across the project, fixing a recurring pattern, migrating an API: grug-far, powered by ripgrep, covers those cases.

{
  "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",
    },
  },
}

<leader>S opens the search panel in a vertical split, pre-filtered on the current file's extension; <leader>sw searches the word under the cursor directly.

What separates grug-far from plain sed: real-time preview of replacements, file-by-file review with individual accept or reject, the full power of ripgrep regex, and centralised exclusion patterns (node_modules, .git, .next, dist, lock files, minified assets).

Diagnostics navigation with Trouble.nvim

Trouble.nvim aggregates every project diagnostic into a navigable list:

{
  "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)" },
  },
}
  • <leader>xx: every diagnostic in the project — errors, warnings, hints.
  • <leader>xX: filters to the current file, useful while fixing one specific file.
  • <leader>xq and <leader>xl: quickfix and location list inside Trouble, far more readable than Vim's native versions.

LSP integration is transparent: TypeScript errors, ESLint warnings and Python diagnostics all show up and navigate with normal keys.

The daily workflow

  1. Edit code — main buffer, window navigation (C-h, C-j, C-k, C-l) and buffer navigation (S-h, S-l)
  2. Check diagnostics<leader>xx to confirm it compiles and lints
  3. Bulk refactor<leader>S for grug-far, do the replacement, validate
  4. Commit<leader>gg for lazygit: stage, message, push
  5. Run tests — `Ctrl-`` for the integrated terminal

Zero mouse, and save (<leader>w) plus quit (<leader>q) complete a fully keyboard-driven workflow.

Wrapping up

Four plugins turn Neovim from a text editor into a complete development environment: an integrated terminal instead of overlapping windows, fast visual Git, stress-free large-scale refactoring, and every problem in one list. Once it's muscle memory, the time saved per session is real.

ShareLinkedInXBluesky

Related articles