-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cohosting: Update Html virtual document from OOP (#10175)
Part of #9519 When cohosting is on, while processing a didOpen or didChange for a Razor document, we now call into OOP to get the generated Html document contents, and then update the virtual buffer.
- Loading branch information
Showing
8 changed files
with
183 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteHtmlDocumentService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor; | ||
|
||
namespace Microsoft.CodeAnalysis.Razor.Remote; | ||
|
||
internal interface IRemoteHtmlDocumentService | ||
{ | ||
ValueTask<string?> GetHtmlDocumentTextAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId razorDocumentId, CancellationToken cancellationToken); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/HtmlDocuments/RemoteHtmlDocumentService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Api; | ||
using Microsoft.CodeAnalysis.Razor.Remote; | ||
using Microsoft.CodeAnalysis.Razor.Workspaces; | ||
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; | ||
using Microsoft.ServiceHub.Framework; | ||
|
||
namespace Microsoft.CodeAnalysis.Remote.Razor; | ||
|
||
internal sealed class RemoteHtmlDocumentService( | ||
IServiceBroker serviceBroker, | ||
DocumentSnapshotFactory documentSnapshotFactory) | ||
: RazorServiceBase(serviceBroker), IRemoteHtmlDocumentService | ||
{ | ||
private readonly DocumentSnapshotFactory _documentSnapshotFactory = documentSnapshotFactory; | ||
|
||
public ValueTask<string?> GetHtmlDocumentTextAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId razorDocumentId, CancellationToken cancellationToken) | ||
=> RazorBrokeredServiceImplementation.RunServiceAsync( | ||
solutionInfo, | ||
ServiceBrokerClient, | ||
solution => GetHtmlDocumentTextAsync(solution, razorDocumentId, cancellationToken), | ||
cancellationToken); | ||
|
||
private async ValueTask<string?> GetHtmlDocumentTextAsync(Solution solution, DocumentId razorDocumentId, CancellationToken _) | ||
{ | ||
var razorDocument = solution.GetAdditionalDocument(razorDocumentId); | ||
if (razorDocument is null) | ||
{ | ||
return null; | ||
} | ||
|
||
var documentSnapshot = _documentSnapshotFactory.GetOrCreate(razorDocument); | ||
var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); | ||
|
||
return codeDocument.GetHtmlSourceText().ToString(); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
...src/Microsoft.CodeAnalysis.Remote.Razor/HtmlDocuments/RemoteHtmlDocumentServiceFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using Microsoft.CodeAnalysis.Razor.Remote; | ||
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; | ||
using Microsoft.ServiceHub.Framework; | ||
using Microsoft.VisualStudio.Composition; | ||
|
||
namespace Microsoft.CodeAnalysis.Remote.Razor; | ||
|
||
internal sealed class RemoteHtmlDocumentServiceFactory : RazorServiceFactoryBase<IRemoteHtmlDocumentService> | ||
{ | ||
// WARNING: We must always have a parameterless constructor in order to be properly handled by ServiceHub. | ||
public RemoteHtmlDocumentServiceFactory() | ||
: base(RazorServices.Descriptors) | ||
{ | ||
} | ||
|
||
protected override IRemoteHtmlDocumentService CreateService(IServiceBroker serviceBroker, ExportProvider exportProvider) | ||
{ | ||
var documentSnapshotFactory = exportProvider.GetExportedValue<DocumentSnapshotFactory>(); | ||
return new RemoteHtmlDocumentService(serviceBroker, documentSnapshotFactory); | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
...Microsoft.VisualStudio.LanguageServerClient.Razor/Cohost/CohostTextDocumentSyncHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Composition; | ||
using System.Diagnostics; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Razor; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor; | ||
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; | ||
using Microsoft.CodeAnalysis.Razor.Logging; | ||
using Microsoft.CodeAnalysis.Razor.Remote; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; | ||
using Microsoft.VisualStudio.LanguageServer.Protocol; | ||
using Microsoft.VisualStudio.Threading; | ||
|
||
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Cohost; | ||
|
||
[Export(typeof(IRazorCohostTextDocumentSyncHandler)), Shared] | ||
[method: ImportingConstructor] | ||
internal class CohostTextDocumentSyncHandler( | ||
IRemoteClientProvider remoteClientProvider, | ||
LSPDocumentManager documentManager, | ||
JoinableTaskContext joinableTaskContext, | ||
IRazorLoggerFactory loggerFactory) : IRazorCohostTextDocumentSyncHandler | ||
{ | ||
private readonly IRemoteClientProvider _remoteClientProvider = remoteClientProvider; | ||
private readonly JoinableTaskContext _joinableTaskContext = joinableTaskContext; | ||
private readonly TrackingLSPDocumentManager _documentManager = documentManager as TrackingLSPDocumentManager ?? throw new InvalidOperationException("Expected TrackingLSPDocumentManager"); | ||
private readonly ILogger _logger = loggerFactory.CreateLogger<CohostTextDocumentSyncHandler>(); | ||
|
||
public async Task HandleAsync(int version, RazorCohostRequestContext context, CancellationToken cancellationToken) | ||
{ | ||
// For didClose, we don't need to do anything. We can't close the virtual document, because that requires the buffer | ||
// so we just no-op and let our VS components handle closure. | ||
if (context.Method == Methods.TextDocumentDidCloseName) | ||
{ | ||
return; | ||
} | ||
|
||
var textDocument = context.TextDocument.AssumeNotNull(); | ||
var textDocumentPath = context.TextDocument.FilePath.AssumeNotNull(); | ||
|
||
_logger.LogDebug("[Cohost] {method} of '{document}' with version {version}.", context.Method, textDocumentPath, version); | ||
|
||
var client = await _remoteClientProvider.TryGetClientAsync(cancellationToken); | ||
if (client is null) | ||
{ | ||
_logger.LogError("[Cohost] Couldn't get remote client for {method} of '{document}'. Html document contents will be stale", context.Method, textDocumentPath); | ||
return; | ||
} | ||
|
||
var htmlText = await client.TryInvokeAsync<IRemoteHtmlDocumentService, string?>(textDocument.Project.Solution, | ||
(service, solutionInfo, ct) => service.GetHtmlDocumentTextAsync(solutionInfo, textDocument.Id, ct), | ||
cancellationToken).ConfigureAwait(false); | ||
|
||
if (!htmlText.HasValue || htmlText.Value is null) | ||
{ | ||
_logger.LogError("[Cohost] Couldn't get Html text for {method} of '{document}'. Html document contents will be stale", context.Method, textDocumentPath); | ||
return; | ||
} | ||
|
||
// Eventually, for VS Code, the following piece of logic needs to make an LSP call rather than directly update the buffer | ||
|
||
// Roslyn might have got changes from the LSP server, but we just get the actual source text, so we just construct one giant change | ||
// from that. Guaranteed no sync issues, though we are passing long strings around unfortunately. | ||
var uri = textDocument.CreateUri(); | ||
if (!_documentManager.TryGetDocument(uri, out var documentSnapshot) || | ||
!documentSnapshot.TryGetVirtualDocument<HtmlVirtualDocumentSnapshot>(out var htmlDocument)) | ||
{ | ||
Debug.Fail("Got an LSP text document update before getting informed of the VS buffer"); | ||
_logger.LogError("[Cohost] Couldn't get an Html document for {method} of '{document}'. Html document contents will be stale (or non-existent?)", context.Method, textDocumentPath); | ||
return; | ||
} | ||
|
||
await _joinableTaskContext.Factory.SwitchToMainThreadAsync(cancellationToken); | ||
|
||
VisualStudioTextChange[] changes = [new(0, htmlDocument.Snapshot.Length, htmlText.Value)]; | ||
_documentManager.UpdateVirtualDocument<HtmlVirtualDocument>(uri, changes, version, state: null); | ||
|
||
_logger.LogDebug("[Cohost] Exiting {method} of '{document}' with version {version}.", context.Method, textDocumentPath, version); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters