-
Notifications
You must be signed in to change notification settings - Fork 418
/
LanguageServerHost.cs
195 lines (170 loc) · 7.43 KB
/
LanguageServerHost.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
using System;
using System.Collections.Generic;
using System.Composition.Hosting;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using OmniSharp.Endpoint;
using OmniSharp.Extensions.LanguageServer;
using OmniSharp.Models.UpdateBuffer;
using OmniSharp.Plugins;
using OmniSharp.Services;
using OmniSharp.LanguageServerProtocol.Logging;
using OmniSharp.Utilities;
using OmniSharp.Stdio.Services;
using OmniSharp.Models.ChangeBuffer;
using OmniSharp.Mef;
using OmniSharp.Models.Diagnostics;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using OmniSharp.LanguageServerProtocol.Eventing;
using OmniSharp.Extensions.LanguageServer.Models;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.LanguageServerProtocol.Handlers;
namespace OmniSharp.LanguageServerProtocol
{
class LanguageServerHost : IDisposable
{
private readonly LanguageServer _server;
private CompositionHost _compositionHost;
private ILoggerFactory _loggerFactory;
private readonly CommandLineApplication _application;
private readonly CancellationTokenSource _cancellationTokenSource;
private IConfiguration _configuration;
private IServiceProvider _serviceProvider;
private IEnumerable<IRequestHandler> _handlers;
private OmniSharpEnvironment _environment;
public LanguageServerHost(
Stream input,
Stream output,
CommandLineApplication application,
CancellationTokenSource cancellationTokenSource)
{
_server = new LanguageServer(input, output);
_server.OnInitialize(Initialize);
_application = application;
_cancellationTokenSource = cancellationTokenSource;
}
public void Dispose()
{
_compositionHost?.Dispose();
_loggerFactory?.Dispose();
_cancellationTokenSource?.Dispose();
}
private static LogLevel GetLogLevel(InitializeTrace initializeTrace)
{
switch (initializeTrace)
{
case InitializeTrace.verbose:
return LogLevel.Trace;
case InitializeTrace.off:
return LogLevel.Warning;
case InitializeTrace.messages:
default:
return LogLevel.Information;
}
}
private void CreateCompositionHost(InitializeParams initializeParams)
{
_server.LogMessage(new LogMessageParams()
{
Message = Helpers.FromUri(initializeParams.RootUri),
Type = MessageType.Warning
});
_environment = new OmniSharpEnvironment(
Helpers.FromUri(initializeParams.RootUri),
Convert.ToInt32(initializeParams.ProcessId ?? -1L),
GetLogLevel(initializeParams.Trace),
_application.OtherArgs.ToArray());
_configuration = new ConfigurationBuilder(_environment).Build();
_serviceProvider = CompositionHostBuilder.CreateDefaultServiceProvider(_configuration);
_loggerFactory = _serviceProvider.GetRequiredService<ILoggerFactory>()
.AddLanguageServer(_server, (category, level) => HostHelpers.LogFilter(category, level, _environment));
var eventEmitter = new LanguageServerEventEmitter(_server);
var plugins = _application.CreatePluginAssemblies();
var compositionHostBuilder = new CompositionHostBuilder(_serviceProvider, _environment, eventEmitter)
.WithOmniSharpAssemblies()
.WithAssemblies(typeof(LanguageServerHost).Assembly)
.WithAssemblies(plugins.AssemblyNames.Select(Assembly.Load).ToArray());
_compositionHost = compositionHostBuilder.Build();
// TODO: Get these with metadata so we can attach languages
// This will thne let us build up a better document filter, and add handles foreach type of handler
// This will mean that we will have a strategy to create handlers from the interface type
_handlers = _compositionHost.GetExports<IRequestHandler>();
}
private Task Initialize(InitializeParams initializeParams)
{
CreateCompositionHost(initializeParams);
// TODO: Will need to be updated for Cake, etc
var documentSelector = new DocumentSelector(
new DocumentFilter()
{
Pattern = "**/*.cs",
Language = "csharp",
}
);
// TODO: Make it easier to resolve handlers from MEF (without having to add more attributes to the services if we can help it)
var workspace = _compositionHost.GetExport<OmniSharpWorkspace>();
_server.AddHandler(new TextDocumentSyncHandler(_handlers, documentSelector, workspace));
_server.AddHandler(new DefinitionHandler(_handlers, documentSelector));
_server.AddHandler(new HoverHandler(_handlers, documentSelector));
_server.LogMessage(new LogMessageParams() {
Message = "Added handlers... waiting for initialize...",
Type = MessageType.Log
});
return Task.CompletedTask;
}
public async Task Start()
{
// TODO: Will need to be updated for Cake, etc
var documentSelector = new DocumentSelector(
new DocumentFilter()
{
Pattern = "**/*.cs",
Language = "csharp",
}
);
_server.LogMessage(new LogMessageParams() {
Message = "Starting server...",
Type = MessageType.Log
});
await _server.Initialize();
_server.LogMessage(new LogMessageParams()
{
Message = "initialized...",
Type = MessageType.Log
});
var logger = _loggerFactory.CreateLogger(typeof(LanguageServerHost));
WorkspaceInitializer.Initialize(_serviceProvider, _compositionHost, _configuration, logger);
// Kick on diagnostics
var diagnosticHandler = _handlers.OfType<IRequestHandler<DiagnosticsRequest, DiagnosticsResponse>>().Single();
await diagnosticHandler.Handle(new DiagnosticsRequest());
logger.LogInformation($"Omnisharp server running using Lsp at location '{_environment.TargetDirectory}' on host {_environment.HostProcessId}.");
Console.CancelKeyPress += (sender, e) =>
{
_cancellationTokenSource.Cancel();
e.Cancel = true;
};
if (_environment.HostProcessId != -1)
{
try
{
var hostProcess = Process.GetProcessById(_environment.HostProcessId);
hostProcess.EnableRaisingEvents = true;
hostProcess.OnExit(() => _cancellationTokenSource.Cancel());
}
catch
{
// If the process dies before we get here then request shutdown
// immediately
_cancellationTokenSource.Cancel();
}
}
}
}
}