mirror of
https://github.com/hexedtech/codemp-vscode.git
synced 2024-12-23 05:54:51 +01:00
fixed cursors and added logger
Co-authored-by: alemi.dev <me@alemi.dev>
This commit is contained in:
parent
5c94ad483e
commit
5df3234e0b
4 changed files with 158 additions and 91 deletions
12
package.json
12
package.json
|
@ -23,13 +23,21 @@
|
|||
"command": "codempvscode.connect",
|
||||
"title": "Connect to a codemp host"
|
||||
},
|
||||
{
|
||||
"command": "codempvscode.login",
|
||||
"title": "Log into a codemp account"
|
||||
},
|
||||
{
|
||||
"command": "codempvscode.join",
|
||||
"title": "Join a codemp workspace"
|
||||
},
|
||||
{
|
||||
"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",
|
||||
|
@ -37,7 +45,7 @@
|
|||
},
|
||||
{
|
||||
"command": "codempvscode.disconnectBuffer",
|
||||
"title": "disconnect from a codemp Buffer"
|
||||
"title": "disconnect from a codemp Buffer (unused)"
|
||||
},
|
||||
{
|
||||
"command": "codempvscode.sync",
|
||||
|
|
125
src/codemp.ts
125
src/codemp.ts
|
@ -1,36 +1,57 @@
|
|||
import * as vscode from 'vscode';
|
||||
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 BUFFERS : string[][] = [];
|
||||
var BUFFERS : BufferMapping[] = [];
|
||||
let smallNumberDecorationType = vscode.window.createTextEditorDecorationType({});
|
||||
let client : codemp.JsCodempClient | null = null;
|
||||
let workspace : codemp.JsWorkspace | null = null;
|
||||
|
||||
|
||||
export async function connect() {
|
||||
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:50052"
|
||||
await codemp.connect(host);
|
||||
vscode.window.showInformationMessage(`Connected to codemp @[${host}]`);
|
||||
/*let host = await vscode.window.showInputBox({prompt: "server host (default to http://codemp.alemi.dev:50053)"});
|
||||
if(host===null) host="http://codemp.alemi.dev:50053";
|
||||
client = await codemp.connect(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() {
|
||||
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 editor = vscode.window.activeTextEditor;
|
||||
if (workspace === undefined) return // user cancelled with ESC
|
||||
if (workspace.length == 0) workspace = "default"
|
||||
if (workspace_id === undefined) return // user cancelled with ESC
|
||||
if (workspace_id.length == 0) workspace_id = "asd"
|
||||
|
||||
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)
|
||||
controller.callback(( event:any) => {
|
||||
let buf : string = event.textEditor.document.uri.toString()
|
||||
let curPos = vscode.window.activeTextEditor?.selection.active;
|
||||
let PosNumber : number = curPos?.line as number;
|
||||
let posizione : vscode.Position = new vscode.Position(0, PosNumber);
|
||||
if(client===null) throw "connect first";
|
||||
workspace = await client.joinWorkspace(workspace_id)
|
||||
let controller = workspace.cursor();
|
||||
controller.callback((event: codemp.JsCursorEvent) => {
|
||||
console.log(`received cursor event, im on ${event.buffer}`)
|
||||
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
|
||||
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)
|
||||
}
|
||||
});
|
||||
for (let tuple of BUFFERS) {
|
||||
if (tuple[0].toString() === buf) {
|
||||
vscode.window.activeTextEditor?.setDecorations(smallNumberDecorationType, [decorationRange]);
|
||||
for (let mapping of BUFFERS) {
|
||||
console.log(`checking tuple ${mapping}`);
|
||||
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) => {
|
||||
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 anchor : [number, number] = [selection.anchor.line, selection.anchor.character];
|
||||
let position : [number, number] = [selection.active.line, selection.active.character+1];
|
||||
for (let tuple of BUFFERS) {
|
||||
if (tuple[0].toString() === buf) {
|
||||
controller.send(tuple[1], anchor, position);
|
||||
for (let mapping of BUFFERS) {
|
||||
if (mapping.vscode.document.uri === buf) {
|
||||
controller.send(mapping.codemp, anchor, position);
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log("workspace id \n");
|
||||
console.log(workspace.id());
|
||||
vscode.window.showInformationMessage(`Connected to workspace @[${workspace}]`);
|
||||
}
|
||||
|
||||
|
||||
export async function createBuffer() {
|
||||
let workspace="default";//ask which workspace
|
||||
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");
|
||||
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() {
|
||||
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("buffer", buffer);
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
|
@ -132,7 +137,7 @@ export async function attach() {
|
|||
vscode.window.showInformationMessage(`Connected to codemp workspace buffer @[${buffer_name}]`);
|
||||
|
||||
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) => {
|
||||
//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"}))!;
|
||||
codemp.disconnectBuffer(buffer);
|
||||
vscode.window.showInformationMessage(`Disconnected from codemp workspace buffer @[${buffer}]`);
|
||||
}
|
||||
}*/
|
||||
|
||||
export async function sync() {
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
if (editor === undefined) { return }
|
||||
for (let tuple of BUFFERS) {
|
||||
console.log(tuple[0].toString());
|
||||
for (let mapping of BUFFERS) {
|
||||
console.log(mapping.vscode.document.uri);
|
||||
//console.log(tuple[1]);
|
||||
console.log("\n");
|
||||
console.log(editor?.document.uri.toString());
|
||||
//console.log(BUFFERS[0]);
|
||||
if (tuple[0].toString() === editor?.document.uri.toString()) {
|
||||
|
||||
let buffer = await codemp.getBuffer(tuple[1]);
|
||||
if (mapping.vscode.document.uri === editor?.document.uri) {
|
||||
if(workspace===null) throw "join a workspace first"
|
||||
let buffer = await workspace.bufferByName(mapping.codemp);
|
||||
if (buffer==null) {
|
||||
vscode.window.showErrorMessage("This buffer does not exist anymore");
|
||||
return;
|
||||
|
@ -195,7 +200,7 @@ export async function sync() {
|
|||
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));
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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 codemp from '../index'; // TODO why won't it work with a custom name???
|
||||
import * as codemplogic from './codemp';
|
||||
|
||||
|
||||
// This method is called when your extension is activated
|
||||
// Your extension is activated the very first time the command is executed
|
||||
// extension is activated the very first time the command is executed
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// 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!');
|
||||
|
||||
// The command has been defined in the package.json file
|
||||
// Now provide the implementation of the command with registerCommand
|
||||
// The commandId parameter must match the command field in package.json
|
||||
let disposable = vscode.commands.registerCommand('codempvscode.helloWorld', () => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
// Display a message box to the user
|
||||
vscode.window.showInformationMessage(process.cwd());
|
||||
});
|
||||
let connectCommand = vscode.commands.registerCommand('codempvscode.connect', codemplogic.connect);
|
||||
let joinCommand = vscode.commands.registerCommand('codempvscode.join', codemplogic.join);
|
||||
let attachCommand = vscode.commands.registerCommand('codempvscode.attach', codemplogic.attach);
|
||||
let createBufferCommand = vscode.commands.registerCommand('codempvscode.createBuffer', codemplogic.createBuffer);
|
||||
let disconnectBufferCommand = vscode.commands.registerCommand('codempvscode.disconnectBuffer', codemplogic.disconnectBuffer);
|
||||
let syncBufferCommand = vscode.commands.registerCommand('codempvscode.sync', codemplogic.sync);
|
||||
context.subscriptions.push(connectCommand);
|
||||
context.subscriptions.push(joinCommand);
|
||||
context.subscriptions.push(attachCommand);
|
||||
context.subscriptions.push(createBufferCommand);
|
||||
context.subscriptions.push(disconnectBufferCommand);
|
||||
context.subscriptions.push(syncBufferCommand);
|
||||
context.subscriptions.push(disposable);
|
||||
// start codemp log poller
|
||||
let channel = vscode.window.createOutputChannel("codemp", {log: true});
|
||||
let logger = new codemp.JsLogger(false);
|
||||
log_poller_task(logger, channel); // don't await it! run it in background forever
|
||||
|
||||
// register commands: the commandId parameter must match the command field in package.json
|
||||
for (let cmd of [
|
||||
vscode.commands.registerCommand('codempvscode.connect', codemplogic.connect),
|
||||
vscode.commands.registerCommand('codempvscode.login', codemplogic.login),
|
||||
vscode.commands.registerCommand('codempvscode.join', codemplogic.join),
|
||||
vscode.commands.registerCommand('codempvscode.attach', codemplogic.attach),
|
||||
vscode.commands.registerCommand('codempvscode.createBuffer', codemplogic.createBuffer),
|
||||
vscode.commands.registerCommand('codempvscode.listBuffers', codemplogic.listBuffers),
|
||||
// vscode.commands.registerCommand('codempvscode.disconnectBuffer', codemplogic.disconnectBuffer),
|
||||
vscode.commands.registerCommand('codempvscode.sync', codemplogic.sync),
|
||||
]) {
|
||||
context.subscriptions.push(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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");
|
||||
}
|
|
@ -13,4 +13,56 @@ impl From::<JsCodempError> for napi::Error {
|
|||
fn from(value: JsCodempError) -> Self {
|
||||
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(()) }
|
||||
}
|
Loading…
Reference in a new issue