1
1
using System ;
2
+ using System . Collections . Concurrent ;
3
+ using System . Collections . Generic ;
4
+ using System . Linq ;
5
+ using System . Runtime . InteropServices . ComTypes ;
2
6
using System . Threading ;
7
+ using System . Threading . Tasks ;
3
8
using JsonRpc . Standard . Client ;
4
9
using JsonRpc . Standard . Contracts ;
5
10
using JsonRpc . Standard . Server ;
11
+ using LanguageServer . VsCode . Contracts ;
6
12
using LanguageServer . VsCode . Contracts . Client ;
7
13
using LanguageServer . VsCode . Server ;
8
14
@@ -18,8 +24,8 @@ public LanguageServerSession(JsonRpcClient rpcClient, IJsonRpcContractResolver c
18
24
RpcClient = rpcClient ;
19
25
var builder = new JsonRpcProxyBuilder { ContractResolver = contractResolver } ;
20
26
Client = new ClientProxy ( builder , rpcClient ) ;
21
- Documents = new TextDocumentCollection ( ) ;
22
- DiagnosticProvider = new DiagnosticProvider ( Documents ) ;
27
+ Documents = new ConcurrentDictionary < Uri , SessionDocument > ( ) ;
28
+ DiagnosticProvider = new DiagnosticProvider ( ) ;
23
29
}
24
30
25
31
public CancellationToken CancellationToken => cts . Token ;
@@ -28,7 +34,7 @@ public LanguageServerSession(JsonRpcClient rpcClient, IJsonRpcContractResolver c
28
34
29
35
public ClientProxy Client { get ; }
30
36
31
- public TextDocumentCollection Documents { get ; }
37
+ public ConcurrentDictionary < Uri , SessionDocument > Documents { get ; }
32
38
33
39
public DiagnosticProvider DiagnosticProvider { get ; }
34
40
@@ -38,6 +44,72 @@ public void StopServer()
38
44
{
39
45
cts . Cancel ( ) ;
40
46
}
41
-
47
+
48
+ }
49
+
50
+ public class SessionDocument
51
+ {
52
+ /// <summary>
53
+ /// Actually makes the changes to the inner document per this milliseconds.
54
+ /// </summary>
55
+ private const int RenderChangesDelay = 100 ;
56
+
57
+ public SessionDocument ( TextDocumentItem doc )
58
+ {
59
+ Document = TextDocument . Load < FullTextDocument > ( doc ) ;
60
+ }
61
+
62
+ private Task updateChangesDelayTask ;
63
+
64
+ private readonly object syncLock = new object ( ) ;
65
+
66
+ private List < TextDocumentContentChangeEvent > impendingChanges = new List < TextDocumentContentChangeEvent > ( ) ;
67
+
68
+ public event EventHandler DocumentChanged ;
69
+
70
+ public TextDocument Document { get ; set ; }
71
+
72
+ public void NotifyChanges ( IEnumerable < TextDocumentContentChangeEvent > changes )
73
+ {
74
+ lock ( syncLock )
75
+ {
76
+ if ( impendingChanges == null )
77
+ impendingChanges = changes . ToList ( ) ;
78
+ else
79
+ impendingChanges . AddRange ( changes ) ;
80
+ }
81
+ if ( updateChangesDelayTask == null || updateChangesDelayTask . IsCompleted )
82
+ {
83
+ updateChangesDelayTask = Task . Delay ( RenderChangesDelay ) ;
84
+ updateChangesDelayTask . ContinueWith ( t => Task . Run ( ( Action ) MakeChanges ) ) ;
85
+ }
86
+ }
87
+
88
+ private void MakeChanges ( )
89
+ {
90
+ List < TextDocumentContentChangeEvent > localChanges ;
91
+ lock ( syncLock )
92
+ {
93
+ localChanges = impendingChanges ;
94
+ if ( localChanges == null || localChanges . Count == 0 ) return ;
95
+ impendingChanges = null ;
96
+ }
97
+ Document = Document . ApplyChanges ( localChanges ) ;
98
+ if ( impendingChanges == null )
99
+ {
100
+ localChanges . Clear ( ) ;
101
+ lock ( syncLock )
102
+ {
103
+ if ( impendingChanges == null )
104
+ impendingChanges = localChanges ;
105
+ }
106
+ }
107
+ OnDocumentChanged ( ) ;
108
+ }
109
+
110
+ protected virtual void OnDocumentChanged ( )
111
+ {
112
+ DocumentChanged ? . Invoke ( this , EventArgs . Empty ) ;
113
+ }
42
114
}
43
115
}
0 commit comments