Skip to content

Commit

Permalink
make server/client async
Browse files Browse the repository at this point in the history
  • Loading branch information
guyutongxue committed Jan 29, 2024
1 parent 9096da6 commit 9de0f6c
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 60 deletions.
47 changes: 22 additions & 25 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,27 @@
import "./editor";
import { CloseAction, ErrorAction } from "vscode-languageclient";
import {
BrowserMessageReader,
BrowserMessageWriter,
} from "vscode-languageclient/browser";
import { MonacoLanguageClient } from "monaco-languageclient";

import ClangdWorker from "./main.worker?worker";
import { LANGUAGE_ID } from "./config";
import { createServer } from "./server";

let lspRunning = false;
let clientRunning = false;
let retry = 0;
let succeeded = false;

export async function createLsp() {
if (lspRunning) {
console.warn("LSP already running");
export async function createClient(serverWorker: Worker) {
if (clientRunning) {
console.warn("Client already running");
}
lspRunning = true;
let clangdResolve = () => {};
const clangdReady = new Promise<void>((r) => (clangdResolve = r));
const worker = new ClangdWorker();
const readyListener = (e: MessageEvent) => {
if (e.data === "ready") {
clangdResolve();
worker.removeEventListener("message", readyListener);
}
};
worker.addEventListener("message", readyListener);
worker.addEventListener("error", restart);

await clangdReady;
clientRunning = true;

const reader = new BrowserMessageReader(worker);
const writer = new BrowserMessageWriter(worker);
serverWorker.addEventListener("error", restart);
const reader = new BrowserMessageReader(serverWorker);
const writer = new BrowserMessageWriter(serverWorker);
const readerOnError = reader.onError(() => restart);
const readerOnClose = reader.onClose(() => restart);
const successCallback = reader.listen(() => {
Expand All @@ -55,26 +44,34 @@ export async function createLsp() {
});

async function restart() {
if (lspRunning) {
if (clientRunning) {
try {
lspRunning = false;
clientRunning = false;
await client.stop();
await client.dispose();
readerOnError.dispose();
readerOnClose.dispose();
writer.end();
writer.dispose();
reader.dispose();
worker.terminate();
serverWorker.terminate();
} finally {
retry++;
if (retry > 5 && !succeeded) {
console.error("Failed to start clangd after 5 retries");
return;
}
setTimeout(createLsp, 1000);
setTimeout(recreateLsp, 1000);
}
}
}
client.start();
}

async function recreateLsp() {
console.log("reloading lsp...");
const serverWorker = await createServer();
createClient(serverWorker);
}

export { createEditor } from "./editor";
4 changes: 4 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ export const COMPILE_ARGS = [
"-pedantic-errors",
"-Wall",
];

export const editorValueGetter = {
get: () => ""
};
27 changes: 11 additions & 16 deletions src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ import EditorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
import { Uri } from "vscode";

import { LIGHT_THEME, DARK_THEME, createTheme } from "./theme";
import { FILE_PATH, LANGUAGE_ID, WORKSPACE_PATH } from "./config";
import { FILE_PATH, LANGUAGE_ID, WORKSPACE_PATH, editorValueGetter } from "./config";

const self = globalThis as any;
self.MonacoEnvironment = { getWorker: () => new EditorWorker() };

let editorInstance: ReturnType<typeof createConfiguredEditor> | null = null;

export async function createEditor(element: HTMLElement, code: string) {
await initServices({
workspaceConfig: {
Expand All @@ -30,33 +28,30 @@ export async function createEditor(element: HTMLElement, code: string) {
},
});

createTheme("light-plus", LIGHT_THEME);
createTheme("dark-plus", DARK_THEME);
createTheme("light", LIGHT_THEME);
createTheme("dark", DARK_THEME);

const modelUrl = Uri.parse(FILE_PATH);

const isDark = document.body.classList.contains("dark");

element.innerHTML = "";
editorInstance = createConfiguredEditor(element, {
const editorInstance = createConfiguredEditor(element, {
model: editor.createModel(code, LANGUAGE_ID, modelUrl),
theme: isDark ? "dark-plus" : "light-plus",
theme: isDark ? "dark" : "light",
quickSuggestionsDelay: 200,
automaticLayout: true,
inlayHints: {
enabled: "offUnlessPressed",
},
});
editorValueGetter.get = () => editorInstance.getValue();
return editorInstance;
}

export function getEditorValue() {
return editorInstance?.getValue() ?? "";
}

function toggleTheme() {
const isDark = document.body.classList.toggle("dark");
editor.setTheme(isDark ? "dark-plus" : "light-plus");
localStorage.setItem("color-theme", isDark ? "dark" : "light");
function toggleEditorTheme() {
const isDark = document.body.classList.contains("dark");
editor.setTheme(isDark ? "dark" : "light");
}
document.querySelector("#toggleTheme")!.addEventListener("click", toggleTheme);
document.querySelector("#toggleTheme")!.addEventListener("click", toggleEditorTheme);

31 changes: 15 additions & 16 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import "./style.css";
import "./ui";

import { createEditor } from "./editor";
import { createLsp } from "./client";

if (!globalThis.crossOriginIsolated) {
document.body.innerHTML = "This page requires cross-origin isolation to work properly. Page will reload in 3s.";
await new Promise(r => setTimeout(r, 3000));
window.location.reload();
document.body.innerHTML =
"This page requires cross-origin isolation to work properly. Page will reload in 3s.";
setTimeout(() => window.location.reload(), 3000);
}

// @ts-ignore
import("iframe-resizer/js/iframeResizer.contentWindow");

let isDark = false;
const userTheme = localStorage.getItem('color-theme');
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (userTheme === 'dark' || (userTheme !== 'light' && systemDark)) {
document.body.classList.toggle('dark', true);
const userTheme = localStorage.getItem("color-theme");
const systemDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
if (userTheme === "dark" || (userTheme !== "light" && systemDark)) {
document.body.classList.toggle("dark", true);
isDark = true;
}
// @ts-ignore
import("iframe-resizer/js/iframeResizer.contentWindow");

const code = `#include <iostream>
#include <format>
Expand All @@ -29,7 +25,10 @@ int main() {
}
`;

await createEditor(document.getElementById("editor")!, code);
console.log("loading lsp...");
await createLsp();
const serverPromise = import("./server").then(({ createServer }) => createServer());

import("./client").then(async ({ createEditor, createClient }) => {
await createEditor(document.getElementById("editor")!, code);
await createClient(await serverPromise);
})

17 changes: 17 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ClangdWorker from "./main.worker?worker";

export async function createServer() {
let clangdResolve = () => {};
const clangdReady = new Promise<void>((r) => (clangdResolve = r));
const worker = new ClangdWorker();
const readyListener = (e: MessageEvent) => {
if (e.data === "ready") {
clangdResolve();
worker.removeEventListener("message", readyListener);
}
};
worker.addEventListener("message", readyListener);
await clangdReady;
return worker;
}

12 changes: 9 additions & 3 deletions src/ui.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getEditorValue } from "./editor";
import { editorValueGetter } from "./config";
import { runCode } from "./runner";

const toggleThemeBtn = document.querySelector<HTMLButtonElement>("#toggleTheme")!;
const buildPanel = document.querySelector<HTMLElement>("#buildPanel")!;
const showBuildPanel = document.querySelector<HTMLElement>("#showBuildPanel")!;
const resizeHandle = document.querySelector<HTMLElement>("#buildPanelResize")!;
Expand Down Expand Up @@ -96,10 +97,9 @@ async function compileAndRun() {
stderr,
didExecute;
({ stdout, stderr, diagnostics, didExecute } = await runCode(
getEditorValue(),
editorValueGetter.get(),
{ stdin }
));
console.log(stdout, stderr);
const outputContainer = document.createElement("pre");
const stdoutEl = document.createElement("span");
stdoutEl.innerText = stdout;
Expand All @@ -119,4 +119,10 @@ async function compileAndRun() {
}
runBtn.addEventListener("click", compileAndRun);

function toggleTheme() {
const isDark = document.body.classList.toggle("dark");
localStorage.setItem("color-theme", isDark ? "dark" : "light");
}
toggleThemeBtn.addEventListener("click", toggleTheme);

export {};

0 comments on commit 9de0f6c

Please sign in to comment.