11using System ;
2+ using System . Collections . Concurrent ;
3+ using System . Collections . Generic ;
4+ using System . Linq ;
5+ using System . Runtime . InteropServices . ComTypes ;
26using System . Threading ;
7+ using System . Threading . Tasks ;
38using JsonRpc . Standard . Client ;
49using JsonRpc . Standard . Contracts ;
510using JsonRpc . Standard . Server ;
11+ using LanguageServer . VsCode . Contracts ;
612using LanguageServer . VsCode . Contracts . Client ;
713using LanguageServer . VsCode . Server ;
814
@@ -18,8 +24,8 @@ public LanguageServerSession(JsonRpcClient rpcClient, IJsonRpcContractResolver c
1824 RpcClient = rpcClient ;
1925 var builder = new JsonRpcProxyBuilder { ContractResolver = contractResolver } ;
2026 Client = new ClientProxy ( builder , rpcClient ) ;
21- Documents = new TextDocumentCollection ( ) ;
22- DiagnosticProvider = new DiagnosticProvider ( Documents ) ;
27+ Documents = new ConcurrentDictionary < Uri , SessionDocument > ( ) ;
28+ DiagnosticProvider = new DiagnosticProvider ( ) ;
2329 }
2430
2531 public CancellationToken CancellationToken => cts . Token ;
@@ -28,7 +34,7 @@ public LanguageServerSession(JsonRpcClient rpcClient, IJsonRpcContractResolver c
2834
2935 public ClientProxy Client { get ; }
3036
31- public TextDocumentCollection Documents { get ; }
37+ public ConcurrentDictionary < Uri , SessionDocument > Documents { get ; }
3238
3339 public DiagnosticProvider DiagnosticProvider { get ; }
3440
@@ -38,6 +44,72 @@ public void StopServer()
3844 {
3945 cts . Cancel ( ) ;
4046 }
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+ }
42114 }
43115}
0 commit comments