fixed issues

This commit is contained in:
2026-02-08 18:32:51 +01:00
parent 2622651dc3
commit c9ad06a441
3 changed files with 90 additions and 32 deletions
+14
View File
@@ -9,9 +9,11 @@
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"@types/diff-match-patch": "^1.0.36",
"@types/express": "^5.0.6", "@types/express": "^5.0.6",
"axios": "^1.13.5", "axios": "^1.13.5",
"cors": "^2.8.6", "cors": "^2.8.6",
"diff-match-patch": "^1.0.5",
"express": "^5.2.1" "express": "^5.2.1"
}, },
"devDependencies": { "devDependencies": {
@@ -302,6 +304,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/diff-match-patch": {
"version": "1.0.36",
"resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz",
"integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==",
"license": "MIT"
},
"node_modules/@types/express": { "node_modules/@types/express": {
"version": "5.0.6", "version": "5.0.6",
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz",
@@ -1244,6 +1252,12 @@
"node": ">=0.3.1" "node": ">=0.3.1"
} }
}, },
"node_modules/diff-match-patch": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
"integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==",
"license": "Apache-2.0"
},
"node_modules/dir-glob": { "node_modules/dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+2
View File
@@ -84,9 +84,11 @@
}, },
"dependencies": { "dependencies": {
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"@types/diff-match-patch": "^1.0.36",
"@types/express": "^5.0.6", "@types/express": "^5.0.6",
"axios": "^1.13.5", "axios": "^1.13.5",
"cors": "^2.8.6", "cors": "^2.8.6",
"diff-match-patch": "^1.0.5",
"express": "^5.2.1" "express": "^5.2.1"
} }
} }
+81 -39
View File
@@ -1,70 +1,112 @@
import * as vscode from "vscode"; import * as vscode from "vscode";
import { diff_match_patch, Diff } from "diff-match-patch";
import { LiveRunMove } from "./types"; import { LiveRunMove } from "./types";
import { addRunMoves } from "./client"; import { addRunMoves } from "./client";
export function startMonitoring(runId: string) { export function startMonitoring(runId: string) {
const dmp = new diff_match_patch();
let moveId = 0; let moveId = 0;
let moves: LiveRunMove[] = []; let moves: LiveRunMove[] = [];
let lastLatency = Date.now();
let lastText = "";
let lastEventTime = Date.now();
let idleTimeout: NodeJS.Timeout | undefined; let idleTimeout: NodeJS.Timeout | undefined;
let isSending = false; let isSending = false;
const SEND_IDLE_MS = 350; const IDLE_MS = 350;
const flushMoves = async () => { const editor = vscode.window.activeTextEditor;
if (editor) {
lastText = editor.document.getText();
}
async function flush() {
if (!moves.length || isSending) return; if (!moves.length || isSending) return;
isSending = true; isSending = true;
const toSend = moves; const batch = moves;
moves = []; moves = [];
try { try {
await addRunMoves(runId, toSend); await addRunMoves(runId, batch);
} finally { } finally {
isSending = false; isSending = false;
} }
};
const docSub = vscode.workspace.onDidChangeTextDocument((e) => {
const editor = vscode.window.activeTextEditor;
if (!editor || e.document !== editor.document) return;
const edit = e.contentChanges[0];
if (!edit) return;
const now = Date.now();
const latency = capToZeroAbove(now - lastLatency, SEND_IDLE_MS);
lastLatency = now;
const cursorOffset = editor.document.offsetAt(editor.selection.active);
moves.push({
latency,
cursor: cursorOffset,
changes: {
from: edit.rangeOffset,
to: edit.rangeOffset + edit.rangeLength,
insert: edit.text,
},
moveId: moveId++,
});
if (idleTimeout) {
clearTimeout(idleTimeout);
} }
idleTimeout = setTimeout(() => { const readInterval = setInterval(() => {
flushMoves(); const editor = vscode.window.activeTextEditor;
}, SEND_IDLE_MS); if (!editor) return;
const newText = editor.document.getText();
if (newText === lastText) return;
const now = Date.now();
const latency = capLatency(now - lastEventTime, IDLE_MS);
lastEventTime = now;
const diffs = dmp.diff_main(lastText, newText);
dmp.diff_cleanupEfficiency(diffs);
const changes = diffsToChanges(diffs);
lastText = newText;
for (const change of changes) {
moves.push({
moveId: moveId++,
latency,
cursor: editor.document.offsetAt(editor.selection.active),
changes: change,
}); });
}
if (idleTimeout) clearTimeout(idleTimeout);
idleTimeout = setTimeout(flush, IDLE_MS);
}, 500);
return () => { return () => {
docSub.dispose(); clearInterval(readInterval);
if (idleTimeout) clearTimeout(idleTimeout); if (idleTimeout) clearTimeout(idleTimeout);
flushMoves(); flush();
}; };
} }
function capToZeroAbove(value: number, max: number) { function diffsToChanges(diffs: Diff[]) {
const changes: {
from: number;
to: number;
insert: string;
}[] = [];
let offset = 0;
for (const [op, text] of diffs) {
if (op === 0) {
// equal
offset += text.length;
} else if (op === -1) {
// delete
changes.push({
from: offset,
to: offset + text.length,
insert: "",
});
} else if (op === 1) {
// insert
changes.push({
from: offset,
to: offset,
insert: text,
});
offset += text.length;
}
}
return changes;
}
function capLatency(value: number, max: number) {
return value > max ? 0 : value; return value > max ? 0 : value;
} }