From b3ef50860b14602699be46116243b8406a60ef56 Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Sat, 22 Jul 2023 00:15:29 -0400 Subject: [PATCH] blog post draft1 --- hugo/content/posts/vim-stt.md | 102 +++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/hugo/content/posts/vim-stt.md b/hugo/content/posts/vim-stt.md index 03d9b71..bf41f5f 100644 --- a/hugo/content/posts/vim-stt.md +++ b/hugo/content/posts/vim-stt.md @@ -1,7 +1,103 @@ --- -title: "Vim Send To Terminal" +title: Vim Send To Terminal date: 2023-07-15T20:18:03-04:00 -draft: true --- -## Semi automate scripts with vim `:terminal` +### 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