diff --git a/Cargo.toml b/Cargo.toml index 3a995c1..75e95d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] path = "src/rust/lib.rs" [dependencies] -codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.4.5", features = ["global"] } +codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", rev = "7fc03e3fd936240fdbadd368bfce38832ce34767", features = ["global"] } #codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", features = ["global"] } tracing = "0.1" tracing-subscriber = "0.3.17" diff --git a/src/extension.ts b/src/extension.ts index 28cb1ab..4a5708f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,12 +1,14 @@ // The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below import * as vscode from 'vscode'; +import { JsTextChange } from '..'; //import * as types from 'index'; //import * as codemp from '..'; //import * as codemp from '/home/***REMOVED***/projects/codemp/mine/codempvscode/codemp.node'; const codemp = require("/home/***REMOVED***/projects/codemp/mine/codempvscode/codemp.node"); var CACHE : string = ""; +let smallNumberDecorationType = vscode.window.createTextEditorDecorationType({}); //import * as codemp from "/home/***REMOVED***/projects/codemp/mine/vscode/target/debug/libcodemp_vscode.node"; // This method is called when your extension is activated @@ -41,9 +43,9 @@ export function activate(context: vscode.ExtensionContext) { async function connect() { - let host = await vscode.window.showInputBox({prompt: "server host (default to http://alemi.dev:50051)"}) + let host = await vscode.window.showInputBox({prompt: "server host (default to http://alemi.dev:50052)"}) if (host === undefined) return // user cancelled with ESC - if (host.length == 0) host = "http://alemi.dev:50051" + if (host.length == 0) host = "http://alemi.dev:50052" await codemp.connect(host); vscode.window.showInformationMessage(`Connected to codemp @[${host}]`); } @@ -75,7 +77,8 @@ async function join() { /*console.log("range_start" ,range_start, "\n"); console.log("range_end" ,range_end, "\n");*/ const decorationRange = new vscode.Range(range_start, range_end); - const smallNumberDecorationType = vscode.window.createTextEditorDecorationType({ //should remove the highlighted text after a while + smallNumberDecorationType.dispose(); + smallNumberDecorationType = vscode.window.createTextEditorDecorationType({ //should remove the highlighted text after a while borderWidth: '5px', borderStyle: 'solid', overviewRulerColor: 'blue', @@ -102,7 +105,7 @@ async function join() { } - vscode.window.onDidChangeTextEditorSelection((event: vscode.TextEditorSelectionChangeEvent)=>{ + vscode.window.onDidChangeTextEditorSelection((event: vscode.TextEditorSelectionChangeEvent) => { if (event.kind == vscode.TextEditorSelectionChangeKind.Command) return; // TODO commands might move cursor too let buf = event.textEditor.document.uri.toString() let selection = event.selections[0] // TODO there may be more than one cursor!! @@ -120,7 +123,7 @@ async function join() { } -async function createBuffer(){ +async function createBuffer() { let workspace="test";//ask which workspace let buffer : any = (await vscode.window.showInputBox({prompt: "path of the buffer to create"}))!; console.log("new buffer created ", buffer, "\n"); @@ -151,26 +154,27 @@ async function attach() { if (editor === undefined) { return } // TODO say something!!!!!! - let range = new vscode.Range( - editor.document.positionAt(0), - editor.document.positionAt(editor.document.getText().length) - ) - await editor.edit(editBuilder => editBuilder.replace(range, buffer.content())) - console.log("Buffer = ", buffer, "\n"); vscode.window.showInformationMessage(`Connected to codemp workspace buffer @[${workspace}]`); - vscode.workspace.onDidChangeTextDocument((event:vscode.TextDocumentChangeEvent) =>{ + vscode.workspace.onDidChangeTextDocument((event:vscode.TextDocumentChangeEvent) => { console.log(event.reason); for (let change of event.contentChanges) { - if (`${change.rangeOffset}${change.text}${change.rangeOffset+change.rangeLength}` === CACHE) continue; - let op = buffer.delta(change.rangeOffset,change.text,change.rangeOffset+change.rangeLength) - if (op != null) { buffer.send(op) } - else { console.log("change is empty") } + if (`${change.rangeOffset}${change.text}${change.rangeOffset+change.rangeLength}` === CACHE) continue; // LMAO + buffer.send({ + span: { + start: change.rangeOffset, + end: change.rangeOffset+change.rangeLength + }, + content: change.text + }); } }); + + //await new Promise((resolve) => setTimeout(resolve, 200)); // tonioware + console.log("test"); - buffer.callback((event:any) =>{ + buffer.callback((event: any) => { CACHE = `${event.span.start}${event.content}${event.span.end}`; //what's the difference between e.text and e.content like it's on lib.rs? if (editor === undefined) { return } // TODO say something!!!!!! @@ -182,7 +186,7 @@ async function attach() { }); } -async function disconnectBuffer(){ +async function disconnectBuffer() { let buffer : string = (await vscode.window.showInputBox({prompt: "buffer name for the file to disconnect from"}))!; codemp.disconnect(buffer); vscode.window.showInformationMessage(`Disconnected from codemp workspace buffer @[${buffer}]`); @@ -197,3 +201,4 @@ async function disconnectBuffer(){ export function deactivate() { //Maybe i should disconnect from every workspace and buffer ??? // TODO } + diff --git a/src/rust/lib.rs b/src/rust/lib.rs index d28cc3f..fa62dbc 100644 --- a/src/rust/lib.rs +++ b/src/rust/lib.rs @@ -3,10 +3,9 @@ use std::sync::Arc; use codemp::{ prelude::*, proto::{RowCol, CursorEvent}, - buffer::factory::OperationFactory, ot::OperationSeq }; use napi_derive::napi; -use napi::{Status, threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode, ErrorStrategy::Fatal, ThreadsafeFunction}, JsBoolean}; +use napi::{Status, threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode, ErrorStrategy::Fatal, ThreadsafeFunction}}; use napi::tokio; #[derive(Debug)] struct JsCodempError(CodempError); @@ -76,7 +75,7 @@ impl JsCursorController { }*/ #[napi(ts_args_type = "fun: (event: JsCursorEvent) => void")] - pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{ //TODO it sucks but v0.5 will improve it!!! + pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{ let tsfn : ThreadsafeFunction = fun.create_threadsafe_function(0, |ctx : ThreadSafeCallContext| { @@ -86,8 +85,13 @@ impl JsCursorController { let _controller = self.0.clone(); tokio::spawn(async move { loop { - let event = _controller.recv().await.expect("could not receive cursor event!"); - tsfn.call(event.clone(), ThreadsafeFunctionCallMode::NonBlocking); //check this shit with tracing also we could use Ok(event) to get the error + match _controller.recv().await { + Ok(event) => { + tsfn.call(event.clone(), ThreadsafeFunctionCallMode::NonBlocking); //check this shit with tracing also we could use Ok(event) to get the error + }, + Err(CodempError::Deadlocked) => continue, + Err(e) => break tracing::warn!("error receiving: {}", e), + } } }); Ok(()) @@ -169,25 +173,19 @@ pub struct JsTextChange { #[napi(object)] pub struct JsRange{ pub start: i32, - pub end: Option, + pub end: i32, } impl From:: for JsTextChange { fn from(value: CodempTextChange) -> Self { JsTextChange { // TODO how is x.. represented ? span.end can never be None - span: JsRange { start: value.span.start as i32, end: Some(value.span.end as i32) }, + span: JsRange { start: value.span.start as i32, end: value.span.end as i32 }, content: value.content, } } } -impl From:: for JsCodempOperationSeq{ - fn from(value: OperationSeq) -> Self { - JsCodempOperationSeq(value) - } -} - impl From::> for JsBufferController { fn from(value: Arc) -> Self { @@ -199,34 +197,23 @@ impl From::> for JsBufferController { #[napi] pub struct JsBufferController(Arc); -#[napi(js_name = "CodempOperationSeq")] -pub struct JsCodempOperationSeq(CodempOperationSeq); - /*#[napi] pub fn delta(string : String, start: i64, txt: String, end: i64 ) -> Option { Some(JsCodempOperationSeq(string.diff(start as usize, &txt, end as usize)?)) }*/ + + + + + #[napi] impl JsBufferController { - - - - #[napi] - pub fn content(&self) -> String{ - self.0.content() - } - - #[napi] - pub fn delta(&self, start: i64, txt: String, end: i64) -> Option { - self.0.delta(start as usize, &txt, end as usize).map(|x| x.into()) - } - #[napi(ts_args_type = "fun: (event: JsTextChange) => void")] - pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{ //TODO it sucks but v0.5 will improve it!!! + pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{ let tsfn : ThreadsafeFunction = fun.create_threadsafe_function(0, |ctx : ThreadSafeCallContext| { @@ -235,14 +222,21 @@ impl JsBufferController { )?; let _controller = self.0.clone(); tokio::spawn(async move { + tokio::time::sleep(std::time::Duration::from_millis(200)).await; loop { - let event = _controller.recv().await.expect("could not receive buffer event!"); - tsfn.call(event, ThreadsafeFunctionCallMode::NonBlocking); //check this shit with tracing also we could use Ok(event) to get the error + match _controller.recv().await { + Ok(event) => { + tsfn.call(event.clone(), ThreadsafeFunctionCallMode::NonBlocking); //check this shit with tracing also we could use Ok(event) to get the error + }, + Err(CodempError::Deadlocked) => continue, + Err(e) => break tracing::warn!("error receiving: {}", e), + } } }); Ok(()) } + #[napi] pub async fn recv(&self) -> napi::Result { Ok( @@ -253,9 +247,13 @@ impl JsBufferController { } #[napi] - pub fn send(&self, op: &JsCodempOperationSeq) -> napi::Result<()> { + pub fn send(&self, op: JsTextChange) -> napi::Result<()> { // TODO might be nice to take ownership of the opseq - self.0.send(op.0.clone()) + let new_text_change = CodempTextChange { + span: op.span.start as usize .. op.span.end as usize, + content: op.content, + }; + self.0.send(new_text_change) .map_err(|e| napi::Error::from(JsCodempError(e))) } }