Last active
November 17, 2024 23:48
-
-
Save cowlicks/5d70685346bf341a71f26e564b795a76 to your computer and use it in GitHub Desktop.
Vim Plugin to rerun last shell-command in last vim terminal buffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Rerun last command plugin | |
-- Unlike the python, this removes the scrollback in the terminal | |
local M = {} | |
-- Store the last terminal buffer job id | |
M.last_terminal_chan_id = nil | |
-- Function to record terminal job id when terminal is opened | |
local function record_terminal_id() | |
local buf = vim.api.nvim_get_current_buf() | |
local chan_id = vim.b[buf].terminal_job_id | |
if chan_id then | |
M.last_terminal_chan_id = chan_id | |
end | |
end | |
-- Function to clear scrollback and screen | |
local function clear_terminal() | |
-- Temporarily set scrollback to 1 to clear history | |
vim.o.scrollback = 1 | |
vim.cmd('sleep 100m') | |
vim.o.scrollback = 10000 | |
-- Send Ctrl-L to clear the screen | |
if M.last_terminal_chan_id then | |
vim.fn.chansend(M.last_terminal_chan_id, vim.api.nvim_replace_termcodes('<C-l>', true, true, true)) | |
end | |
end | |
-- Function to rerun last command | |
function M.rerun_last_command() | |
if not M.last_terminal_chan_id then | |
vim.notify("No terminal found", vim.log.levels.ERROR) | |
return | |
end | |
-- Clear terminal | |
clear_terminal() | |
-- Send commands to rerun last command | |
local keys = vim.api.nvim_replace_termcodes('<C-u>!!<CR><CR>', true, true, true) | |
vim.fn.chansend(M.last_terminal_chan_id, keys) | |
end | |
-- Function to send Ctrl-C to terminal | |
function M.send_ctrl_c() | |
if not M.last_terminal_chan_id then | |
vim.notify("No terminal found", vim.log.levels.ERROR) | |
return | |
end | |
local keys = vim.api.nvim_replace_termcodes('<C-c><CR><CR>', true, true, true) | |
vim.fn.chansend(M.last_terminal_chan_id, keys) | |
end | |
-- Setup function | |
function M.setup() | |
-- Create autocmd to record terminal job id | |
vim.api.nvim_create_autocmd("TermOpen", { | |
callback = record_terminal_id, | |
}) | |
-- Create user commands | |
vim.api.nvim_create_user_command('RerunLastThingInLastTerminal', M.rerun_last_command, {}) | |
vim.api.nvim_create_user_command('CancelInLastTerminal', M.send_ctrl_c, {}) | |
-- Add keymaps | |
vim.keymap.set('n', '<leader>p', ':w<CR>:RerunLastThingInLastTerminal<CR>', { silent = true }) | |
vim.keymap.set('n', '<leader>c', ':w<CR>:CancelInLastTerminal<CR>', { silent = true }) | |
end | |
return M |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
This plugin creates a vim command that re-runs the last shell command in the last vim terminal buffer. | |
This is useful for getting quick feedback while working on something. This workflow would look like: | |
* open a terminal in a vim window with `:terminal` | |
* run a shell command like `cargo check` | |
* Go back to editing and re-run the shell command from the previous step with :RerunLastThingInLastTerminal | |
Installation: | |
Save this file to "rplugin/python3" in a vim 'runtimepath' directory (~/.config/nvim/rplugin/python3/runlast.py for example). | |
Usage: | |
You probably want to map this command to a keybinding. I use "<leader>p" Drop the following in your .vimrc: | |
``` | |
" save the current file and re-run the most recent command in the most recent terminal buffer | |
map <leader>p :w \|:RerunLastThingInLastTerminal <cr> | |
``` | |
Development: | |
If you update this file in place you *might* need to run `:UpdateRemotePlugins` for the changes to take effect. | |
For a long time i've use a similiar command where I re-run the last thing in tmux. I did this with: | |
map ,t :w \|:! tmux send-keys -t 0:$(tmux display-message -p '\#I').1 C-l C-u "\!\!" Enter Enter <cr><cr> | |
But I wanted to be able to do this with a vim terminal buffer because it can take up less screen space. | |
Thank you whoever asked this question: | |
https://vi.stackexchange.com/questions/21449/send-keys-to-a-terminal-buffer | |
https://www.reddit.com/r/neovim/comments/qjkx12/send_upcr_to_term_buffer_using_chansend_to_run/ | |
''' | |
import pynvim | |
rerun_command_name = 'RerunLastThingInLastTerminal' | |
cancel_command_name = 'CancelInLastTerminal' | |
string_to_rerun_last_thing = '"\\<C-l>\\<C-u>!!\\<cr>\\<cr>"' | |
string_to_cancel = '"\\<C-c>\\<cr>\\<cr>"' | |
global_terminal_channel_id_variable_name = 'g:last_terminal_chan_id' | |
@pynvim.plugin | |
class Rerunner(object): | |
def __init__(self, nvim): | |
self.nvim = nvim | |
@pynvim.autocmd('TermOpen', sync=True) | |
def record_terminal_channel_id(self): | |
self.nvim.command(f'let {global_terminal_channel_id_variable_name} = b:terminal_job_id') | |
@pynvim.command(rerun_command_name) | |
def rerun_last_thing_in_last_terminal(self): | |
self.nvim.command_output(f'call chansend(g:last_terminal_chan_id, {string_to_rerun_last_thing})') | |
@pynvim.command(cancel_command_name) | |
def cancel_in_last_terminal(self): | |
self.nvim.command_output(f'call chansend(g:last_terminal_chan_id, {string_to_cancel})') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment