diff --git a/bindings/codemp_client.cpython-38-darwin.so.REMOVED.git-id b/bindings/codemp_client.cpython-38-darwin.so.REMOVED.git-id index 3df941f..d43fe94 100644 --- a/bindings/codemp_client.cpython-38-darwin.so.REMOVED.git-id +++ b/bindings/codemp_client.cpython-38-darwin.so.REMOVED.git-id @@ -1 +1 @@ -80ba7b16f0b0647e2f1d8520f3a90c51000bbd2c \ No newline at end of file +8114809f135d7ea9f88d0a45a9de8fc93fdbd9ff \ No newline at end of file diff --git a/plugin.py b/plugin.py index 9a8d2bd..b6c6561 100644 --- a/plugin.py +++ b/plugin.py @@ -9,9 +9,9 @@ import time # UGLYYYY, find a way to not have global variables laying around. _tasks = [] -_client = CodempClient() +_client = None _cursor_controller = None -_op_controller = None +_buffer_controller = None _setting_key = "codemp_buffer" def store_task(name = None): @@ -23,6 +23,8 @@ def store_task(name = None): return store_named_task def plugin_loaded(): + global _client + _client = CodempClient() sublime_asyncio.acquire() # instantiate and start a global event loop. class CodempClientViewEventListener(sublime_plugin.ViewEventListener): @@ -47,24 +49,24 @@ class CodempClientTextChangeListener(sublime_plugin.TextChangeListener): return False def on_text_changed(self, changes): - global _op_controller - if _op_controller: + global _buffer_controller + if _buffer_controller: for change in changes: sublime_asyncio.dispatch(apply_changes(change)) async def apply_changes(change): - global _op_controller + global _buffer_controller text = change.str skip = change.a.pt if change.len_utf8 == 0: # we are inserting new text. - tail = len(_op_controller.get_content()) - skip + tail = len(_buffer_controller.get_content()) - skip else: # we are changing an existing region of text of length len_utf8 - tail = len(_op_controller.get_content()) - skip - change.len_utf8 + tail = len(_buffer_controller.get_content()) - skip - change.len_utf8 - tail_skip = len(_op_controller.get_content()) - tail + tail_skip = len(_buffer_controller.get_content()) - tail print("[buff change]", skip, text, tail_skip) - await _op_controller.apply(skip, text, tail) + await _buffer_controller.apply(skip, text, tail) async def make_connection(server_host): global _client @@ -90,7 +92,7 @@ async def sync_buffer(caller, start, end, txt): async def share_buffer(buffer): global _client global _cursor_controller - global _op_controller + global _buffer_controller if not _client.ready: sublime.error_message("No connected client.") @@ -106,8 +108,8 @@ async def share_buffer(buffer): sublime.error_message("Could not share buffer.") return - _op_controller = await _client.attach(buffer) - _op_controller.callback(sync_buffer, _client.id) + _buffer_controller = await _client.attach(buffer) + _buffer_controller.callback(sync_buffer, _client.id) _cursor_controller = await _client.listen() _cursor_controller.callback(move_cursor, _client.id) @@ -115,7 +117,7 @@ async def share_buffer(buffer): if not _cursor_controller: sublime.error_message("Could not subsribe a listener.") return - if not _op_controller: + if not _buffer_controller: sublime.error_message("Could not attach to the buffer.") return @@ -127,7 +129,7 @@ async def share_buffer(buffer): async def join_buffer(window, buffer): global _client global _cursor_controller - global _op_controller + global _buffer_controller if not _client.ready: sublime.error_message("No connected client.") @@ -138,8 +140,8 @@ async def join_buffer(window, buffer): sublime.status_message("[codemp] Joining buffer {}".format(buffer)) print("[codemp] Joining buffer {}".format(buffer)) - _op_controller = await _client.attach(buffer) - content = _op_controller.get_content() + _buffer_controller = await _client.attach(buffer) + content = _buffer_controller.get_content() view.run_command("codemp_replace_view", {"content": content}) _cursor_controller = await _client.listen() @@ -149,7 +151,7 @@ async def join_buffer(window, buffer): if not _cursor_controller: sublime.error_message("Could not subsribe a listener.") return - if not _op_controller: + if not _buffer_controller: sublime.error_message("Could not attach to the buffer.") return diff --git a/src/codemp_client.py b/src/codemp_client.py index b6749a3..cb8c6ba 100644 --- a/src/codemp_client.py +++ b/src/codemp_client.py @@ -4,68 +4,109 @@ import Codemp.bindings.codemp_client as libcodemp class CodempClient(): def __init__(self): - self.handle = None - self.id = None + self.handle = libcodemp.codemp_init() self.ready = False - async def connect(self, server_host): - self.handle = await libcodemp.connect(server_host) - self.id = await self.handle.get_id() + async def connect(self, server_host): # -> None + await self.handle.connect(server_host) self.ready = True - def disconnect(self): + def disconnect(self): # -> None + # disconnect all buffers + # stop all callbacks self.handle = None - self.id = None self.ready = False - # some code that tells the server to unsubscribe stuff as well. - async def get_id(self): - if self.ready and not self.id: - self.id = await self.handle.get_id() - return self.id - elif self.ready: - return self.id - else: - raise RuntimeError("Attemp to get id without an established connection.") - - async def create(self, path, content=None): + async def create(self, path, content=None): # -> None if self.ready: return await self.handle.create(path, content) - else: - raise RuntimeError("Attemp to create a buffer without a connection.") - - async def listen(self): + + async def join(self, session): # -> CursorController if self.ready: - return CursorController(await self.handle.listen()) - else: - raise RuntimeError("Attempt to listen without a connection.") - - async def attach(self, path): + return CursorController(await self.handle.join(session)) + + async def attach(self, path): # -> BufferController if self.ready: - return ContentController(await self.handle.attach(path)) - else: - raise RuntimeError("Attempt to attach without a connection.") + return BufferController(await self.handle.attach(path)) + + async def get_cursor(self): # -> CursorController + if self.ready: + return CursorController(await self.handle.get_cursor()) + + async def get_buffer(self, path): # -> BufferController + if self.ready: + return BufferController(await self.handle.get_buffer()) + + async def remove_buffer(self, path): # -> None + if self.ready: + await self.handle.disconnect_buffer(path) class CursorController(): def __init__(self, handle): self.handle = handle - async def send(self, path, start, end): - await self.handle.send(path, start, end) + def send(self, path, start, end): # -> None + self.handle.send(path, start, end) - def callback(self, coro, id): + def try_recv(self): # -> Optional[CursorEvent] + return self.handle.try_recv() + + async def recv(self): # -> CursorEvent + return await self.handle.recv() + + async def poll(self): # -> None + # await until new cursor event, then returns + return await self.handle.poll() + + def drop_callback(self): # -> None + self.handle.drop_callback() + + def callback(self, coro): # -> None self.handle.callback(coro, id) -class ContentController(): +class BufferController(): def __init__(self, handle): self.handle = handle - def get_content(self): + def get_content(self): # -> String return self.handle.content() - async def apply(self, skip, text, tail): - return await self.handle.apply(skip, text, tail) + def replace(self, txt): # -> None + # replace the whole buffer. + self.handle.replace(txt) + + def insert(self, txt, pos): # -> None + # insert text at buffer position pos + self.handle.insert(txt, pos) + + def delta(self, start, txt, end): # -> None + # delta in the region start..end with txt new content + self.handle.delta(start, txt, end) + + def delete(self, pos, count): # -> None + # delete starting from pos, count chars. + self.handle.delete(pos, count) + + def cancel(self, pos, count): # -> None + # cancel backward `count` elements from pos. + self.handle.cancle(pos, count) + + def try_recv(self): # -> Optional[TextChange] + return self.handle.try_recv() + + async def recv(self): # -> TextChange + return await self.handle.recv() + + async def poll(self): # -> ?? + return await self.handle.poll() + + def drop_callback(self): # -> None + self.handle.drop_callback() + + def callback(self, coro): # -> None + self.handle.callback(coro) + + + - def callback(self, coro, id): - self.handle.callback(coro, id) diff --git a/src/lib.rs b/src/lib.rs index 07d19c8..c061156 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,7 @@ impl From:: for PyClientHandle { #[pymethods] impl PyClientHandle { + fn connect<'a>(&'a self, py: Python<'a>, addr: String) ->PyResult<&'a PyAny> { let rc = self.0.clone(); @@ -232,7 +233,7 @@ impl PyCursorController { } } - fn send<'a>(&'a self, py: Python<'a>, path: String, start: (i32, i32), end: (i32, i32)) -> PyResult<&'a PyAny> { + fn send<'a>(&'a self, path: String, start: (i32, i32), end: (i32, i32)) -> PyResult<()> { let rc = self.handle.clone(); let pos = CodempCursorPosition { buffer: path, @@ -240,12 +241,8 @@ impl PyCursorController { end: Some(end.into()) }; - pyo3_asyncio::tokio::future_into_py(py, async move { - rc.send(pos) - .map_err(PyCodempError::from)?; - Ok(()) - }) - + rc.send(pos).map_err(PyCodempError::from)?; + Ok(()) } fn try_recv(&self, py: Python<'_>) -> PyResult {