From f5465bb1ff8c42e8a2ca32baae4eb928693e7d14 Mon Sep 17 00:00:00 2001 From: Oles Date: Thu, 23 Sep 2021 10:39:34 -0400 Subject: [PATCH] Detect project.godot files automatically and let users select which to use --- package.json | 2 +- src/extension.ts | 93 +++++++++++++++++++++++++++++++------------ src/project-select.ts | 35 ++++++++++++++++ 3 files changed, 103 insertions(+), 27 deletions(-) create mode 100644 src/project-select.ts diff --git a/package.json b/package.json index ef840d5..f58354f 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "Other" ], "activationEvents": [ - "workspaceContains:project.godot", + "workspaceContains:**/project.godot", "onDebugResolve:godot" ], "main": "./dist/extension.bundled.js", diff --git a/src/extension.ts b/src/extension.ts index c6cb128..ad2dcf9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,10 +3,12 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { Client, Peer, MessageContent, MessageStatus, ILogger, IMessageHandler } from './godot-tools-messaging/client'; import * as completion_provider from './completion-provider'; import { fixPathForGodot } from './godot-utils'; -import * as path from 'path'; -import * as fs from 'fs'; +import { findProjectFiles, ProjectLocation, promptForProject } from './project-select' let client: Client; +let codeCompletionProvider: vscode.Disposable; +let debugConfigProvider: vscode.Disposable; +let statusBarItem: vscode.StatusBarItem; class Logger implements ILogger { logDebug(message: string): void { @@ -86,40 +88,77 @@ class MessageHandler implements IMessageHandler { } } -export function activate(context: vscode.ExtensionContext) { - let godotProjectDir = vscode.workspace.workspaceFolders?.find((workspaceFolder) => { - let rootPath = workspaceFolder.uri.fsPath; - let godotProjectFile = path.join(rootPath, 'project.godot'); - - return fs.existsSync(godotProjectFile); - })?.uri.fsPath; - - if (godotProjectDir === undefined) { +export async function activate(context: vscode.ExtensionContext) { + let foundProjects: ProjectLocation[] = await findProjectFiles(); + // No project.godot files found. The extension doesn't need to do anything more. + if (foundProjects.length == 0) { return; } - godotProjectDir = fixPathForGodot(godotProjectDir); + // Setup the status bar / project selector and prompt for project if necessary + const commandId = 'csharpGodot.selectProject'; + statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0); + statusBarItem.command = commandId; + statusBarItem.show(); + context.subscriptions.push(statusBarItem); + context.subscriptions.push(vscode.commands.registerCommand(commandId, async () => { + let project = await promptForProject(); // project.godot + if (project !== undefined) { + setupProject(project, context); + } + })); - client = new Client('VisualStudioCode', godotProjectDir, new MessageHandler(), new Logger()); + // One project.godot files found. Use it. + if (foundProjects.length == 1) { + setupProject(foundProjects[0], context); + } + // Multiple project.godot files found. Prompt the user for which one they want to use. + else { + let project = await promptForProject(); + if (project !== undefined) { + setupProject(project, context); + } + } +} + +function setupProject(project: ProjectLocation, context: vscode.ExtensionContext) { + let statusBarPath:string = project.relativeProjectPath === '.' ? './' : project.relativeProjectPath; + statusBarItem.text = `$(folder) Godot Project: ${statusBarPath}`; + // Setup client + if (client !== undefined) { + client.dispose(); + } + client = new Client( + 'VisualStudioCode', + fixPathForGodot(project.absoluteProjectPath), + new MessageHandler(), + new Logger() + ); client.start(); - const debugConfigProvider = vscode.debug.registerDebugConfigurationProvider( + // Setup debug provider + if (debugConfigProvider) { + debugConfigProvider.dispose(); + } + debugConfigProvider = vscode.debug.registerDebugConfigurationProvider( 'godot-mono', - new GodotMonoDebugConfigProvider() + new GodotMonoDebugConfigProvider(project.absoluteProjectPath) ); + context.subscriptions.push(debugConfigProvider); + // Setup completion provider // There's no way to extend OmniSharp without having to provide our own language server. // That will be a big task so for now we will provide this basic completion provider. - const codeCompletionProvider = vscode.languages.registerCompletionItemProvider( + if (codeCompletionProvider !== undefined) { + codeCompletionProvider.dispose(); + } + // Create client, create provider, register and subscribe provider + codeCompletionProvider = vscode.languages.registerCompletionItemProvider( 'csharp', new completion_provider.GodotCompletionProvider(client), // Trigger characters '(', '"', ',', ' ' ); - - context.subscriptions.push( - debugConfigProvider, - codeCompletionProvider - ); + context.subscriptions.push(codeCompletionProvider); } export function deactivate() { @@ -127,6 +166,12 @@ export function deactivate() { } class GodotMonoDebugConfigProvider implements vscode.DebugConfigurationProvider { + godotProjectPath: string; + + constructor(godotProjectPath: string) { + this.godotProjectPath = godotProjectPath; + } + public async resolveDebugConfiguration( folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration, @@ -135,11 +180,7 @@ class GodotMonoDebugConfigProvider implements vscode.DebugConfigurationProvider if (!debugConfiguration.__exceptionOptions) { debugConfiguration.__exceptionOptions = convertToExceptionOptions(getModel()); } - - if (folder !== undefined) { - debugConfiguration['godotProjectDir'] = folder.uri.fsPath; - } - + debugConfiguration['godotProjectDir'] = this.godotProjectPath; return debugConfiguration; } } diff --git a/src/project-select.ts b/src/project-select.ts new file mode 100644 index 0000000..fda7da7 --- /dev/null +++ b/src/project-select.ts @@ -0,0 +1,35 @@ +import * as vscode from 'vscode'; +import * as path from 'path'; + +export interface ProjectLocation{ + relativeFilePath: string + absoluteFilePath: string + relativeProjectPath: string + absoluteProjectPath: string +} + +export async function findProjectFiles(): Promise { + let projectFiles = await vscode.workspace.findFiles("**/project.godot"); + return projectFiles.map((x) => { + return { + relativeFilePath: vscode.workspace.asRelativePath(x), + absoluteFilePath: x.path, + relativeProjectPath: path.dirname(vscode.workspace.asRelativePath(x)), + absoluteProjectPath: path.dirname(x.path) + } + }); +} + +export async function promptForProject(): Promise { + let godotProjectFiles = await findProjectFiles(); + let selectionOptions = godotProjectFiles?.map((x) => { + return { + label: x.relativeFilePath, + ...x + } + }); + return vscode.window.showQuickPick(selectionOptions, { + title: 'Select a Godot project', + placeHolder: 'Select a Godot project' + }); +} \ No newline at end of file