@@ -75,6 +75,8 @@ public class CapabilityRegistration {
7575 private final Set <AbstractDynamicCapability <?>> staticCapabilities ;
7676
7777 private final AtomicReference <Collection <ICapabilityParams >> lastParams = new AtomicReference <>(Collections .emptyList ());
78+ private final AtomicReference <CompletableFuture <Void >> currentUpdate ;
79+
7880 // Map of method names with current registration values
7981 private final Map <String , Registration > currentRegistrations = new ConcurrentHashMap <>();
8082
@@ -87,6 +89,7 @@ public CapabilityRegistration(LanguageClient client, Executor exec, ClientCapabi
8789 this .client = client ;
8890 this .exec = exec ;
8991 this .noop = CompletableFutureUtils .completedFuture (null , exec );
92+ this .currentUpdate = new AtomicReference <>(noop );
9093
9194 // Check whether to register capabilities dynamically or statically
9295 var dynamicCaps = new HashSet <AbstractDynamicCapability <?>>();
@@ -120,16 +123,19 @@ public void registerStaticCapabilities(ServerCapabilities result) {
120123 * @return A future that completes with a boolean that is false when any registration failed, and true otherwise.
121124 */
122125 public CompletableFuture <Void > update (Collection <ICapabilityParams > languages ) {
123- logger .debug ("Updating {} dynamic capabilities for {} languages" , dynamicCapabilities .size (), languages .size ());
124126 // Copy the contributions so we know we are looking at a stable collection of elements.
125-
126127 /*
127128 *VERY IMPORTANT* Setting the atomic reference from the thread that called us.
128129 We need to be sure that the `lastContributions` reference actually points to the most recently known contributions.
129130 Therefore, we need to set this reference before delegating any work to futures, where we lose guaranteed execution order.
130131 Additionally, this function should be called from a thread pool with predictable execution order.
131132 */
132133 lastParams .set (List .copyOf (languages ));
134+ return currentUpdate .updateAndGet (current -> current .thenComposeAsync (v -> doUpdate (languages ), exec ));
135+ }
136+
137+ private CompletableFuture <Void > doUpdate (Collection <ICapabilityParams > languages ) {
138+ logger .debug ("Updating {} dynamic capabilities for {} languages" , dynamicCapabilities .size (), languages .size ());
133139 return CompletableFutureUtils .reduce (dynamicCapabilities .stream ().map (this ::updateRegistration ), exec )
134140 .thenAccept (_v -> logger .debug ("Done updating dynamic capabilities" ));
135141 }
@@ -200,6 +206,7 @@ private <T> CompletableFuture<Void> updateRegistration(AbstractDynamicCapability
200206 result = register (registration , existingRegistration );
201207 }
202208
209+ // TODO Check/Fix that if one capability fails, the rest are still registered
203210 return result .handle ((_v , t ) -> {
204211 if (t != null ) {
205212 // An error occurred. Inform the user and do not recurse.
0 commit comments