Skip to content

Commit 0319ed5

Browse files
committed
chore(codemirror): migrate problems page of acode
1 parent 603089a commit 0319ed5

File tree

4 files changed

+241
-49
lines changed

4 files changed

+241
-49
lines changed

src/cm/lsp/clientManager.js

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import {
55
languageServerExtensions,
66
} from "@codemirror/lsp-client";
77
import { MapMode } from "@codemirror/state";
8+
import Uri from "utils/Uri";
89
import { ensureServerRunning } from "./serverLauncher";
910
import serverRegistry from "./serverRegistry";
1011
import { createTransport } from "./transport";
1112
import AcodeWorkspace from "./workspace";
12-
import Uri from "utils/Uri";
1313

1414
function asArray(value) {
1515
if (!value) return [];
@@ -159,8 +159,10 @@ export class LspClientManager {
159159

160160
async #ensureClient(server, context) {
161161
const resolvedRoot = await this.#resolveRootUri(server, context);
162-
const { normalizedRootUri, originalRootUri } =
163-
normalizeRootUriForServer(server, resolvedRoot);
162+
const { normalizedRootUri, originalRootUri } = normalizeRootUriForServer(
163+
server,
164+
resolvedRoot,
165+
);
164166
const key = pluginKey(server.id, normalizedRootUri);
165167
if (this.#clients.has(key)) {
166168
return this.#clients.get(key);
@@ -259,24 +261,15 @@ export class LspClientManager {
259261
console.info(`[LSP:${server.id}] server info`, info);
260262
}
261263
if (normalizedRootUri) {
262-
if (
263-
originalRootUri &&
264-
originalRootUri !== normalizedRootUri
265-
) {
264+
if (originalRootUri && originalRootUri !== normalizedRootUri) {
266265
console.info(
267266
`[LSP:${server.id}] root ${normalizedRootUri} (from ${originalRootUri})`,
268267
);
269268
} else {
270-
console.info(
271-
`[LSP:${server.id}] root`,
272-
normalizedRootUri,
273-
);
269+
console.info(`[LSP:${server.id}] root`, normalizedRootUri);
274270
}
275271
} else if (originalRootUri) {
276-
console.info(
277-
`[LSP:${server.id}] root ignored`,
278-
originalRootUri,
279-
);
272+
console.info(`[LSP:${server.id}] root ignored`, originalRootUri);
280273
}
281274
client.__acodeLoggedInfo = true;
282275
}

src/cm/lsp/diagnostics.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,31 @@ import { MapMode, StateEffect, StateField } from "@codemirror/state";
44

55
const setPublishedDiagnostics = StateEffect.define();
66

7+
export const LSP_DIAGNOSTICS_EVENT = "acode:lsp-diagnostics-updated";
8+
9+
function emitDiagnosticsUpdated() {
10+
if (
11+
typeof document === "undefined" ||
12+
typeof document.dispatchEvent !== "function"
13+
) {
14+
return;
15+
}
16+
17+
let event;
18+
try {
19+
event = new CustomEvent(LSP_DIAGNOSTICS_EVENT);
20+
} catch (_) {
21+
try {
22+
event = document.createEvent("CustomEvent");
23+
event.initCustomEvent(LSP_DIAGNOSTICS_EVENT, false, false, undefined);
24+
} catch (_) {
25+
return;
26+
}
27+
}
28+
29+
document.dispatchEvent(event);
30+
}
31+
732
const lspPublishedDiagnostics = StateField.define({
833
create() {
934
return [];
@@ -119,6 +144,7 @@ export function lspDiagnosticsExtension() {
119144
effects: storeLspDiagnostics(plugin, params.diagnostics),
120145
});
121146
forceLinting(view);
147+
emitDiagnosticsUpdated();
122148
return true;
123149
},
124150
},
@@ -142,3 +168,14 @@ export default lspDiagnosticsExtension;
142168
export function clearDiagnosticsEffect() {
143169
return setPublishedDiagnostics.of([]);
144170
}
171+
172+
export function getLspDiagnostics(state) {
173+
if (!state || typeof state.field !== "function") return [];
174+
try {
175+
const stored = state.field(lspPublishedDiagnostics, false);
176+
if (!stored || !Array.isArray(stored)) return [];
177+
return stored.map((diagnostic) => ({ ...diagnostic }));
178+
} catch (_) {
179+
return [];
180+
}
181+
}

src/lib/editorManager.js

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ import {
3434
} from "@emmetio/codemirror6-plugin";
3535
import createBaseExtensions from "cm/baseExtensions";
3636
import lspClientManager from "cm/lsp/clientManager";
37-
import lspDiagnosticsExtension from "cm/lsp/diagnostics";
37+
import lspDiagnosticsExtension, {
38+
getLspDiagnostics,
39+
LSP_DIAGNOSTICS_EVENT,
40+
} from "cm/lsp/diagnostics";
3841
import { stopManagedServer } from "cm/lsp/serverLauncher";
3942
import serverRegistry from "cm/lsp/serverRegistry";
4043
// CodeMirror mode management
@@ -1103,6 +1106,29 @@ async function EditorManager($header, $body) {
11031106
},
11041107
};
11051108

1109+
if (typeof document !== "undefined") {
1110+
const globalTarget =
1111+
typeof globalThis !== "undefined" ? globalThis : document;
1112+
const diagnosticsListenerKey = "__acodeDiagnosticsListener";
1113+
const existing = globalTarget?.[diagnosticsListenerKey];
1114+
if (typeof existing === "function") {
1115+
document.removeEventListener(LSP_DIAGNOSTICS_EVENT, existing);
1116+
}
1117+
const listener = () => {
1118+
const active = manager.activeFile;
1119+
if (active?.type === "editor") {
1120+
try {
1121+
active.session = editor.state;
1122+
} catch (_) {}
1123+
}
1124+
toggleProblemButton();
1125+
};
1126+
document.addEventListener(LSP_DIAGNOSTICS_EVENT, listener);
1127+
if (globalTarget) {
1128+
globalTarget[diagnosticsListenerKey] = listener;
1129+
}
1130+
}
1131+
11061132
lspClientManager.setOptions({
11071133
resolveRoot: resolveRootUriForContext,
11081134
onClientIdle: ({ server }) => {
@@ -1268,6 +1294,7 @@ async function EditorManager($header, $body) {
12681294
appSettings.on("update:showSideButtons", function () {
12691295
updateMargin();
12701296
updateSideButtonContainer();
1297+
toggleProblemButton();
12711298
});
12721299

12731300
appSettings.on("update:showAnnotations", function () {
@@ -1311,6 +1338,7 @@ async function EditorManager($header, $body) {
13111338
events.emit("file-content-changed", file);
13121339
manager.onupdate("file-changed");
13131340
manager.emit("update", "file-changed");
1341+
toggleProblemButton();
13141342

13151343
const { autosave } = appSettings.value;
13161344
if (file.uri && changed && autosave) {
@@ -1348,6 +1376,7 @@ async function EditorManager($header, $body) {
13481376

13491377
manager.on(["remove-file"], (file) => {
13501378
detachLspForFile(file);
1379+
toggleProblemButton();
13511380
});
13521381

13531382
manager.on(["rename-file"], (file) => {
@@ -1375,6 +1404,7 @@ async function EditorManager($header, $body) {
13751404
manager.files.push(file);
13761405
manager.openFileList.append(file.tab);
13771406
$header.text = file.name;
1407+
toggleProblemButton();
13781408
}
13791409

13801410
/**
@@ -1512,6 +1542,7 @@ async function EditorManager($header, $body) {
15121542

15131543
updateMargin(true);
15141544
updateSideButtonContainer();
1545+
toggleProblemButton();
15151546
// TODO: Implement scroll margin for CodeMirror
15161547
// editor.renderer.setScrollMargin(
15171548
// scrollMarginTop,
@@ -1738,18 +1769,48 @@ async function EditorManager($header, $body) {
17381769
/**
17391770
* Toggles the visibility of the problem button based on the presence of annotations in the files.
17401771
*/
1741-
// TODO: Implement problem button toggle for CodeMirror
1772+
function fileHasProblems(file) {
1773+
const state = getDiagnosticStateForFile(file);
1774+
if (!state) return false;
1775+
1776+
const session = file.session;
1777+
if (session && typeof session.getAnnotations === "function") {
1778+
try {
1779+
const annotations = session.getAnnotations() || [];
1780+
if (annotations.length) return true;
1781+
} catch (_) {}
1782+
}
1783+
1784+
if (typeof state.field !== "function") return false;
1785+
try {
1786+
const diagnostics = getLspDiagnostics(state);
1787+
return diagnostics.length > 0;
1788+
} catch (_) {}
1789+
1790+
return false;
1791+
}
1792+
17421793
function toggleProblemButton() {
1743-
// const fileWithProblems = manager.files.find((file) => {
1744-
// if (file.type !== "editor") return false;
1745-
// const annotations = file?.session?.getAnnotations();
1746-
// return !!annotations.length;
1747-
// });
1748-
// if (fileWithProblems) {
1749-
// problemButton.show();
1750-
// } else {
1751-
// problemButton.hide();
1752-
// }
1794+
const { showSideButtons } = appSettings.value;
1795+
if (!showSideButtons) {
1796+
problemButton.hide();
1797+
return;
1798+
}
1799+
1800+
const hasProblems = manager.files.some((file) => fileHasProblems(file));
1801+
if (hasProblems) {
1802+
problemButton.show();
1803+
} else {
1804+
problemButton.hide();
1805+
}
1806+
}
1807+
1808+
function getDiagnosticStateForFile(file) {
1809+
if (!file || file.type !== "editor") return null;
1810+
if (manager.activeFile?.id === file.id && editor?.state) {
1811+
return editor.state;
1812+
}
1813+
return file.session || null;
17531814
}
17541815

17551816
/**
@@ -1863,6 +1924,8 @@ async function EditorManager($header, $body) {
18631924
$header.text = file.filename;
18641925
manager.onupdate("switch-file");
18651926
events.emit("switch-file", file);
1927+
1928+
toggleProblemButton();
18661929
}
18671930

18681931
/**

0 commit comments

Comments
 (0)