/tman.nvim

Terminal Manager for Neovim, focused on running commands, tests, etc

Primary LanguageLua

Neovim Terminal Manager

Introduction

Tman.nvim is a terminal manager for Neovim, focused on running commands, tests, etc.
Inspird by ThePrimeagen/harpoon and emacs compilation-mode.

Works really well with the vim-test plugin as a custom stratergy to run tests using a single terminal buffer.

How to install

Add this to your packer or Lazy config

{
  'Bhanukamax/tman.nvim',
}

Setup

Lua

local tman = require('tman')

-- setup how the terminal buffer is displayed
-- Note: you don't need to do this if you are okay with using the defaults
tman.setup {
  split = "bottom", -- supported values: "bottom", "right"
  -- set width and height as a percentage of the terminal width and height
  -- should be a integer between 1 to 100
  width = 50, -- default is 50
  height = 40, -- default is 40
}

Basic keybindings

-- This is my favourite way to toggle tman terminal, you don't have to care which mode you are in the terminal, just one keybind to toggle back and forth
vim.keymap.set("n", "<A-;>", function () tman.toggleLast({insert = true}) end)
vim.keymap.set("t", "<A-;>", tman.toggleLast)

Advance Usage

Have a look at :help tman.nvim for complete API docs

toggle terminal from a specific side

-- toggle terminal from a specific side
vim.keymap.set("n", "<leader>tr", tman.toggleRight)
vim.keymap.set("n", "<leader>tb", tman.toggleBottom)

-- toggle terminal from the last open side
vim.keymap.set("n", "<leader>tt", tman.toggleLast)

Send commands interactively

Prompts to Send a command to the terminal

:TmanCmd

Resend the last command

:TmanCmdLast

These commands are useful when you want to run things like build commands, test runner commands, for example: cargo build, go build, etc.

How to use these
  • When you run :TmanCmd it'll propmt for you to enter a command.
  • Once you type in the command and press enter it'll open the Tman terminal and run the command you entered.
  • You can also run :TmanCmdLast to resend the last command you ran.

One nice thing about using these commands is that you never have to go to insert mode in the terminal buffer, so you can just use these to run commands and navigate/visual select/yank text on terminal buffer without ever worrying about going between modes in the terminal buffer.

TmanCmd and TmanCmdLast in action

tman-cargo-build

And they works best with some nice remaps like these:

  vim.keymap.set("n", "<leader>tc", ":TmanCmd<CR>")
  vim.keymap.set("n", "<leader>tn", ":TmanCmdLast<CR>") -- <leader>tl or <leader>tr would be a better mnemonic binding
TmanCmd and TmanCmdLast with remaps in action

tman-cargo-build-with-keybinds

Send commands programmatically

call to send some command to the terminal buffer

require("tman").sendCommand(cmd, opts)

cmd: string -> command to send

opts: table

  • opts.split: "right" or "bottom": pass a split possition to override default when the command is executed
  • opts.open: bool -> if true, open the terminal buffer (always opens if there is no previous terminal buffer)
  • opts.pre: string -> a command to excute before the currend cmd
  • opts.scrollTop: bool (default: true) -> scroll the prompt to top before executing the currently sent command, this is works better than sending clear as the pre command.
use gitk for the current file
local gitk_file = function()
  local filename = vim.fn.expand('%')
  local cmd = "gitk " .. filename .. "\r"
  require("tman").sendCommand(cmd, {})
end
use as a vim-test stratergy
-- ~/.config/nvim/plugins/vim-test.lua (if using lazy.nvim as your plugin manager)

vim.cmd[[

function! Tman(cmd)
  let g:cmd = a:cmd . "\n"
  lua require("tman").sendCommand(vim.g.cmd, {open = true, split = "last"})
endfunction

let g:test#custom_strategies = {'tman': function('Tman')}
let g:test#strategy = 'tman'

]]

vim.keymap.set("n", "<leader>tf", ":TestFile<CR>")
vim.keymap.set("n", "<leader>ts", ":TestNearest<CR>")
vim.keymap.set("n", "<leader>tl", ":TestLast<CR>")

return {
  'vim-test/vim-test',
  cmd = {'TestNearest', 'TestFile', 'TestLast'},
  dependencies = {
    'Bhanukamax/tman.nvim',
  }
}
open magit for the current working directory using emacsclient
    local open_magit_status = function ()
      tman.sendCommand('emacsclient -cn  -e "(magit-status)" \r', {})
    end

    vim.keymap.set("n", "<leader>cgg", open_magit_status)

Interacting with neovim terminal

  • neotermman uses the neovim terminal,
  • by defualt terminal buffer will open in the terminal mode which is similar to normal mode.
  • to interact with the terminal you need to go into insert mode by pressing i key.

After using terminal

  • to exit out of the insert mode in the terminal, you need to use the neovim terminal escape key sequence which is <C-\><C-N>.
  • since above key sequence is not very easy, you can rebind it to something else.
  • I have found that C-x works best for me for this.
Lua
vim.keymap.set("t", "<C-x>", "<C-\\><C-N>", {})