fixed cursors and added logger

Co-authored-by: alemi.dev <me@alemi.dev>
This commit is contained in:
frelodev 2024-02-12 19:22:50 +01:00
parent 5c94ad483e
commit 5df3234e0b
4 changed files with 158 additions and 91 deletions

View file

@ -23,13 +23,21 @@
"command": "codempvscode.connect", "command": "codempvscode.connect",
"title": "Connect to a codemp host" "title": "Connect to a codemp host"
}, },
{
"command": "codempvscode.login",
"title": "Log into a codemp account"
},
{ {
"command": "codempvscode.join", "command": "codempvscode.join",
"title": "Join a codemp workspace" "title": "Join a codemp workspace"
}, },
{ {
"command": "codempvscode.createBuffer", "command": "codempvscode.createBuffer",
"title": "create a codemp buffer" "title": "Create a codemp buffer"
},
{
"command": "codempvscode.listBuffers",
"title": "List all buffers of joined Workspace"
}, },
{ {
"command": "codempvscode.attach", "command": "codempvscode.attach",
@ -37,7 +45,7 @@
}, },
{ {
"command": "codempvscode.disconnectBuffer", "command": "codempvscode.disconnectBuffer",
"title": "disconnect from a codemp Buffer" "title": "disconnect from a codemp Buffer (unused)"
}, },
{ {
"command": "codempvscode.sync", "command": "codempvscode.sync",

View file

@ -1,36 +1,57 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as codemp from '../index'; // TODO why won't it work with a custom name??? import * as codemp from '../index'; // TODO why won't it work with a custom name???
class BufferMapping {
codemp: string;
vscode: vscode.TextEditor;
constructor(codemp_path: string, editor: vscode.TextEditor) {
this.codemp = codemp_path;
this.vscode = editor;
}
}
var CACHE = new codemp.OpCache(); var CACHE = new codemp.OpCache();
var BUFFERS : string[][] = []; var BUFFERS : BufferMapping[] = [];
let smallNumberDecorationType = vscode.window.createTextEditorDecorationType({}); let smallNumberDecorationType = vscode.window.createTextEditorDecorationType({});
let client : codemp.JsCodempClient | null = null;
let workspace : codemp.JsWorkspace | null = null;
export async function connect() { export async function connect() {
let host = await vscode.window.showInputBox({prompt: "server host (default to http://alemi.dev:50052)"}); /*let host = await vscode.window.showInputBox({prompt: "server host (default to http://codemp.alemi.dev:50053)"});
if (host === undefined) return // user cancelled with ESC if(host===null) host="http://codemp.alemi.dev:50053";
if (host.length == 0) host = "http://alemi.dev:50052" client = await codemp.connect(host);
await codemp.connect(host); vscode.window.showInformationMessage(`Connected to codemp @[${host}]`);*/
vscode.window.showInformationMessage(`Connected to codemp @[${host}]`); client = await codemp.connect();
vscode.window.showInformationMessage('Connected to codemp with default host');
}
export async function login(){
let username = await vscode.window.showInputBox({prompt: "enter username"});
let workspace_name = await vscode.window.showInputBox({prompt: "enter workspace name"});
if(client===null) throw "connect first";
if(workspace_name===null) workspace_name="asd";
await client.login(username!,"lmaodefaultpassword",workspace_name);
vscode.window.showInformationMessage("Logged with username " + username + " into workspace " + workspace_name);
} }
export async function join() { export async function join() {
let workspace = await vscode.window.showInputBox({prompt: "workspace to attach (default to default)"}); let workspace_id = 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 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 = vscode.window.activeTextEditor;
if (workspace === undefined) return // user cancelled with ESC if (workspace_id === undefined) return // user cancelled with ESC
if (workspace.length == 0) workspace = "default" if (workspace_id.length == 0) workspace_id = "asd"
if (buffer === undefined) return // user cancelled with ESC if (buffer === undefined) return // user cancelled with ESC
if (buffer.length == 0) {workspace = "default"; buffer="fucl"; } if (buffer.length == 0) {workspace_id = "asd"; buffer="fucl"; }
let controller : codemp.JsCursorController = await codemp.join(workspace) if(client===null) throw "connect first";
controller.callback(( event:any) => { workspace = await client.joinWorkspace(workspace_id)
let buf : string = event.textEditor.document.uri.toString() let controller = workspace.cursor();
let curPos = vscode.window.activeTextEditor?.selection.active; controller.callback((event: codemp.JsCursorEvent) => {
let PosNumber : number = curPos?.line as number; console.log(`received cursor event, im on ${event.buffer}`)
let posizione : vscode.Position = new vscode.Position(0, PosNumber);
let range_start : vscode.Position = new vscode.Position(event.start.row , event.start.col); // -1? let range_start : vscode.Position = new vscode.Position(event.start.row , event.start.col); // -1?
let range_end : vscode.Position = 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 let range_end : vscode.Position = 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
const decorationRange = new vscode.Range(range_start, range_end); const decorationRange = new vscode.Range(range_start, range_end);
@ -49,57 +70,40 @@ export async function join() {
borderColor: 'lightblue' //should create this color based on event.user (uuid) borderColor: 'lightblue' //should create this color based on event.user (uuid)
} }
}); });
for (let tuple of BUFFERS) { for (let mapping of BUFFERS) {
if (tuple[0].toString() === buf) { console.log(`checking tuple ${mapping}`);
vscode.window.activeTextEditor?.setDecorations(smallNumberDecorationType, [decorationRange]); if (mapping.codemp === event.buffer) {
mapping.vscode.setDecorations(smallNumberDecorationType, [decorationRange]);
return
} }
} }
console.log(`wtf buffers didn't contain it???? ${BUFFERS}`)
}); });
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 if (event.kind == vscode.TextEditorSelectionChangeKind.Command) return; // TODO commands might move cursor too
let buf : string = event.textEditor.document.uri.toString() let buf = event.textEditor.document.uri;
let selection : vscode.Selection = event.selections[0] // TODO there may be more than one cursor!! let selection : vscode.Selection = event.selections[0] // TODO there may be more than one cursor!!
let anchor : [number, number] = [selection.anchor.line, selection.anchor.character]; let anchor : [number, number] = [selection.anchor.line, selection.anchor.character];
let position : [number, number] = [selection.active.line, selection.active.character+1]; let position : [number, number] = [selection.active.line, selection.active.character+1];
for (let tuple of BUFFERS) { for (let mapping of BUFFERS) {
if (tuple[0].toString() === buf) { if (mapping.vscode.document.uri === buf) {
controller.send(tuple[1], anchor, position); controller.send(mapping.codemp, anchor, position);
} }
} }
}); });
console.log("workspace id \n");
console.log(workspace.id());
vscode.window.showInformationMessage(`Connected to workspace @[${workspace}]`); vscode.window.showInformationMessage(`Connected to workspace @[${workspace}]`);
} }
export async function createBuffer() { export async function createBuffer() {
let workspace="default";//ask which workspace
let bufferName : any = (await vscode.window.showInputBox({prompt: "path of the buffer to create"}))!; let bufferName : any = (await vscode.window.showInputBox({prompt: "path of the buffer to create"}))!;
codemp.create(bufferName); if(workspace===null) throw "join a workspace first"
workspace.create(bufferName);
console.log("new buffer created ", bufferName, "\n"); console.log("new buffer created ", bufferName, "\n");
let editor = vscode.window.activeTextEditor;
if (editor === undefined) { return } // TODO say something!!!!!!
/*let range = new vscode.Range(
editor.document.positionAt(0),
editor.document.positionAt(editor.document.getText().length)
)*/
let buffer : codemp.JsBufferController = await codemp.attach(bufferName);
console.log("buffer");
console.log(buffer);
//let opSeq = {range.start,editor.document.getText(),range.end}
//buffer.send(range.start,editor.document.getText(),range.end); //test it plz coded this at 10am :(
buffer.send({
span: {
start: 0,
end: 0 //previous length is 0
},
content: editor.document.getText()
});
console.log("sent all the content", editor.document.getText());
//Should i disconnect or stay attached to buffer???
} }
@ -108,7 +112,8 @@ export async function createBuffer() {
export async function attach() { export async function attach() {
let buffer_name : any = (await vscode.window.showInputBox({prompt: "buffer to attach to"}))!; let buffer_name : any = (await vscode.window.showInputBox({prompt: "buffer to attach to"}))!;
let buffer : codemp.JsBufferController = await codemp.attach(buffer_name); if(workspace===null) throw "join a workspace first"
let buffer : codemp.JsBufferController = await workspace.attach(buffer_name);
console.log("attached to buffer", buffer_name); console.log("attached to buffer", buffer_name);
console.log("buffer", buffer); console.log("buffer", buffer);
let editor = vscode.window.activeTextEditor; let editor = vscode.window.activeTextEditor;
@ -132,7 +137,7 @@ export async function attach() {
vscode.window.showInformationMessage(`Connected to codemp workspace buffer @[${buffer_name}]`); vscode.window.showInformationMessage(`Connected to codemp workspace buffer @[${buffer_name}]`);
let file_uri : vscode.Uri = editor.document.uri; let file_uri : vscode.Uri = editor.document.uri;
BUFFERS.push([file_uri, buffer_name]); BUFFERS.push(new BufferMapping(buffer_name, editor));
vscode.workspace.onDidChangeTextDocument((event:vscode.TextDocumentChangeEvent) => { vscode.workspace.onDidChangeTextDocument((event:vscode.TextDocumentChangeEvent) => {
//console.log(event.reason); //console.log(event.reason);
@ -167,24 +172,24 @@ export async function attach() {
}); });
} }
export async function disconnectBuffer() { /*export async function disconnectBuffer() { TODO i should just set buffer=null
let buffer : string = (await vscode.window.showInputBox({prompt: "buffer name for the file to disconnect from"}))!; let buffer : string = (await vscode.window.showInputBox({prompt: "buffer name for the file to disconnect from"}))!;
codemp.disconnectBuffer(buffer); codemp.disconnectBuffer(buffer);
vscode.window.showInformationMessage(`Disconnected from codemp workspace buffer @[${buffer}]`); vscode.window.showInformationMessage(`Disconnected from codemp workspace buffer @[${buffer}]`);
} }*/
export async function sync() { export async function sync() {
let editor = vscode.window.activeTextEditor; let editor = vscode.window.activeTextEditor;
if (editor === undefined) { return } if (editor === undefined) { return }
for (let tuple of BUFFERS) { for (let mapping of BUFFERS) {
console.log(tuple[0].toString()); console.log(mapping.vscode.document.uri);
//console.log(tuple[1]); //console.log(tuple[1]);
console.log("\n"); console.log("\n");
console.log(editor?.document.uri.toString()); console.log(editor?.document.uri.toString());
//console.log(BUFFERS[0]); //console.log(BUFFERS[0]);
if (tuple[0].toString() === editor?.document.uri.toString()) { if (mapping.vscode.document.uri === editor?.document.uri) {
if(workspace===null) throw "join a workspace first"
let buffer = await codemp.getBuffer(tuple[1]); let buffer = await workspace.bufferByName(mapping.codemp);
if (buffer==null) { if (buffer==null) {
vscode.window.showErrorMessage("This buffer does not exist anymore"); vscode.window.showErrorMessage("This buffer does not exist anymore");
return; return;
@ -195,7 +200,7 @@ export async function sync() {
editor.document.positionAt(editor.document.getText().length) editor.document.positionAt(editor.document.getText().length)
); );
CACHE.put(tuple[1],0,content,editor.document.getText().length); CACHE.put(mapping.codemp, 0, content, editor.document.getText().length);
editor.edit(editBuilder => editBuilder.replace(range, content)); editor.edit(editBuilder => editBuilder.replace(range, content));
return; return;
} }
@ -205,7 +210,11 @@ export async function sync() {
} }
} }
export async function listBuffers(){
if(workspace===null) throw "join a workspace first"
let buffers = workspace.filetree();
console.log(buffers); // improve UX
}

View file

@ -1,41 +1,39 @@
// 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 vscode from 'vscode';
import * as codemp from '../index'; // TODO why won't it work with a custom name??? import * as codemp from '../index'; // TODO why won't it work with a custom name???
import * as codemplogic from './codemp'; import * as codemplogic from './codemp';
// extension is activated the very first time the command is executed
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) { export function activate(context: vscode.ExtensionContext) {
// Use the console to output diagnostic information (console.log) and errors (console.error) // Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "codempvscode" is now active!'); console.log('Congratulations, your extension "codempvscode" is now active!');
// The command has been defined in the package.json file // start codemp log poller
// Now provide the implementation of the command with registerCommand let channel = vscode.window.createOutputChannel("codemp", {log: true});
// The commandId parameter must match the command field in package.json let logger = new codemp.JsLogger(false);
let disposable = vscode.commands.registerCommand('codempvscode.helloWorld', () => { log_poller_task(logger, channel); // don't await it! run it in background forever
// The code you place here will be executed every time your command is executed
// Display a message box to the user // register commands: the commandId parameter must match the command field in package.json
vscode.window.showInformationMessage(process.cwd()); for (let cmd of [
}); vscode.commands.registerCommand('codempvscode.connect', codemplogic.connect),
let connectCommand = vscode.commands.registerCommand('codempvscode.connect', codemplogic.connect); vscode.commands.registerCommand('codempvscode.login', codemplogic.login),
let joinCommand = vscode.commands.registerCommand('codempvscode.join', codemplogic.join); vscode.commands.registerCommand('codempvscode.join', codemplogic.join),
let attachCommand = vscode.commands.registerCommand('codempvscode.attach', codemplogic.attach); vscode.commands.registerCommand('codempvscode.attach', codemplogic.attach),
let createBufferCommand = vscode.commands.registerCommand('codempvscode.createBuffer', codemplogic.createBuffer); vscode.commands.registerCommand('codempvscode.createBuffer', codemplogic.createBuffer),
let disconnectBufferCommand = vscode.commands.registerCommand('codempvscode.disconnectBuffer', codemplogic.disconnectBuffer); vscode.commands.registerCommand('codempvscode.listBuffers', codemplogic.listBuffers),
let syncBufferCommand = vscode.commands.registerCommand('codempvscode.sync', codemplogic.sync); // vscode.commands.registerCommand('codempvscode.disconnectBuffer', codemplogic.disconnectBuffer),
context.subscriptions.push(connectCommand); vscode.commands.registerCommand('codempvscode.sync', codemplogic.sync),
context.subscriptions.push(joinCommand); ]) {
context.subscriptions.push(attachCommand); context.subscriptions.push(cmd);
context.subscriptions.push(createBufferCommand); }
context.subscriptions.push(disconnectBufferCommand);
context.subscriptions.push(syncBufferCommand);
context.subscriptions.push(disposable);
} }
async function log_poller_task(logger: codemp.JsLogger, channel: vscode.LogOutputChannel) {
console.log("starting logger task");
while (true) {
let message = await logger.message();
if (message === null) break;
console.log(message);
channel.info(message);
}
console.log("stopping logger task");
}

View file

@ -13,4 +13,56 @@ impl From::<JsCodempError> for napi::Error {
fn from(value: JsCodempError) -> Self { fn from(value: JsCodempError) -> Self {
napi::Error::new(napi::Status::GenericFailure, &format!("CodempError: {:?}", value)) napi::Error::new(napi::Status::GenericFailure, &format!("CodempError: {:?}", value))
} }
}
use napi_derive::napi;
#[napi]
pub struct JsLogger(std::sync::Arc<tokio::sync::Mutex<tokio::sync::mpsc::Receiver<String>>>);
#[napi]
impl JsLogger {
#[napi(constructor)]
pub fn new(debug: Option<bool>) -> JsLogger {
let (tx, rx) = tokio::sync::mpsc::channel(256);
let level = if debug.unwrap_or(false) { tracing::Level::DEBUG } else {tracing::Level::INFO }; //TODO: study this tracing subscriber and customize it
let format = tracing_subscriber::fmt::format()
.with_level(true)
.with_target(true)
.with_thread_ids(false)
.with_thread_names(false)
.with_ansi(false)
.with_file(false)
.with_line_number(false)
.with_source_location(false)
.compact();
tracing_subscriber::fmt()
.event_format(format)
.with_max_level(level)
.with_writer(std::sync::Mutex::new(JsLoggerProducer(tx)))
.init();
JsLogger(std::sync::Arc::new(tokio::sync::Mutex::new(rx)))
}
#[napi]
pub async fn message(&self) -> Option<String> {
self.0
.lock()
.await
.recv()
.await
}
}
#[derive(Debug, Clone)]
struct JsLoggerProducer(tokio::sync::mpsc::Sender<String>);
impl std::io::Write for JsLoggerProducer {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
// TODO this is a LOSSY logger!!
let _ = self.0.try_send(String::from_utf8_lossy(buf).to_string()); // ignore: logger disconnected or with full buffer
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
} }