Vim Send To Terminal
│ vim │ development
Semi automatic scripts with vim :terminal
Sometimes, fully automating a task is not worth the effort. So I end up running
a set of commands usually from a cheat sheet text file slightly modifying the
arguments each time. I used the below in vim to send line under cursor to vim’s
:terminal
open in a split
:call term_list()[0]->term_sendkeys(getline('.') .. "\<CR>")
To send another line @:
and then for every other line @@
. This works because, last
command run is stored in register :
and the last macro executed using @
is
stored in register @
.
To do the same another day, :call te<UP arrow>
to recall from vim’s command
history. Or better, add a function and mapping.
def SendToTerminal()
if term_list()->empty()
echomsg "No Terminal windows found"
return
endif
terms[0]->term_sendkeys(getline(.) .. "\<CR>")
enddef
nnoremap <silent><leader>s call SendToTerminal()<CR>
More cool features
For most use-cases that was enough. However added a few more nice features which is very helpful when you need it
- Support sending a range of lines (visual selection) at a time. E.g. Send a function block to a python shell
- Add a delay between lines in milliseconds. This is useful when the previous command reads from standard input and takes some time to complete
- Support sending
ctrl
characters likectrl d
,ctrl c
etc,
def g:SendRangeToTerminal(start_line: number, end_line: number)
const terms = term_list()
if terms->empty()
echomsg "No Terminal windows found"
return
endif
var line_num = start_line
for line in getline(start_line, end_line)
line_num += 1
const spl_cmd = line->matchlist('\vVIMST (sleep|ctrl) ([0-9]+|[a-z])')
if !spl_cmd->empty()
const [_, cmd, arg1; _] = spl_cmd
if cmd == "sleep"
timer_start(str2nr(arg1), (_) => g:SendRangeToTerminal(line_num, end_line))
return
elseif cmd == "ctrl"
terms[0]->term_sendkeys(nr2char(char2nr(arg1) - 96))
continue
endif
endif
terms[0]->term_sendkeys(line .. "\<CR>")
endfor
enddef
command -range -bar SendToTerm :call g:SendRangeToTerminal(<line1>, <line2>)
vnoremap <silent><leader>s :SendToTerm<CR>
nnoremap <silent><leader>s :SendToTerm<CR>
More cool mapping
Wouldn’t it be nice to just double-click commands with mouse? Like a simple GUI! ;)
nnoremap <silent><2-LeftMouse> :SendToTerm<CR>
Or just hit Enter
?
nnoremap <buffer> <CR> :SendToTerm \| norm j<CR>
Automatically add those mappings for cheat.sh
autocmd BufNewFile,BufRead cheat.sh nnoremap <buffer> <CR> :SendToTerm \| norm j<CR>
autocmd BufNewFile,BufRead cheat.sh nnoremap <buffer> <silent><2-LeftMouse> :SendToTerm<CR>
Demo
Using
Copying above snippets to your vimrc should work in a recent vim. Checked in ubuntu 22.04 and archlinux. Git: repo
neovim/tmux/screen
Since neovim uses a different terminal API, above snippets don’t work in
neovim. vim-slime plugin (available
since 2007!) supports different types of terminal. However it does not support
adding delay and ctrl
characters in text.