diff --git a/README.md b/README.md
index 3423b4a5..cb565480 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[](https://github.com/leanprover-community/lean4web/blob/main/LICENSE)
-[](https://github.com/leanprover-community/lean4web/actions/workflows/build.yml)
+[](https://github.com/leanprover-community/lean4web/actions/workflows/ci.yml)
# Lean Web
diff --git a/client/index.html b/client/index.html
index e435ad2f..0bb26079 100644
--- a/client/index.html
+++ b/client/index.html
@@ -22,6 +22,7 @@
+
diff --git a/client/package.json b/client/package.json
index 3bd4bc8b..2081009d 100644
--- a/client/package.json
+++ b/client/package.json
@@ -20,7 +20,7 @@
"jotai-react": "^0.0.0",
"jotai-tanstack-query": "^0.11.0",
"jotai": "^2.16.1",
- "lean4monaco": "^1.1.9",
+ "lean4monaco": "^1.1.11",
"lz-string": "^1.5.0",
"react-dom": "^19.2.0",
"react-split": "^2.0.14",
diff --git a/client/src/App.tsx b/client/src/App.tsx
index e8e8fec8..48612314 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -21,11 +21,6 @@ import { currentProjectAtom } from './store/project-atoms'
import { screenWidthAtom } from './store/window-atoms'
import { save } from './utils/SaveToFile'
-/** Returns true if the browser wants dark mode */
-function isBrowserDefaultDark() {
- return window.matchMedia('(prefers-color-scheme: dark)').matches
-}
-
function App() {
const editorRef = useRef(null)
const infoviewRef = useRef(null)
diff --git a/client/src/context/NavBarContext.tsx b/client/src/context/NavBarContext.tsx
index 9db49b58..b9514aae 100644
--- a/client/src/context/NavBarContext.tsx
+++ b/client/src/context/NavBarContext.tsx
@@ -10,24 +10,23 @@ type NavBarContextType = {
const NavBarContext = createContext(undefined);
export const NavBarProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
- const [requiresNavBar, setRequiresNavBar] = useState(0);
+ const [requiresNavBar, setRequiresNavBar] = useState(() => {
+ const params = new URLSearchParams(window.location.search);
+ const fromParam = params.get("from");
+ if (fromParam === "mathlib") return 1;
+ else if (fromParam === "lean") return 2;
+ return 0;
+ });
const [hideNavBar, setHideNavBar] = useState(() => {
+ const params = new URLSearchParams(window.location.search);
+ const hideParam = params.get("hide");
+ if (hideParam) return hideParam === "true";
+
const stored = localStorage.getItem("hideNavBar");
return stored ? stored === "true" : false;
});
- useEffect(() => {
- const params = new URLSearchParams(window.location.search);
- const fromParam = params.get("from");
- if (fromParam === "mathlib") setRequiresNavBar(1);
- else if (fromParam === "lean") setRequiresNavBar(2);
- else setRequiresNavBar(0);
-
- const hideParam = params.get("hide");
- if (hideParam) setHideNavBar(hideParam === "true");
- }, []);
-
useEffect(() => {
localStorage.setItem("hideNavBar", hideNavBar.toString());
}, [hideNavBar]);
diff --git a/client/src/editor/code-atoms.ts b/client/src/editor/code-atoms.ts
index bf873917..2833ac3b 100644
--- a/client/src/editor/code-atoms.ts
+++ b/client/src/editor/code-atoms.ts
@@ -4,7 +4,6 @@ import LZString from 'lz-string'
import { settingsAtom } from '../settings/settings-atoms'
import { importedCodeAtom, importUrlAtom, importUrlBaseAtom } from '../store/import-atoms'
import { urlArgsAtom, urlArgsStableAtom } from '../store/url-atoms'
-import { fixedEncodeURIComponent } from '../utils/UrlParsing'
/** Atom which represents the editor content and synchronises it with the url hash. */
export const codeAtom = atom(
@@ -37,7 +36,7 @@ export const codeAtom = atom(
if (code == importedCode) {
set(urlArgsAtom, {
...urlArgs,
- url: fixedEncodeURIComponent(url),
+ url: url,
code: undefined,
codez: undefined,
})
@@ -49,11 +48,10 @@ export const codeAtom = atom(
...urlArgs,
url: undefined,
code: undefined,
- codez: fixedEncodeURIComponent(compressedCode),
+ codez: compressedCode,
})
} else {
- const encodedCode = fixedEncodeURIComponent(code)
- set(urlArgsAtom, { ...urlArgs, url: undefined, code: encodedCode, codez: undefined })
+ set(urlArgsAtom, { ...urlArgs, url: undefined, code: code, codez: undefined })
}
},
)
diff --git a/client/src/settings/settings-types.ts b/client/src/settings/settings-types.ts
index 163c86fb..feb0bb59 100644
--- a/client/src/settings/settings-types.ts
+++ b/client/src/settings/settings-types.ts
@@ -1,13 +1,3 @@
-// const isBrowserDefaultDark = () => window.matchMedia('(prefers-color-scheme: dark)').matches
-
-export type Theme =
- | 'Visual Studio Light'
- | 'Visual Studio Dark'
- | 'Default High Contrast'
- | 'Cobalt'
-
-export type MobileValues = boolean | 'auto'
-
/** Type for the settings, including internal ones */
export interface Settings {
/** Lead character to trigger unicode input mode */
@@ -38,6 +28,8 @@ export interface Settings {
/** The settings which are not internal */
export type UserSettings = Omit
+export type MobileValues = boolean | 'auto'
+
/** Same as `UserSettings` but everything is optional, since single keys might be missing in the browser store */
export type PartialUserSettings = Partial
@@ -49,13 +41,24 @@ export const defaultSettings: UserSettings = {
showExpectedType: false,
compress: true,
mobile: 'auto',
- theme: 'Visual Studio Light', // TODO: introduce "auto" which takes the browser setting.
+ theme: isBrowserDefaultDark() ? 'Visual Studio Dark' : 'Visual Studio Light',
wordWrap: true,
}
+export type Theme =
+ | 'Visual Studio Light'
+ | 'Visual Studio Dark'
+ | 'Default High Contrast'
+ | 'Cobalt'
+
/**
* For CodeMirror (on mobile only)
* If you add a Monaco theme, the mobile code-mirror editor will default to its dark theme,
* unless the theme is in this list.
*/
export const lightThemes: Theme[] = ['Visual Studio Light']
+
+/** Returns true if the browser wants dark mode */
+function isBrowserDefaultDark() {
+ return window.matchMedia('(prefers-color-scheme: dark)').matches
+}
diff --git a/client/src/store/import-atoms.ts b/client/src/store/import-atoms.ts
index 6679345f..0fe21d7d 100644
--- a/client/src/store/import-atoms.ts
+++ b/client/src/store/import-atoms.ts
@@ -1,7 +1,7 @@
import { atom } from 'jotai'
import { atomWithQuery } from 'jotai-tanstack-query'
-import { fixedEncodeURIComponent, lookupUrl } from '../utils/UrlParsing'
+import { lookupUrl } from '../utils/UrlParsing'
import { currentProjectAtom } from './project-atoms'
import { urlArgsAtom, urlArgsStableAtom } from './url-atoms'
@@ -26,7 +26,7 @@ export const importUrlAtom = atom(
set(importUrlBaseAtom, url)
set(urlArgsAtom, {
...urlArgs,
- url: fixedEncodeURIComponent(url),
+ url: url,
code: undefined,
codez: undefined,
})
diff --git a/client/src/store/url-converters.ts b/client/src/store/url-converters.ts
index e022286d..86735d8a 100644
--- a/client/src/store/url-converters.ts
+++ b/client/src/store/url-converters.ts
@@ -1,3 +1,4 @@
+import { fixedEncodeURIComponent } from '../utils/UrlParsing'
import { UrlArgs } from './url-types'
/**
@@ -9,7 +10,7 @@ export function formatArgs(args: UrlArgs): string {
'#' +
Object.entries(args)
.filter(([_key, val]) => (val?.trim().length ?? 0) > 0)
- .map(([key, val]) => `${key}=${val}`)
+ .map(([key, val]) => `${key}=${fixedEncodeURIComponent(val)}`)
.join('&')
if (out == '#') {
return ''
diff --git a/cypress/e2e/encoding.cy.ts b/cypress/e2e/encoding.cy.ts
new file mode 100644
index 00000000..05456080
--- /dev/null
+++ b/cypress/e2e/encoding.cy.ts
@@ -0,0 +1,23 @@
+describe("", () => {
+ it("changing projects with uncompressed code should preserve the code", () => {
+ const payload = "def foo := 1 + 2";
+ cy.visit("/");
+
+ // disable compression in the settings
+ cy.get(".dropdown>.nav-link>.fa-bars").click();
+ cy.contains(".nav-link", "Settings").click();
+ cy.get("input#compress")
+ .should("be.checked")
+ .click()
+ .should("not.be.checked");
+ cy.get("input#saveSettings").click();
+
+ cy.get("div.view-lines").type(payload);
+
+ // change project
+ cy.get("nav>*>select[name='leanVersion']").select("Stable Lean");
+ cy.url().should("include", "project=Stable");
+
+ cy.contains("div.view-line", payload).should("exist");
+ });
+});
diff --git a/cypress/e2e/spec.cy.ts b/cypress/e2e/spec.cy.ts
index 8f768864..c95eb75d 100644
--- a/cypress/e2e/spec.cy.ts
+++ b/cypress/e2e/spec.cy.ts
@@ -199,7 +199,7 @@ describe("The Editor", () => {
.should("exist");
});
- it("shows correct go-to definitions", () => {
+ it.skip("shows correct go-to definitions", () => {
const isOnDarwin = Cypress.platform === "darwin";
const alertShown = cy.stub().as("alertShown");
cy.on("window:confirm", alertShown);
diff --git a/package-lock.json b/package-lock.json
index d4131e8e..699810f1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -53,7 +53,7 @@
"jotai-location": "^0.6.2",
"jotai-react": "^0.0.0",
"jotai-tanstack-query": "^0.11.0",
- "lean4monaco": "^1.1.9",
+ "lean4monaco": "^1.1.11",
"lz-string": "^1.5.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
@@ -8405,9 +8405,9 @@
}
},
"node_modules/lean4monaco": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/lean4monaco/-/lean4monaco-1.1.9.tgz",
- "integrity": "sha512-oCnCA4HlRaJJhPvs6uLZrdKGXcrqEU1Q9MadzRQJXfhKJY7oLfaM/qJbU9pWxmYmLTHj7c5524EanjAkN/USag==",
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/lean4monaco/-/lean4monaco-1.1.11.tgz",
+ "integrity": "sha512-4BWuDZxhBCLy8BhX7HUzJymTegPiMDwjIaucGx9WLFFGEbhL8r2cO7UzJejylerXdRIWMiUV969aN7uq9AOzBw==",
"license": "Apache-2.0",
"dependencies": {
"@leanprover/infoview": "~0.8.5",
diff --git a/server/index.mjs b/server/index.mjs
index 62d193ac..c225dd75 100755
--- a/server/index.mjs
+++ b/server/index.mjs
@@ -194,7 +194,7 @@ function startServerProcess(project) {
return serverProcess;
}
-/** Transform client URI to valid file on the server */
+/** Transform client URI to valid file on the server. (mutates the input `obj`) */
function urisToFilenames(prefix, obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
@@ -213,7 +213,7 @@ function urisToFilenames(prefix, obj) {
return obj;
}
-/** Transform server file back into client URI */
+/** Transform server file back into client URI. (mutates the input `obj`) */
function FilenamesToUri(prefix, obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
@@ -256,7 +256,7 @@ wss.addListener("connection", async function (ws, req) {
return;
}
- const socket = {
+ const reader = new rpc.WebSocketMessageReader({
onMessage: (cb) => {
ws.on("message", cb);
},
@@ -266,12 +266,12 @@ wss.addListener("connection", async function (ws, req) {
onClose: (cb) => {
ws.on("close", cb);
},
+ });
+ const writer = new rpc.WebSocketMessageWriter({
send: (data, cb) => {
ws.send(data, cb);
},
- };
- const reader = new rpc.WebSocketMessageReader(socket);
- const writer = new rpc.WebSocketMessageWriter(socket);
+ });
const socketConnection = jsonrpcserver.createConnection(reader, writer, () =>
ws.close(),
);
@@ -279,7 +279,7 @@ wss.addListener("connection", async function (ws, req) {
socketConnection.forward(serverConnection, (message) => {
const prefix = isDevelopment ? PROJECTS_BASE_PATH : "";
- if (!message.method === "textDocument/definition") {
+ if (message.method != "textDocument/definition") {
urisToFilenames(prefix, message);
}