Postprocessing files saved by vim
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.
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/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
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
Finally, the hook in
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.