Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ internal abstract class AbstractRefreshQueue :
private readonly CancellationTokenSource _disposalTokenSource;
private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService;

protected bool _isQueueCreated;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed this. we already have the presence/absence of the queue we can check.


protected abstract string GetFeatureAttribute();
protected abstract bool? GetRefreshSupport(ClientCapabilities clientCapabilities);
protected abstract string GetWorkspaceRefreshName();
Expand All @@ -42,7 +40,6 @@ public AbstractRefreshQueue(
LspWorkspaceManager lspWorkspaceManager,
IClientLanguageServerManager notificationManager)
{
_isQueueCreated = false;
_asyncListener = asynchronousOperationListenerProvider.GetListener(GetFeatureAttribute());
_lspWorkspaceRegistrationService = lspWorkspaceRegistrationService;
_disposalTokenSource = new();
Expand Down Expand Up @@ -71,7 +68,6 @@ public void Initialize(ClientCapabilities clientCapabilities)
equalityComparer: EqualityComparer<DocumentUri?>.Default,
asyncListener: _asyncListener,
_disposalTokenSource.Token);
_isQueueCreated = true;
_lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged;
}
}
Expand All @@ -95,16 +91,15 @@ protected virtual void OnLspSolutionChanged(object? sender, WorkspaceChangeEvent
}
}

/// <summary>
/// Enqueues a request to refresh the workspace. If <paramref name="documentUri"/> is null, then the refresh will
/// always happen. If non-null, the refresh will only happen if the client is <em>not</em> tracking that document.
/// If the client is tracking the document, no refresh is necessary as the client clearly knows about the change.
/// </summary>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added docs as the semantics weren't previous clear to me.

protected void EnqueueRefreshNotification(DocumentUri? documentUri)
{
if (_isQueueCreated)
{
Contract.ThrowIfNull(_refreshQueue);
_refreshQueue.AddWork(documentUri);
}
}
=> _refreshQueue?.AddWork(documentUri);

private ValueTask FilterLspTrackedDocumentsAsync(
private async ValueTask FilterLspTrackedDocumentsAsync(
LspWorkspaceManager lspWorkspaceManager,
IClientLanguageServerManager notificationManager,
ImmutableSegmentedList<DocumentUri?> documentUris,
Expand All @@ -117,7 +112,11 @@ private ValueTask FilterLspTrackedDocumentsAsync(
{
try
{
return notificationManager.SendRequestAsync(GetWorkspaceRefreshName(), cancellationToken);
// Fire the notification and immediately return. Refresh notifications are server-wide, and are not
// associated with a particular project/document. So once we've sent one, we can stop processing
// entirely.
await notificationManager.SendRequestAsync(GetWorkspaceRefreshName(), cancellationToken).ConfigureAwait(false);
return;
}
catch (Exception ex) when (ex is ObjectDisposedException or ConnectionLostException)
{
Expand All @@ -128,7 +127,6 @@ private ValueTask FilterLspTrackedDocumentsAsync(
}

// LSP is already tracking all changed documents so we don't need to send a refresh request.
return ValueTask.CompletedTask;
}

public virtual void Dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,27 +120,25 @@ await newProject.GetDependentVersionAsync(_disposalTokenSource.Token).ConfigureA
}
}

private ValueTask RefreshSourceGeneratedDocumentsAsync(
private async ValueTask RefreshSourceGeneratedDocumentsAsync(
CancellationToken cancellationToken)
{
var hasOpenSourceGeneratedDocuments = _lspWorkspaceManager.GetTrackedLspText().Keys.Any(uri => uri.ParsedUri?.Scheme == SourceGeneratedDocumentUri.Scheme);
if (!hasOpenSourceGeneratedDocuments)
{
// There are no opened source generated documents - we don't need to bother asking the client to refresh anything.
return ValueTask.CompletedTask;
return;
}

try
{
return _notificationManager.SendNotificationAsync(RefreshSourceGeneratedDocumentName, cancellationToken);
await _notificationManager.SendNotificationAsync(RefreshSourceGeneratedDocumentName, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex) when (ex is ObjectDisposedException or ConnectionLostException)
{
// It is entirely possible that we're shutting down and the connection is lost while we're trying to send a notification
// as this runs outside of the guaranteed ordering in the queue. We can safely ignore this exception.
}

return ValueTask.CompletedTask;
}

public void Dispose()
Expand Down
Loading