Processing vim buffers through an external program on save, is a technique that is probably in use, and that I have not found documented anywhere, so here we go. Skip to the details for the entertaining example.
I wanted to integrate egt with TaskWarrior so that every time I am editing an egt project file in vim, if I write a line in a certain way then a new taskwarrior task is created. Also, I have never written a vim plugin, and I don't want to dive into another rabbit hole just yet.
Lynoure brought to my attention that taskwiki processes things when the file is saved, so I thought that I can probably get a long way by piping the file from vim into egt and reading it back before saving.
I created a new egt annotate
command that reads a project file, tweaks it,
and then prints it out; I opened a project file in vim; I typed
:%!egt annotate %:p --stdin
and saw that it could be done.
I find the result quite fun: I type 15 March: 18:00-21:00
in a log in egt,
save the file, and it becomes 15 March: 18:00-21:00 3h
. I do something in
TaskWarrior, save the file in egt, and the lines that are TaskWarrior tasks
update with the new task states.
Details
Here's a step by step example of how to hook into vim in this way.
First thing, create a filter script that processes text files in some way.
Let's call this /usr/local/bin/pyvimshell
:
#!/usr/bin/python3
import sys
import subprocess
for line in sys.stdin:
print(line.rstrip(), file=sys.stdout)
line = line.strip()
if line == "$":
pass
elif line.startswith("$"):
out = subprocess.check_output(["sh", "-c", line[1:].strip()], universal_newlines=True)
sys.stdout.write(out)
if not out.endswith("\n"):
sys.stdout.write("\n")
print("$ ", file=sys.stdout)
Then let's create a new filetype in ~/.vim/filetype.vim
for our special magic
text files:
if exists("did_load_filetypes")
finish
endif
augroup filetypedetect
au! BufNewFile,BufRead *.term setf SillyShell
augroup END
If you create a file example.term
, open it in vim and type :set ft
it
should say SillyShell
.
Finally, the hook in ~/.vim/after/ftplugin/SillyShell.vim
:
function! SillyShellRun()
:%!/home/enrico/dev/egt/pyvimshell
:$
endfunction
autocmd BufWritePre,FileWritePre <buffer> :silent call SillyShellRun()
Now you can create a file example.term
, open it in vim, type $ ls
, save it,
and suddenly you have a terminal with infinite scrollback.
For egt, I actually want to preserve my cursor position across saves, and egt also needs to know the path to the project file, so here is the egt version of the hook:
function! EgtAnnotate()
let l:cur_pos = getpos(".")
:%!egt annotate --stdin %:p
call setpos(".", l:cur_pos)
endfunction
autocmd BufWritePre,FileWritePre <buffer> :silent call EgtAnnotate()
I find this adorably dangerous. Have fun.