diff --git a/src/LanguageServer.ts b/src/LanguageServer.ts index fc00c95f6..28379fd2e 100644 --- a/src/LanguageServer.ts +++ b/src/LanguageServer.ts @@ -210,7 +210,9 @@ export class LanguageServer { hoverProvider: true, executeCommandProvider: { commands: [ - CustomCommands.TranspileFile + CustomCommands.transpileFile, + CustomCommands.getProjectsInfo, + CustomCommands.reloadProject ] } } as ServerCapabilities @@ -258,6 +260,7 @@ export class LanguageServer { }); } await this.waitAllProgramFirstRuns(false); + this.sendProjectsChanged(); workspaceCreatedDeferred.resolve(); await this.sendDiagnostics(); } catch (e) { @@ -275,7 +278,11 @@ export class LanguageServer { * Send a critical failure notification to the client, which should show a notification of some kind */ private sendCriticalFailure(message: string) { - this.connection.sendNotification('critical-failure', message); + this.connection.sendNotification(CustomNotifications.criticalFailure, message); + } + + private sendProjectsChanged() { + this.connection.sendNotification(CustomNotifications.projectsChanged, null); } /** @@ -605,6 +612,7 @@ export class LanguageServer { //wait for all of the programs to finish starting up await this.waitAllProgramFirstRuns(); + this.sendProjectsChanged(); // valdiate all workspaces this.validateAllThrottled(); //eslint-disable-line } @@ -767,6 +775,12 @@ export class LanguageServer { workspaces.map((workspace) => this.handleFileChanges(workspace, changes)) ); } + + //notify the client anytime the project creates or deletes files + if (changes.find(x => x.type === FileChangeType.Created || x.type === FileChangeType.Deleted)) { + this.sendProjectsChanged(); + } + this.connection.sendNotification('build-status', 'success'); } @@ -1069,10 +1083,21 @@ export class LanguageServer { } } + private getWorkspace(workspacePath: string) { + return this.workspaces.find(x => s(workspacePath) === s(x.workspacePath)); + } + public async onExecuteCommand(params: ExecuteCommandParams) { + this.connection.console.log('onExecuteCommand: ' + JSON.stringify(params)); await this.waitAllProgramFirstRuns(); - if (params.command === CustomCommands.TranspileFile) { + if (params.command === CustomCommands.transpileFile) { return this.transpileFile(params.arguments[0]); + } else if (params.command === CustomCommands.getProjectsInfo) { + return this.getProjectsInfo(); + } else if (params.command === CustomCommands.reloadProject) { + return this.reloadWorkspaces([ + this.getWorkspace(params.arguments[0]) + ]); } } @@ -1088,6 +1113,24 @@ export class LanguageServer { } } + /** + * Returns a list of project information for all projects + */ + private async getProjectsInfo() { + await this.waitAllProgramFirstRuns(); + let result = []; + for (let workspace of this.workspaces) { + const program = workspace.builder.program; + result.push({ + name: program.getName(), + workspaceFolder: program.options.cwd, + rootDir: program.options.rootDir, + files: Object.keys(program.files).map(src => ({ src: src, dest: program.files[src].pkgPath })) + }); + } + return result; + } + public dispose() { this.loggerSubscription?.(); this.validateThrottler.dispose(); @@ -1105,5 +1148,23 @@ export interface Workspace { } export enum CustomCommands { - TranspileFile = 'TranspileFile' + transpileFile = 'transpileFile', + getProjectsInfo = 'getProjectsInfo', + reloadProject = 'reloadProject' +} + +export interface ProjectInfo { + name: string; + workspaceFolder: string; + rootDir: string; + files: ProjectInfoFile[]; +} +export interface ProjectInfoFile { + src: string; + dest: string; +} + +export enum CustomNotifications { + criticalFailure = 'critical-failure', + projectsChanged = 'projects-changed' } diff --git a/src/Program.ts b/src/Program.ts index c63f79846..d5faa155d 100644 --- a/src/Program.ts +++ b/src/Program.ts @@ -79,6 +79,21 @@ export class Program { this.createGlobalScope(); } + /** + * Get the name of the project. + * This is the name from the manifest (if manifest.title is set), + * or the folder name of cwd otherwise + */ + public getName() { + const manifest = this.getManifest(); + + if (manifest.has('title')) { + return manifest.get('title'); + } else { + return path.basename(this.options.cwd ?? this.options.rootDir); + } + } + public logger: Logger; private createGlobalScope() { diff --git a/src/index.ts b/src/index.ts index 0792c4100..273ca4a87 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,4 +12,5 @@ export * from './lexer'; export * from './parser'; export * from './BsConfig'; export * from './deferred'; +export * from './Throttler'; export * from './astUtils';