From 5884cc2ecba6a23ee960bdd190653fe33f28474b Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Tue, 30 Jun 2026 01:24:14 +0200 Subject: feat(terminal): follow output by default, toggle with G Terminal buffers track their latest output by default: leaving terminal mode or the window, and re-entering the window, jumps to the bottom (G). Toggle per terminal with G in terminal mode or the :TerminalFollow command; an active follow shows as +T in the statusline. --- init.lua | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) (limited to 'init.lua') diff --git a/init.lua b/init.lua index 1ba8311..c14246a 100644 --- a/init.lua +++ b/init.lua @@ -73,6 +73,38 @@ local function terminal_put_register() vim.api.nvim_put({ value }, "c", true, true) end +-- Toggle "follow" mode for the current terminal: while on, leaving terminal mode or the terminal +-- window jumps to the bottom (G) so the view tracks the latest output. Shown as `+T` in the +-- statusline (50-color.lua). +local function toggle_terminal_follow() + if vim.bo.buftype ~= "terminal" then + vim.notify("TerminalFollow only applies to terminal buffers", vim.log.levels.WARN) + return + end + vim.b.terminal_follow = not vim.b.terminal_follow +end + +-- Enter terminal mode and follow output by default when a terminal opens +local function terminal_open() + vim.b.terminal_follow = true + vim.cmd.startinsert() +end + +-- Jump to the bottom (G) when follow mode is on, so the view tracks the latest terminal output +local function terminal_follow_to_bottom() + if vim.b.terminal_follow then + vim.cmd.normal({ "G", bang = true }) + end +end + +-- Keep following after entering a terminal window: defer so a mouse click's cursor placement runs +-- first, then override it with G +local function terminal_follow_on_enter() + if vim.b.terminal_follow then + vim.schedule(terminal_follow_to_bottom) + end +end + -- Kill from the cursor to the end of the command line, akin to Readline's kill-line local function cmdline_kill_line() local pos = vim.fn.getcmdpos() -- 1-based byte index of the cursor @@ -134,6 +166,11 @@ vim.api.nvim_create_user_command( show_buf_diff_orig, { desc = "Show diff between current buffer and file" } ) +vim.api.nvim_create_user_command( + "TerminalFollow", + toggle_terminal_follow, + { desc = "Toggle following terminal output" } +) ------------------------------------------------------------------------------------------------------------------------ -- Keymaps (there's more in the different plugins) @@ -187,11 +224,23 @@ vim.keymap.set("t", "", "", { desc = "Exit terminal mode" }) vim.keymap.set("t", "", "", { desc = "Send to the terminal program" }) vim.keymap.set("t", "", "", { desc = "Execute one normal-mode command" }) vim.keymap.set("t", "", terminal_put_register, { desc = "Paste register" }) +vim.keymap.set("t", "G", "TerminalFollow", { desc = "Toggle following terminal output" }) -- stylua: ignore end -vim.api.nvim_create_autocmd( - "TermOpen", - { pattern = "*", command = "startinsert", desc = "Enter terminal mode" } -) +vim.api.nvim_create_autocmd("TermOpen", { + desc = "Follow terminal output by default", + group = vim.g.dotfiles.augroup, + callback = terminal_open, +}) +vim.api.nvim_create_autocmd({ "TermLeave", "WinLeave" }, { + desc = "Follow terminal output", + group = vim.g.dotfiles.augroup, + callback = terminal_follow_to_bottom, +}) +vim.api.nvim_create_autocmd("WinEnter", { + desc = "Follow terminal output", + group = vim.g.dotfiles.augroup, + callback = terminal_follow_on_enter, +}) ------------------------------------------------------------------------------------------------------------------------ -- Options -- cgit v1.3.1