Skip to content

Commit 8b8a445

Browse files
initial non-working dap
1 parent 8b4d407 commit 8b8a445

File tree

6 files changed

+260
-13
lines changed

6 files changed

+260
-13
lines changed

NuGet.Config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<add key="disableSourceControlIntegration" value="true" />
55
</solution>
66
<packageSources>
7+
<add key="local" value="/Users/tyler/Code/CSharp/csharp-language-server-protocol/artifacts/nuget" />
78
<add key="omnisharp" value="https://www.myget.org/F/omnisharp/api/v3/index.json" protocolVersion="3" />
89
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
910
</packageSources>

PowerShellEditorServices.build.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ $script:RequiredBuildAssets = @{
6464
'publish/OmniSharp.Extensions.JsonRpc.dll',
6565
'publish/OmniSharp.Extensions.LanguageProtocol.dll',
6666
'publish/OmniSharp.Extensions.LanguageServer.dll',
67+
'publish/OmniSharp.Extensions.DebugAdapter.dll',
68+
'publish/OmniSharp.Extensions.DebugAdapter.Server.dll',
6769
'publish/runtimes/linux-64/native/libdisablekeyecho.so',
6870
'publish/runtimes/osx-64/native/libdisablekeyecho.dylib',
6971
'publish/Serilog.dll',

src/PowerShellEditorServices.Engine/Hosting/EditorServicesHost.cs

Lines changed: 123 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
using System;
77
using System.Collections.Generic;
88
using System.Diagnostics;
9+
using System.IO.Pipes;
910
using System.Linq;
1011
using System.Management.Automation;
1112
using System.Management.Automation.Host;
1213
using System.Reflection;
1314
using System.Runtime.InteropServices;
15+
using System.Security.AccessControl;
16+
using System.Security.Principal;
1417
using System.Threading;
1518
using System.Threading.Tasks;
1619
using Microsoft.Extensions.Logging;
@@ -58,6 +61,15 @@ public class EditorServicesHost
5861
{
5962
#region Private Fields
6063

64+
// This int will be casted to a PipeOptions enum that only exists in .NET Core 2.1 and up which is why it's not available to us in .NET Standard.
65+
private const int CurrentUserOnly = 0x20000000;
66+
67+
// In .NET Framework, NamedPipeServerStream has a constructor that takes in a PipeSecurity object. We will use reflection to call the constructor,
68+
// since .NET Framework doesn't have the `CurrentUserOnly` PipeOption.
69+
// doc: https://docs.microsoft.com/en-us/dotnet/api/system.io.pipes.namedpipeserverstream.-ctor?view=netframework-4.7.2#System_IO_Pipes_NamedPipeServerStream__ctor_System_String_System_IO_Pipes_PipeDirection_System_Int32_System_IO_Pipes_PipeTransmissionMode_System_IO_Pipes_PipeOptions_System_Int32_System_Int32_System_IO_Pipes_PipeSecurity_
70+
private static readonly ConstructorInfo s_netFrameworkPipeServerConstructor =
71+
typeof(NamedPipeServerStream).GetConstructor(new[] { typeof(string), typeof(PipeDirection), typeof(int), typeof(PipeTransmissionMode), typeof(PipeOptions), typeof(int), typeof(int), typeof(PipeSecurity) });
72+
6173
private readonly HostDetails _hostDetails;
6274

6375
private readonly PSHost _internalHost;
@@ -69,6 +81,7 @@ public class EditorServicesHost
6981
private readonly string[] _additionalModules;
7082

7183
private PsesLanguageServer _languageServer;
84+
private PsesDebugServer _debugServer;
7285

7386
private Microsoft.Extensions.Logging.ILogger _logger;
7487

@@ -229,8 +242,6 @@ public void StartLanguageService(
229242

230243
_logger.LogInformation($"LSP NamedPipe: {config.InOutPipeName}\nLSP OutPipe: {config.OutPipeName}");
231244

232-
233-
234245
switch (config.TransportType)
235246
{
236247
case EditorServiceTransportType.NamedPipe:
@@ -280,17 +291,42 @@ public void StartDebugService(
280291
ProfilePaths profilePaths,
281292
bool useExistingSession)
282293
{
283-
/*
284-
this.debugServiceListener = CreateServiceListener(MessageProtocolType.DebugAdapter, config);
285-
this.debugServiceListener.ClientConnect += OnDebugServiceClientConnect;
286-
this.debugServiceListener.Start();
294+
while (!System.Diagnostics.Debugger.IsAttached)
295+
{
296+
System.Console.WriteLine($"{Process.GetCurrentProcess().Id}");
297+
Thread.Sleep(2000);
298+
}
287299

288-
this.logger.Write(
289-
LogLevel.Normal,
290-
string.Format(
291-
"Debug service started, type = {0}, endpoint = {1}",
292-
config.TransportType, config.Endpoint));
293-
*/
300+
_logger.LogInformation($"Debug NamedPipe: {config.InOutPipeName}\nDebug OutPipe: {config.OutPipeName}");
301+
302+
switch (config.TransportType)
303+
{
304+
case EditorServiceTransportType.NamedPipe:
305+
NamedPipeServerStream inNamedPipe = CreateNamedPipe(
306+
config.InOutPipeName ?? config.InPipeName,
307+
config.OutPipeName,
308+
out NamedPipeServerStream outNamedPipe);
309+
310+
_debugServer = new PsesDebugServer(
311+
_factory,
312+
inNamedPipe,
313+
outNamedPipe ?? inNamedPipe);
314+
315+
Task[] tasks = outNamedPipe != null
316+
? new[] { inNamedPipe.WaitForConnectionAsync(), outNamedPipe.WaitForConnectionAsync() }
317+
: new[] { inNamedPipe.WaitForConnectionAsync() };
318+
Task.WhenAll(tasks)
319+
.ContinueWith(async task => {
320+
_logger.LogInformation("Starting debug server");
321+
await _debugServer.StartAsync();
322+
_logger.LogInformation(
323+
$"Debug service started, type = {config.TransportType}, endpoint = {config.Endpoint}");
324+
});
325+
break;
326+
327+
default:
328+
throw new NotSupportedException("not supported");
329+
}
294330
}
295331

296332
/// <summary>
@@ -350,6 +386,81 @@ private void CurrentDomain_UnhandledException(
350386
_logger.LogError($"FATAL UNHANDLED EXCEPTION: {e.ExceptionObject}");
351387
}
352388

389+
private static NamedPipeServerStream CreateNamedPipe(
390+
string inOutPipeName,
391+
string outPipeName,
392+
out NamedPipeServerStream outPipe)
393+
{
394+
// .NET Core implementation is simplest so try that first
395+
if (VersionUtils.IsNetCore)
396+
{
397+
outPipe = outPipeName == null
398+
? null
399+
: new NamedPipeServerStream(
400+
pipeName: outPipeName,
401+
direction: PipeDirection.Out,
402+
maxNumberOfServerInstances: 1,
403+
transmissionMode: PipeTransmissionMode.Byte,
404+
options: (PipeOptions)CurrentUserOnly);
405+
406+
return new NamedPipeServerStream(
407+
pipeName: inOutPipeName,
408+
direction: PipeDirection.InOut,
409+
maxNumberOfServerInstances: 1,
410+
transmissionMode: PipeTransmissionMode.Byte,
411+
options: PipeOptions.Asynchronous | (PipeOptions)CurrentUserOnly);
412+
}
413+
414+
// Now deal with Windows PowerShell
415+
// We need to use reflection to get a nice constructor
416+
417+
var pipeSecurity = new PipeSecurity();
418+
419+
WindowsIdentity identity = WindowsIdentity.GetCurrent();
420+
WindowsPrincipal principal = new WindowsPrincipal(identity);
421+
422+
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
423+
{
424+
// Allow the Administrators group full access to the pipe.
425+
pipeSecurity.AddAccessRule(new PipeAccessRule(
426+
new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).Translate(typeof(NTAccount)),
427+
PipeAccessRights.FullControl, AccessControlType.Allow));
428+
}
429+
else
430+
{
431+
// Allow the current user read/write access to the pipe.
432+
pipeSecurity.AddAccessRule(new PipeAccessRule(
433+
WindowsIdentity.GetCurrent().User,
434+
PipeAccessRights.ReadWrite, AccessControlType.Allow));
435+
}
436+
437+
outPipe = outPipeName == null
438+
? null
439+
: (NamedPipeServerStream)s_netFrameworkPipeServerConstructor.Invoke(
440+
new object[] {
441+
outPipeName,
442+
PipeDirection.InOut,
443+
1, // maxNumberOfServerInstances
444+
PipeTransmissionMode.Byte,
445+
PipeOptions.Asynchronous,
446+
1024, // inBufferSize
447+
1024, // outBufferSize
448+
pipeSecurity
449+
});
450+
451+
return (NamedPipeServerStream)s_netFrameworkPipeServerConstructor.Invoke(
452+
new object[] {
453+
inOutPipeName,
454+
PipeDirection.InOut,
455+
1, // maxNumberOfServerInstances
456+
PipeTransmissionMode.Byte,
457+
PipeOptions.Asynchronous,
458+
1024, // inBufferSize
459+
1024, // outBufferSize
460+
pipeSecurity
461+
});
462+
}
463+
353464
#endregion
354465
}
355466
}

src/PowerShellEditorServices.Engine/PowerShellEditorServices.Engine.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
</PropertyGroup>
2222
<ItemGroup>
2323
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="2.2.0" />
24-
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.13.2-*" />
24+
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="1.0.0" />
2525
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
2626
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.4" />
2727
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
2828
<PackageReference Include="System.IO.Pipes.AccessControl" Version="4.5.1" />
2929
<PackageReference Include="System.Security.Principal" Version="4.3.0" />
3030
<PackageReference Include="System.Security.Principal.Windows" Version="4.5.1" />
3131
<PackageReference Include="UnixConsoleEcho" Version="0.1.0" />
32+
<PackageReference Include="OmniSharp.Extensions.DebugAdapter.Server" Version="1.0.0" />
3233
</ItemGroup>
3334

3435
</Project>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Management.Automation;
9+
using System.Management.Automation.Host;
10+
using System.Management.Automation.Runspaces;
11+
using System.Reflection;
12+
using System.Threading.Tasks;
13+
using Microsoft.Extensions.DependencyInjection;
14+
using Microsoft.Extensions.Logging;
15+
using Microsoft.PowerShell.EditorServices.Engine.Handlers;
16+
using Microsoft.PowerShell.EditorServices.Engine.Hosting;
17+
using Microsoft.PowerShell.EditorServices.Engine.Services;
18+
using Microsoft.PowerShell.EditorServices.Engine.Services.PowerShellContext;
19+
using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization;
20+
using OmniSharp.Extensions.JsonRpc;
21+
using OmniSharp.Extensions.LanguageServer.Server;
22+
23+
namespace Microsoft.PowerShell.EditorServices.Engine.Server
24+
{
25+
internal class PsesDebugServer
26+
{
27+
protected readonly ILoggerFactory _loggerFactory;
28+
private readonly Stream _inputStream;
29+
private readonly Stream _outputStream;
30+
private readonly TaskCompletionSource<bool> _serverStart;
31+
32+
33+
private IJsonRpcServer _jsonRpcServer;
34+
35+
internal PsesDebugServer(
36+
ILoggerFactory factory,
37+
Stream inputStream,
38+
Stream outputStream)
39+
{
40+
_loggerFactory = factory;
41+
_inputStream = inputStream;
42+
_outputStream = outputStream;
43+
_serverStart = new TaskCompletionSource<bool>();
44+
45+
}
46+
47+
public async Task StartAsync()
48+
{
49+
_jsonRpcServer = await JsonRpcServer.From(options =>
50+
{
51+
options.Serializer = new DapProtocolSerializer();
52+
options.Reciever = new DapReciever();
53+
options.LoggerFactory = _loggerFactory;
54+
ILogger logger = options.LoggerFactory.CreateLogger("DebugOptionsStartup");
55+
options.AddHandler<PowershellInitializeHandler>();
56+
// options.Services = new ServiceCollection()
57+
// .AddSingleton<WorkspaceService>()
58+
// .AddSingleton<SymbolsService>()
59+
// .AddSingleton<ConfigurationService>()
60+
// .AddSingleton<PowerShellContextService>(
61+
// (provider) =>
62+
// GetFullyInitializedPowerShellContext(
63+
// provider.GetService<OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServer>(),
64+
// _profilePaths))
65+
// .AddSingleton<TemplateService>()
66+
// .AddSingleton<EditorOperationsService>()
67+
// .AddSingleton<ExtensionService>(
68+
// (provider) =>
69+
// {
70+
// var extensionService = new ExtensionService(
71+
// provider.GetService<PowerShellContextService>(),
72+
// provider.GetService<OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServer>());
73+
// extensionService.InitializeAsync(
74+
// serviceProvider: provider,
75+
// editorOperations: provider.GetService<EditorOperationsService>())
76+
// .Wait();
77+
// return extensionService;
78+
// })
79+
// .AddSingleton<AnalysisService>(
80+
// (provider) =>
81+
// {
82+
// return AnalysisService.Create(
83+
// provider.GetService<ConfigurationService>(),
84+
// provider.GetService<OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServer>(),
85+
// options.LoggerFactory.CreateLogger<AnalysisService>());
86+
// });
87+
88+
options
89+
.WithInput(_inputStream)
90+
.WithOutput(_outputStream);
91+
92+
logger.LogInformation("Adding handlers");
93+
94+
logger.LogInformation("Handlers added");
95+
});
96+
}
97+
98+
public async Task WaitForShutdown()
99+
{
100+
await _serverStart.Task;
101+
//await _languageServer.;
102+
}
103+
}
104+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.Extensions.Logging;
9+
using OmniSharp.Extensions.DebugAdapter.Protocol.Requests;
10+
11+
namespace Microsoft.PowerShell.EditorServices.Engine.Handlers
12+
{
13+
internal class PowershellInitializeHandler : InitializeHandler
14+
{
15+
private readonly ILogger<PowershellInitializeHandler> _logger;
16+
17+
public PowershellInitializeHandler(ILoggerFactory factory)
18+
{
19+
_logger = factory.CreateLogger<PowershellInitializeHandler>();
20+
}
21+
22+
public override Task<InitializeResponse> Handle(InitializeRequestArguments request, CancellationToken cancellationToken)
23+
{
24+
_logger.LogTrace("We did it.");
25+
return Task.FromResult(new InitializeResponse());
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)