Upsilon-VsCode/UpsilonLanguageServer/UpsilonLanguageServer/Program.cs

104 lines
4.2 KiB
C#

// #define WAIT_FOR_DEBUGGER
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using JsonRpc.Standard.Client;
using JsonRpc.Standard.Contracts;
using JsonRpc.Standard.Server;
using JsonRpc.Streams;
using LanguageServer.VsCode;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Debug;
namespace UpsilonLanguageServer
{
static class Program
{
static void Main(string[] args)
{
var debugMode = args.Any(a => a.Equals("--debug", StringComparison.OrdinalIgnoreCase));
#if WAIT_FOR_DEBUGGER
while (!Debugger.IsAttached) Thread.Sleep(1000);
Debugger.Break();
#endif
StreamWriter logWriter = null;
if (debugMode)
{
logWriter = File.CreateText("messages-" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".log");
logWriter.AutoFlush = true;
}
using (logWriter)
using (var cin = Console.OpenStandardInput())
using (var bcin = new BufferedStream(cin))
using (var cout = Console.OpenStandardOutput())
using (var reader = new PartwiseStreamMessageReader(bcin))
using (var writer = new PartwiseStreamMessageWriter(cout))
{
var contractResolver = new JsonRpcContractResolver
{
NamingStrategy = new CamelCaseJsonRpcNamingStrategy(),
ParameterValueConverter = new CamelCaseJsonValueConverter(),
};
var clientHandler = new StreamRpcClientHandler();
var client = new JsonRpcClient(clientHandler);
if (debugMode)
{
// We want to capture log all the LSP server-to-client calls as well
clientHandler.MessageSending += (_, e) =>
{
lock (logWriter) logWriter.WriteLine("{0} <C{1}", Utility.GetTimeStamp(), e.Message);
};
clientHandler.MessageReceiving += (_, e) =>
{
lock (logWriter) logWriter.WriteLine("{0} >C{1}", Utility.GetTimeStamp(), e.Message);
};
}
// Configure & build service host
var session = new LanguageServerSession(client, contractResolver);
var host = BuildServiceHost(logWriter, contractResolver, debugMode);
var serverHandler = new StreamRpcServerHandler(host,
StreamRpcServerHandlerOptions.ConsistentResponseSequence |
StreamRpcServerHandlerOptions.SupportsRequestCancellation);
serverHandler.DefaultFeatures.Set(session);
// If we want server to stop, just stop the "source"
using (serverHandler.Attach(reader, writer))
using (clientHandler.Attach(reader, writer))
{
// Wait for the "stop" request.
session.CancellationToken.WaitHandle.WaitOne();
}
logWriter?.WriteLine("Exited");
}
}
private static IJsonRpcServiceHost BuildServiceHost(TextWriter logWriter,
IJsonRpcContractResolver contractResolver, bool debugMode)
{
var loggerFactory = new LoggerFactory();
loggerFactory.AddProvider(new DebugLoggerProvider(null));
var builder = new JsonRpcServiceHostBuilder
{
ContractResolver = contractResolver,
LoggerFactory = loggerFactory
};
builder.UseCancellationHandling();
builder.Register(typeof(Program).GetTypeInfo().Assembly);
if (debugMode)
{
// Log all the client-to-server calls.
builder.Intercept(async (context, next) =>
{
lock (logWriter) logWriter.WriteLine("{0} > {1}", Utility.GetTimeStamp(), context.Request);
await next();
lock (logWriter) logWriter.WriteLine("{0} < {1}", Utility.GetTimeStamp(), context.Response);
});
}
return builder.Build();
}
}
}