Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lsp-progress #2649

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
11 changes: 9 additions & 2 deletions src/OmniSharp.Abstractions/Eventing/IEventEmitterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public static void UnresolvedDepdendencies(this IEventEmitter emitter, string pr
});
}

public static void ProjectLoadingStarted(this IEventEmitter emitter, string projectPath) =>
emitter.Emit(
EventTypes.ProjectLoadingStarted,
projectPath);

public static void ProjectInformation(this IEventEmitter emitter,
HashedString projectId,
HashedString sessionId,
Expand All @@ -55,7 +60,8 @@ public static void ProjectInformation(this IEventEmitter emitter,
IEnumerable<HashedString> references,
IEnumerable<HashedString> fileExtensions,
IEnumerable<int> fileCounts,
bool sdkStyleProject)
bool sdkStyleProject,
string projectFilePath)
{
var projectConfiguration = new ProjectConfigurationMessage()
{
Expand All @@ -68,7 +74,8 @@ public static void ProjectInformation(this IEventEmitter emitter,
References = references.Select(hashed => hashed.Value),
FileExtensions = fileExtensions.Select(hashed => hashed.Value),
FileCounts = fileCounts,
SdkStyleProject = sdkStyleProject
SdkStyleProject = sdkStyleProject,
ProjectFilePath = projectFilePath
};

emitter.Emit(
Expand Down
1 change: 1 addition & 0 deletions src/OmniSharp.Abstractions/Models/Events/EventTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace OmniSharp.Models.Events
{
public static class EventTypes
{
public const string ProjectLoadingStarted = nameof(ProjectLoadingStarted);
public const string ProjectAdded = nameof(ProjectAdded);
public const string ProjectChanged = nameof(ProjectChanged);
public const string ProjectRemoved = nameof(ProjectRemoved);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ public class ProjectConfigurationMessage
public IEnumerable<string> FileExtensions { get; set; }
public IEnumerable<int> FileCounts { get; set; }
public bool SdkStyleProject { get; set; }
public string ProjectFilePath { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Concurrent;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
Expand All @@ -6,6 +7,7 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Extensions.LanguageServer.Protocol.Server.WorkDone;
using OmniSharp.LanguageServerProtocol.Handlers;
using OmniSharp.Models.Diagnostics;
using OmniSharp.Models.Events;
Expand All @@ -16,6 +18,8 @@ public class LanguageServerEventEmitter : IEventEmitter
{
private readonly ILanguageServer _server;
private readonly DocumentVersions _documentVersions;
private readonly ConcurrentDictionary<string, IWorkDoneObserver> _projectObservers = new();
private IWorkDoneObserver _restoreObserver;

public LanguageServerEventEmitter(ILanguageServer server)
{
Expand Down Expand Up @@ -46,6 +50,14 @@ public void Emit(string kind, object args)
}
}
break;
case EventTypes.ProjectLoadingStarted:
string projectPath = (string)args;
IWorkDoneObserver projectObserver = _server.WorkDoneManager
.Create(new WorkDoneProgressBegin { Title = $"Loading {projectPath}" })
.GetAwaiter()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can we change signature to async here?

.GetResult();
_projectObservers.TryAdd(projectPath, projectObserver);
break;
case EventTypes.ProjectAdded:
case EventTypes.ProjectChanged:
case EventTypes.ProjectRemoved:
Expand All @@ -54,13 +66,31 @@ public void Emit(string kind, object args)

// work done??
case EventTypes.PackageRestoreStarted:
_server.SendNotification($"o#/{kind}".ToLowerInvariant(), JToken.FromObject(args));
_restoreObserver = _server.WorkDoneManager
.Create(new WorkDoneProgressBegin { Title = "Restoring" })
.GetAwaiter()
.GetResult();
break;
case EventTypes.PackageRestoreFinished:
_server.SendNotification($"o#/{kind}".ToLowerInvariant(), JToken.FromObject(args));
_restoreObserver.OnNext(new WorkDoneProgressReport { Message = "Restored" });
_restoreObserver.OnCompleted();
break;
case EventTypes.UnresolvedDependencies:
_server.SendNotification($"o#/{kind}".ToLowerInvariant(), JToken.FromObject(args));
break;

case EventTypes.Error:
case EventTypes.ProjectConfiguration:
_server.SendNotification($"o#/{kind}".ToLowerInvariant(), JToken.FromObject(args));
ProjectConfigurationMessage projectMessage = (ProjectConfigurationMessage)args;
if (_projectObservers.TryGetValue(projectMessage.ProjectFilePath, out IWorkDoneObserver obs))
{
obs.OnNext(new WorkDoneProgressReport { Message = $"Loaded {projectMessage.ProjectFilePath}" });
obs.OnCompleted();
}
break;
case EventTypes.ProjectDiagnosticStatus:
_server.SendNotification($"o#/{kind}".ToLowerInvariant(), JToken.FromObject(args));
break;
Expand Down
35 changes: 29 additions & 6 deletions src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class LanguageServerHost : IDisposable
private CompositionHost _compositionHost;
private IServiceProvider _serviceProvider;
private readonly Action<ILoggingBuilder> _configureLogging;
private IObserver<WorkDoneProgressReport> _workDoneObserver;

public LanguageServerHost(
Stream input,
Expand All @@ -65,6 +66,7 @@ public LanguageServerHost(
.ConfigureLogging(AddLanguageProtocolLogging(application.LogLevel))
.OnInitialize(Initialize)
.OnInitialized(Initialized)
.OnStarted(Started)
.WithServices(ConfigureServices);

_application = application;
Expand Down Expand Up @@ -137,6 +139,19 @@ public async Task Start()

logger.LogInformation($"Omnisharp server running using Lsp at location '{environment.TargetDirectory}' on host {environment.HostProcessId}.");

await Task.WhenAll(
_compositionHost
.GetExports<IProjectSystem>()
.Select(ps => ps.WaitForIdleAsync())
.ToArray());

_workDoneObserver?.OnNext(new WorkDoneProgressReport
{
Message = "Language Server ready",
Percentage = 100,
});
_workDoneObserver?.OnCompleted();

Console.CancelKeyPress += (sender, e) =>
{
Cancel();
Expand Down Expand Up @@ -330,6 +345,7 @@ static Func<JToken, CancellationToken, Task<JToken>> CreateInteropHandler(
private Task Initialize(ILanguageServer server, InitializeParams initializeParams,
CancellationToken cancellationToken)
{
_workDoneObserver = server.WorkDoneManager.For(initializeParams, new WorkDoneProgressBegin { Message = "Initialize Language Server" });
(_serviceProvider, _compositionHost) =
CreateCompositionHost(server, initializeParams, _application, _services, _configureLogging);
var handlers = ConfigureCompositionHost(server, _compositionHost);
Expand All @@ -342,18 +358,25 @@ private Task Initialize(ILanguageServer server, InitializeParams initializeParam
_serviceProvider.GetRequiredService<IFileSystemNotifier>()));
});

_workDoneObserver.OnNext(new WorkDoneProgressReport { Message = "Initialized handlers", Percentage = 10 });
return Task.CompletedTask;
}

public async Task Initialized(ILanguageServer server, InitializeParams request, InitializeResult response, CancellationToken cancellationToken)
public Task Initialized(ILanguageServer server, InitializeParams request, InitializeResult response, CancellationToken cancellationToken)
{
_workDoneObserver.OnNext(new WorkDoneProgressReport { Message = "Initialize workspace", Percentage = 20 });
WorkspaceInitializer.Initialize(_serviceProvider, _compositionHost);
return Task.CompletedTask;
}

await Task.WhenAll(
_compositionHost
.GetExports<IProjectSystem>()
.Select(ps => ps.WaitForIdleAsync())
.ToArray());
public Task Started(ILanguageServer server, CancellationToken cancellationToken)
{
_workDoneObserver.OnNext(new WorkDoneProgressReport
{
Message = "Language Server started",
Percentage = 30,
});
return Task.CompletedTask;
}

internal void UnderTest(IServiceProvider serviceProvider, CompositionHost compositionHost)
Expand Down
1 change: 1 addition & 0 deletions src/OmniSharp.MSBuild/Notification/IMSBuildEventSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
public interface IMSBuildEventSink
{
void ProjectLoadingStarted(string projectPath);
void ProjectLoaded(ProjectLoadedEventArgs e);
}
}
16 changes: 15 additions & 1 deletion src/OmniSharp.MSBuild/ProjectLoadListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public ProjectLoadListener(ILoggerFactory loggerFactory, IEventEmitter eventEmit
_eventEmitter = eventEmitter;
}

public void ProjectLoadingStarted(string projectPath) =>
_eventEmitter.ProjectLoadingStarted(projectPath);

public void ProjectLoaded(ProjectLoadedEventArgs args)
{
try
Expand All @@ -53,7 +56,18 @@ public void ProjectLoaded(ProjectLoadedEventArgs args)
var (hashedFileExtensions, fileCounts) = GetUniqueHashedFileExtensionsAndCounts(args);

var sdkStyleProject = IsSdkStyleProject(args);
_eventEmitter.ProjectInformation(projectId, sessionId, (int)outputKind, projectCapabilities, targetFrameworks, sdkVersion, hashedReferences, hashedFileExtensions, fileCounts, sdkStyleProject);
_eventEmitter.ProjectInformation(
projectId,
sessionId,
(int)outputKind,
projectCapabilities,
targetFrameworks,
sdkVersion,
hashedReferences,
hashedFileExtensions,
fileCounts,
sdkStyleProject,
args.Project.ProjectFileLocation.File);
}
catch (Exception ex)
{
Expand Down
19 changes: 15 additions & 4 deletions src/OmniSharp.MSBuild/ProjectManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using OmniSharp.Eventing;
Expand All @@ -18,15 +20,13 @@
using OmniSharp.MSBuild.Models.Events;
using OmniSharp.MSBuild.Notification;
using OmniSharp.MSBuild.ProjectFile;
using OmniSharp.Options;
using OmniSharp.Roslyn.CSharp.Services.Diagnostics;
using OmniSharp.Roslyn.CSharp.Services.Refactoring.V2;
using OmniSharp.Options;
using OmniSharp.Roslyn.EditorConfig;
using OmniSharp.Roslyn.Utilities;
using OmniSharp.Services;
using OmniSharp.Utilities;
using System.Reflection;
using Microsoft.CodeAnalysis.Diagnostics;
using OmniSharp.Roslyn.EditorConfig;

namespace OmniSharp.MSBuild
{
Expand Down Expand Up @@ -310,6 +310,17 @@ private void ProcessQueue(CancellationToken cancellationToken)
private (ProjectFileInfo, ProjectLoadedEventArgs) LoadOrReloadProject(string projectFilePath, Func<(ProjectFileInfo, ImmutableArray<MSBuildDiagnostic>, ProjectLoadedEventArgs)> loader)
{
_logger.LogInformation($"Loading project: {projectFilePath}");
foreach (IMSBuildEventSink eventSink in _eventSinks)
{
try
{
eventSink.ProjectLoadingStarted(projectFilePath);
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception thrown while calling event sinks");
}
}

try
{
Expand Down
4 changes: 4 additions & 0 deletions tests/OmniSharp.MSBuild.Tests/NotificationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public void ProjectLoaded(ProjectLoadedEventArgs e)
{
_onLoaded(e);
}

public void ProjectLoadingStarted(string projectPath)
{
}
}

[Fact]
Expand Down
Loading