Make completions computation properly async

This commit is contained in:
Kris De Volder
2016-11-28 13:26:32 -08:00
parent 1c633b8865
commit 14feb0f0c6
5 changed files with 32 additions and 26 deletions

View File

@@ -20,22 +20,23 @@ import org.springframework.ide.vscode.commons.languageserver.util.TextDocument;
import org.springframework.ide.vscode.commons.util.Futures;
import org.springframework.ide.vscode.commons.util.StringUtil;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
/**
* Adapts a {@link ICompletionEngine}, wrapping it, to implement {@link VscodeCompletionEngine}
*/
public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
private final static int MAX_COMPLETIONS = 20;
private int maxCompletions = MAX_COMPLETIONS;
final static Logger logger = LoggerFactory.getLogger(VscodeCompletionEngineAdapter.class);
public static final String VS_CODE_CURSOR_MARKER = "{{}}";
private SimpleLanguageServer server;
private ICompletionEngine engine;
public VscodeCompletionEngineAdapter(SimpleLanguageServer server, ICompletionEngine engine) {
this.server = server;
this.engine = engine;
@@ -47,13 +48,20 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
@Override
public CompletableFuture<CompletionList> getCompletions(TextDocumentPositionParams params) {
//TODO: This returns a CompletableFuture which suggests we should try to do expensive work asyncly.
// We are currently just doing all this in a blocking way and wrapping the already computed list into
// a trivial pre-resolved future.
try {
SimpleTextDocumentService documents = server.getTextDocumentService();
TextDocument doc = documents.get(params);
if (doc!=null) {
return getCompletionsMono(params).toFuture();
}
private Mono<CompletionList> getCompletionsMono(TextDocumentPositionParams params) {
SimpleTextDocumentService documents = server.getTextDocumentService();
TextDocument doc = documents.get(params);
if (doc!=null) {
return Mono.fromCallable(() -> {
//TODO: This callable is a 'big lump of work' so can't be canceled in pieces.
// Should we push using of reactive streems down further and compose this all
// using reactive style? If not then this is overkill could just as well use
// only standard Java AP such as Executor and CompletableFuture's directly.
int offset = doc.toOffset(params.getPosition());
List<ICompletionProposal> completions = new ArrayList<>(engine.getCompletions(doc, offset));
Collections.sort(completions, ScoreableProposal.COMPARATOR);
@@ -75,12 +83,11 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
}
}
list.setItems(items);
return Futures.of(list);
}
} catch (Exception e) {
logger.error("error computing completions", e);
return list;
})
.subscribeOn(Schedulers.single()); //!!! without this the mono will just be computed on the same thread that calls it.
}
return SimpleTextDocumentService.NO_COMPLETIONS;
return Mono.just(SimpleTextDocumentService.NO_COMPLETIONS);
}
private CompletionItem adaptItem(TextDocument doc, ICompletionProposal completion, SortKeys sortkeys) throws Exception {

View File

@@ -166,11 +166,9 @@ public class SimpleTextDocumentService implements TextDocumentService {
return doc;
}
public final static CompletableFuture<CompletionList> NO_COMPLETIONS = Futures.of(
new CompletionList(false, Collections.emptyList()));
public final static CompletableFuture<Hover> NO_HOVER = Futures.of(new Hover(ImmutableList.of(), null));
public final static CompletionList NO_COMPLETIONS = new CompletionList(false, Collections.emptyList());
public final static CompletableFuture<Hover> NO_HOVER = CompletableFuture.completedFuture(new Hover(ImmutableList.of(), null));
@Override
public CompletableFuture<CompletionList> completion(TextDocumentPositionParams position) {
@@ -178,7 +176,7 @@ public class SimpleTextDocumentService implements TextDocumentService {
if (h!=null) {
return completionHandler.handle(position);
}
return NO_COMPLETIONS;
return CompletableFuture.completedFuture(NO_COMPLETIONS);
}
@Override

View File

@@ -4,10 +4,12 @@ import java.util.concurrent.CompletableFuture;
public class Futures {
/**
* Depcrecated. Use {@link CompletableFuture}.completedFuture() instead.
*/
@Deprecated
public static <T> CompletableFuture<T> of(T value) {
CompletableFuture<T> f = new CompletableFuture<T>();
f.complete(value);
return f;
return CompletableFuture.completedFuture(value);
}
}

View File

@@ -21,12 +21,12 @@ import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SKeyNode;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNodeType;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SRootNode;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SSeqNode;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil;
/**

View File

@@ -39,8 +39,7 @@ public class ApplicationPropertiesLanguageServer extends SimpleLanguageServer {
private VscodeCompletionEngineAdapter completionEngine;
private SpringPropertiesReconcileEngine reconcileEngine;
private VscodeHoverEngineAdapter hoverEngine;
public ApplicationPropertiesLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder javaProjectFinder) {
this.indexProvider = indexProvider;
this.typeUtilProvider = typeUtilProvider;