Skip to content

Commit 9d67a98

Browse files
authored
Don't monitor the whole workspace for config files in Visual Studio (#9601)
Fixes #9600
2 parents b01b03c + 3a52122 commit 9d67a98

File tree

13 files changed

+90
-67
lines changed

13 files changed

+90
-67
lines changed

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ConfigurableLanguageServerFeatureOptions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal class ConfigurableLanguageServerFeatureOptions : LanguageServerFeatureO
2222
private readonly bool? _usePreciseSemanticTokenRanges;
2323
private readonly bool? _updateBuffersForClosedDocuments;
2424
private readonly bool? _includeProjectKeyInGeneratedFilePath;
25+
private readonly bool? _monitorWorkspaceFolderForConfigurationFiles;
2526

2627
public override bool SupportsFileManipulation => _supportsFileManipulation ?? _defaults.SupportsFileManipulation;
2728
public override string ProjectConfigurationFileName => _projectConfigurationFileName ?? _defaults.ProjectConfigurationFileName;
@@ -35,6 +36,7 @@ internal class ConfigurableLanguageServerFeatureOptions : LanguageServerFeatureO
3536
public override bool UsePreciseSemanticTokenRanges => _usePreciseSemanticTokenRanges ?? _defaults.UsePreciseSemanticTokenRanges;
3637
public override bool UpdateBuffersForClosedDocuments => _updateBuffersForClosedDocuments ?? _defaults.UpdateBuffersForClosedDocuments;
3738
public override bool IncludeProjectKeyInGeneratedFilePath => _includeProjectKeyInGeneratedFilePath ?? _defaults.IncludeProjectKeyInGeneratedFilePath;
39+
public override bool MonitorWorkspaceFolderForConfigurationFiles => _monitorWorkspaceFolderForConfigurationFiles ?? _defaults.MonitorWorkspaceFolderForConfigurationFiles;
3840

3941
public ConfigurableLanguageServerFeatureOptions(string[] args)
4042
{
@@ -57,6 +59,7 @@ public ConfigurableLanguageServerFeatureOptions(string[] args)
5759
TryProcessBoolOption(nameof(UsePreciseSemanticTokenRanges), ref _usePreciseSemanticTokenRanges, option, args, i);
5860
TryProcessBoolOption(nameof(UpdateBuffersForClosedDocuments), ref _updateBuffersForClosedDocuments, option, args, i);
5961
TryProcessBoolOption(nameof(IncludeProjectKeyInGeneratedFilePath), ref _includeProjectKeyInGeneratedFilePath, option, args, i);
62+
TryProcessBoolOption(nameof(MonitorWorkspaceFolderForConfigurationFiles), ref _monitorWorkspaceFolderForConfigurationFiles, option, args, i);
6063
}
6164
}
6265

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultLanguageServerFeatureOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ public override bool ReturnCodeActionAndRenamePathsWithPrefixedSlash
3838
public override bool IncludeProjectKeyInGeneratedFilePath => false;
3939

4040
public override bool UsePreciseSemanticTokenRanges => false;
41+
42+
public override bool MonitorWorkspaceFolderForConfigurationFiles => true;
4143
}

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,14 @@ public static void AddDocumentManagementServices(this IServiceCollection service
210210
services.AddSingleton<IProjectConfigurationFileChangeListener, ProjectConfigurationStateSynchronizer>();
211211
services.AddSingleton<IRazorFileChangeListener, RazorFileSynchronizer>();
212212

213-
// File Change detectors
214-
services.AddSingleton<IFileChangeDetector, ProjectConfigurationFileChangeDetector>();
213+
// If we're not monitoring the whole workspace folder for configuration changes, then we don't actually need the the file change
214+
// detector wired up via DI, as the razor/monitorProjectConfigurationFilePath endpoint will directly construct one. This means
215+
// it can be a little simpler, and doesn't need to worry about which folders it's told to listen to.
216+
if (featureOptions.MonitorWorkspaceFolderForConfigurationFiles)
217+
{
218+
services.AddSingleton<IFileChangeDetector, ProjectConfigurationFileChangeDetector>();
219+
}
220+
215221
services.AddSingleton<IFileChangeDetector, RazorFileChangeDetector>();
216222

217223
// Document processed listeners

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IMonitorProjectConfigurationFilePathHandler.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MonitorProjectConfigurationFilePathEndpoint.cs renamed to src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/MonitorProjectConfigurationFilePathEndpoint.cs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@
77
using System.IO;
88
using System.Threading;
99
using System.Threading.Tasks;
10+
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
1011
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
1112
using Microsoft.AspNetCore.Razor.Utilities;
1213
using Microsoft.CodeAnalysis.Razor;
1314
using Microsoft.CodeAnalysis.Razor.Workspaces;
15+
using Microsoft.CommonLanguageServerProtocol.Framework;
1416
using Microsoft.Extensions.Logging;
1517

16-
namespace Microsoft.AspNetCore.Razor.LanguageServer;
18+
namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
1719

18-
internal class MonitorProjectConfigurationFilePathEndpoint : IMonitorProjectConfigurationFilePathHandler, IDisposable
20+
[LanguageServerEndpoint(LanguageServerConstants.RazorMonitorProjectConfigurationFilePathEndpoint)]
21+
internal class MonitorProjectConfigurationFilePathEndpoint : IRazorNotificationHandler<MonitorProjectConfigurationFilePathParams>, IDisposable
1922
{
2023
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
2124
private readonly WorkspaceDirectoryPathResolver _workspaceDirectoryPathResolver;
@@ -81,28 +84,31 @@ public async Task HandleNotificationAsync(MonitorProjectConfigurationFilePathPar
8184
}
8285

8386
var configurationDirectory = Path.GetDirectoryName(request.ConfigurationFilePath);
84-
var normalizedConfigurationDirectory = FilePathNormalizer.NormalizeDirectory(configurationDirectory);
85-
var workspaceDirectory = _workspaceDirectoryPathResolver.Resolve();
86-
var normalizedWorkspaceDirectory = FilePathNormalizer.NormalizeDirectory(workspaceDirectory);
87-
8887
Assumes.NotNull(configurationDirectory);
8988

9089
var previousMonitorExists = _outputPathMonitors.TryGetValue(request.ProjectKeyId, out var entry);
9190

92-
if (normalizedConfigurationDirectory.StartsWith(normalizedWorkspaceDirectory, FilePathComparison.Instance))
91+
if (_options.MonitorWorkspaceFolderForConfigurationFiles)
9392
{
94-
if (previousMonitorExists)
95-
{
96-
_logger.LogInformation("Configuration directory changed from external directory -> internal directory for project '{0}, terminating existing monitor'.", request.ProjectKeyId);
97-
RemoveMonitor(request.ProjectKeyId);
98-
}
99-
else
93+
var normalizedConfigurationDirectory = FilePathNormalizer.NormalizeDirectory(configurationDirectory);
94+
var workspaceDirectory = _workspaceDirectoryPathResolver.Resolve();
95+
var normalizedWorkspaceDirectory = FilePathNormalizer.NormalizeDirectory(workspaceDirectory);
96+
97+
if (normalizedConfigurationDirectory.StartsWith(normalizedWorkspaceDirectory, FilePathComparison.Instance))
10098
{
101-
_logger.LogInformation("No custom configuration directory required. The workspace directory is sufficient for '{0}'.", request.ProjectKeyId);
99+
if (previousMonitorExists)
100+
{
101+
_logger.LogInformation("Configuration directory changed from external directory -> internal directory for project '{0}, terminating existing monitor'.", request.ProjectKeyId);
102+
RemoveMonitor(request.ProjectKeyId);
103+
}
104+
else
105+
{
106+
_logger.LogInformation("No custom configuration directory required. The workspace directory is sufficient for '{0}'.", request.ProjectKeyId);
107+
}
108+
109+
// Configuration directory is already in the workspace directory. We already monitor everything in the workspace directory.
110+
return;
102111
}
103-
104-
// Configuration directory is already in the workspace directory. We already monitor everything in the workspace directory.
105-
return;
106112
}
107113

108114
if (previousMonitorExists)
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT license. See License.txt in the project root for license information.
33

4-
namespace Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
4+
namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
55

66
internal class MonitorProjectConfigurationFilePathParams
77
{
88
public required string ProjectKeyId { get; set; }
99

10-
public required string ConfigurationFilePath { get; set; }
10+
public required string? ConfigurationFilePath { get; set; }
1111
}

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using Microsoft.AspNetCore.Razor.LanguageServer.LinkedEditingRange;
1919
using Microsoft.AspNetCore.Razor.LanguageServer.MapCode;
2020
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectContexts;
21+
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
2122
using Microsoft.AspNetCore.Razor.LanguageServer.Refactoring;
2223
using Microsoft.AspNetCore.Razor.LanguageServer.SignatureHelp;
2324
using Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag;
@@ -181,7 +182,7 @@ protected override ILspServices ConstructLspServices()
181182

182183
static void AddHandlers(IServiceCollection services)
183184
{
184-
// Not calling AddHandler because we want to register this endpoint as an IOnIntialized too
185+
// Not calling AddHandler because we want to register this endpoint as an IOnInitialized too
185186
services.AddSingleton<RazorConfigurationEndpoint>();
186187
services.AddSingleton<IMethodHandler, RazorConfigurationEndpoint>(s => s.GetRequiredService<RazorConfigurationEndpoint>());
187188
// Transient because it should only be used once and I'm hoping it doesn't stick around.

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LanguageServerFeatureOptions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,13 @@ internal abstract class LanguageServerFeatureOptions
3434
/// ensure a unique file path per project.
3535
/// </summary>
3636
public abstract bool IncludeProjectKeyInGeneratedFilePath { get; }
37+
38+
/// <summary>
39+
/// Whether to monitor the entire workspace folder for any project.razor.bin files
40+
/// </summary>
41+
/// <remarks>
42+
/// When this is off, the language server won't have any project knowledge unless the
43+
/// razor/monitorProjectConfigurationFilePath notification is sent.
44+
/// </remarks>
45+
public abstract bool MonitorWorkspaceFolderForConfigurationFiles { get; }
3746
}

src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/MonitorProjectConfigurationFilePathParams.cs

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading.Tasks;
1010
using Microsoft.AspNetCore.Razor.LanguageServer;
1111
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
12+
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
1213
using Microsoft.AspNetCore.Razor.Telemetry;
1314
using Microsoft.CodeAnalysis.Host;
1415
using Microsoft.CodeAnalysis.Razor;

0 commit comments

Comments
 (0)