Skip to content

Conversation

@davidwengier
Copy link
Member

As part of porting cohosting to VS Code we need to implement the Html document sync system, but my original implementation here was quite leaky. This fixes that, but making the synchronizer and publisher just do the job their names imply, and abstracting away any ContainedLanguage dependency from the endpoints. It also abstract it away from the synchronizer, so that can be shared, which is good since its complicated. The publisher will have to be re-implemented, but its implementation will be different enough that it makes sense.

Review commit-at-a-time probably is easiest, and I must admit, I fixed a couple of minor things in the middle that aren't strictly related :)

After allowing for telemetry in the API, I realised diagnostics and completion in cohosting never got any actual code for it written 🤦‍♂️
The "generate code" bit of the publisher is IDE-agnostic, the rest isn't, so it would have had to be duplicated.

Plus it was a terrible abstraction, I've no idea what I was thinking. I would introduce an IHtmlDocumentGenerator but it seems like overkill.
@davidwengier davidwengier requested a review from a team as a code owner April 22, 2025 08:53
Copy link
Contributor

@ryzngard ryzngard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Had some small nits and questions about design as a whole, and one musing that is unrelated to the PR but made me think of it.

public async Task TrySynchronize_NewDocument_Generates()
{
var publisher = new TestHtmlDocumentPublisher();
var synchronizer = new HtmlDocumentSynchronizer(StrictMock.Of<TrackingLSPDocumentManager>(), publisher, LoggerFactory);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥳

public static Task<TResponse?> MakeHtmlLspRequestAsync<TRequest, TResponse>(this IHtmlRequestInvoker requestInvoker, TextDocument razorDocument, string method, TRequest request, CancellationToken cancellationToken)
where TRequest : notnull
{
return requestInvoker.MakeHtmlLspRequestAsync<TRequest, TResponse>(razorDocument, method, request, threshold: TimeSpan.Zero, correlationId: Guid.Empty, cancellationToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what instances do we not want a correlation id?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever we don't want telemetry for a request. Currently we only report for map code, diagnostics, semantic tokens and completion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha. Do we plan on adding to those?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your guess is as good as mine.

Comment on lines +34 to +41
var syncResult = await _htmlDocumentSynchronizer.TrySynchronizeAsync(razorDocument, cancellationToken).ConfigureAwait(false);
if (!syncResult)
{
_logger.LogDebug($"Couldn't synchronize for {razorDocument.FilePath}");
return default;
}

if (!_documentManager.TryGetDocument(razorDocument.CreateUri(), out var snapshot))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not specifically for this review, but it always felt weird to me to have a pattern of

var synchronized = TrySynchronize();
....
var snapshot = GetSnapshot()

This could just be a separation of interests. But the synchronization result could include the snapshot that it synchronized for. In a purely "snapshot" based way that is more accurate than allowing something else to publish in between these two calls.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the synchronization result could include the snapshot that it synchronized for.

This is what it used to be like, and I agree it feels weird to "wait" for synchronization without getting something meaningful back, but in VS Code there is no snapshot, its really just "wait for the document to have been published". If the sync result included the snapshot, then the sync code can't be shared.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love to take this offline and workshop a bit. It seems like we could fix this, but it would be an infectious change rather than an isolated change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to. I did have an IHtmlDocumentResult so VS Code and VS could have their own "buffer"/"snapshot" types, but in VS Code it only needs the Uri, so the abstraction was useless.


_logger.LogDebug($"Making LSP request for {method} from {htmlDocument.Uri}{(request is ITextDocumentPositionParams positionParams ? $" at {positionParams.Position}" : "")}.");

// Passing Guid.Empty to this method will mean no tracking
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be the pattern everywhere, not sure why it's specifically called out here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to reassure readers that I didn't forget argument validation

@davidwengier davidwengier enabled auto-merge April 23, 2025 02:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants