Additional decorators - events and opfuncs
averagehat opened this issue · 7 comments
just as there is a key_map
decorator it would be great if there was a decorator for things like:
:autocmd CursorMoved * call MyPythonFunc()
Is that feasible?
from snake import *
from time import time
def my_python_func():
print("moved! at %d" % time())
call = register_fn(my_python_func)
command("autocmd CursorMoved * :python %s" % call))
that's how you would do it. you could easily make a helper that registered a function to an autocmd event.
Okay, I think that would be a good fit for this library--I can make a PR with decorators for the basic events if you agree.
How about custom operators? It would be cool to be able to define them in the same fashion. There is a project for a vim shortcut here: https://github.com/tommcdo/vim-express
Decorators would be great. If you make a generalized autocmd helper that takes an event name and a python function, and does all the things to register that function to that event, that would make it super reusable. Then we could make more specific decorators for specific events like CursorMoved, if they make sense.
Not sure about your operator question. I'm not sure what a custom operator is.
Custom Operators allow you to apply a function to text selected by an arbitrary motion. The selected text then serves as the "noun" the function "verbs" with. They seem to be called by a number of different names and the straight VimL implementation is quite obscure.
:help :map-operator
Example from my blog post
:nmap <silent> <F4> :set opfunc=Echo<CR>g@
:vmap <silent> <F4> :<C-U>call Echo(visualmode(), 1)<CR>
The function definition (you can see it's quite a mess of boilerplate):
" uses [/] marks along with visual mode to yank a custom selection of text.
fun! Echo(type, ...)
"backticks=' (goto mark), have to avoid out-quoting string
"clear the @q register for use in this function.
"@q is the reserved phonim register.
let @q=""
" see :h g@ for more info and how to save and restore a register, which
" would allow us to use 'q' only temporarily and then restore it
if a:0 " Invoked from Visual mode, use '< and '> marks.
silent exe "normal! `<" . a:type . '`>"qy'
elseif a:type == 'line'
silent exe 'normal! `[V`]"qy'
elseif a:type == 'block' " column ('block') selection.
silent exe 'normal! `[\<C-V>`]"qy'
"v -> visual mode but stay in-line
else " Stay in-line
silent exe 'normal! `[v`]"qy'
endif
echo @q
endfun
. . . . . opfunc
works by setting [
and ]
marks to the beginning and end of the user motiton (i.e. to the next whitespace if it is W
or the next like if it is j
). The Echo
function simply yanks the text between these two marks and stores them in the q
register. The if statements gaurantee that the selection will work the same in visual and normal mode (v
is for inline visual selection; V
is for column or "block" selection).
Could you provide a use-case that would be difficult to achieve another way? I'm still having trouble grasping how this would be used.
The use case in vim-express is to comment out (e.g. with /*
) an arbitrary block of code. The custom operator saves whatever you selected (say w
a word, k
, two lines) to a register and re-writes it wrapped in /* ... */
. Another example would be to send an arbitrary block of text to a REPL or vimgrep or something. This way you define the function once and it works for both visual and normal mode and with all possible vim motions. This way you can avoid re-writing different functions with getcurrentline
, getcurrentword
.... or for normal and visual mode.
In some (all?) cases you could have a vmap
that does something by fetching the visually selected text, but this requires entering visual mode. This isn't enough in my case (I want instant feedback from a screen-reader) or getting live feedback from a REPL.
Interesting. In theory it sounds like it could be implemented in snake. I'd be for merging it if you can pull it off in a PR. Writing a test might be hard though