From 4d3d63b09a7265157a8f8fa653603263904d7524 Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 22 Nov 2023 14:26:54 +0100 Subject: [PATCH] feat(autosave): save the editor content to local browser storage and use a debounce to keep it fast --- WebSocketClient/index.html | 1 - WebSocketClient/package-lock.json | 6 ++++ WebSocketClient/package.json | 1 + WebSocketClient/src/main.ts | 41 ++++++++++++++++++---------- WebSocketLanguageServer/src/index.ts | 19 +++++++------ 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/WebSocketClient/index.html b/WebSocketClient/index.html index aff935d..83825bc 100644 --- a/WebSocketClient/index.html +++ b/WebSocketClient/index.html @@ -30,7 +30,6 @@

UVL Playground

-
diff --git a/WebSocketClient/package-lock.json b/WebSocketClient/package-lock.json index a633e77..41ef745 100644 --- a/WebSocketClient/package-lock.json +++ b/WebSocketClient/package-lock.json @@ -19,6 +19,7 @@ "@codingame/monaco-vscode-theme-service-override": "~1.83.2", "@viz-js/viz": "^3.2.3", "dotenv": "^16.3.1", + "lodash": "^4.17.21", "monaco-editor": "^0.44.0", "monaco-editor-workers": "~0.44.0", "monaco-languageclient": "^6.6.0", @@ -598,6 +599,11 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", diff --git a/WebSocketClient/package.json b/WebSocketClient/package.json index 262beda..9115e1c 100644 --- a/WebSocketClient/package.json +++ b/WebSocketClient/package.json @@ -28,6 +28,7 @@ "@codingame/monaco-vscode-theme-service-override": "~1.83.2", "@viz-js/viz": "^3.2.3", "dotenv": "^16.3.1", + "lodash": "^4.17.21", "monaco-editor": "^0.44.0", "monaco-editor-workers": "~0.44.0", "monaco-languageclient": "^6.6.0", diff --git a/WebSocketClient/src/main.ts b/WebSocketClient/src/main.ts index fa89434..3a7e4ac 100644 --- a/WebSocketClient/src/main.ts +++ b/WebSocketClient/src/main.ts @@ -22,6 +22,7 @@ import config from './config.js'; import { instance } from "@viz-js/viz"; import { Message } from 'vscode-jsonrpc'; import { v4 as uuidv4 } from 'uuid'; +import lodash from 'lodash'; import { buildWorkerDefinition } from 'monaco-editor-workers'; buildWorkerDefinition('./node_modules/monaco-editor-workers/dist/workers', new URL('', window.location.href).href, false); @@ -29,6 +30,7 @@ buildWorkerDefinition('./node_modules/monaco-editor-workers/dist/workers', new U const languageId = 'uvls'; let languageClient: MonacoLanguageClient; let fileID; +let model; const createUrl = (hostname: string, port: number, path: string, searchParams: Record = {}, secure: boolean): string => { const protocol = secure ? 'wss' : 'ws'; @@ -138,11 +140,6 @@ function createDiagramFromDot(res: string): void { }); } -function generateDiagram(): void { - vscode.commands.executeCommand("uvls/generate_diagram", `file:///workspace/${fileID}.uvl`) - .then((res) => createDiagramFromDot(res as string)); -} - export const startPythonClient = async () => { // init vscode-api const useDebugLogging = config.debug ? LogLevel.Debug : LogLevel.Off; @@ -182,14 +179,6 @@ export const startPythonClient = async () => { }; registerExtension(extension, ExtensionHostKind.LocalProcess); - const button = document.getElementById("rerender"); - if(button){ - button.onclick = () => generateDiagram(); - } - else{ - console.log("I cannot find the button") - } - updateUserConfiguration(`{ "editor.fontSize": 14, "workbench.colorTheme": "Default Dark Modern", @@ -198,7 +187,7 @@ export const startPythonClient = async () => { const fileSystemProvider = new RegisteredFileSystemProvider(false); fileID = uuidv4(); - fileSystemProvider.registerFile(new RegisteredMemoryFile(vscode.Uri.file(`/workspace/${fileID}.uvl`), 'features\n\tfeature1\n\t\tor\n\t\t\tfeature2\n\t\t\tfeature3\n\nconstraints\n\tfeature1')); + fileSystemProvider.registerFile(new RegisteredMemoryFile(vscode.Uri.file(`/workspace/${fileID}.uvl`), getInitialFm())); registerFileSystemOverlay(1, fileSystemProvider); // create the web socket and configure to start the language client on open, can add extra parameters to the url if needed. @@ -212,6 +201,14 @@ export const startPythonClient = async () => { // use the file create before const modelRef = await createModelReference(monaco.Uri.file(`/workspace/${fileID}.uvl`)); + model = modelRef.object; + + const debouncedSave = lodash.debounce(saveFm, 1000); + modelRef.object.onDidChangeContent(() => { + debouncedSave(); + }); + + modelRef.object.setLanguageId(languageId); // create monaco editor @@ -220,3 +217,19 @@ export const startPythonClient = async () => { automaticLayout: true }); }; + +function getInitialFm(){ + let initialFm = "features\n\tfeature1\n\t\tor\n\t\t\tfeature2\n\t\t\tfeature3\n\nconstraints\n\tfeature1"; + const storedFm = window.localStorage.getItem("fm"); + if(storedFm !== null){ + initialFm = storedFm; + } + return initialFm; +} + +function saveFm(){ + if(model !== undefined){ + const content = model.textEditorModel?.getValue(); + window.localStorage.setItem("fm", content); + } +} \ No newline at end of file diff --git a/WebSocketLanguageServer/src/index.ts b/WebSocketLanguageServer/src/index.ts index d74dd0f..0f9bbf3 100644 --- a/WebSocketLanguageServer/src/index.ts +++ b/WebSocketLanguageServer/src/index.ts @@ -91,7 +91,10 @@ const initUVLS = () => { if (typedMessage.method === "client/registerCapability") { initMessage2 = newMessage; } else if (typedMessage.method === "workspace/executeCommand") { - console.log(typedMessage); + const fileUri = typedMessage.params?.["arguments"][0]?.["uri"].split("create/").pop(); + if(fileUri !== undefined){ + socketConnection = uriToConnectionMap.get(fileUri); + } } } else if (Message.isResponse(message)) { @@ -111,12 +114,12 @@ const initUVLS = () => { } else if (Message.isNotification(message)) { const typedMessage = message as NotificationMessage; const uri: string | undefined = typedMessage.params?.["uri"]; - if (uri !== undefined) { - socketConnection = uriToConnectionMap.get(uri); + if (uri !== undefined && uri.split("///").length === 2) { + socketConnection = uriToConnectionMap.get(uri.split("///")[1]); + } } if (socketConnection) { - console.log(newMessage); socketConnection.writer.write(newMessage); } else { console.log(`Could not resolve destination of server message to right client\nMessage: ${JSON.stringify(message)}`) @@ -139,7 +142,6 @@ function multiplexHandler(socket: IWebSocket) { socketConnection.writer.write(initMessage1); return; } else if (typedMessage.method === "workspace/executeCommand") { - console.log(typedMessage); const serverScopeId = getServerScopeIdFromClientScopeId(Number(typedMessage.id), clientId); newMessage["id"] = serverScopeId; } else { @@ -160,18 +162,17 @@ function multiplexHandler(socket: IWebSocket) { return; } else if (typedMessage.method === "textDocument/didOpen") { const uri: string | undefined = typedMessage.params?.["textDocument"]?.["uri"]; - if (uri !== undefined) { - uriToConnectionMap.set(uri, socketConnection); + if (uri !== undefined && uri.split("///").length === 2) { + uriToConnectionMap.set(uri.split("///")[1], socketConnection); } } else if (typedMessage.method === "$/cancelRequest") { - console.log(JSON.stringify(newMessage)); newMessage["params"]["id"] = getServerScopeIdFromClientScopeId(newMessage["params"]["id"], clientId); } else if (typedMessage.method === "initialized" && initMessage2 !== undefined) { socketConnection.writer.write(initMessage2); return; } else { - console.log(JSON.stringify(newMessage)); + // other messages are just forwarded to the uvls } }