blog post draft1
This commit is contained in:
parent
5b676a6f86
commit
b3ef50860b
@ -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`
|
||||
|
||||
<!--more-->
|
||||
|
||||
For a long time, I used the below to send current line to vim's `:terminal`
|
||||
```vim
|
||||
:call term_list()[0]->term_sendkeys(getline('.') .. "\<CR>")
|
||||
```
|
||||
|
||||
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<UP arrow>` 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(.) .. "\<CR>")
|
||||
enddef
|
||||
|
||||
nnoremap <silent><leader>s call SendToTerminal()<CR>
|
||||
```
|
||||
|
||||
### 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 .. "\<CR>")
|
||||
endfor
|
||||
enddef
|
||||
|
||||
command -range -bar SendToTerm :call <SID>SendRangeToTerminal(<line1>, <line2>)
|
||||
vnoremap <silent><leader>s :SendToTerm<CR>
|
||||
nnoremap <silent><leader>s :SendToTerm<CR>
|
||||
```
|
||||
|
||||
Wouldn't it be nice to just double-click commands with mouse? Like a simple GUI! ;)
|
||||
|
||||
```vim
|
||||
nnoremap <silent><2-LeftMouse> :SendToTerm<CR>
|
||||
```
|
||||
|
||||
Or just `Enter`?
|
||||
|
||||
```vim
|
||||
nnoremap <buffer> <CR> :SendToTerm \| norm j<CR>
|
||||
```
|
||||
|
||||
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 <buffer> <silent><2-LeftMouse> :SendToTerm<CR>
|
||||
nnoremap <buffer> <CR> :SendToTerm \| norm j<CR>
|
||||
}
|
||||
```
|
||||
|
||||
### 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
|
||||
|
Loading…
Reference in New Issue
Block a user