From 9e2d372e5e25444f80d3e3a84e1cedf1d966eccb Mon Sep 17 00:00:00 2001 From: frelodev Date: Sun, 1 Oct 2023 10:47:53 +0200 Subject: [PATCH] New features: receiving and sending cursor events --- Cargo.toml | 1 + src/extension.ts | 92 +++++++++++++++++++++++++++++++++++------------- src/rust/lib.rs | 48 ++++++++++++++++++------- tsconfig.json | 1 - 4 files changed, 104 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2dfa517..3a995c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ 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", features = ["global"] } tracing = "0.1" tracing-subscriber = "0.3.17" uuid = { version = "1.3.1", features = ["v4"] } diff --git a/src/extension.ts b/src/extension.ts index 4f53d6a..2366215 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,9 +1,13 @@ // 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 * as codempp from '/home/***REMOVED***/projects/codemp/mine/codempvscode/codemp.node'; -const codemp = require("/home/***REMOVED***/projects/codemp/mine/codempvscode/index.node"); -// import * as codemp from "/home/***REMOVED***/projects/codemp/mine/vscode/target/debug/libcodemp_vscode.node"; +//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 = ""; +//import * as codemp from "/home/***REMOVED***/projects/codemp/mine/vscode/target/debug/libcodemp_vscode.node"; // This method is called when your extension is activated // Your extension is activated the very first time the command is executed @@ -35,54 +39,92 @@ async function connect() { if (host === undefined) return // user cancelled with ESC if (host.length == 0) host = "http://alemi.dev:50051" await codemp.connect(host); - vscode.window.showInformationMessage(`Connected to codemp ***REMOVED*** @[${host}]`); + vscode.window.showInformationMessage(`Connected to codemp @[${host}]`); } async function join() { - let workspace = await vscode.window.showInputBox({prompt: "workspace to attach (default to default)"}) - let buffer = await vscode.window.showInputBox({prompt: "buffer name for the file needed to update other clients cursors"}) + let workspace = await vscode.window.showInputBox({prompt: "workspace to attach (default to default)"}); + let buffer : string = (await vscode.window.showInputBox({prompt: "buffer name for the file needed to update other clients cursors"}))!; + let editor = vscode.window.activeTextEditor; + //let editor = activeEditor.document.getText(); + //let doc = editor?.document; if (workspace === undefined) return // user cancelled with ESC if (workspace.length == 0) workspace = "default" if (buffer === undefined) return // user cancelled with ESC - if (buffer.length == 0) workspace = "test" - - - + if (buffer.length == 0) {workspace = "test"; buffer="test"; } + let controller = await codemp.join(workspace) - controller.callback((event:any) => { - console.log(event); + try{ + controller.callback(( event:any) => { + try{ + //console.log(event); + let curPos = vscode.window.activeTextEditor?.selection.active; + let PosNumber = curPos?.line as number; + let posizione = new vscode.Position(0, PosNumber); + //console.log("posizione", posizione, "\n"); + let range_start = new vscode.Position(event.start.row , event.start.col); // -1? + let range_end = new vscode.Position(event.end.row, event.end.col); // -1? idk if this works it's kinda funny, should test with someone with a working version of codemp + /*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({ + borderWidth: '5px', + borderStyle: 'solid', + overviewRulerColor: 'blue', + overviewRulerLane: vscode.OverviewRulerLane.Right, + light: { + // this color will be used in light color themes + borderColor: 'darkblue' + }, + dark: { + // this color will be used in dark color themes + borderColor: 'lightblue' + } + }); + //let DECORATION = vscode.window.createTextEditorDecorationType({backgroundColor: 'red', color: 'white'}); + /*console.log("Editor" ,editor, "\n"); + console.log("Decoration range " , [decorationRange], "\n");*/ + editor?.setDecorations(smallNumberDecorationType, [decorationRange]); + }catch(e){ + console.log("Error", e, "\n"); + } }); +}catch(e){ + console.log("Error", e, "\n"); +} vscode.window.onDidChangeTextEditorSelection((event: vscode.TextEditorSelectionChangeEvent)=>{ - if(event.kind==1 || event.kind ==2){ + 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!! //let anchor = [selection.anchor.line+1, selection.anchor.character] //let position = [selection.active.line+1, selection.active.character+1] - let anchor = [selection.anchor.line, selection.anchor.character] - let position = [selection.active.line, selection.active.character+1] - console.log("Buffer from selection" + buffer+"\n"); + let anchor : [number, number] = [selection.anchor.line, selection.anchor.character]; + let position : [number, number] = [selection.active.line, selection.active.character+1]; + /*console.log("Buffer from selection" + buffer+"\n"); console.log("selection " + selection+"\n"); console.log("Anchor selection" + anchor+"\n"); - console.log("position selection" + position+"\n"); + console.log("position selection" + position+"\n");*/ controller.send(buffer, anchor, position); - } }); vscode.window.showInformationMessage(`Connected to workspace @[${workspace}]`); } -/*async function attach() { - let workspace = await vscode.window.showInputBox({prompt: "workspace to attach (default to default)"}) - if (workspace === undefined) return // user cancelled with ESC - if (workspace.length == 0) workspace = "default" - await codemp.attach(workspace); - vscode.window.showInformationMessage(`Connected to codemp ***REMOVED*** @[${workspace}]`); -}*/ + + + + + + + + + + // This method is called when your extension is deactivated diff --git a/src/rust/lib.rs b/src/rust/lib.rs index befe705..2c7bca6 100644 --- a/src/rust/lib.rs +++ b/src/rust/lib.rs @@ -1,16 +1,13 @@ #![deny(clippy::all)] - use std::sync::Arc; -use futures::prelude::*; use codemp::{ prelude::*, proto::{RowCol, CursorEvent}, buffer::factory::OperationFactory, ot::OperationSeq }; use napi_derive::napi; -use napi::{CallContext, Status, threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode, ErrorStrategy::{CalleeHandled, Fatal}, ThreadsafeFunction}}; -use napi::tokio::{self, fs}; - +use napi::{Status, threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode, ErrorStrategy::Fatal, ThreadsafeFunction}, JsBoolean}; +use napi::tokio; #[derive(Debug)] struct JsCodempError(CodempError); @@ -18,18 +15,16 @@ struct JsCodempError(CodempError); - - - impl From:: for napi::Error { fn from(value: JsCodempError) -> Self { napi::Error::new(Status::GenericFailure, &format!("CodempError: {:?}", value)) } } + #[napi] pub async fn connect(addr: String) -> napi::Result<()> { - let f = std::fs::File::create("/home/***REMOVED***/projects/codemp/mine/vscode/***REMOVED***.txt").unwrap(); + let f = std::fs::File::create("/home/***REMOVED***/projects/codemp/mine/codempvscode/***REMOVED***.txt").unwrap(); tracing_subscriber::fmt() .with_ansi(false) .with_max_level(tracing::Level::INFO) @@ -157,11 +152,11 @@ impl From:: for JsRowCol { /// BUFFER #[napi(object)] pub struct JsTextChange { - pub span: JSRange, + pub span: JsRange, pub content: String, } #[napi(object)] -pub struct JSRange{ +pub struct JsRange{ pub start: i32, pub end: Option, } @@ -170,7 +165,7 @@ 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: Some(value.span.end as i32) }, content: value.content, } } @@ -197,16 +192,44 @@ pub struct JsBufferController(Arc); 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!!! + let tsfn : ThreadsafeFunction = + fun.create_threadsafe_function(0, + |ctx : ThreadSafeCallContext| { + Ok(vec![JsTextChange::from(ctx.value)]) + } + )?; + let _controller = self.0.clone(); + tokio::spawn(async move { + 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 + } + }); + Ok(()) + } + #[napi] pub async fn recv(&self) -> napi::Result { Ok( @@ -238,3 +261,4 @@ pub async fn attach(path: String) -> napi::Result { .into() ) } + diff --git a/tsconfig.json b/tsconfig.json index 5b7343d..c6d14f6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,5 +14,4 @@ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ }, - "exclude": ["index.d.ts"] }