Skip to content
This repository has been archived by the owner on Jun 24, 2023. It is now read-only.

Additional decorators - events and opfuncs #15

Open
averagehat opened this issue Sep 24, 2015 · 7 comments
Open

Additional decorators - events and opfuncs #15

averagehat opened this issue Sep 24, 2015 · 7 comments

Comments

@averagehat
Copy link
Contributor

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?

@amoffat
Copy link
Owner

amoffat commented Sep 24, 2015

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.

@averagehat averagehat changed the title Decorator for events? Additional decorators - events and opfuncs Sep 24, 2015
@averagehat
Copy link
Contributor Author

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

@amoffat
Copy link
Owner

amoffat commented Sep 24, 2015

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.

@averagehat
Copy link
Contributor Author

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).

@amoffat
Copy link
Owner

amoffat commented Sep 24, 2015

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.

@averagehat
Copy link
Contributor Author

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.

@amoffat
Copy link
Owner

amoffat commented Sep 24, 2015

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants