Skip to content

Commit

Permalink
Fix FUSE hook up in VS Code (#11175)
Browse files Browse the repository at this point in the history
This one might be a _little_ controversial in terms of how I wired the
`LanguageServerFeatureOptions` up through the `ProjectSnapshot`, but
it's somewhat similar to how it works in cohosting, with
`RemoteProjectSnapshot -> RemoteSolutionSnapshot ->
SolutionSnapshotManager -> LanguageServerFeatureOptions`.

Aside from that aspect of the specific implementation, which you're more
than welcome to critique and suggest an alternative to, the fundamental
change here is removing `LanguageServerFlags` and using
`LanguageServerFeatureOptions` directly. It seems that
`LanguageServerFlags` was intended to encapsulate the feature options
for the compiler, but since that time they are never actually used by
the compiler, and just ended up in a weird spot. They were "flags for
the language server", but were only ever initialized in VS. We we
essentially ended up with this unnecessary middle-man, that didn't
always exist. The `LanguageServerFeatureFlags` on the other hand are
always set in VS, VS Code, etc.

TL;DR: Now that all of the code for deciding whether to use runtime
compilation is entirely on the tooling side, it just makes sense to use
the tooling side options class directly.
  • Loading branch information
davidwengier authored Nov 8, 2024
2 parents 62b6d9b + 87c0163 commit 34cacfa
Show file tree
Hide file tree
Showing 31 changed files with 148 additions and 175 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,20 @@ public sealed record class RazorConfiguration(
string ConfigurationName,
ImmutableArray<RazorExtension> Extensions,
bool UseConsolidatedMvcViews = true,
bool SuppressAddComponentParameter = false,
LanguageServerFlags? LanguageServerFlags = null)
bool SuppressAddComponentParameter = false)
{
public static readonly RazorConfiguration Default = new(
RazorLanguageVersion.Latest,
ConfigurationName: "unnamed",
Extensions: [],
UseConsolidatedMvcViews: true,
SuppressAddComponentParameter: false,
LanguageServerFlags: null);
SuppressAddComponentParameter: false);

public bool Equals(RazorConfiguration? other)
=> other is not null &&
LanguageVersion == other.LanguageVersion &&
ConfigurationName == other.ConfigurationName &&
SuppressAddComponentParameter == other.SuppressAddComponentParameter &&
LanguageServerFlags == other.LanguageServerFlags &&
UseConsolidatedMvcViews == other.UseConsolidatedMvcViews &&
Extensions.SequenceEqual(other.Extensions);

Expand All @@ -40,7 +37,6 @@ public override int GetHashCode()
hash.Add(Extensions);
hash.Add(SuppressAddComponentParameter);
hash.Add(UseConsolidatedMvcViews);
hash.Add(LanguageServerFlags);
return hash;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Immutable;
using System.IO;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.Logging;
Expand Down Expand Up @@ -53,6 +54,7 @@ internal ProjectSnapshotManager CreateProjectSnapshotManager()
{
return new ProjectSnapshotManager(
projectEngineFactoryProvider: StaticProjectEngineFactoryProvider.Instance,
languageServerFeatureOptions: new DefaultLanguageServerFeatureOptions(),
loggerFactory: EmptyLoggerFactory.Instance);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;

namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;

internal class LspProjectSnapshotManager(
IProjectEngineFactoryProvider projectEngineFactoryProvider,
LanguageServerFeatureOptions languageServerFeatureOptions,
ILoggerFactory loggerFactory)
: ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory, initializer: AddMiscFilesProject)
: ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions, loggerFactory, initializer: AddMiscFilesProject)
{
private static void AddMiscFilesProject(Updater updater)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using Microsoft.AspNetCore.Razor.Language;

namespace Microsoft.CodeAnalysis.Razor.Workspaces;

internal abstract class LanguageServerFeatureOptions
Expand Down Expand Up @@ -41,7 +39,4 @@ internal abstract class LanguageServerFeatureOptions
/// When enabled, design time code will not be generated. All tooling will be using runtime code generation.
/// </summary>
public abstract bool ForceRuntimeCodeGeneration { get; }

public LanguageServerFlags ToLanguageServerFlags()
=> new(ForceRuntimeCodeGeneration);
}
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ static void PropagateToTaskCompletionSource(
}

var tagHelpers = await project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false);
var forceRuntimeCodeGeneration = project.Configuration.LanguageServerFlags?.ForceRuntimeCodeGeneration ?? false;
var forceRuntimeCodeGeneration = project.LanguageServerFeatureOptions.ForceRuntimeCodeGeneration;
var codeDocument = await GenerateCodeDocumentAsync(document, project.GetProjectEngine(), imports, tagHelpers, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false);
return (codeDocument, inputVersion);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Razor.Workspaces;

namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;

Expand All @@ -23,6 +24,7 @@ internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot
private readonly Dictionary<string, DocumentSnapshot> _filePathToDocumentMap = new(FilePathNormalizingComparer.Instance);

public HostProject HostProject => _state.HostProject;
public LanguageServerFeatureOptions LanguageServerFeatureOptions => _state.LanguageServerFeatureOptions;

public ProjectKey Key => _state.HostProject.Key;
public RazorConfiguration Configuration => _state.HostProject.Configuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Threading;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
Expand All @@ -27,6 +28,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
internal partial class ProjectSnapshotManager : IProjectSnapshotManager, IDisposable
{
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
private readonly Dispatcher _dispatcher;
private readonly bool _initialized;

Expand Down Expand Up @@ -64,16 +66,19 @@ internal partial class ProjectSnapshotManager : IProjectSnapshotManager, IDispos
/// </summary>
/// <param name="projectEngineFactoryProvider">The <see cref="IProjectEngineFactoryProvider"/> to
/// use when creating <see cref="ProjectState"/>.</param>
/// <param name="languageServerFeatureOptions">The options that were used to start the language server</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use.</param>
/// <param name="initializer">An optional callback to set up the initial set of projects and documents.
/// Note that this is called during construction, so it does not run on the dispatcher and notifications
/// will not be sent.</param>
public ProjectSnapshotManager(
IProjectEngineFactoryProvider projectEngineFactoryProvider,
LanguageServerFeatureOptions languageServerFeatureOptions,
ILoggerFactory loggerFactory,
Action<Updater>? initializer = null)
{
_projectEngineFactoryProvider = projectEngineFactoryProvider;
_languageServerFeatureOptions = languageServerFeatureOptions;
_dispatcher = new(loggerFactory);

initializer?.Invoke(new(this));
Expand Down Expand Up @@ -437,6 +442,7 @@ private bool TryUpdate(

var state = ProjectState.Create(
_projectEngineFactoryProvider,
_languageServerFeatureOptions,
hostProject,
ProjectWorkspaceState.Default);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
Expand All @@ -35,37 +36,26 @@ internal class ProjectState
private readonly object _lock;

private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
private RazorProjectEngine? _projectEngine;

public static ProjectState Create(
IProjectEngineFactoryProvider projectEngineFactoryProvider,
LanguageServerFeatureOptions languageServerFeatureOptions,
HostProject hostProject,
ProjectWorkspaceState projectWorkspaceState)
{
if (projectEngineFactoryProvider is null)
{
throw new ArgumentNullException(nameof(projectEngineFactoryProvider));
}

if (hostProject is null)
{
throw new ArgumentNullException(nameof(hostProject));
}

if (projectWorkspaceState is null)
{
throw new ArgumentNullException(nameof(projectWorkspaceState));
}

return new ProjectState(projectEngineFactoryProvider, hostProject, projectWorkspaceState);
return new ProjectState(projectEngineFactoryProvider, languageServerFeatureOptions, hostProject, projectWorkspaceState);
}

private ProjectState(
IProjectEngineFactoryProvider projectEngineFactoryProvider,
LanguageServerFeatureOptions languageServerFeatureOptions,
HostProject hostProject,
ProjectWorkspaceState projectWorkspaceState)
{
_projectEngineFactoryProvider = projectEngineFactoryProvider;
_languageServerFeatureOptions = languageServerFeatureOptions;
HostProject = hostProject;
ProjectWorkspaceState = projectWorkspaceState;
Documents = s_emptyDocuments;
Expand All @@ -85,32 +75,8 @@ private ProjectState(
ImmutableDictionary<string, DocumentState> documents,
ImmutableDictionary<string, ImmutableArray<string>> importsToRelatedDocuments)
{
if (older is null)
{
throw new ArgumentNullException(nameof(older));
}

if (hostProject is null)
{
throw new ArgumentNullException(nameof(hostProject));
}

if (documents is null)
{
throw new ArgumentNullException(nameof(documents));
}

if (importsToRelatedDocuments is null)
{
throw new ArgumentNullException(nameof(importsToRelatedDocuments));
}

if (projectWorkspaceState is null)
{
throw new ArgumentNullException(nameof(projectWorkspaceState));
}

_projectEngineFactoryProvider = older._projectEngineFactoryProvider;
_languageServerFeatureOptions = older._languageServerFeatureOptions;
Version = older.Version.GetNewerVersion();

HostProject = hostProject;
Expand Down Expand Up @@ -169,6 +135,8 @@ private ProjectState(

public HostProject HostProject { get; }

internal LanguageServerFeatureOptions LanguageServerFeatureOptions => _languageServerFeatureOptions;

public ProjectWorkspaceState ProjectWorkspaceState { get; }

public ImmutableArray<TagHelperDescriptor> TagHelpers => ProjectWorkspaceState.TagHelpers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ async Task<RazorCodeDocument> GetRazorCodeDocumentAsync(bool forceRuntimeCodeGen
var imports = await DocumentState.GetImportsAsync(this, projectEngine, cancellationToken).ConfigureAwait(false);

return await DocumentState
.GenerateCodeDocumentAsync(this, projectEngine, imports, tagHelpers, forceRuntimeCodeGeneration: forceRuntimeCodeGeneration, cancellationToken)
.GenerateCodeDocumentAsync(this, projectEngine, imports, tagHelpers, forceRuntimeCodeGeneration, cancellationToken)
.ConfigureAwait(false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.ProjectSystem;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Microsoft.VisualStudio.Shell;
Expand All @@ -28,7 +27,12 @@ namespace Microsoft.VisualStudio.Razor.ProjectSystem;
// MSBuild provides configuration support (>= 2.1).
[AppliesTo("DotNetCoreRazor & DotNetCoreRazorConfiguration")]
[Export(ExportContractNames.Scopes.UnconfiguredProject, typeof(IProjectDynamicLoadComponent))]
internal class DefaultWindowsRazorProjectHost : WindowsRazorProjectHostBase
[method: ImportingConstructor]
internal class DefaultWindowsRazorProjectHost(
IUnconfiguredProjectCommonServices commonServices,
[Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider,
IProjectSnapshotManager projectManager)
: WindowsRazorProjectHostBase(commonServices, serviceProvider, projectManager)
{
private const string RootNamespaceProperty = "RootNamespace";
private static readonly ImmutableHashSet<string> s_ruleNames = ImmutableHashSet.CreateRange(new string[]
Expand All @@ -40,24 +44,12 @@ internal class DefaultWindowsRazorProjectHost : WindowsRazorProjectHostBase
Rules.RazorGenerateWithTargetPath.SchemaName,
ConfigurationGeneralSchemaName,
});
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;

[ImportingConstructor]
public DefaultWindowsRazorProjectHost(
IUnconfiguredProjectCommonServices commonServices,
[Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider,
IProjectSnapshotManager projectManager,
LanguageServerFeatureOptions languageServerFeatureOptions)
: base(commonServices, serviceProvider, projectManager)
{
_languageServerFeatureOptions = languageServerFeatureOptions;
}

protected override ImmutableHashSet<string> GetRuleNames() => s_ruleNames;

protected override async Task HandleProjectChangeAsync(string sliceDimensions, IProjectVersionedValue<IProjectSubscriptionUpdate> update)
{
if (TryGetConfiguration(update.Value.CurrentState, _languageServerFeatureOptions.ToLanguageServerFlags(), out var configuration) &&
if (TryGetConfiguration(update.Value.CurrentState, out var configuration) &&
TryGetIntermediateOutputPath(update.Value.CurrentState, out var intermediatePath))
{
TryGetRootNamespace(update.Value.CurrentState, out var rootNamespace);
Expand Down Expand Up @@ -134,7 +126,6 @@ await UpdateAsync(
// Internal for testing
internal static bool TryGetConfiguration(
IImmutableDictionary<string, IProjectRuleSnapshot> state,
LanguageServerFlags? languageServerFlags,
[NotNullWhen(returnValue: true)] out RazorConfiguration? configuration)
{
if (!TryGetDefaultConfiguration(state, out var defaultConfiguration))
Expand Down Expand Up @@ -165,8 +156,7 @@ internal static bool TryGetConfiguration(
configuration = new(
languageVersion,
configurationItem.Key,
extensions,
LanguageServerFlags: languageServerFlags);
extensions);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@ namespace Microsoft.VisualStudio.Razor.ProjectSystem;
[method: ImportingConstructor]
internal sealed class FallbackProjectManager(
[Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider,
LanguageServerFeatureOptions languageServerFeatureOptions,
IProjectSnapshotManager projectManager,
IWorkspaceProvider workspaceProvider,
ITelemetryReporter telemetryReporter)
{
private readonly IServiceProvider _serviceProvider = serviceProvider;
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions;
private readonly IProjectSnapshotManager _projectManager = projectManager;
private readonly IWorkspaceProvider _workspaceProvider = workspaceProvider;
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter;
Expand Down Expand Up @@ -108,7 +106,7 @@ private void AddFallbackProject(ProjectId projectId, string filePath, Cancellati

var rootNamespace = project.DefaultNamespace;

var configuration = FallbackRazorConfiguration.Latest with { LanguageServerFlags = _languageServerFeatureOptions.ToLanguageServerFlags() };
var configuration = FallbackRazorConfiguration.Latest;

// We create this as a fallback project so that other parts of the system can reason about them - eg we don't do code
// generation for closed files for documents in these projects. If these projects become "real", either because capabilities
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;

namespace Microsoft.VisualStudio.Razor.ProjectSystem;

[Export(typeof(IProjectSnapshotManager))]
[method: ImportingConstructor]
internal sealed class VisualStudioProjectSnapshotManager(
IProjectEngineFactoryProvider projectEngineFactoryProvider,
LanguageServerFeatureOptions languageServerFeatureOptions,
ILoggerFactory loggerFactory)
: ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory)
: ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions, loggerFactory)
{
}
Loading

0 comments on commit 34cacfa

Please sign in to comment.