diff --git a/extensions/vscode/.gitignore b/extensions/vscode/.gitignore index fc7e732e25..34960bea4b 100644 --- a/extensions/vscode/.gitignore +++ b/extensions/vscode/.gitignore @@ -12,6 +12,7 @@ dist dist-ssr *.local *.vsix +**/*.map # Editor directories and files .vscode/* diff --git a/extensions/vscode/src/config.ts b/extensions/vscode/src/config.ts new file mode 100644 index 0000000000..5ad1abeaf6 --- /dev/null +++ b/extensions/vscode/src/config.ts @@ -0,0 +1,41 @@ +import * as vscode from "vscode" +import * as fs from 'fs' +import * as path from 'path' + +export const getProjectOrWorkspaceRoot = async (): Promise => { + const workspaceFolders = vscode.workspace.workspaceFolders + if (!workspaceFolders) { + vscode.window.showErrorMessage("FTL extension requires an open folder or workspace to work correctly.") + return "" + } + + // Check each folder for the 'ftl-project.toml' file + for (const folder of workspaceFolders) { + const workspaceRootPath = folder.uri.fsPath + const ftlProjectPath = await findFileInWorkspace(workspaceRootPath, 'ftl-project.toml') + if (ftlProjectPath) { + return ftlProjectPath.replace('ftl-project.toml', '') + } + } + + return workspaceFolders[0].uri.fsPath +} + +export const findFileInWorkspace = async (rootPath: string, fileName: string): Promise => { + try { + const filesAndFolders = await fs.promises.readdir(rootPath, { withFileTypes: true }) + + for (const dirent of filesAndFolders) { + const fullPath = path.join(rootPath, dirent.name) + if (dirent.isDirectory()) { + const result = await findFileInWorkspace(fullPath, fileName) + if (result) { return result } + } else if (dirent.isFile() && dirent.name === fileName) { + return fullPath + } + } + } catch (error) { + console.error('Failed to read directory:', rootPath) + } + return null +} diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index 23246574e9..6516059bf5 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -7,6 +7,7 @@ import { } from "vscode-languageclient/node" import * as vscode from "vscode" import { FTLStatus } from "./status" +import { getProjectOrWorkspaceRoot } from "./config" const clientName = "ftl languge server" const clientId = "ftl" @@ -56,7 +57,7 @@ export async function activate(context: ExtensionContext) { statusBarItem.command = "ftl.statusItemClicked" statusBarItem.show() - startClient(context) + await startClient(context) context.subscriptions.push( restartCmd, @@ -71,43 +72,34 @@ export async function deactivate() { await stopClient() } -function startClient(context: ExtensionContext) { + +async function startClient(context: ExtensionContext) { console.log("Starting client") FTLStatus.starting(statusBarItem) + outputChannel = vscode.window.createOutputChannel("FTL", 'log') + const ftlConfig = vscode.workspace.getConfiguration("ftl") - const ftlPath = ftlConfig.get("executablePath") ?? "ftl" + const ftlPath = ftlConfig.get("executablePath") ?? "ftl" const userFlags = ftlConfig.get("devCommandFlags") ?? [] - let workspaceRootPath = - vscode.workspace.workspaceFolders && - vscode.workspace.workspaceFolders.length > 0 - ? vscode.workspace.workspaceFolders[0].uri.fsPath - : null - - if (!workspaceRootPath) { - vscode.window.showErrorMessage( - "FTL extension requires an open folder to work correctly." - ) - return - } - + const root = await getProjectOrWorkspaceRoot() const flags = ["--lsp", ...userFlags] let serverOptions: ServerOptions = { run: { command: `${ftlPath}`, args: ["dev", ".", ...flags], - options: { cwd: workspaceRootPath }, + options: { cwd: root } }, debug: { command: `${ftlPath}`, args: ["dev", ".", ...flags], - options: { cwd: workspaceRootPath }, + options: { cwd: root } }, } + outputChannel.appendLine(`Running ${ftlPath} with flags: ${flags.join(" ")}`) console.log(serverOptions.debug.args) - outputChannel = vscode.window.createOutputChannel("FTL Logs") let clientOptions: LanguageClientOptions = { documentSelector: [ { scheme: "file", language: "kotlin" },