Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LS: Support multi-root-workspaces #6645

Merged
merged 14 commits into from
Nov 18, 2024
77 changes: 52 additions & 25 deletions vscode-cairo/src/cairols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
registerVfsProvider,
registerViewAnalyzedCratesProvider,
} from "./textDocumentProviders";
import assert from "node:assert";

export interface LanguageServerExecutableProvider {
languageServerExecutable(): lc.Executable;
Expand All @@ -25,13 +26,49 @@ function notifyScarbMissing(ctx: Context) {
ctx.log.error(errorMessage);
}

async function allFoldersHaveSameLSProvider(
ctx: Context,
executables: LSExecutable[],
): Promise<boolean> {
if (executables.length < 2) {
return true;
}

// If every executable is scarb based, check if the versions match
if (executables.every((v) => !!v.scarb)) {
const versions = await Promise.all(executables.map((v) => v.scarb!.getVersion(ctx)));
const primaryVersion = versions[0];

return versions.slice(1).every((x) => x === primaryVersion);
}

const primaryExecutable = executables[0]!;
return executables.slice(1).every((x) => primaryExecutable.run.command === x.run.command);
}

export async function setupLanguageServer(ctx: Context): Promise<lc.LanguageClient> {
// TODO(mkaput): Support multi-root workspaces.
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
const executables = (
await Promise.all(
(vscode.workspace.workspaceFolders || []).map((workspaceFolder) =>
getLanguageServerExecutable(workspaceFolder, ctx),
),
)
).filter((x) => !!x) as LSExecutable[];

const scarb = await findScarbForWorkspaceFolder(workspaceFolder, ctx);
const sameProvider = await allFoldersHaveSameLSProvider(ctx, executables);
assert(sameProvider, "Multiple versions of scarb in one workspace is not supported");

// First one is good as any of them since they should be all the same at this point
const lsExecutable = executables[0];

assert(lsExecutable, "Failed to start Cairo LS");

const serverOptions = await getServerOptions(workspaceFolder, scarb, ctx);
const { run, scarb } = lsExecutable;
setupEnv(run, ctx);

ctx.log.debug(`using CairoLS: ${quoteServerExecutable(run)}`);

const serverOptions = { run, debug: run };

const client = new lc.LanguageClient(
"cairoLanguageServer",
Expand Down Expand Up @@ -154,33 +191,23 @@ async function findScarbForWorkspaceFolder(
}
}

async function getServerOptions(
interface LSExecutable {
run: lc.Executable;
scarb: Scarb | undefined;
}

async function getLanguageServerExecutable(
workspaceFolder: vscode.WorkspaceFolder | undefined,
scarb: Scarb | undefined,
ctx: Context,
): Promise<lc.ServerOptions> {
let serverExecutableProvider: LanguageServerExecutableProvider | undefined;
): Promise<LSExecutable | undefined> {
const scarb = await findScarbForWorkspaceFolder(workspaceFolder, ctx);
try {
serverExecutableProvider = await determineLanguageServerExecutableProvider(
workspaceFolder,
scarb,
ctx,
);
const provider = await determineLanguageServerExecutableProvider(workspaceFolder, scarb, ctx);
return { run: provider.languageServerExecutable(), scarb };
} catch (e) {
ctx.log.error(`${e}`);
}

const run = serverExecutableProvider?.languageServerExecutable();
if (run == undefined) {
ctx.log.error("failed to start CairoLS");
throw new Error("failed to start CairoLS");
}

setupEnv(run, ctx);

ctx.log.debug(`using CairoLS: ${quoteServerExecutable(run)}`);

return { run, debug: run };
return undefined;
}

async function determineLanguageServerExecutableProvider(
Expand Down
1 change: 0 additions & 1 deletion vscode-cairo/src/statusBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export class StatusBar {

private async updateScarbVersion(): Promise<void> {
try {
// TODO(mkaput): Support multi-root workspaces.
const scarb = await Scarb.find(vscode.workspace.workspaceFolders?.[0], this.context);
if (scarb) {
const version = await scarb.getVersion(this.context);
Expand Down
Loading