1 """Event loop implementation that uses pyuv(libuv-python bindings)."""
3 from collections import deque
7 from pynvim.msgpack_rpc.event_loop.base import BaseEventLoop
10 class UvEventLoop(BaseEventLoop):
12 """`BaseEventLoop` subclass that uses `pvuv` as a backend."""
15 self._loop = pyuv.Loop()
16 self._async = pyuv.Async(self._loop, self._on_async)
17 self._connection_error = None
18 self._error_stream = None
19 self._callbacks = deque()
21 def _on_connect(self, stream, error):
24 msg = 'Cannot connect to {}: {}'.format(
25 self._connect_address, pyuv.errno.strerror(error))
26 self._connection_error = OSError(msg)
28 self._read_stream = self._write_stream = stream
30 def _on_read(self, handle, data, error):
32 msg = pyuv.errno.strerror(error) if error else 'EOF'
35 if handle == self._error_stream:
39 def _on_write(self, handle, error):
41 msg = pyuv.errno.strerror(error)
44 def _on_exit(self, handle, exit_status, term_signal):
47 def _disconnected(self, *args):
48 raise OSError('Not connected to Nvim')
50 def _connect_tcp(self, address, port):
51 stream = pyuv.TCP(self._loop)
52 self._connect_address = '{}:{}'.format(address, port)
53 stream.connect((address, port), self._on_connect)
55 def _connect_socket(self, path):
56 stream = pyuv.Pipe(self._loop)
57 self._connect_address = path
58 stream.connect(path, self._on_connect)
60 def _connect_stdio(self):
61 self._read_stream = pyuv.Pipe(self._loop)
62 self._read_stream.open(sys.stdin.fileno())
63 self._write_stream = pyuv.Pipe(self._loop)
64 self._write_stream.open(sys.stdout.fileno())
66 def _connect_child(self, argv):
67 self._write_stream = pyuv.Pipe(self._loop)
68 self._read_stream = pyuv.Pipe(self._loop)
69 self._error_stream = pyuv.Pipe(self._loop)
70 stdin = pyuv.StdIO(self._write_stream,
71 flags=pyuv.UV_CREATE_PIPE + pyuv.UV_READABLE_PIPE)
72 stdout = pyuv.StdIO(self._read_stream,
73 flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
74 stderr = pyuv.StdIO(self._error_stream,
75 flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
76 pyuv.Process.spawn(self._loop,
78 exit_callback=self._on_exit,
79 flags=pyuv.UV_PROCESS_WINDOWS_HIDE,
80 stdio=(stdin, stdout, stderr,))
81 self._error_stream.start_read(self._on_read)
83 def _start_reading(self):
84 if self._transport_type in ['tcp', 'socket']:
86 if self._connection_error:
87 self.run = self.send = self._disconnected
88 raise self._connection_error
89 self._read_stream.start_read(self._on_read)
91 def _send(self, data):
92 self._write_stream.write(data, self._on_write)
95 self._loop.run(pyuv.UV_RUN_DEFAULT)
103 def _threadsafe_call(self, fn):
104 self._callbacks.append(fn)
107 def _on_async(self, handle):
108 while self._callbacks:
109 self._callbacks.popleft()()
111 def _setup_signals(self, signals):
112 self._signal_handles = []
114 def handler(h, signum):
115 self._on_signal(signum)
117 for signum in signals:
118 handle = pyuv.Signal(self._loop)
119 handle.start(handler, signum)
120 self._signal_handles.append(handle)
122 def _teardown_signals(self):
123 for handle in self._signal_handles: