mirror of
https://github.com/hexedtech/codemp-sublime.git
synced 2024-11-22 06:44:48 +01:00
First steps towards the migration, updated the bindings, and python side wrapper
Former-commit-id: fe60dec9d36c28b9f86048a0791349a804c66c8f
This commit is contained in:
parent
9a964a099b
commit
8808405a3a
4 changed files with 81 additions and 256 deletions
|
@ -9,7 +9,7 @@ name = "codemp_client"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.4.4"}
|
codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", branch = "woot"}
|
||||||
pyo3 = { version = "0.19", features = ["extension-module"] }
|
pyo3 = { version = "0.19", features = ["extension-module"] }
|
||||||
pyo3-asyncio = { version = "0.19", features = ["tokio-runtime"] }
|
pyo3-asyncio = { version = "0.19", features = ["tokio-runtime"] }
|
||||||
tokio = "1.29.1"
|
tokio = "1.29.1"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
a4493ce329ed791cd4bd17b102efdde3ca4acd8f
|
293406e9737fd8937bf0b8c3e835778531c58115
|
|
@ -5,34 +5,40 @@ class CodempClient():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.handle = libcodemp.codemp_init()
|
self.handle = libcodemp.codemp_init()
|
||||||
|
## Bindings
|
||||||
async def connect(self, server_host): # -> None
|
async def connect(self, server_host): # -> None
|
||||||
await self.handle.connect(server_host)
|
await self.handle.connect(server_host)
|
||||||
|
|
||||||
def disconnect(self): # -> None
|
async def join(self, session): # -> CursorController
|
||||||
self.handle = None
|
return CursorController(await self.handle.join(session))
|
||||||
|
|
||||||
async def create(self, path, content=None): # -> None
|
async def create(self, path, content=None): # -> None
|
||||||
await self.handle.create(path, content)
|
await self.handle.create(path, content)
|
||||||
|
|
||||||
# join a workspace
|
|
||||||
async def join(self, session): # -> CursorController
|
|
||||||
return CursorController(await self.handle.join(session))
|
|
||||||
|
|
||||||
async def attach(self, path): # -> BufferController
|
async def attach(self, path): # -> BufferController
|
||||||
return BufferController(await self.handle.attach(path))
|
return BufferController(await self.handle.attach(path))
|
||||||
|
|
||||||
async def get_cursor(self): # -> CursorController
|
async def get_cursor(self): # -> CursorController
|
||||||
return CursorController(await self.handle.get_cursor())
|
return CursorController(await self.handle.get_cursor())
|
||||||
|
|
||||||
async def get_buffer(self, path): # -> BufferController
|
async def get_buffer(self, path): # -> BufferController
|
||||||
return BufferController(await self.handle.get_buffer())
|
return BufferController(await self.handle.get_buffer())
|
||||||
|
|
||||||
async def disconnect_buffer(self, path): # -> None
|
|
||||||
await self.handle.disconnect_buffer(path)
|
|
||||||
|
|
||||||
async def leave_workspace(self): # -> None
|
async def leave_workspace(self): # -> None
|
||||||
pass # todo
|
await self.handle.leave_workspace()
|
||||||
|
|
||||||
|
async def disconnect_buffer(self, path): # -> None
|
||||||
|
await self.handle.disconnect_buffer(path)
|
||||||
|
|
||||||
|
async def select_buffer(): # -> String
|
||||||
|
await self.handle.select_buffer()
|
||||||
|
|
||||||
|
## Custom
|
||||||
|
async def disconnect(self): # -> None
|
||||||
|
# disconnect all buffers and workspaces first, maybe?
|
||||||
|
await self.leave_workspace()
|
||||||
|
# drop the handle, it will require a new instantiation
|
||||||
|
self.handle = None
|
||||||
|
|
||||||
class CursorController():
|
class CursorController():
|
||||||
def __init__(self, handle):
|
def __init__(self, handle):
|
||||||
|
@ -51,38 +57,12 @@ class CursorController():
|
||||||
# await until new cursor event, then returns
|
# await until new cursor event, then returns
|
||||||
return await self.handle.poll()
|
return await self.handle.poll()
|
||||||
|
|
||||||
def drop_callback(self): # -> None
|
|
||||||
self.handle.drop_callback()
|
|
||||||
|
|
||||||
def callback(self, coro): # -> None
|
|
||||||
self.handle.callback(coro)
|
|
||||||
|
|
||||||
class BufferController():
|
class BufferController():
|
||||||
def __init__(self, handle):
|
def __init__(self, handle):
|
||||||
self.handle = handle
|
self.handle = handle
|
||||||
|
|
||||||
def get_content(self): # -> String
|
def send(self, start, end, txt): # -> None
|
||||||
return self.handle.content()
|
self.handle.send(start, end, txt)
|
||||||
|
|
||||||
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]
|
def try_recv(self): # -> Optional[TextChange]
|
||||||
return self.handle.try_recv()
|
return self.handle.try_recv()
|
||||||
|
@ -93,12 +73,6 @@ class BufferController():
|
||||||
async def poll(self): # -> ??
|
async def poll(self): # -> ??
|
||||||
return await self.handle.poll()
|
return await self.handle.poll()
|
||||||
|
|
||||||
def drop_callback(self): # -> None
|
|
||||||
self.handle.drop_callback()
|
|
||||||
|
|
||||||
def callback(self, coro): # -> None
|
|
||||||
self.handle.callback(coro)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
259
src/lib.rs
259
src/lib.rs
|
@ -5,8 +5,7 @@ use codemp::errors::Error as CodempError;
|
||||||
|
|
||||||
use pyo3::{
|
use pyo3::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
exceptions::{PyConnectionError, PyRuntimeError, PyBaseException},
|
exceptions::{PyConnectionError, PyRuntimeError, PyBaseException}
|
||||||
types::PyString
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PyCodempError(CodempError);
|
struct PyCodempError(CodempError);
|
||||||
|
@ -28,6 +27,9 @@ impl From<PyCodempError> for PyErr {
|
||||||
CodempError::InvalidState { msg } => {
|
CodempError::InvalidState { msg } => {
|
||||||
PyRuntimeError::new_err(format!("Invalid state: {}", msg))
|
PyRuntimeError::new_err(format!("Invalid state: {}", msg))
|
||||||
},
|
},
|
||||||
|
CodempError::Deadlocked => {
|
||||||
|
PyRuntimeError::new_err(format!("Deadlock, retry."))
|
||||||
|
},
|
||||||
CodempError::Filler { message } => {
|
CodempError::Filler { message } => {
|
||||||
PyBaseException::new_err(format!("Generic error: {}", message))
|
PyBaseException::new_err(format!("Generic error: {}", message))
|
||||||
}
|
}
|
||||||
|
@ -42,7 +44,6 @@ fn codemp_init<'a>(py: Python<'a>) -> PyResult<Py<PyClientHandle>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Clone)]
|
|
||||||
struct PyClientHandle(Arc<CodempInstance>);
|
struct PyClientHandle(Arc<CodempInstance>);
|
||||||
|
|
||||||
impl From::<CodempInstance> for PyClientHandle {
|
impl From::<CodempInstance> for PyClientHandle {
|
||||||
|
@ -65,6 +66,22 @@ impl PyClientHandle {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// join a workspace
|
||||||
|
fn join<'a>(&'a self, py: Python<'a>, session: String) -> PyResult<&'a PyAny> {
|
||||||
|
let rc = self.0.clone();
|
||||||
|
|
||||||
|
pyo3_asyncio::tokio::future_into_py(py, async move {
|
||||||
|
let curctrl: PyCursorController = rc.join(session.as_str())
|
||||||
|
.await
|
||||||
|
.map_err(PyCodempError::from)?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
Ok(Py::new(py, curctrl)?)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn create<'a>(&'a self, py: Python<'a>, path: String, content: Option<String>) -> PyResult<&'a PyAny> {
|
fn create<'a>(&'a self, py: Python<'a>, path: String, content: Option<String>) -> PyResult<&'a PyAny> {
|
||||||
let rc = self.0.clone();
|
let rc = self.0.clone();
|
||||||
|
|
||||||
|
@ -90,22 +107,6 @@ impl PyClientHandle {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// join a workspace
|
|
||||||
fn join<'a>(&'a self, py: Python<'a>, session: String) -> PyResult<&'a PyAny> {
|
|
||||||
let rc = self.0.clone();
|
|
||||||
|
|
||||||
pyo3_asyncio::tokio::future_into_py(py, async move {
|
|
||||||
let curctrl: PyCursorController = rc.join(session.as_str())
|
|
||||||
.await
|
|
||||||
.map_err(PyCodempError::from)?
|
|
||||||
.into();
|
|
||||||
|
|
||||||
Python::with_gil(|py| {
|
|
||||||
Ok(Py::new(py, curctrl)?)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_cursor<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
fn get_cursor<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
||||||
let rc = self.0.clone();
|
let rc = self.0.clone();
|
||||||
|
@ -158,98 +159,47 @@ impl PyClientHandle {
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[pyclass]
|
fn select_buffer<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
||||||
struct PyCursorController {
|
let rc = self.0.clone();
|
||||||
handle: Arc<CodempCursorController>,
|
|
||||||
cb_trigger: Option<tokio::sync::mpsc::UnboundedSender<()>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From::<Arc<CodempCursorController>> for PyCursorController {
|
pyo3_asyncio::tokio::future_into_py(py, async move {
|
||||||
fn from(value: Arc<CodempCursorController>) -> Self {
|
let cont = rc.select_buffer()
|
||||||
PyCursorController {
|
.await
|
||||||
handle: value,
|
.map_err(PyCodempError::from)?;
|
||||||
cb_trigger: None
|
|
||||||
}
|
Ok(cont)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn py_cursor_callback_wrapper(cb: PyObject)
|
|
||||||
-> Box<dyn FnMut(CodempCursorEvent) -> () + Send + Sync + 'static>
|
/* ########################################################################### */
|
||||||
{
|
|
||||||
let closure = move |data: CodempCursorEvent| {
|
#[pyclass]
|
||||||
let args: PyCursorEvent = data.into();
|
struct PyCursorController(Arc<CodempCursorController>);
|
||||||
Python::with_gil(|py| { let _ = cb.call1(py, (args,)); });
|
|
||||||
};
|
impl From::<Arc<CodempCursorController>> for PyCursorController {
|
||||||
Box::new(closure)
|
fn from(value: Arc<CodempCursorController>) -> Self {
|
||||||
|
PyCursorController(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PyCursorController {
|
impl PyCursorController {
|
||||||
// fn callback<'a>(&'a self, py: Python<'a>, coro_py: Py<PyAny>, caller_id: Py<PyString>) -> PyResult<&'a PyAny> {
|
|
||||||
// let mut rc = self.0.clone();
|
|
||||||
// let cb = coro_py.clone();
|
|
||||||
// // We want to start polling the ControlHandle and call the callback every time
|
|
||||||
// // we have something.
|
|
||||||
|
|
||||||
// pyo3_asyncio::tokio::future_into_py(py, async move {
|
|
||||||
// while let Some(op) = rc.poll().await {
|
|
||||||
// let start = op.start.unwrap_or(Position { row: 0, col: 0});
|
|
||||||
// let end = op.end.unwrap_or(Position { row: 0, col: 0});
|
|
||||||
|
|
||||||
// let cb_fut = Python::with_gil(|py| -> PyResult<_> {
|
|
||||||
// let args = (op.user, caller_id.clone(), op.buffer, (start.row, start.col), (end.row, end.col));
|
|
||||||
// let coro = cb.call1(py, args)?;
|
|
||||||
// pyo3_asyncio::tokio::into_future(coro.into_ref(py))
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// cb_fut.await?;
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
fn drop_callback(&mut self) -> PyResult<()> {
|
|
||||||
if let Some(channel) = &self.cb_trigger {
|
|
||||||
channel.send(())
|
|
||||||
.map_err(CodempError::from)
|
|
||||||
.map_err(PyCodempError::from)?;
|
|
||||||
|
|
||||||
self.cb_trigger = None;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn callback<'a>(&'a mut self, py_cb: Py<PyAny>) -> PyResult<()> {
|
|
||||||
if let Some(_channel) = &self.cb_trigger {
|
|
||||||
Err(PyCodempError::from(CodempError::InvalidState { msg: "A callback is already running.".into() }).into())
|
|
||||||
} else {
|
|
||||||
let rt = pyo3_asyncio::tokio::get_runtime();
|
|
||||||
|
|
||||||
// create a channel to stop the callback task running on the tokio runtime.
|
|
||||||
// and save the sendent inside the python object, so that we can later call it.
|
|
||||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
|
||||||
self.cb_trigger = Some(tx);
|
|
||||||
|
|
||||||
self.handle.callback(rt, rx, py_cursor_callback_wrapper(py_cb));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send<'a>(&'a self, path: String, start: (i32, i32), end: (i32, i32)) -> PyResult<()> {
|
fn send<'a>(&'a self, path: String, start: (i32, i32), end: (i32, i32)) -> PyResult<()> {
|
||||||
let rc = self.handle.clone();
|
|
||||||
let pos = CodempCursorPosition {
|
let pos = CodempCursorPosition {
|
||||||
buffer: path,
|
buffer: path,
|
||||||
start: Some(start.into()),
|
start: Some(start.into()),
|
||||||
end: Some(end.into())
|
end: Some(end.into())
|
||||||
};
|
};
|
||||||
|
|
||||||
rc.send(pos).map_err(PyCodempError::from)?;
|
Ok(self.0.send(pos).map_err(PyCodempError::from)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_recv(&self, py: Python<'_>) -> PyResult<PyObject> {
|
fn try_recv(&self, py: Python<'_>) -> PyResult<PyObject> {
|
||||||
match self.handle.try_recv().map_err(PyCodempError::from)? {
|
match self.0.try_recv().map_err(PyCodempError::from)? {
|
||||||
Some(cur_event) => {
|
Some(cur_event) => {
|
||||||
let evt = PyCursorEvent::from(cur_event);
|
let evt = PyCursorEvent::from(cur_event);
|
||||||
Ok(evt.into_py(py))
|
Ok(evt.into_py(py))
|
||||||
|
@ -259,7 +209,7 @@ impl PyCursorController {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
fn recv<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
||||||
let rc = self.handle.clone();
|
let rc = self.0.clone();
|
||||||
|
|
||||||
pyo3_asyncio::tokio::future_into_py(py, async move {
|
pyo3_asyncio::tokio::future_into_py(py, async move {
|
||||||
let cur_event: PyCursorEvent = rc.recv()
|
let cur_event: PyCursorEvent = rc.recv()
|
||||||
|
@ -273,7 +223,7 @@ impl PyCursorController {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
fn poll<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
||||||
let rc = self.handle.clone();
|
let rc = self.0.clone();
|
||||||
|
|
||||||
pyo3_asyncio::tokio::future_into_py(py, async move {
|
pyo3_asyncio::tokio::future_into_py(py, async move {
|
||||||
Ok(rc.poll().await.map_err(PyCodempError::from)?)
|
Ok(rc.poll().await.map_err(PyCodempError::from)?)
|
||||||
|
@ -282,129 +232,30 @@ impl PyCursorController {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct PyBufferController {
|
struct PyBufferController(Arc<CodempBufferController>);
|
||||||
handle: Arc<CodempBufferController>,
|
|
||||||
cb_trigger: Option<tokio::sync::mpsc::UnboundedSender<()>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From::<Arc<CodempBufferController>> for PyBufferController {
|
impl From::<Arc<CodempBufferController>> for PyBufferController {
|
||||||
fn from(value: Arc<CodempBufferController>) -> Self {
|
fn from(value: Arc<CodempBufferController>) -> Self {
|
||||||
PyBufferController{
|
PyBufferController(value)
|
||||||
handle: value,
|
|
||||||
cb_trigger: None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn py_buffer_callback_wrapper(cb: PyObject)
|
|
||||||
-> Box<dyn FnMut(CodempTextChange) -> () + Send + Sync + 'static>
|
|
||||||
{
|
|
||||||
let closure = move |data: CodempTextChange| {
|
|
||||||
let args: PyTextChange = data.into();
|
|
||||||
Python::with_gil(|py| { let _ = cb.call1(py, (args,)); });
|
|
||||||
};
|
|
||||||
Box::new(closure)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PyBufferController {
|
impl PyBufferController {
|
||||||
// fn callback<'a>(&'a self, py: Python<'a>, coro_py: Py<PyAny>, caller_id: Py<PyString>) -> PyResult<&'a PyAny> {
|
|
||||||
// let mut rc = self.0.clone();
|
|
||||||
// let cb = coro_py.clone();
|
|
||||||
// // We want to start polling the ControlHandle and call the callback every time
|
|
||||||
// // we have something.
|
|
||||||
|
|
||||||
// pyo3_asyncio::tokio::future_into_py(py, async move {
|
|
||||||
// while let Some(edit) = rc.poll().await {
|
|
||||||
// let start = edit.span.start;
|
|
||||||
// let end = edit.span.end;
|
|
||||||
// let text = edit.content;
|
|
||||||
|
|
||||||
// let cb_fut = Python::with_gil(|py| -> PyResult<_> {
|
|
||||||
// let args = (caller_id.clone(), start, end, text);
|
|
||||||
// let coro = cb.call1(py, args)?;
|
|
||||||
// pyo3_asyncio::tokio::into_future(coro.into_ref(py))
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// cb_fut.await?;
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn drop_callback(&mut self) -> PyResult<()> {
|
|
||||||
if let Some(channel) = &self.cb_trigger {
|
|
||||||
channel.send(())
|
|
||||||
.map_err(CodempError::from)
|
|
||||||
.map_err(PyCodempError::from)?;
|
|
||||||
|
|
||||||
self.cb_trigger = None;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn callback<'a>(&'a mut self, py_cb: Py<PyAny>) -> PyResult<()> {
|
|
||||||
if let Some(_channel) = &self.cb_trigger {
|
|
||||||
Err(PyCodempError::from(CodempError::InvalidState { msg: "A callback is already running.".into() }).into())
|
|
||||||
} else {
|
|
||||||
let rt = pyo3_asyncio::tokio::get_runtime();
|
|
||||||
|
|
||||||
// could this be a oneshot channel?
|
|
||||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
|
||||||
self.cb_trigger = Some(tx);
|
|
||||||
|
|
||||||
self.handle.callback(rt, rx, py_buffer_callback_wrapper(py_cb));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn replace(&self, txt: &str) -> PyResult<()> {
|
|
||||||
if let Some(op) = self.handle.replace(txt) {
|
|
||||||
self.handle.send(op).map_err(PyCodempError::from)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delta(&self, start: usize, txt: &str, end: usize) -> PyResult<()> {
|
|
||||||
if let Some(op) = self.handle.delta(start, txt, end){
|
|
||||||
self.handle.send(op).map_err(PyCodempError::from)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&self, txt: &str, pos: u64) -> PyResult<()> {
|
|
||||||
let op = self.handle.insert(txt, pos);
|
|
||||||
self.handle.send(op).map_err(PyCodempError::from)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete(&self, pos: u64, count: u64) -> PyResult<()> {
|
|
||||||
let op = self.handle.delete(pos, count);
|
|
||||||
self.handle.send(op).map_err(PyCodempError::from)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cancel(&self, pos: u64, count: u64) -> PyResult<()> {
|
|
||||||
let op = self.handle.cancel(pos, count);
|
|
||||||
self.handle.send(op).map_err(PyCodempError::from)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn content(&self, py: Python<'_>) -> PyResult<Py<PyString>> {
|
|
||||||
let cont: Py<PyString> = PyString::new(py, self.handle.content().as_str()).into();
|
|
||||||
Ok(cont)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: What to do with this send?
|
// TODO: What to do with this send?
|
||||||
// does it make sense to implement it at all for the python side??
|
// does it make sense to implement it at all for the python side??
|
||||||
|
|
||||||
// fn send<'a>(&self, py: Python<'a>, skip: usize, text: String, tail: usize) -> PyResult<&'a PyAny>{
|
fn send(&self, start: usize, end: usize, txt: String) -> PyResult<()>{
|
||||||
// todo!()
|
let op = CodempTextChange {
|
||||||
// }
|
span: start..end,
|
||||||
|
content: txt.into()
|
||||||
|
};
|
||||||
|
Ok(self.0.send(op).map_err(PyCodempError::from)?)
|
||||||
|
}
|
||||||
|
|
||||||
fn try_recv(&self, py: Python<'_>) -> PyResult<PyObject> {
|
fn try_recv(&self, py: Python<'_>) -> PyResult<PyObject> {
|
||||||
match self.handle.try_recv().map_err(PyCodempError::from)? {
|
match self.0.try_recv().map_err(PyCodempError::from)? {
|
||||||
Some(txt_change) => {
|
Some(txt_change) => {
|
||||||
let evt = PyTextChange::from(txt_change);
|
let evt = PyTextChange::from(txt_change);
|
||||||
Ok(evt.into_py(py))
|
Ok(evt.into_py(py))
|
||||||
|
@ -414,7 +265,7 @@ impl PyBufferController {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
fn recv<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
||||||
let rc = self.handle.clone();
|
let rc = self.0.clone();
|
||||||
|
|
||||||
pyo3_asyncio::tokio::future_into_py(py, async move {
|
pyo3_asyncio::tokio::future_into_py(py, async move {
|
||||||
let txt_change: PyTextChange = rc.recv()
|
let txt_change: PyTextChange = rc.recv()
|
||||||
|
@ -428,7 +279,7 @@ impl PyBufferController {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
fn poll<'a>(&'a self, py: Python<'a>) -> PyResult<&'a PyAny> {
|
||||||
let rc = self.handle.clone();
|
let rc = self.0.clone();
|
||||||
|
|
||||||
pyo3_asyncio::tokio::future_into_py(py, async move {
|
pyo3_asyncio::tokio::future_into_py(py, async move {
|
||||||
Ok(rc.poll().await.map_err(PyCodempError::from)?)
|
Ok(rc.poll().await.map_err(PyCodempError::from)?)
|
||||||
|
|
Loading…
Reference in a new issue