Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions frontend/src/core/codemirror/language/languages/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { FederatedLanguageServerClient } from "../../lsp/federated-lsp";
import { NotebookLanguageServerClient } from "../../lsp/notebook-lsp";
import { createTransport } from "../../lsp/transports";
import { CellDocumentUri, type ILanguageServerClient } from "../../lsp/types";
import { getLSPDocumentRootUri } from "../../lsp/utils";
import { getLspRootUri, getLspWorkspaceFolders } from "../../lsp/utils";
import {
clickablePlaceholderExtension,
smartPlaceholderExtension,
Expand All @@ -54,8 +54,8 @@ const pylspClient = once((lspConfig: LSPConfig) => {

const lspClientOpts = {
transport,
rootUri: getLSPDocumentRootUri(),
workspaceFolders: [],
rootUri: getLspRootUri(),
workspaceFolders: getLspWorkspaceFolders(),
};
const config = lspConfig?.pylsp;

Expand Down Expand Up @@ -161,8 +161,8 @@ const tyLspClient = once((_: LSPConfig) => {

const lspClientOpts = {
transport,
rootUri: getLSPDocumentRootUri(),
workspaceFolders: [],
rootUri: getLspRootUri(),
workspaceFolders: getLspWorkspaceFolders(),
};

// We wrap the client in a NotebookLanguageServerClient to add some
Expand Down Expand Up @@ -192,8 +192,8 @@ const pyreflyClient = once(

const lspClientOpts = {
transport,
rootUri: getLSPDocumentRootUri(),
workspaceFolders: [],
rootUri: getLspRootUri(),
workspaceFolders: getLspWorkspaceFolders(),
};

// We wrap the client in a NotebookLanguageServerClient to add some
Expand Down Expand Up @@ -230,8 +230,8 @@ const pyrightClient = once((_: LSPConfig) => {

const lspClientOpts = {
transport,
rootUri: getLSPDocumentRootUri(),
workspaceFolders: [],
rootUri: getLspRootUri(),
workspaceFolders: getLspWorkspaceFolders(),
};

// We wrap the client in a NotebookLanguageServerClient to add some
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { cellId } from "@/__tests__/branded";
import type { CellId } from "@/core/cells/ids";
import { store } from "@/core/state/jotai";
import { topologicalCodesAtom } from "../../copilot/getCodes";
import { lspWorkspaceAtom } from "@/core/saving/file-state";
import { languageAdapterState } from "../../language/extension";
import { PythonLanguageAdapter } from "../../language/languages/python";
import { languageMetadataField } from "../../language/metadata";
Expand Down Expand Up @@ -285,6 +286,12 @@ describe("NotebookLanguageServerClient", () => {
},
};
}
if (atom === lspWorkspaceAtom) {
return {
rootUri: "file:///project",
documentUri: "file:///project/__marimo_notebook__.py",
};
}
return undefined;
});

Expand Down Expand Up @@ -421,7 +428,7 @@ describe("NotebookLanguageServerClient", () => {
expect(result).toEqual(mockCompletionResponse);
expect(mockClient.textDocumentCompletion).toHaveBeenCalledWith(
expect.objectContaining({
textDocument: { uri: "file:///__marimo_notebook__.py" },
textDocument: { uri: "file:///project/__marimo_notebook__.py" },
}),
);
});
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/core/codemirror/lsp/federated-lsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type * as LSP from "vscode-languageserver-protocol";
import { Objects } from "@/utils/objects";
import type { ILanguageServerClient } from "./types";
import { getLSPDocument } from "./utils";
import { getLspDocumentUri } from "./utils";

function removeFalseyValues<T extends object>(obj: T): T {
return Objects.filter(obj, (value) => value !== false && value !== null) as T;
Expand All @@ -20,7 +20,7 @@ export class FederatedLanguageServerClient implements ILanguageServerClient {

constructor(clients: ILanguageServerClient[]) {
this.clients = clients;
this.documentUri = getLSPDocument();
this.documentUri = getLspDocumentUri();
}

onNotification(
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/core/codemirror/lsp/notebook-lsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
type ILanguageServerClient,
isClientWithNotify,
} from "./types";
import { getLSPDocument } from "./utils";
import { getLspDocumentUri } from "./utils";

/**
* Check if a variable name is private (starts with underscore but not dunder).
Expand Down Expand Up @@ -189,7 +189,7 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
EditorView | null | undefined
> = defaultGetNotebookEditors,
) {
this.documentUri = getLSPDocument();
this.documentUri = getLspDocumentUri();
this.getNotebookEditors = getNotebookEditors;
this.initialSettings = initialSettings;
this.client = client;
Expand Down
27 changes: 21 additions & 6 deletions frontend/src/core/codemirror/lsp/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
/* Copyright 2026 Marimo. All rights reserved. */
import { getFilenameFromDOM } from "@/core/dom/htmlUtils";
import { Paths } from "@/utils/paths";
import { lspWorkspaceAtom } from "@/core/saving/file-state";
import { store } from "@/core/state/jotai";

export function getLSPDocument() {
return `file://${getFilenameFromDOM() ?? "/__marimo_notebook__.py"}`;
export function getLspRootUri() {
const lspWorkspace = store.get(lspWorkspaceAtom);
// The backend provides rootUri for active notebook sessions.
// For non-notebook pages (home, gallery), lspWorkspace is null,
// so return a valid file URI fallback.
return lspWorkspace?.rootUri ?? "file:///";
}

export function getLSPDocumentRootUri() {
return `file://${Paths.dirname(getFilenameFromDOM() ?? "/")}`;
export function getLspWorkspaceFolders() {
const lspWorkspace = store.get(lspWorkspaceAtom);
const rootUri = lspWorkspace?.rootUri;
// Return workspace folders only if rootUri is set; empty array otherwise.
return rootUri ? [{ uri: rootUri, name: "marimo" }] : [];
}

export function getLspDocumentUri() {
const lspWorkspace = store.get(lspWorkspaceAtom);
// The backend provides documentUri for active notebook sessions.
// For non-notebook pages (home, gallery), lspWorkspace is null,
// so return a valid file URI fallback.
return lspWorkspace?.documentUri ?? "file:///__marimo_notebook__.py";
}
Loading