4
4
using System ;
5
5
using System . Threading ;
6
6
using System . Threading . Tasks ;
7
+ using Microsoft . AspNetCore . Razor . Threading ;
7
8
using Microsoft . CodeAnalysis . Razor ;
8
9
using Microsoft . CodeAnalysis . Razor . Protocol ;
9
10
using Microsoft . CodeAnalysis . Razor . Workspaces ;
10
11
using Microsoft . CommonLanguageServerProtocol . Framework ;
11
12
using Microsoft . VisualStudio . LanguageServer . Protocol ;
12
13
using Microsoft . VisualStudio . RpcContracts . Settings ;
14
+ using Microsoft . VisualStudio . Threading ;
13
15
14
16
namespace Microsoft . AspNetCore . Razor . LanguageServer ;
15
17
16
- internal sealed class CapabilitiesManager ( ILspServices lspServices )
17
- : IInitializeManager < InitializeParams , InitializeResult > , IClientCapabilitiesService , IWorkspaceRootPathProvider
18
+ internal sealed class CapabilitiesManager : IInitializeManager < InitializeParams , InitializeResult > , IClientCapabilitiesService , IWorkspaceRootPathProvider
18
19
{
19
- private readonly ILspServices _lspServices = lspServices ;
20
- private InitializeParams ? _initializeParams ;
20
+ private readonly ILspServices _lspServices ;
21
+ private readonly TaskCompletionSource < InitializeParams > _initializeParamsTaskSource ;
22
+ private readonly AsyncLazy < string > _lazyRootPath ;
21
23
22
- public bool HasInitialized => _initializeParams is not null ;
24
+ public bool HasInitialized => _initializeParamsTaskSource . Task . IsCompleted ;
23
25
24
26
public bool CanGetClientCapabilities => HasInitialized ;
25
27
26
28
public VSInternalClientCapabilities ClientCapabilities => GetInitializeParams ( ) . Capabilities . ToVSInternalClientCapabilities ( ) ;
27
29
30
+ public CapabilitiesManager ( ILspServices lspServices )
31
+ {
32
+ _lspServices = lspServices ;
33
+
34
+ _initializeParamsTaskSource = new ( ) ;
35
+
36
+ #pragma warning disable VSTHRD012 // Provide JoinableTaskFactory where allowed
37
+ _lazyRootPath = new ( ComputeRootPathAsync ) ;
38
+ #pragma warning restore VSTHRD012
39
+ }
40
+
28
41
public InitializeParams GetInitializeParams ( )
29
- => _initializeParams ??
30
- throw new InvalidOperationException ( $ "{ nameof ( GetInitializeParams ) } was called before '{ Methods . InitializeName } '") ;
42
+ {
43
+ return _initializeParamsTaskSource . Task . VerifyCompleted ( ) ;
44
+ }
31
45
32
46
public InitializeResult GetInitializeResult ( )
33
47
{
@@ -51,39 +65,32 @@ public InitializeResult GetInitializeResult()
51
65
52
66
public void SetInitializeParams ( InitializeParams request )
53
67
{
54
- _initializeParams = request ?? throw new ArgumentNullException ( nameof ( request ) ) ;
68
+ if ( _initializeParamsTaskSource . Task . IsCompleted )
69
+ {
70
+ throw new InvalidOperationException ( $ "{ nameof ( SetInitializeParams ) } already called.") ;
71
+ }
72
+
73
+ _initializeParamsTaskSource . TrySetResult ( request ) ;
55
74
}
56
75
57
- public ValueTask < string > GetRootPathAsync ( CancellationToken cancellationToken )
76
+ private async Task < string > ComputeRootPathAsync ( )
58
77
{
59
- return HasInitialized
60
- ? new ( GetRootPath ( ) )
61
- : new ( GetRootPathCoreAsync ( this , cancellationToken ) ) ;
78
+ #pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks
79
+ var initializeParams = await _initializeParamsTaskSource . Task . ConfigureAwaitRunInline ( ) ;
80
+ #pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks
62
81
63
- static async Task < string > GetRootPathCoreAsync ( CapabilitiesManager manager , CancellationToken cancellationToken )
82
+ if ( initializeParams . RootUri is Uri rootUri )
64
83
{
65
- while ( ! manager . HasInitialized )
66
- {
67
- cancellationToken . ThrowIfCancellationRequested ( ) ;
68
- await Task . Delay ( millisecondsDelay : 1 , cancellationToken ) . ConfigureAwait ( false ) ;
69
- }
70
-
71
- return manager . GetRootPath ( ) ;
84
+ return rootUri . GetAbsoluteOrUNCPath ( ) ;
72
85
}
73
- }
74
86
75
- private string GetRootPath ( )
76
- {
77
- var initializeParams = GetInitializeParams ( ) ;
87
+ // RootUri was added in LSP3, fall back to RootPath
78
88
79
- if ( initializeParams . RootUri is null )
80
- {
81
89
#pragma warning disable CS0618 // Type or member is obsolete
82
- // RootUri was added in LSP3, fallback to RootPath
83
- return initializeParams . RootPath . AssumeNotNull ( ) ;
90
+ return initializeParams . RootPath . AssumeNotNull ( ) ;
84
91
#pragma warning restore CS0618 // Type or member is obsolete
85
- }
86
-
87
- return initializeParams . RootUri . GetAbsoluteOrUNCPath ( ) ;
88
92
}
93
+
94
+ public Task < string > GetRootPathAsync ( CancellationToken cancellationToken )
95
+ => _lazyRootPath . GetValueAsync ( cancellationToken ) ;
89
96
}
0 commit comments