Skip to content

Commit fc265b6

Browse files
committed
feat(lsp): implement LSP subsystem with server management and context integration
- Add LSP subsystem public API in `index.ts` for managing language server workers. - Create `lspContext.tsx` for React integration, providing LSP server manager via context. - Implement `lspServer.worker.ts` to handle LSP server communication in a dedicated Web Worker. - Develop `lspServerManager.ts` to manage LSP server lifecycle, document events, and diagnostics. - Define LSP types in `types.ts` for request/response structures and server configurations. - Introduce `workspaceConfig.ts` for reading and managing workspace configurations from `.dir/settings.json`.
1 parent 29796c6 commit fc265b6

28 files changed

Lines changed: 2220 additions & 99 deletions

.dir/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"workspace": true
3+
}

packages/ui/lib/DotDir.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { builtInCommandContributions } from "@/features/commands/builtInCommandC
66
import { useCommandRegistry } from "@dotdirfm/commands";
77
import { ExtensionHostClientProvider } from "@/features/extensions/extensionHostClient";
88
import { ExtensionHostWorkspaceSync } from "@/features/extensions/extensionHostWorkspaceSync";
9+
import { LspManagerProvider } from "@/features/extensions/lsp/lspContext";
910
import { FssProvider } from "@/features/fss/fss";
1011
import { PanelControllersProvider } from "@/features/panels/panelControllers";
1112
import { UserSettingsProvider } from "@/features/settings/useUserSettings";
@@ -106,6 +107,7 @@ export const DotDir = forwardRef<DotDirHandle, DotDirProps>(function DotDir({ br
106107
[AppServicesProvider],
107108
[FssProvider],
108109
[ExtensionHostClientProvider],
110+
[LspManagerProvider],
109111
[PanelControllersProvider],
110112
]}
111113
>

packages/ui/lib/features/extensions/ExtensionContainer.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { useLanguageRegistry } from "@/features/languages/languageRegistry";
1616
import { getActiveColorThemeData, onColorThemeChange } from "@/features/themes/vscodeColorTheme";
1717
import { useFocusContext, useManagedFocusLayer } from "@dotdirfm/ui-focus";
1818
import styles from "@/styles/viewers.module.css";
19+
import { LspStatusBar } from "@/features/extensions/lsp/LspStatusBar";
1920
import { isContainerPath, parseContainerPath } from "@dotdirfm/ui-utils";
2021
import { basename, dirname, join, normalizePath } from "@dotdirfm/ui-utils";
2122
import { getStyleHostElement } from "@dotdirfm/ui-utils";
@@ -1504,6 +1505,7 @@ export function EditorContainer({
15041505
style={{ width: "100%", height: "100%" }}
15051506
/>
15061507
</div>
1508+
<LspStatusBar languageId={currentLangId} filePath={filePath} />
15071509
</>
15081510
);
15091511

packages/ui/lib/features/extensions/builtins/MonacoEditorSurface.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { useEffect, useRef } from "react";
1818
import { useCommandRegistry } from "@dotdirfm/commands";
1919
import { registerMountedExtensionCommandHandler } from "@/features/extensions/extensionCommandHandlers";
2020
import { useExtensionHostClient, type ExtensionHostClient } from "@/features/extensions/extensionHostClient";
21+
import { useLspManager } from "@/features/extensions/lsp/lspContext";
2122
import { attachMonacoBridges, type AttachedBridges } from "@/features/extensions/monacoBridge";
2223
import {
2324
DOTDIR_MONACO_EXECUTE_ACTION,
@@ -166,19 +167,27 @@ function overlayWidgetColors(isDark: boolean): Record<string, string> {
166167
};
167168
}
168169

170+
import type { LspServerManager } from "@/features/extensions/lsp/lspServerManager";
171+
169172
let attachedBridgeClient: ExtensionHostClient | null = null;
170173
let attachedBridges: AttachedBridges | null = null;
174+
let attachedLspManager: LspServerManager | null = null;
171175

172-
export async function ensureMonacoBridgesAttached(client: ExtensionHostClient): Promise<void> {
173-
if (attachedBridgeClient === client) return;
176+
export async function ensureMonacoBridgesAttached(
177+
client: ExtensionHostClient,
178+
lspManager?: LspServerManager | null,
179+
): Promise<void> {
180+
if (attachedBridgeClient === client && attachedLspManager === lspManager) return;
174181
if (attachedBridges) {
175182
attachedBridges.detach();
176183
attachedBridges = null;
177184
attachedBridgeClient = null;
185+
attachedLspManager = null;
178186
}
179187
const monaco = await loadSharedMonaco();
180-
attachedBridges = attachMonacoBridges(monaco, client);
188+
attachedBridges = attachMonacoBridges(monaco, client, lspManager ?? null);
181189
attachedBridgeClient = client;
190+
attachedLspManager = lspManager ?? null;
182191
}
183192

184193
function stripLangSuffix(scope: string): string {
@@ -974,6 +983,7 @@ export function MonacoEditorSurface({ hostApi, props, active, onInteract }: Mona
974983
const apiRef = useRef<EditorExtensionApi | null>(null);
975984
const commandRegistry = useCommandRegistry();
976985
const extensionHost = useExtensionHostClient();
986+
const lspManager = useLspManager();
977987
const monacoCommandDisposerRef = useRef<(() => void) | null>(null);
978988
const monacoCommandSignatureRef = useRef<string>("");
979989
const activatedLanguageEventsRef = useRef(new Set<string>());
@@ -1004,10 +1014,10 @@ export function MonacoEditorSurface({ hostApi, props, active, onInteract }: Mona
10041014
}
10051015

10061016
useEffect(() => {
1007-
void ensureMonacoBridgesAttached(extensionHost).catch((err) => {
1017+
void ensureMonacoBridgesAttached(extensionHost, lspManager).catch((err) => {
10081018
console.warn("[MonacoEditorSurface] failed to attach extension-host bridges", err);
10091019
});
1010-
}, [extensionHost]);
1020+
}, [extensionHost, lspManager]);
10111021

10121022
useEffect(() => {
10131023
const root = rootRef.current;

packages/ui/lib/features/extensions/ehProtocol.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,14 @@ export interface ConfigurationUpdateMsg {
262262
value: unknown;
263263
}
264264

265+
export interface ConfigurationWorkspaceMsg {
266+
type: "configuration/workspace";
267+
/** Absolute path to the workspace root. */
268+
root: string;
269+
/** Merged workspace-level settings (from .dir/settings.json). */
270+
values: Record<string, unknown>;
271+
}
272+
265273
export interface ActiveEditorMsg {
266274
type: "editor/active";
267275
uri: string | null;
@@ -299,6 +307,7 @@ export type MainToHostMessage =
299307
| DocumentSaveMsg
300308
| WorkspaceFoldersMsg
301309
| ConfigurationUpdateMsg
310+
| ConfigurationWorkspaceMsg
302311
| ActiveEditorMsg
303312
| ProviderInvokeMsg
304313
| ProviderCancelMsg

0 commit comments

Comments
 (0)