Skip to content

Commit

Permalink
Add coi sw; some ui update
Browse files Browse the repository at this point in the history
  • Loading branch information
guyutongxue committed Jan 29, 2024
1 parent 33cc2a3 commit 50935a5
Show file tree
Hide file tree
Showing 11 changed files with 366 additions and 14 deletions.
19 changes: 17 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,25 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Clangd Web</title>
<script async src="https://www.unpkg.com/iframe-resizer@4.3.9/js/iframeResizer.contentWindow.js"></script>
<script>window.coi = { quiet: false };</script>
<script src="/sw.js" ></script>
</head>
<body>
<div id="editor"></div>
<div id="app">
<div id="editor"></div>
<div id="buildPanel" class="display-none"></div>
<div id="footer">
<div>
<div id="status"></div>
<div id="progress"></div>
</div>
<div>
<button id="showBuildPanel"><i class="icon build-icon"></i></button>
<button id="toggleTheme"><i class="icon toggle-theme-icon"></i></button>
<span> <a href="https://guyutongxue.site" target="_blank">Guyutongxue</a> &copy; 2024</span>
</div>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"@codingame/monaco-vscode-language-pack-zh-hans": "~1.85.6",
"@codingame/monaco-vscode-theme-defaults-default-extension": "~1.85.6",
"iframe-resizer": "^4.3.9",
"monaco-editor": "npm:@codingame/monaco-editor-treemended@>=1.85.0 <1.86.0",
"monaco-languageclient": ">= 7.3.0 < 7.4.0",
"vscode": "npm:@codingame/monaco-vscode-api@>=1.85.0 <1.86.0",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

166 changes: 166 additions & 0 deletions public/sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
let coepCredentialless = false;
if (typeof window === "undefined") {
self.addEventListener("install", () => self.skipWaiting());
self.addEventListener("activate", (event) =>
event.waitUntil(self.clients.claim())
);

self.addEventListener("message", (ev) => {
if (!ev.data) {
return;
} else if (ev.data.type === "deregister") {
self.registration
.unregister()
.then(() => {
return self.clients.matchAll();
})
.then((clients) => {
clients.forEach((client) => client.navigate(client.url));
});
} else if (ev.data.type === "coepCredentialless") {
coepCredentialless = ev.data.value;
}
});

self.addEventListener("fetch", function (event) {
const r = event.request;
if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
return;
}

const request =
coepCredentialless && r.mode === "no-cors"
? new Request(r, {
credentials: "omit",
})
: r;
event.respondWith(
fetch(request)
.then((response) => {
if (response.status === 0) {
return response;
}

const newHeaders = new Headers(response.headers);
newHeaders.set(
"Cross-Origin-Embedder-Policy",
coepCredentialless ? "credentialless" : "require-corp"
);
if (!coepCredentialless) {
newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
}
newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");

return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders,
});
})
.catch((e) => console.error(e))
);
});
} else {
(() => {
const reloadedBySelf = window.sessionStorage.getItem("coiReloadedBySelf");
window.sessionStorage.removeItem("coiReloadedBySelf");
const coepDegrading = reloadedBySelf == "coepdegrade";

// You can customize the behavior of this script through a global `coi` variable.
const coi = {
shouldRegister: () => !reloadedBySelf,
shouldDeregister: () => false,
coepCredentialless: () => true,
coepDegrade: () => true,
doReload: () => window.location.reload(),
quiet: false,
...window.coi,
};

const n = navigator;
const controlling = n.serviceWorker && n.serviceWorker.controller;

// Record the failure if the page is served by serviceWorker.
if (controlling && !window.crossOriginIsolated) {
window.sessionStorage.setItem("coiCoepHasFailed", "true");
}
const coepHasFailed = window.sessionStorage.getItem("coiCoepHasFailed");

if (controlling) {
// Reload only on the first failure.
const reloadToDegrade =
coi.coepDegrade() && !(coepDegrading || window.crossOriginIsolated);
n.serviceWorker.controller.postMessage({
type: "coepCredentialless",
value:
reloadToDegrade || (coepHasFailed && coi.coepDegrade())
? false
: coi.coepCredentialless(),
});
if (reloadToDegrade) {
!coi.quiet && console.log("Reloading page to degrade COEP.");
window.sessionStorage.setItem("coiReloadedBySelf", "coepdegrade");
coi.doReload("coepdegrade");
}

if (coi.shouldDeregister()) {
n.serviceWorker.controller.postMessage({ type: "deregister" });
}
}

// If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are
// already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here.
if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return;

if (!window.isSecureContext) {
!coi.quiet &&
console.log(
"COOP/COEP Service Worker not registered, a secure context is required."
);
return;
}

// In some environments (e.g. Firefox private mode) this won't be available
if (!n.serviceWorker) {
!coi.quiet &&
console.error(
"COOP/COEP Service Worker not registered, perhaps due to private mode."
);
return;
}

n.serviceWorker.register(window.document.currentScript.src).then(
(registration) => {
!coi.quiet &&
console.log(
"COOP/COEP Service Worker registered",
registration.scope
);

registration.addEventListener("updatefound", () => {
!coi.quiet &&
console.log(
"Reloading page to make use of updated COOP/COEP Service Worker."
);
window.sessionStorage.setItem("coiReloadedBySelf", "updatefound");
coi.doReload();
});

// If the registration is active, but it's not controlling the page
if (registration.active && !n.serviceWorker.controller) {
!coi.quiet &&
console.log(
"Reloading page to make use of COOP/COEP Service Worker."
);
window.sessionStorage.setItem("coiReloadedBySelf", "notcontrolling");
coi.doReload();
}
},
(err) => {
!coi.quiet &&
console.error("COOP/COEP Service Worker failed to register:", err);
}
);
})();
}
12 changes: 12 additions & 0 deletions src/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@


const buildPanel = document.querySelector("#buildPanel")!;
const showBuildPanel = document.querySelector("#showBuildPanel")!;

function toggleBuildPanel() {
buildPanel.classList.toggle("display-none");
showBuildPanel.classList.toggle("display-none");
}
showBuildPanel.addEventListener("click", toggleBuildPanel);

export {};
11 changes: 11 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import ClangdWorker from "./main.worker?worker";
import { LANGUAGE_ID } from "./config";

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

export async function createLsp() {
if (lspRunning) {
Expand All @@ -33,6 +35,10 @@ export async function createLsp() {
const writer = new BrowserMessageWriter(worker);
const readerOnError = reader.onError(() => restart);
const readerOnClose = reader.onClose(() => restart);
const successCallback = reader.listen(() => {
succeeded = true;
successCallback.dispose();
});

const client = new MonacoLanguageClient({
name: "Monaco Language Client",
Expand Down Expand Up @@ -61,6 +67,11 @@ export async function createLsp() {
reader.dispose();
worker.terminate();
} finally {
retry++;
if (retry > 5 && !succeeded) {
console.error("Failed to start clangd after 5 retries");
return;
}
setTimeout(createLsp, 1000);
}
}
Expand Down
13 changes: 11 additions & 2 deletions src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,22 @@ export async function createEditor(element: HTMLElement, code: string) {

const modelUrl = Uri.parse(FILE_PATH);

createConfiguredEditor(element, {
const isDark = document.body.classList.contains("dark");

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

function toggleTheme() {
const isDark = document.body.classList.toggle("dark");
editor.setTheme(isDark ? "dark-plus" : "light-plus");
localStorage.setItem("color-theme", isDark ? "dark" : "light");
}
document.querySelector("#toggleTheme")!.addEventListener("click", toggleTheme);
21 changes: 20 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,34 @@ import "./style.css";

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

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();
}

// @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);
isDark = true;
}

const code = `#include <iostream>
#include <format>
int main() {
std::cout << std::format("Hello, {}!", "world");
std::cout << std::format("Hello, {}!\\n", "world");
}
`;

await createEditor(document.getElementById("editor")!, code);
console.log("loading lsp...");
await createLsp();

2 changes: 1 addition & 1 deletion src/main.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ console.log(clangd);

const flags = [
"-xc++",
"-std=c++2a",
"-std=c++2b",
"-pedantic-errors",
"-Wall",
// "--target=wasm32-wasi",
Expand Down
Loading

0 comments on commit 50935a5

Please sign in to comment.