mirror of
https://github.com/hexedtech/codemp-nvim.git
synced 2024-11-22 15:34:53 +01:00
feat: implemented basic cursor sharing in vscode
This commit is contained in:
parent
38911bdc31
commit
44c6f9eb1a
2 changed files with 124 additions and 121 deletions
|
@ -3,6 +3,8 @@ const codemp = require("./codemp.node");
|
||||||
|
|
||||||
var CLIENT = null
|
var CLIENT = null
|
||||||
var CONTROLLER
|
var CONTROLLER
|
||||||
|
var CURSOR
|
||||||
|
var DECORATION = null
|
||||||
var OP_CACHE = new Set()
|
var OP_CACHE = new Set()
|
||||||
|
|
||||||
async function activate(context) {
|
async function activate(context) {
|
||||||
|
@ -71,9 +73,59 @@ async function join() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _order_tuples(a, b) {
|
||||||
|
if (a[0] < b[0]) return (a, b)
|
||||||
|
if (a[0] > b[0]) return (b, a)
|
||||||
|
if (a[1] < b[1]) return (a, b)
|
||||||
|
return (b, a)
|
||||||
|
}
|
||||||
|
|
||||||
async function _attach(path) {
|
async function _attach(path) {
|
||||||
let doc = vscode.window.activeTextEditor.document;
|
let editor = vscode.window.activeTextEditor
|
||||||
|
let doc = editor.document;
|
||||||
|
|
||||||
|
CURSOR = await CLIENT.listen()
|
||||||
|
CURSOR.callback((usr, path, start, end) => {
|
||||||
|
try {
|
||||||
|
if (DECORATION != null) {
|
||||||
|
DECORATION.dispose()
|
||||||
|
DECORATION = null
|
||||||
|
}
|
||||||
|
const range_start = new vscode.Position(start[0] - 1, start[1]);
|
||||||
|
const range_end = new vscode.Position(start[0] - 1, start[1] + 1);
|
||||||
|
const decorationRange = new vscode.Range(range_start, range_end);
|
||||||
|
DECORATION = vscode.window.createTextEditorDecorationType(
|
||||||
|
{backgroundColor: 'red', color: 'white'}
|
||||||
|
)
|
||||||
|
editor.setDecorations(DECORATION, [decorationRange])
|
||||||
|
} catch (err) {
|
||||||
|
vscode.window.showErrorMessage("fuck! " + err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
vscode.window.onDidChangeTextEditorSelection(async (e) => {
|
||||||
|
let buf = e.textEditor.document.uri.toString()
|
||||||
|
let selection = e.selections[0] // TODO there may be more than one cursor!!
|
||||||
|
let anchor = [selection.anchor.line+1, selection.anchor.character]
|
||||||
|
let position = [selection.active.line+1, selection.active.character]
|
||||||
|
// (anchor, position) = _order_tuples(anchor, position)
|
||||||
|
await CURSOR.send(buf, anchor, position)
|
||||||
|
})
|
||||||
|
|
||||||
CONTROLLER = await CLIENT.attach(path)
|
CONTROLLER = await CLIENT.attach(path)
|
||||||
|
CONTROLLER.callback((start, end) => {
|
||||||
|
// TODO only change affected document range
|
||||||
|
let content = CONTROLLER.content()
|
||||||
|
let range = new vscode.Range(
|
||||||
|
editor.document.positionAt(0),
|
||||||
|
editor.document.positionAt(editor.document.getText().length)
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
OP_CACHE.add((range, content))
|
||||||
|
editor.edit(editBuilder => editBuilder.replace(range, content))
|
||||||
|
} catch (err) {
|
||||||
|
vscode.window.showErrorMessage("could not set buffer: " + err)
|
||||||
|
}
|
||||||
|
})
|
||||||
vscode.workspace.onDidChangeTextDocument(async (e) => {
|
vscode.workspace.onDidChangeTextDocument(async (e) => {
|
||||||
if (e.document != doc) return
|
if (e.document != doc) return
|
||||||
for (let change of e.contentChanges) {
|
for (let change of e.contentChanges) {
|
||||||
|
@ -88,21 +140,6 @@ async function _attach(path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let editor = vscode.window.activeTextEditor
|
|
||||||
CONTROLLER.set_callback((start, end) => {
|
|
||||||
// TODO only change affected document range
|
|
||||||
let content = CONTROLLER.content()
|
|
||||||
let range = new vscode.Range(
|
|
||||||
editor.document.positionAt(0),
|
|
||||||
editor.document.positionAt(editor.document.getText().length)
|
|
||||||
)
|
|
||||||
try {
|
|
||||||
OP_CACHE.add((range, content))
|
|
||||||
editor.edit(editBuilder => editBuilder.replace(range, content))
|
|
||||||
} catch (err) {
|
|
||||||
vscode.window.showErrorMessage("could not set buffer: " + err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return CONTROLLER
|
return CONTROLLER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ use std::sync::Arc;
|
||||||
use neon::prelude::*;
|
use neon::prelude::*;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use codemp::{
|
use codemp::{
|
||||||
cursor::Cursor, client::CodempClient, operation::{OperationController, OperationFactory, OperationProcessor},
|
cursor::{CursorControllerHandle, CursorSubscriber}, client::CodempClient, operation::{OperationController, OperationFactory, OperationProcessor},
|
||||||
proto::buffer_client::BufferClient,
|
proto::buffer_client::BufferClient,
|
||||||
};
|
};
|
||||||
use codemp::tokio::{runtime::Runtime, sync::{Mutex, broadcast}};
|
use codemp::tokio::{runtime::Runtime, sync::Mutex};
|
||||||
|
|
||||||
fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
|
fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
|
||||||
static RUNTIME: OnceCell<Runtime> = OnceCell::new();
|
static RUNTIME: OnceCell<Runtime> = OnceCell::new();
|
||||||
|
@ -17,6 +17,22 @@ fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tuple<'a, C: Context<'a>>(cx: &mut C, a: i32, b: i32) -> NeonResult<Handle<'a, JsArray>> {
|
||||||
|
let obj = cx.empty_array();
|
||||||
|
let a_val = cx.number(a);
|
||||||
|
obj.set(cx, 0, a_val)?;
|
||||||
|
let b_val = cx.number(b);
|
||||||
|
obj.set(cx, 1, b_val)?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unpack_tuple<'a, C: Context<'a>>(cx: &mut C, arr: Handle<'a, JsArray>) -> NeonResult<(i32, i32)> {
|
||||||
|
Ok((
|
||||||
|
arr.get::<JsNumber, _, u32>(cx, 0)?.value(cx) as i32,
|
||||||
|
arr.get::<JsNumber, _, u32>(cx, 1)?.value(cx) as i32,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
struct ClientHandle(Arc<Mutex<CodempClient>>);
|
struct ClientHandle(Arc<Mutex<CodempClient>>);
|
||||||
impl Finalize for ClientHandle {}
|
impl Finalize for ClientHandle {}
|
||||||
|
|
||||||
|
@ -33,16 +49,12 @@ fn connect(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
let obj = cx.empty_object();
|
let obj = cx.empty_object();
|
||||||
let boxed_value = cx.boxed(ClientHandle(Arc::new(Mutex::new(c.into()))));
|
let boxed_value = cx.boxed(ClientHandle(Arc::new(Mutex::new(c.into()))));
|
||||||
obj.set(&mut cx, "boxed", boxed_value)?;
|
obj.set(&mut cx, "boxed", boxed_value)?;
|
||||||
let method_create = JsFunction::new(&mut cx, create)?;
|
let method_create = JsFunction::new(&mut cx, create_client)?;
|
||||||
obj.set(&mut cx, "create", method_create)?;
|
obj.set(&mut cx, "create", method_create)?;
|
||||||
let method_listen = JsFunction::new(&mut cx, listen)?;
|
let method_listen = JsFunction::new(&mut cx, listen_client)?;
|
||||||
obj.set(&mut cx, "listen", method_listen)?;
|
obj.set(&mut cx, "listen", method_listen)?;
|
||||||
let method_attach = JsFunction::new(&mut cx, attach)?;
|
let method_attach = JsFunction::new(&mut cx, attach_client)?;
|
||||||
obj.set(&mut cx, "attach", method_attach)?;
|
obj.set(&mut cx, "attach", method_attach)?;
|
||||||
let method_cursor = JsFunction::new(&mut cx, cursor)?;
|
|
||||||
obj.set(&mut cx, "cursor", method_cursor)?;
|
|
||||||
let test = cx.null();
|
|
||||||
obj.set(&mut cx, "test", test)?;
|
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -51,7 +63,7 @@ fn connect(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
Ok(promise)
|
Ok(promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
fn create_client(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
||||||
let content = cx.argument::<JsString>(1).ok().map(|x| x.value(&mut cx));
|
let content = cx.argument::<JsString>(1).ok().map(|x| x.value(&mut cx));
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
|
@ -71,7 +83,7 @@ fn create(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
Ok(promise)
|
Ok(promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn listen(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
fn listen_client(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
|
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
|
||||||
|
|
||||||
|
@ -82,13 +94,14 @@ fn listen(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
runtime(&mut cx)?.spawn(async move {
|
runtime(&mut cx)?.spawn(async move {
|
||||||
match rc.lock().await.listen().await {
|
match rc.lock().await.listen().await {
|
||||||
Ok(controller) => {
|
Ok(controller) => {
|
||||||
let sub = controller.sub();
|
|
||||||
deferred.settle_with(&channel, move |mut cx| {
|
deferred.settle_with(&channel, move |mut cx| {
|
||||||
let obj = cx.empty_object();
|
let obj = cx.empty_object();
|
||||||
let boxed_value = cx.boxed(CursorEventsHandle(Arc::new(Mutex::new(sub))));
|
let boxed_value = cx.boxed(CursorEventsHandle(controller));
|
||||||
obj.set(&mut cx, "boxed", boxed_value)?;
|
obj.set(&mut cx, "boxed", boxed_value)?;
|
||||||
let poll_method = JsFunction::new(&mut cx, poll_cursor)?;
|
let callback_method = JsFunction::new(&mut cx, callback_cursor)?;
|
||||||
obj.set(&mut cx, "poll", poll_method)?;
|
obj.set(&mut cx, "callback", callback_method)?;
|
||||||
|
let send_method = JsFunction::new(&mut cx, send_cursor)?;
|
||||||
|
obj.set(&mut cx, "send", send_method)?;
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -99,7 +112,7 @@ fn listen(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
Ok(promise)
|
Ok(promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attach(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
fn attach_client(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
|
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
|
||||||
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
||||||
|
@ -117,12 +130,10 @@ fn attach(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
obj.set(&mut cx, "boxed", boxed_value)?;
|
obj.set(&mut cx, "boxed", boxed_value)?;
|
||||||
let apply_method = JsFunction::new(&mut cx, apply_operation)?;
|
let apply_method = JsFunction::new(&mut cx, apply_operation)?;
|
||||||
obj.set(&mut cx, "apply", apply_method)?;
|
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)?;
|
let content_method = JsFunction::new(&mut cx, content_operation)?;
|
||||||
obj.set(&mut cx, "content", content_method)?;
|
obj.set(&mut cx, "content", content_method)?;
|
||||||
let callback_method = JsFunction::new(&mut cx, callback_operation)?;
|
let callback_method = JsFunction::new(&mut cx, callback_operation)?;
|
||||||
obj.set(&mut cx, "set_callback", callback_method)?;
|
obj.set(&mut cx, "callback", callback_method)?;
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -133,28 +144,6 @@ fn attach(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
Ok(promise)
|
Ok(promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
|
||||||
let this = cx.this();
|
|
||||||
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
|
|
||||||
|
|
||||||
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
|
||||||
let row = cx.argument::<JsNumber>(1)?.value(&mut cx) as i64;
|
|
||||||
let col = cx.argument::<JsNumber>(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::<_, Handle<JsString>>(e.to_string())),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(promise)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct OperationControllerHandle(Arc<OperationController>);
|
struct OperationControllerHandle(Arc<OperationController>);
|
||||||
impl Finalize for OperationControllerHandle {}
|
impl Finalize for OperationControllerHandle {}
|
||||||
|
@ -174,43 +163,13 @@ fn apply_operation(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
let op = rc.delta(skip, text.as_str(), tail);
|
let op = rc.delta(skip, text.as_str(), tail);
|
||||||
match rc.apply(op) {
|
match rc.apply(op) {
|
||||||
Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<_, Handle<JsString>>(format!("could not apply operation: {}", e))),
|
Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<_, Handle<JsString>>(format!("could not apply operation: {}", e))),
|
||||||
Ok(span) => deferred.settle_with(&channel, move |mut cx| {
|
Ok(span) => deferred.settle_with(&channel, move |mut cx| tuple(&mut cx, span.start as i32, span.end as i32)),
|
||||||
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)
|
Ok(promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_operation(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
|
||||||
let this = cx.this();
|
|
||||||
let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?;
|
|
||||||
|
|
||||||
let rc = boxed.0.clone();
|
|
||||||
let (deferred, promise) = cx.promise();
|
|
||||||
let channel = cx.channel();
|
|
||||||
|
|
||||||
runtime(&mut cx)?.spawn(async move {
|
|
||||||
let span = rc.wait().await;
|
|
||||||
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 content_operation(mut cx: FunctionContext) -> JsResult<JsString> {
|
fn content_operation(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?;
|
let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?;
|
||||||
|
@ -239,51 +198,59 @@ fn callback_operation(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(cx.undefined())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CursorEventsHandle(CursorControllerHandle);
|
||||||
|
impl Finalize for CursorEventsHandle {}
|
||||||
|
|
||||||
|
fn callback_cursor(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||||
|
let this = cx.this();
|
||||||
|
let boxed : Handle<JsBox<CursorEventsHandle>> = this.get(&mut cx, "boxed")?;
|
||||||
|
let callback = Arc::new(cx.argument::<JsFunction>(0)?.root(&mut cx));
|
||||||
|
|
||||||
|
let mut rc = boxed.0.clone();
|
||||||
|
let channel = cx.channel();
|
||||||
|
|
||||||
|
// TODO when garbage collecting OperationController stop this worker
|
||||||
|
runtime(&mut cx)?.spawn(async move {
|
||||||
|
while let Some(op) = rc.poll().await {
|
||||||
|
let cb = callback.clone();
|
||||||
|
channel.send(move |mut cx| {
|
||||||
|
cb.to_inner(&mut cx)
|
||||||
|
.call_with(&cx)
|
||||||
|
.arg(cx.string(op.user))
|
||||||
|
.arg(cx.string(op.buffer))
|
||||||
|
.arg(tuple(&mut cx, op.start.row as i32, op.start.col as i32)?)
|
||||||
|
.arg(tuple(&mut cx, op.end.row as i32, op.end.col as i32)?)
|
||||||
|
.apply::<JsUndefined, _>(&mut cx)?;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(cx.undefined())
|
Ok(cx.undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_cursor(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
|
|
||||||
struct CursorEventsHandle(Arc<Mutex<broadcast::Receiver<(String, Cursor)>>>);
|
|
||||||
impl Finalize for CursorEventsHandle {}
|
|
||||||
|
|
||||||
fn poll_cursor(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let boxed : Handle<JsBox<CursorEventsHandle>> = this.get(&mut cx, "boxed")?;
|
let boxed : Handle<JsBox<CursorEventsHandle>> = this.get(&mut cx, "boxed")?;
|
||||||
let rc = boxed.0.clone();
|
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
||||||
|
let start_obj = cx.argument::<JsArray>(1)?;
|
||||||
|
let start = unpack_tuple(&mut cx, start_obj)?;
|
||||||
|
let end_obj = cx.argument::<JsArray>(2)?;
|
||||||
|
let end = unpack_tuple(&mut cx, end_obj)?;
|
||||||
|
|
||||||
|
let rc = boxed.0.clone();
|
||||||
let (deferred, promise) = cx.promise();
|
let (deferred, promise) = cx.promise();
|
||||||
let channel = cx.channel();
|
let channel = cx.channel();
|
||||||
|
|
||||||
runtime(&mut cx)?.spawn(async move {
|
runtime(&mut cx)?.spawn(async move {
|
||||||
match rc.lock().await.recv().await {
|
rc.send(&path, start.into(), end.into()).await;
|
||||||
Ok((name, cursor)) => {
|
deferred.settle_with(&channel, |mut cx| Ok(cx.undefined()))
|
||||||
deferred.settle_with(&channel, move |mut cx| {
|
|
||||||
let obj = cx.empty_object();
|
|
||||||
let name_value = cx.string(name);
|
|
||||||
obj.set(&mut cx, "user", name_value)?;
|
|
||||||
let buffer_value = cx.string(cursor.buffer);
|
|
||||||
obj.set(&mut cx, "buffer", buffer_value)?;
|
|
||||||
let start_value = cx.empty_array();
|
|
||||||
let start_value_row = cx.number(cursor.start.row as i32);
|
|
||||||
start_value.set(&mut cx, 0, start_value_row)?;
|
|
||||||
let start_value_col = cx.number(cursor.start.col as i32);
|
|
||||||
start_value.set(&mut cx, 0, start_value_col)?;
|
|
||||||
obj.set(&mut cx, "start", start_value)?;
|
|
||||||
let end_value = cx.empty_array();
|
|
||||||
let end_value_row = cx.number(cursor.end.row as i32);
|
|
||||||
end_value.set(&mut cx, 0, end_value_row)?;
|
|
||||||
let end_value_col = cx.number(cursor.end.col as i32);
|
|
||||||
end_value.set(&mut cx, 0, end_value_col)?;
|
|
||||||
obj.set(&mut cx, "end", end_value)?;
|
|
||||||
Ok(obj)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<String, neon::handle::Handle<JsString>>(e.to_string())),
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(promise)
|
Ok(promise)
|
||||||
|
@ -291,7 +258,6 @@ fn poll_cursor(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
|
|
||||||
#[neon::main]
|
#[neon::main]
|
||||||
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||||
|
|
||||||
cx.export_function("connect", connect)?;
|
cx.export_function("connect", connect)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue