Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronous calls from an asynchronous context #339

Open
numirias opened this issue May 15, 2018 · 2 comments
Open

Synchronous calls from an asynchronous context #339

numirias opened this issue May 15, 2018 · 2 comments
Labels

Comments

@numirias
Copy link

numirias commented May 15, 2018

I have a use case which I'd think is really common. From an asynchronous context I want to get the result of a synchronous call. E.g., in this asynchronous method I want to access the current buffer content:

class MyPlugin:

    @neovim.autocmd(..., sync=False)
    def my_async_cmd(self):
       # This obviously doesn't work because the function is async
       code = self._vim.current.buffer[:]

Of course, I could hack together my own synchronization construct using e.g. threading.Event:

import threading

class MyPlugin:
    ...
    def _wait_for(self, func):
        event = threading.Event()
        res = None
        def wrapper():
            nonlocal res
            res = func()
            event.set()
        self._vim.async_call(wrapper)
        event.wait()
        return res

With that I could now just use code = self._wait_for(lambda: self._vim.current.buffer[:]) to get the code, but this seems really sketchy and I feel there must be an elegant pattern (which would maybe be more obvious to me if I had a firmer grasp of greenlets).

Could you point me in the right direction here? (I've also read #229 but it doesn't seem to refer to the same problem.)

@bfredl
Copy link
Member

bfredl commented May 15, 2018

the code

class MyPlugin:

   @neovim.autocmd(..., sync=False)
   def my_async_cmd(self):
      # This obviously doesn't work because the function is async
      code = self._vim.current.buffer[:]

should actually work. Using threading.Event should only be necessary for multi-threaded code. An alternative can also be to use expr='some code' as documented in http://pynvim.readthedocs.io/en/latest/usage/remote-plugins.html, to avoid extra RPC overhead, or to be sure to evaluate the expression in context of the autocmd.

@numirias
Copy link
Author

@bfredl Thanks for the quick follow-up. I'm sorry, you're absolutely right. The code does indeed work.

In fact, I'm making that call from a thread. In that case, is my solution using threading.Event as good as it gets or is there a more elegant way?

import threading
class MyPlugin:

   @neovim.autocmd(..., sync=False)
   def my_async_cmd(self):

        def func():
            code = self._vim.current.buffer[:]
            ...
        thread = threading.Thread(target=func)
        thread.start()

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

No branches or pull requests

3 participants