33namespace Phpactor \LanguageServer \Core \Diagnostics ;
44
55use Amp \CancelledException ;
6+ use Amp \Success ;
67use Phpactor \LanguageServerProtocol \Diagnostic ;
78use Phpactor \LanguageServerProtocol \TextDocument ;
89use Phpactor \LanguageServer \Core \Server \ClientApi ;
@@ -43,6 +44,16 @@ class DiagnosticsEngine
4344 */
4445 private array $ versions = [];
4546
47+ /**
48+ * @var array<string,Deferred>
49+ */
50+ private array $ locks = [];
51+
52+ /**
53+ * @var array<string,int>
54+ */
55+ private array $ concurrencies = [];
56+
4657 /**
4758 * @param DiagnosticsProvider[] $providers
4859 */
@@ -99,12 +110,27 @@ public function run(CancellationToken $token): Promise
99110 $ this ->next = null ;
100111 }
101112
102- foreach ($ this ->providers as $ i => $ provider ) {
103- asyncCall (function () use ($ provider , $ token , $ textDocument ) {
113+ foreach ($ this ->providers as $ providerId => $ provider ) {
114+ asyncCall (function () use ($ providerId , $ provider , $ token , $ textDocument ) {
104115 $ start = microtime (true );
105116
117+ yield $ this ->await ($ providerId );
118+
119+ if (!$ this ->isDocumentCurrent ($ textDocument )) {
120+ return ;
121+ }
122+
123+ $ this ->locks [$ providerId ] = new Deferred ();
124+
106125 /** @var Diagnostic[] $diagnostics */
107126 $ diagnostics = yield $ provider ->provideDiagnostics ($ textDocument , $ token ) ;
127+
128+ if (isset ($ this ->locks [$ providerId ])) {
129+ $ lock = $ this ->locks [$ providerId ];
130+ unset($ this ->locks [$ providerId ]);
131+ $ lock ->resolve (true );
132+ }
133+
108134 $ elapsed = (int )round ((microtime (true ) - $ start ) / 1000 );
109135
110136 $ this ->diagnostics [$ textDocument ->uri ] = array_merge (
@@ -118,7 +144,7 @@ public function run(CancellationToken $token): Promise
118144 yield delay ($ timeToSleep );
119145 }
120146
121- if ($ textDocument -> version !== ( $ this ->versions [ $ textDocument-> uri ] ?? - 1 )) {
147+ if (! $ this ->isDocumentCurrent ( $ textDocument )) {
122148 return ;
123149 }
124150
@@ -147,4 +173,19 @@ public function enqueue(TextDocumentItem $textDocument): void
147173 $ this ->running = true ;
148174 $ this ->deferred ->resolve ($ textDocument );
149175 }
176+
177+ private function isDocumentCurrent (?TextDocumentItem $ textDocument ): bool
178+ {
179+ return $ textDocument ->version === ($ this ->versions [$ textDocument ->uri ] ?? -1 );
180+ }
181+
182+ private function await ($ providerId ): Promise
183+ {
184+ if (!array_key_exists ($ providerId , $ this ->locks )) {
185+ return new Success (true );
186+ }
187+
188+ return $ this ->locks [$ providerId ]->promise ();
189+
190+ }
150191}
0 commit comments