From 4563cfdd0903a03f77314fd5d577071cc4979acf Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 4 Jul 2023 00:59:32 +0200 Subject: [PATCH] feat: bindings for changes and callback --- client/vscode/src/lib.rs | 90 ++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/client/vscode/src/lib.rs b/client/vscode/src/lib.rs index e1d7de8..5f1d126 100644 --- a/client/vscode/src/lib.rs +++ b/client/vscode/src/lib.rs @@ -2,7 +2,11 @@ use std::sync::Arc; use neon::prelude::*; use once_cell::sync::OnceCell; -use codemp::{cursor::Cursor, client::CodempClient, tokio::{runtime::Runtime, sync::{Mutex, broadcast}}, proto::buffer_client::BufferClient, operation::{OperationController, OperationFactory}}; +use codemp::{ + cursor::Cursor, client::CodempClient, operation::{OperationController, OperationFactory, OperationProcessor}, + proto::buffer_client::BufferClient, +}; +use codemp::tokio::{runtime::Runtime, sync::{Mutex, broadcast}}; fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> { static RUNTIME: OnceCell = OnceCell::new(); @@ -52,8 +56,8 @@ fn create(mut cx: FunctionContext) -> JsResult { let content = cx.argument::(1).ok().map(|x| x.value(&mut cx)); let this = cx.this(); let boxed : Handle> = this.get(&mut cx, "boxed")?; - let rc = boxed.0.clone(); + let rc = boxed.0.clone(); let (deferred, promise) = cx.promise(); let channel = cx.channel(); @@ -70,8 +74,8 @@ fn create(mut cx: FunctionContext) -> JsResult { fn listen(mut cx: FunctionContext) -> JsResult { let this = cx.this(); let boxed : Handle> = this.get(&mut cx, "boxed")?; - let rc = boxed.0.clone(); + let rc = boxed.0.clone(); let (deferred, promise) = cx.promise(); let channel = cx.channel(); @@ -98,9 +102,9 @@ fn listen(mut cx: FunctionContext) -> JsResult { fn attach(mut cx: FunctionContext) -> JsResult { let this = cx.this(); let boxed : Handle> = this.get(&mut cx, "boxed")?; - let rc = boxed.0.clone(); let path = cx.argument::(0)?.value(&mut cx); + let rc = boxed.0.clone(); let (deferred, promise) = cx.promise(); let channel = cx.channel(); @@ -111,10 +115,14 @@ fn attach(mut cx: FunctionContext) -> JsResult { let obj = cx.empty_object(); let boxed_value = cx.boxed(OperationControllerHandle(controller)); obj.set(&mut cx, "boxed", boxed_value)?; + let apply_method = JsFunction::new(&mut cx, apply_operation)?; + obj.set(&mut cx, "apply", apply_method)?; let poll_method = JsFunction::new(&mut cx, poll_operation)?; obj.set(&mut cx, "poll", poll_method)?; let content_method = JsFunction::new(&mut cx, content_operation)?; obj.set(&mut cx, "content", content_method)?; + let callback_method = JsFunction::new(&mut cx, callback_operation)?; + obj.set(&mut cx, "set_callback", callback_method)?; Ok(obj) }) }, @@ -128,18 +136,19 @@ fn attach(mut cx: FunctionContext) -> JsResult { fn cursor(mut cx: FunctionContext) -> JsResult { let this = cx.this(); let boxed : Handle> = this.get(&mut cx, "boxed")?; - let rc = boxed.0.clone(); - let path = cx.argument::(0)?.value(&mut cx); - let row = cx.argument::(0)?.value(&mut cx) as i64; - let col = cx.argument::(0)?.value(&mut cx) as i64; + let path = cx.argument::(0)?.value(&mut cx); + let row = cx.argument::(1)?.value(&mut cx) as i64; + let col = cx.argument::(2)?.value(&mut cx) as i64; + + let rc = boxed.0.clone(); let (deferred, promise) = cx.promise(); let channel = cx.channel(); runtime(&mut cx)?.spawn(async move { match rc.lock().await.cursor(path, row, col).await { Ok(accepted) => deferred.settle_with(&channel, move |mut cx| Ok(cx.boolean(accepted))), - Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::>(e.to_string())), + Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<_, Handle>(e.to_string())), } }); @@ -150,11 +159,40 @@ fn cursor(mut cx: FunctionContext) -> JsResult { struct OperationControllerHandle(Arc); impl Finalize for OperationControllerHandle {} +fn apply_operation(mut cx: FunctionContext) -> JsResult { + let this = cx.this(); + let boxed : Handle> = this.get(&mut cx, "boxed")?; + let skip = cx.argument::(0)?.value(&mut cx).round() as usize; + let text = cx.argument::(1)?.value(&mut cx); + let tail = cx.argument::(2)?.value(&mut cx).round() as usize; + + let rc = boxed.0.clone(); + let (deferred, promise) = cx.promise(); + let channel = cx.channel(); + + runtime(&mut cx)?.spawn(async move { + let op = rc.delta(skip, text.as_str(), tail); + match rc.apply(op) { + Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<_, Handle>(format!("could not apply operation: {}", e))), + Ok(span) => deferred.settle_with(&channel, move |mut cx| { + let obj = cx.empty_array(); + let start_value = cx.number(span.start as u32); + obj.set(&mut cx, 0, start_value)?; + let end_value = cx.number(span.end as u32); + obj.set(&mut cx, 1, end_value)?; + Ok(obj) + }), + } + }); + + Ok(promise) +} + fn poll_operation(mut cx: FunctionContext) -> JsResult { let this = cx.this(); let boxed : Handle> = this.get(&mut cx, "boxed")?; - let rc = boxed.0.clone(); + let rc = boxed.0.clone(); let (deferred, promise) = cx.promise(); let channel = cx.channel(); @@ -173,22 +211,38 @@ fn poll_operation(mut cx: FunctionContext) -> JsResult { Ok(promise) } -fn content_operation(mut cx: FunctionContext) -> JsResult { +fn content_operation(mut cx: FunctionContext) -> JsResult { let this = cx.this(); let boxed : Handle> = this.get(&mut cx, "boxed")?; - let rc = boxed.0.clone(); + Ok(cx.string(boxed.0.content())) +} - let (deferred, promise) = cx.promise(); +fn callback_operation(mut cx: FunctionContext) -> JsResult { + let this = cx.this(); + let boxed : Handle> = this.get(&mut cx, "boxed")?; + let callback = Arc::new(cx.argument::(0)?.root(&mut cx)); + + let rc = boxed.0.clone(); let channel = cx.channel(); + // TODO when garbage collecting OperationController stop this worker runtime(&mut cx)?.spawn(async move { - let content = rc.content(); - deferred.settle_with(&channel, move |mut cx| { - Ok(cx.string(content)) - }); + loop{ + let span = rc.wait().await; + let cb = callback.clone(); + channel.send(move |mut cx| { + cb.to_inner(&mut cx) + .call_with(&cx) + .arg(cx.number(span.start as i32)) + .arg(cx.number(span.end as i32)) + .apply::(&mut cx)?; + Ok(()) + }); + } + }); - Ok(promise) + Ok(cx.undefined()) }