--- title: Vim Send To Terminal date: 2023-07-15T20:18:03-04:00 --- ### Semi automatic scripts with vim `:terminal` For a long time, I used the below to send current line to vim's `:terminal` ```vim :call term_list()[0]->term_sendkeys(getline('.') .. "\") ``` This is very useful if you have a text file with complex shell commands. To run again, `@:` and then again, `@@`. This works because, last command run is stored in `register :` and the last macro executed using `@` is stored in `register @`. And then to run another day, do `:call te` to recall from vim's command history. Since this was very useful, I then wrapped it in a function and added a mapping ```vim def SendToTerminal() if term_list()->empty() echomsg "No Terminal windows found" return endif terms[0]->term_sendkeys(getline(.) .. "\") enddef nnoremap s call SendToTerminal() ``` ### Adding more features So far good for shell commands. But when working with python, had to send a block of functions to the `ipython` shell. So added support for range of lines. But then when sending a range of lines to shell, sometimes there had to be a small delay (sleep) between commands so that the previous command can complete and not eat the rest of commands. Then finally added support for sending `ctrl` characters like `ctrl c`, `ctrl l` ```vim vim9script def SendRangeToTerminal(start_line: number, end_line: number, _ = 0) 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(arg1->str2nr(), funcref('SendRangeToTerminal', [line_num, end_line])) return elseif cmd == "ctrl" terms[0]->term_sendkeys(nr2char(arg1->char2nr() - 96)) continue endif endif terms[0]->term_sendkeys(line .. "\") endfor enddef command -range -bar SendToTerm :call SendRangeToTerminal(, ) vnoremap s :SendToTerm nnoremap s :SendToTerm ``` Wouldn't it be nice to just double-click commands with mouse? Like a simple GUI! ;) ```vim nnoremap <2-LeftMouse> :SendToTerm ``` Or just `Enter`? ```vim nnoremap :SendToTerm \| norm j ``` Of course, mapping `Enter` for any file is a bad idea. So lets just map in our cheat file ```vim autocmd BufNewFile,BufRead cheat.sh { nnoremap <2-LeftMouse> :SendToTerm nnoremap :SendToTerm \| norm j } ``` ### Demo! ### What about neovim/tmux/screen? I am not the only one who thought about this. See [vim-slime](https://github.com/jpalardy/vim-slime) since 2007. However it does not support adding a sleep or sending arbitrary `ctrl` characters without additional mappings