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
18 changes: 12 additions & 6 deletions src/Stampeded.RoslynLsp/RoslynLspServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ async Task HandleNotificationAsync(string method, JsonElement parameters, Cancel
case "textDocument/didChange":
// The client sends what the review is showing, which may be a revision that
// is not on disk. An overlay is how the workspace is told.
Overlay(parameters);
await OverlayAsync(parameters, ct);
break;
case "initialized":
case "$/cancelRequest":
Expand Down Expand Up @@ -206,8 +206,14 @@ void WatchParent(JsonElement parameters)
});
}

// An event handler cannot await, and the client only needs the notification to arrive
// eventually: the write lock queues waiters in order, so states are still sent in the
// order they were reached.
void ReportState()
=> Notify("stampeded/state", new { state = head.State.ToString(), detail = head.StateDetail });
=> NotifyAsync("stampeded/state", new { state = head.State.ToString(), detail = head.StateDetail })
.ContinueWith(
t => CliLog.Write("roslyn-lsp", $"state notification failed: {t.Exception?.GetBaseException().Message}"),
TaskContinuationOptions.OnlyOnFaulted);

/// <summary>Derives the base-side workspace from the head one, given the texts of the
/// revision being compared against.</summary>
Expand Down Expand Up @@ -242,7 +248,7 @@ static Dictionary<string, string> ReadTexts(JsonElement parameters, string name)
return texts;
}

void Overlay(JsonElement parameters)
async Task OverlayAsync(JsonElement parameters, CancellationToken ct)
{
if (!parameters.TryGetProperty("textDocument", out var document)
|| !document.TryGetProperty("uri", out var uri))
Expand All @@ -261,7 +267,7 @@ void Overlay(JsonElement parameters)
// Only when it differs from what the workspace has: the client opens a document to
// be able to ask about it at all, and re-stating the file on disk would throw away
// the compilation that already knows it.
if (target.Service.GetDocumentTextAsync(target.RelPath, CancellationToken.None).Result is { } current
if (await target.Service.GetDocumentTextAsync(target.RelPath, ct) is { } current
&& string.Equals(current.ReplaceLineEndings("\n"), text.ReplaceLineEndings("\n"), StringComparison.Ordinal))
{
return;
Expand Down Expand Up @@ -619,11 +625,11 @@ async Task RespondAsync(JsonElement id, object? result)
await SendAsync(payload);
}

void Notify(string method, object parameters)
Task NotifyAsync(string method, object parameters)
{
var payload = JsonSerializer.SerializeToUtf8Bytes(
new { jsonrpc = "2.0", method, @params = parameters }, Json);
SendAsync(payload).GetAwaiter().GetResult();
return SendAsync(payload);
}

async Task SendAsync(byte[] payload)
Expand Down
16 changes: 8 additions & 8 deletions tests/Stampeded.Core.Tests/GeneratedSourcesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ public void KeepsOutputOfTheSameGeneratorInDifferentProjectsApart()
}

[Test]
public void PairsTheTwoSidesEvenWhenTheyWereBuiltDifferently()
public async Task PairsTheTwoSidesEvenWhenTheyWereBuiltDifferently()
{
string baseTree = NewDirectory(), headTree = NewDirectory();
Write(baseTree, "src/Lib/obj/Debug/net10.0/generated/G/E/Thing.g.cs", "one\ntwo\n");
Write(headTree, "src/Lib/obj/Release/net11.0/generated/G/E/Thing.g.cs", "one\ntwo changed\n");

var files = GeneratedSources.DiffAsync(baseTree, headTree).GetAwaiter().GetResult();
var files = await GeneratedSources.DiffAsync(baseTree, headTree);

Assert.That(files, Has.Count.EqualTo(1));
Assert.That(files[0].Kind, Is.EqualTo(FileChangeKind.Modified));
Expand All @@ -69,13 +69,13 @@ public void PairsTheTwoSidesEvenWhenTheyWereBuiltDifferently()
}

[Test]
public void ReportsWhatOnlyOneSideGenerated()
public async Task ReportsWhatOnlyOneSideGenerated()
{
string baseTree = NewDirectory(), headTree = NewDirectory();
Write(baseTree, "src/Lib/obj/Debug/net10.0/generated/G/E/Gone.g.cs", "was here\n");
Write(headTree, "src/Lib/obj/Debug/net10.0/generated/G/E/New.g.cs", "is here\n");

var files = GeneratedSources.DiffAsync(baseTree, headTree).GetAwaiter().GetResult();
var files = await GeneratedSources.DiffAsync(baseTree, headTree);

Assert.That(files.Select(f => (f.Path, f.Kind)), Is.EquivalentTo(new[] {
("src/Lib/generated/G/E/Gone.g.cs", FileChangeKind.Deleted),
Expand All @@ -84,24 +84,24 @@ public void ReportsWhatOnlyOneSideGenerated()
}

[Test]
public void LeavesOutGeneratedFilesTheChangeDidNotMove()
public async Task LeavesOutGeneratedFilesTheChangeDidNotMove()
{
string baseTree = NewDirectory(), headTree = NewDirectory();
Write(baseTree, "src/Lib/obj/Debug/net10.0/generated/G/E/Same.g.cs", "unchanged\n");
Write(headTree, "src/Lib/obj/Debug/net10.0/generated/G/E/Same.g.cs", "unchanged\n");

Assert.That(GeneratedSources.DiffAsync(baseTree, headTree).GetAwaiter().GetResult(), Is.Empty,
Assert.That(await GeneratedSources.DiffAsync(baseTree, headTree), Is.Empty,
"a generator whose output stands still is not part of the change");
}

[Test]
public void CarriesWhereEachSideCanBeReadFrom()
public async Task CarriesWhereEachSideCanBeReadFrom()
{
string baseTree = NewDirectory(), headTree = NewDirectory();
Write(baseTree, "src/Lib/obj/Debug/net10.0/generated/G/E/Thing.g.cs", "before\n");
Write(headTree, "src/Lib/obj/Debug/net10.0/generated/G/E/Thing.g.cs", "after\n");

var file = GeneratedSources.DiffAsync(baseTree, headTree).GetAwaiter().GetResult().Single();
var file = (await GeneratedSources.DiffAsync(baseTree, headTree)).Single();

// Nothing can read these out of a commit, so the diff has to say where they are.
Assert.That(file.IsGenerated, Is.True);
Expand Down