From 23155a831852553900c1d0b0a39f5a29142c1c99 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Mon, 21 Oct 2024 17:14:03 -0700 Subject: [PATCH 1/2] Disable the Razor project context status bar. We need to properly call the rzls endpoint to get project contexts. Will reenable as part of that work. --- src/lsptoolshost/languageStatusBar.ts | 5 +---- src/lsptoolshost/services/projectContextService.ts | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lsptoolshost/languageStatusBar.ts b/src/lsptoolshost/languageStatusBar.ts index ba09b4d9c..8dc0137ee 100644 --- a/src/lsptoolshost/languageStatusBar.ts +++ b/src/lsptoolshost/languageStatusBar.ts @@ -29,10 +29,7 @@ function combineDocumentSelectors(...selectors: vscode.DocumentSelector[]): vsco class WorkspaceStatus { static createStatusItem(context: vscode.ExtensionContext, languageServerEvents: RoslynLanguageServerEvents) { - const documentSelector = combineDocumentSelectors( - languageServerOptions.documentSelector, - RazorLanguage.documentSelector - ); + const documentSelector = combineDocumentSelectors(languageServerOptions.documentSelector); const openSolutionCommand = { command: 'dotnet.openSolution', title: vscode.l10n.t('Open solution'), diff --git a/src/lsptoolshost/services/projectContextService.ts b/src/lsptoolshost/services/projectContextService.ts index be4a4b17a..d63c866fb 100644 --- a/src/lsptoolshost/services/projectContextService.ts +++ b/src/lsptoolshost/services/projectContextService.ts @@ -47,7 +47,7 @@ export class ProjectContextService { public async refresh() { const textEditor = vscode.window.activeTextEditor; const languageId = textEditor?.document?.languageId; - if (languageId !== 'csharp' && languageId !== 'aspnetcorerazor') { + if (languageId !== 'csharp') { return; } From 6a4e3219df67771acac17759b439f261e235d51a Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Thu, 24 Oct 2024 00:21:52 -0700 Subject: [PATCH 2/2] Delay the Misc Files warning toast. Give the project system time to update with any newly added or renamed files. Then, refresh the active document's project context before displaying a warning toast. --- src/lsptoolshost/languageStatusBar.ts | 7 +-- src/lsptoolshost/miscellaneousFileNotifier.ts | 5 +- .../services/projectContextService.ts | 48 +++++++++++++++++-- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/lsptoolshost/languageStatusBar.ts b/src/lsptoolshost/languageStatusBar.ts index 8dc0137ee..d0656e47f 100644 --- a/src/lsptoolshost/languageStatusBar.ts +++ b/src/lsptoolshost/languageStatusBar.ts @@ -76,9 +76,10 @@ class ProjectContextStatus { // Show a warning when the active file is part of the Miscellaneous File workspace and // project initialization is complete. if (languageServer.state === ServerState.ProjectInitializationComplete) { - item.severity = e.context._vs_is_miscellaneous - ? vscode.LanguageStatusSeverity.Warning - : vscode.LanguageStatusSeverity.Information; + item.severity = + e.context._vs_is_miscellaneous && e.isVerified + ? vscode.LanguageStatusSeverity.Warning + : vscode.LanguageStatusSeverity.Information; } else { item.severity = vscode.LanguageStatusSeverity.Information; } diff --git a/src/lsptoolshost/miscellaneousFileNotifier.ts b/src/lsptoolshost/miscellaneousFileNotifier.ts index 71e550668..100f73c17 100644 --- a/src/lsptoolshost/miscellaneousFileNotifier.ts +++ b/src/lsptoolshost/miscellaneousFileNotifier.ts @@ -21,6 +21,7 @@ export function registerMiscellaneousFileNotifier( // Only warn for C# miscellaneous files when the workspace is fully initialized. if ( e.languageId !== 'csharp' || + !e.isVerified || !e.context._vs_is_miscellaneous || languageServer.state !== ServerState.ProjectInitializationComplete ) { @@ -39,10 +40,10 @@ export function registerMiscellaneousFileNotifier( const hash = createHash(e.uri.toString(/*skipEncoding:*/ true)); if (NotifiedDocuments.has(hash)) { return; - } else { - NotifiedDocuments.add(hash); } + NotifiedDocuments.add(hash); + const message = vscode.l10n.t( 'The active document is not part of the open workspace. Not all language features will be available.' ); diff --git a/src/lsptoolshost/services/projectContextService.ts b/src/lsptoolshost/services/projectContextService.ts index d63c866fb..8dd9589b7 100644 --- a/src/lsptoolshost/services/projectContextService.ts +++ b/src/lsptoolshost/services/projectContextService.ts @@ -15,8 +15,14 @@ export interface ProjectContextChangeEvent { languageId: string; uri: vscode.Uri; context: VSProjectContext; + isVerified: boolean; } +const VerificationDelay = 2 * 1000; + +let _verifyTimeout: NodeJS.Timeout | undefined; +let _documentUriToVerify: vscode.Uri | undefined; + export class ProjectContextService { private readonly _contextChangeEmitter = new vscode.EventEmitter(); private _source = new vscode.CancellationTokenSource(); @@ -57,19 +63,55 @@ export class ProjectContextService { const uri = textEditor!.document.uri; + // Whether we have refreshed the active document's project context. + let isVerifyPass = false; + + if (_verifyTimeout) { + // If we have changed active document then do not verify the previous one. + clearTimeout(_verifyTimeout); + _verifyTimeout = undefined; + } + + if (_documentUriToVerify) { + if (uri.toString() === _documentUriToVerify.toString()) { + // We have rerequested project contexts for the active document + // and we can now notify if the document isn't part of the workspace. + isVerifyPass = true; + } + + _documentUriToVerify = undefined; + } + if (!this._languageServer.isRunning()) { - this._contextChangeEmitter.fire({ languageId, uri, context: this._emptyProjectContext }); + this._contextChangeEmitter.fire({ languageId, uri, context: this._emptyProjectContext, isVerified: false }); return; } const contextList = await this.getProjectContexts(uri, this._source.token); if (!contextList) { - this._contextChangeEmitter.fire({ languageId, uri, context: this._emptyProjectContext }); + this._contextChangeEmitter.fire({ languageId, uri, context: this._emptyProjectContext, isVerified: false }); return; } const context = contextList._vs_projectContexts[contextList._vs_defaultIndex]; - this._contextChangeEmitter.fire({ languageId, uri, context }); + const isVerified = !context._vs_is_miscellaneous || isVerifyPass; + this._contextChangeEmitter.fire({ languageId, uri, context, isVerified }); + + if (context._vs_is_miscellaneous && !isVerifyPass) { + // Request the active project context be refreshed but delay the request to give + // time for the project system to update with new files. + _verifyTimeout = setTimeout(() => { + _verifyTimeout = undefined; + _documentUriToVerify = uri; + + // Trigger a refresh, but don't block on refresh completing. + this.refresh().catch((e) => { + throw new Error(`Error refreshing project context status ${e}`); + }); + }, VerificationDelay); + + return; + } } private async getProjectContexts(