--- /dev/null
+"""Event loop implementation that uses pyuv(libuv-python bindings)."""
+import sys
+from collections import deque
+
+import pyuv
+
+from pynvim.msgpack_rpc.event_loop.base import BaseEventLoop
+
+
+class UvEventLoop(BaseEventLoop):
+
+ """`BaseEventLoop` subclass that uses `pvuv` as a backend."""
+
+ def _init(self):
+ self._loop = pyuv.Loop()
+ self._async = pyuv.Async(self._loop, self._on_async)
+ self._connection_error = None
+ self._error_stream = None
+ self._callbacks = deque()
+
+ def _on_connect(self, stream, error):
+ self.stop()
+ if error:
+ msg = 'Cannot connect to {}: {}'.format(
+ self._connect_address, pyuv.errno.strerror(error))
+ self._connection_error = OSError(msg)
+ return
+ self._read_stream = self._write_stream = stream
+
+ def _on_read(self, handle, data, error):
+ if error or not data:
+ msg = pyuv.errno.strerror(error) if error else 'EOF'
+ self._on_error(msg)
+ return
+ if handle == self._error_stream:
+ return
+ self._on_data(data)
+
+ def _on_write(self, handle, error):
+ if error:
+ msg = pyuv.errno.strerror(error)
+ self._on_error(msg)
+
+ def _on_exit(self, handle, exit_status, term_signal):
+ self._on_error('EOF')
+
+ def _disconnected(self, *args):
+ raise OSError('Not connected to Nvim')
+
+ def _connect_tcp(self, address, port):
+ stream = pyuv.TCP(self._loop)
+ self._connect_address = '{}:{}'.format(address, port)
+ stream.connect((address, port), self._on_connect)
+
+ def _connect_socket(self, path):
+ stream = pyuv.Pipe(self._loop)
+ self._connect_address = path
+ stream.connect(path, self._on_connect)
+
+ def _connect_stdio(self):
+ self._read_stream = pyuv.Pipe(self._loop)
+ self._read_stream.open(sys.stdin.fileno())
+ self._write_stream = pyuv.Pipe(self._loop)
+ self._write_stream.open(sys.stdout.fileno())
+
+ def _connect_child(self, argv):
+ self._write_stream = pyuv.Pipe(self._loop)
+ self._read_stream = pyuv.Pipe(self._loop)
+ self._error_stream = pyuv.Pipe(self._loop)
+ stdin = pyuv.StdIO(self._write_stream,
+ flags=pyuv.UV_CREATE_PIPE + pyuv.UV_READABLE_PIPE)
+ stdout = pyuv.StdIO(self._read_stream,
+ flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
+ stderr = pyuv.StdIO(self._error_stream,
+ flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
+ pyuv.Process.spawn(self._loop,
+ args=argv,
+ exit_callback=self._on_exit,
+ flags=pyuv.UV_PROCESS_WINDOWS_HIDE,
+ stdio=(stdin, stdout, stderr,))
+ self._error_stream.start_read(self._on_read)
+
+ def _start_reading(self):
+ if self._transport_type in ['tcp', 'socket']:
+ self._loop.run()
+ if self._connection_error:
+ self.run = self.send = self._disconnected
+ raise self._connection_error
+ self._read_stream.start_read(self._on_read)
+
+ def _send(self, data):
+ self._write_stream.write(data, self._on_write)
+
+ def _run(self):
+ self._loop.run(pyuv.UV_RUN_DEFAULT)
+
+ def _stop(self):
+ self._loop.stop()
+
+ def _close(self):
+ pass
+
+ def _threadsafe_call(self, fn):
+ self._callbacks.append(fn)
+ self._async.send()
+
+ def _on_async(self, handle):
+ while self._callbacks:
+ self._callbacks.popleft()()
+
+ def _setup_signals(self, signals):
+ self._signal_handles = []
+
+ def handler(h, signum):
+ self._on_signal(signum)
+
+ for signum in signals:
+ handle = pyuv.Signal(self._loop)
+ handle.start(handler, signum)
+ self._signal_handles.append(handle)
+
+ def _teardown_signals(self):
+ for handle in self._signal_handles:
+ handle.stop()