initial re-work of async behavior of language server, looking at the text document service first
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -75,8 +75,9 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder {
|
||||
@Override
|
||||
public List<LocationLink> handle(DefinitionParams params) {
|
||||
try {
|
||||
TextDocument doc = server.getTextDocumentService().get(params.getTextDocument().getUri());
|
||||
if (doc!=null) {
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params);
|
||||
|
||||
if (doc != null) {
|
||||
YamlFileAST ast = asts.getSafeAst(doc, false);
|
||||
if (ast!=null) {
|
||||
Node refNode = ast.findNode(doc.toOffset(params.getPosition()));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -128,8 +128,10 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
|
||||
private Mono<CompletionList> getCompletionsMono(TextDocumentPositionParams params) {
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
if (documents.get(params) != null) {
|
||||
TextDocument doc = documents.getDocumentSnapshot(params.getTextDocument());
|
||||
|
||||
TextDocument doc = documents.getLatestSnapshot(params);
|
||||
if (doc != null) {
|
||||
|
||||
return Mono.fromCallable(() -> {
|
||||
log.info("Starting completion handling");
|
||||
if (resolver!=null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -11,9 +11,7 @@
|
||||
package org.springframework.ide.vscode.commons.languageserver.composable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -21,8 +19,6 @@ import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.HoverParams;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.CompositeCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
@@ -86,7 +82,7 @@ public class CompositeLanguageServerComponents implements LanguageServerComponen
|
||||
this.hoverHandler = new HoverHandler() {
|
||||
@Override
|
||||
public Hover handle(HoverParams params) {
|
||||
TextDocument doc = server.getTextDocumentService().get(params.getTextDocument().getUri());
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params.getTextDocument().getUri());
|
||||
LanguageId language = doc.getLanguageId();
|
||||
LanguageServerComponents subComponents = componentsByLanguageId.get(language);
|
||||
if (subComponents!=null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -41,7 +41,8 @@ public class SimpleDefinitionFinder implements DefinitionHandler {
|
||||
@Override
|
||||
public List<LocationLink> handle(DefinitionParams params) {
|
||||
try {
|
||||
TextDocument doc = server.getTextDocumentService().get(params.getTextDocument().getUri());
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params.getTextDocument().getUri());
|
||||
|
||||
if (doc != null) {
|
||||
int offset = doc.toOffset(params.getPosition());
|
||||
int start = offset;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -60,7 +60,8 @@ public class VscodeHoverEngineAdapter implements HoverHandler {
|
||||
public Hover handle(HoverParams params) {
|
||||
try {
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
TextDocument doc = documents.get(params.getTextDocument().getUri());
|
||||
TextDocument doc = documents.getLatestSnapshot(params.getTextDocument().getUri());
|
||||
|
||||
if (doc != null) {
|
||||
int offset = doc.toOffset(params.getPosition());
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -534,13 +534,13 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, LanguageC
|
||||
public void validateWith(TextDocumentIdentifier docId, IReconcileEngine engine) {
|
||||
SimpleTextDocumentService documents = getTextDocumentService();
|
||||
|
||||
TextDocument document = documents.getDocument(docId.getUri());
|
||||
if (document == null) {
|
||||
TextDocument doc = documents.getLatestSnapshot(docId.getUri());
|
||||
if (doc == null) {
|
||||
log.debug("Reconcile skipped due to document doesn't exist anymore {}", docId.getUri());
|
||||
return;
|
||||
}
|
||||
|
||||
int requestedVersion = document.getVersion();
|
||||
int requestedVersion = doc.getVersion();
|
||||
VersionedTextDocumentIdentifier request = new VersionedTextDocumentIdentifier(docId.getUri(), requestedVersion);
|
||||
log.debug("Reconcile requested {} - {}", request.getUri(), request.getVersion());
|
||||
if (!queuedReconcileRequests.add(request)) {
|
||||
@@ -557,13 +557,13 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, LanguageC
|
||||
queuedReconcileRequests.remove(request);
|
||||
log.debug("Reconcile starting {} - {}", request.getUri(), request.getVersion());
|
||||
|
||||
TextDocument doc = documents.getDocument(docId.getUri()).copy();
|
||||
// TextDocument doc = documents.getDocument(docId.getUri()).copy();
|
||||
|
||||
if (doc == null) {
|
||||
log.debug("Reconcile aborted due to document doesn't exist {} - {}", request.getUri(), request.getVersion());
|
||||
//Do not bother reconciling if document doesn't exist anymore (got closed in the meantime)
|
||||
return;
|
||||
}
|
||||
// if (doc == null) {
|
||||
// log.debug("Reconcile aborted due to document doesn't exist {} - {}", request.getUri(), request.getVersion());
|
||||
// //Do not bother reconciling if document doesn't exist anymore (got closed in the meantime)
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (requestedVersion != doc.getVersion()) {
|
||||
log.debug("Reconcile aborted due to document being already stale {} - {}", request.getUri(), request.getVersion());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -10,13 +10,12 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -46,7 +45,6 @@ import org.eclipse.lsp4j.HoverParams;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.PublishDiagnosticsParams;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.ReferenceParams;
|
||||
import org.eclipse.lsp4j.RenameParams;
|
||||
import org.eclipse.lsp4j.SignatureHelp;
|
||||
@@ -59,6 +57,7 @@ import org.eclipse.lsp4j.TextDocumentPositionParams;
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.WorkspaceEdit;
|
||||
import org.eclipse.lsp4j.jsonrpc.CompletableFutures;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.eclipse.lsp4j.services.LanguageClient;
|
||||
import org.eclipse.lsp4j.services.TextDocumentService;
|
||||
@@ -67,182 +66,132 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerProperties;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.AsyncRunner;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class SimpleTextDocumentService implements TextDocumentService, DocumentEventListenerManager {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(SimpleTextDocumentService.class);
|
||||
|
||||
final private SimpleLanguageServer server;
|
||||
final private LanguageServerProperties props;
|
||||
private Map<String, TrackedDocument> documents = new HashMap<>();
|
||||
private ListenerList<TextDocumentContentChange> documentChangeListeners = new ListenerList<>();
|
||||
private ListenerList<TextDocument> documentCloseListeners = new ListenerList<>();
|
||||
private ListenerList<TextDocument> documentOpenListeners = new ListenerList<>();
|
||||
private final SimpleLanguageServer server;
|
||||
private final LanguageServerProperties props;
|
||||
|
||||
private final ConcurrentMap<String, TrackedDocument> documents = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, TextDocument> documentSnapshots = new ConcurrentHashMap<>();
|
||||
|
||||
private CompletionHandler completionHandler = null;
|
||||
private CompletionResolveHandler completionResolveHandler = null;
|
||||
private final ListenerList<TextDocumentContentChange> documentChangeListeners = new ListenerList<>();
|
||||
private final ListenerList<TextDocument> documentCloseListeners = new ListenerList<>();
|
||||
private final ListenerList<TextDocument> documentOpenListeners = new ListenerList<>();
|
||||
private List<Consumer<TextDocumentSaveChange>> documentSaveListeners = ImmutableList.of();
|
||||
|
||||
private HoverHandler hoverHandler = null;
|
||||
private CompletionHandler completionHandler;
|
||||
private CompletionResolveHandler completionResolveHandler;
|
||||
private HoverHandler hoverHandler;
|
||||
private DefinitionHandler definitionHandler;
|
||||
private ReferencesHandler referencesHandler;
|
||||
|
||||
private DocumentSymbolHandler documentSymbolHandler;
|
||||
private DocumentHighlightHandler documentHighlightHandler;
|
||||
|
||||
private CodeLensHandler codeLensHandler;
|
||||
private CodeLensResolveHandler codeLensResolveHandler;
|
||||
|
||||
private List<Consumer<TextDocumentSaveChange>> documentSaveListeners = ImmutableList.of();
|
||||
private AsyncRunner async;
|
||||
|
||||
|
||||
public SimpleTextDocumentService(SimpleLanguageServer server, LanguageServerProperties props) {
|
||||
this.server = server;
|
||||
this.props = props;
|
||||
this.async = server.getAsync();
|
||||
}
|
||||
|
||||
public synchronized void onHover(HoverHandler h) {
|
||||
Assert.isNull("A hover handler is already set, multiple handlers not supported yet", hoverHandler);
|
||||
this.hoverHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onCodeLens(CodeLensHandler h) {
|
||||
Assert.isNull("A code lens handler is already set, multiple handlers not supported yet", codeLensHandler);
|
||||
this.codeLensHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onCodeLensResolve(CodeLensResolveHandler h) {
|
||||
Assert.isNull("A code lens resolve handler is already set, multiple handlers not supported yet", codeLensResolveHandler);
|
||||
this.codeLensResolveHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onDocumentSymbol(DocumentSymbolHandler h) {
|
||||
Assert.isNull("A DocumentSymbolHandler is already set, multiple handlers not supported yet", documentSymbolHandler);
|
||||
this.documentSymbolHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onDocumentHighlight(DocumentHighlightHandler h) {
|
||||
Assert.isNull("A DocumentHighlightHandler is already set, multiple handlers not supported yet", documentHighlightHandler);
|
||||
this.documentHighlightHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onCompletion(CompletionHandler h) {
|
||||
Assert.isNull("A completion handler is already set, multiple handlers not supported yet", completionHandler);
|
||||
this.completionHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onCompletionResolve(CompletionResolveHandler h) {
|
||||
Assert.isNull("A completionResolveHandler handler is already set, multiple handlers not supported yet", completionResolveHandler);
|
||||
this.completionResolveHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onDefinition(DefinitionHandler h) {
|
||||
Assert.isNull("A defintion handler is already set, multiple handlers not supported yet", definitionHandler);
|
||||
this.definitionHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onReferences(ReferencesHandler h) {
|
||||
Assert.isNull("A references handler is already set, multiple handlers not supported yet", referencesHandler);
|
||||
this.referencesHandler = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all documents this service is tracking, generally these are the documents that have been opened / changed,
|
||||
* and not yet closed.
|
||||
*/
|
||||
public synchronized Collection<TextDocument> getAll() {
|
||||
return documents.values().stream()
|
||||
.map((td) -> td.getDocument())
|
||||
public Collection<TextDocument> getAll() {
|
||||
return documentSnapshots.values().stream()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void didChange(DidChangeTextDocumentParams params) {
|
||||
async.execute(() -> {
|
||||
public void didOpen(DidOpenTextDocumentParams params) {
|
||||
log.info("change arrived: " + params.getTextDocument().getVersion());
|
||||
|
||||
TextDocumentItem docId = params.getTextDocument();
|
||||
|
||||
String url = docId.getUri();
|
||||
LanguageId languageId = LanguageId.of(docId.getLanguageId());
|
||||
int version = docId.getVersion();
|
||||
|
||||
if (url != null) {
|
||||
|
||||
String text = params.getTextDocument().getText();
|
||||
TrackedDocument td = createDocument(url, languageId, version, text).open();
|
||||
|
||||
log.debug("Opened " + td.getOpenCount() + " times: " + url);
|
||||
TextDocument doc = td.getDocument();
|
||||
|
||||
TextDocument snapshot = doc.copy();
|
||||
documentSnapshots.put(url, snapshot);
|
||||
|
||||
documentOpenListeners.fire(snapshot);
|
||||
|
||||
TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent(text);
|
||||
TextDocumentContentChange evt = new TextDocumentContentChange(snapshot, ImmutableList.of(change));
|
||||
|
||||
documentChangeListeners.fire(evt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChange(DidChangeTextDocumentParams params) {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
log.info("change arrived: " + params.getTextDocument().getVersion());
|
||||
|
||||
try {
|
||||
VersionedTextDocumentIdentifier docId = params.getTextDocument();
|
||||
String url = docId.getUri();
|
||||
// Log.debug("didChange: "+url);
|
||||
|
||||
if (url != null) {
|
||||
TextDocument doc = getDocument(url);
|
||||
TextDocument doc = getInternalDocument(url);
|
||||
|
||||
if (doc != null) {
|
||||
List<TextDocumentContentChangeEvent> changes = params.getContentChanges();
|
||||
doc.apply(params);
|
||||
didChangeContent(doc, changes);
|
||||
|
||||
TextDocument snapshot = doc.copy();
|
||||
documentSnapshots.put(url, snapshot);
|
||||
documentChangeListeners.fire(new TextDocumentContentChange(snapshot, changes));
|
||||
}
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didOpen(DidOpenTextDocumentParams params) {
|
||||
async.execute(() -> {
|
||||
TextDocumentItem docId = params.getTextDocument();
|
||||
String url = docId.getUri();
|
||||
//Log.info("didOpen: "+params.getTextDocument().getUri());
|
||||
LanguageId languageId = LanguageId.of(docId.getLanguageId());
|
||||
int version = docId.getVersion();
|
||||
if (url != null) {
|
||||
|
||||
String text = params.getTextDocument().getText();
|
||||
TrackedDocument td = createDocument(url, languageId, version, text).open();
|
||||
log.debug("Opened " + td.getOpenCount() + " times: " + url);
|
||||
TextDocument doc = td.getDocument();
|
||||
|
||||
documentOpenListeners.fire(doc);
|
||||
|
||||
TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent() {
|
||||
@Override
|
||||
public Range getRange() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getRangeLength() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
TextDocumentContentChange evt = new TextDocumentContentChange(doc, ImmutableList.of(change));
|
||||
documentChangeListeners.fire(evt);
|
||||
}
|
||||
});
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("change message work done in " + (end - start) + "ms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didClose(DidCloseTextDocumentParams params) {
|
||||
async.execute(() -> {
|
||||
//Log.info("didClose: "+params.getTextDocument().getUri());
|
||||
String url = params.getTextDocument().getUri();
|
||||
if (url!=null) {
|
||||
|
||||
if (url != null) {
|
||||
|
||||
TrackedDocument doc = documents.get(url);
|
||||
if (doc != null) {
|
||||
|
||||
if (doc.close()) {
|
||||
documents.remove(url);
|
||||
TextDocument lastSnapshot = documentSnapshots.remove(url);
|
||||
|
||||
log.info("Closed: "+url);
|
||||
//Clear diagnostics when a file is closed. This makes the errors disapear when the language is changed for
|
||||
// a document (this resulst in a dicClose even as being sent to the language server if that changes make the
|
||||
// document go 'out of scope'.
|
||||
publishDiagnostics(params.getTextDocument(), ImmutableList.of());
|
||||
documentCloseListeners.fire(doc.getDocument());
|
||||
documents.remove(url);
|
||||
|
||||
documentCloseListeners.fire(lastSnapshot);
|
||||
} else {
|
||||
log.warn("Close event ignored! Assuming document still open because openCount = "+doc.getOpenCount());
|
||||
}
|
||||
@@ -250,11 +199,6 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
log.warn("Document closed, but it didn't exist! Close event ignored");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void didChangeContent(TextDocument doc, List<TextDocumentContentChangeEvent> changes) {
|
||||
documentChangeListeners.fire(new TextDocumentContentChange(doc, changes));
|
||||
}
|
||||
|
||||
public void onDidOpen(Consumer<TextDocument> l) {
|
||||
@@ -277,24 +221,24 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
documentSaveListeners = builder.build();
|
||||
}
|
||||
|
||||
public synchronized TextDocument getDocument(String url) {
|
||||
public TextDocument getLatestSnapshot(String url) {
|
||||
return documentSnapshots.get(url);
|
||||
}
|
||||
|
||||
public TextDocument getLatestSnapshot(TextDocumentPositionParams params) {
|
||||
return getLatestSnapshot(params.getTextDocument().getUri());
|
||||
}
|
||||
|
||||
private TextDocument getInternalDocument(String url) {
|
||||
TrackedDocument doc = documents.get(url);
|
||||
return doc != null ? doc.getDocument() : null;
|
||||
}
|
||||
|
||||
private synchronized TrackedDocument createDocument(String url, LanguageId languageId, int version, String text) {
|
||||
TrackedDocument existingDoc = documents.get(url);
|
||||
|
||||
if (existingDoc != null) {
|
||||
log.warn("Creating document ["+url+"] but it already exists. Reusing existing!");
|
||||
return existingDoc;
|
||||
}
|
||||
|
||||
TrackedDocument doc = new TrackedDocument(new TextDocument(url, languageId, version, text));
|
||||
documents.put(url, doc);
|
||||
return doc;
|
||||
|
||||
private TrackedDocument createDocument(final String url, final LanguageId languageId, final int version, final String text) {
|
||||
return documents.computeIfAbsent(url, key -> new TrackedDocument(new TextDocument(url, languageId, version, text)));
|
||||
}
|
||||
|
||||
|
||||
public final static CompletionList NO_COMPLETIONS = new CompletionList(false, Collections.emptyList());
|
||||
public final static Hover NO_HOVER = new Hover(ImmutableList.of(), null);
|
||||
public final static List<? extends Location> NO_REFERENCES = ImmutableList.of();
|
||||
@@ -304,8 +248,10 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(CompletionParams position) {
|
||||
log.info("completion request arrived: " + position.getTextDocument().getUri());
|
||||
|
||||
CompletionHandler h = completionHandler;
|
||||
if (h!=null) {
|
||||
if (h != null) {
|
||||
return completionHandler.handle(position)
|
||||
.map(Either::<List<CompletionItem>, CompletionList>forRight)
|
||||
.toFuture();
|
||||
@@ -316,13 +262,16 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
@Override
|
||||
public CompletableFuture<CompletionItem> resolveCompletionItem(CompletionItem unresolved) {
|
||||
log.info("Completion item resolve request received: {}", unresolved.getLabel());
|
||||
return async.invoke(() -> {
|
||||
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
try {
|
||||
CompletionResolveHandler h = completionResolveHandler;
|
||||
if (h!=null) {
|
||||
if (h != null) {
|
||||
log.info("Completion item resolve request starting {}", unresolved.getLabel());
|
||||
return h.handle(unresolved);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("exception resolving completion item", e);
|
||||
} finally {
|
||||
log.info("Completion item resolve request terminated.");
|
||||
}
|
||||
@@ -333,10 +282,18 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
@Override
|
||||
public CompletableFuture<Hover> hover(HoverParams hoverParams) {
|
||||
log.debug("hover requested for {}", hoverParams.getPosition());
|
||||
long timeout = props.getHoverTimeout();
|
||||
return timeout <= 0 ? async.invoke(() -> computeHover(hoverParams)) : async.invoke(Duration.ofMillis(timeout), () -> computeHover(hoverParams), Mono.fromRunnable(() -> {
|
||||
log.error("Hover Request handler timed out after {} ms.", timeout);
|
||||
}));
|
||||
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
return computeHover(hoverParams);
|
||||
});
|
||||
|
||||
|
||||
// TODO: timeout still necessary ?????
|
||||
|
||||
// long timeout = props.getHoverTimeout();
|
||||
// return timeout <= 0 ? async.invoke(() -> computeHover(hoverParams)) : async.invoke(Duration.ofMillis(timeout), () -> computeHover(hoverParams), Mono.fromRunnable(() -> {
|
||||
// log.error("Hover Request handler timed out after {} ms.", timeout);
|
||||
// }));
|
||||
}
|
||||
|
||||
private Hover computeHover(HoverParams hoverParams) {
|
||||
@@ -353,20 +310,15 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<SignatureHelp> signatureHelp(SignatureHelpParams signatureHelpParams) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(
|
||||
DefinitionParams definitionParams) {
|
||||
|
||||
DefinitionHandler h = this.definitionHandler;
|
||||
if (h != null) {
|
||||
return async.invoke(() -> {
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
List<LocationLink> locations = h.handle(definitionParams);
|
||||
if (locations==null) {
|
||||
if (locations == null) {
|
||||
// vscode client does not like to receive null result. See: https://github.com/spring-projects/sts4/issues/309
|
||||
locations = ImmutableList.of();
|
||||
}
|
||||
@@ -382,27 +334,42 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
}
|
||||
});
|
||||
}
|
||||
return CompletableFuture.completedFuture(Either.forLeft(ImmutableList.of()));
|
||||
else {
|
||||
return CompletableFuture.completedFuture(Either.forLeft(ImmutableList.of()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<? extends Location>> references(ReferenceParams params) {
|
||||
return async.invoke(() -> {
|
||||
ReferencesHandler h = this.referencesHandler;
|
||||
if (h != null) {
|
||||
List<? extends Location> list = h.handle(params);
|
||||
return list != null && list.isEmpty() ? null : list;
|
||||
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
List<? extends Location> list = h.handle(params);
|
||||
return list != null && list.isEmpty() ? null : list;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return CompletableFuture.completedFuture(ImmutableList.of());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> documentSymbol(DocumentSymbolParams params) {
|
||||
return async.invoke(() -> {
|
||||
DocumentSymbolHandler h = this.documentSymbolHandler;
|
||||
if (h!=null) {
|
||||
server.waitForReconcile();
|
||||
DocumentSymbolHandler h = this.documentSymbolHandler;
|
||||
if (h != null) {
|
||||
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
try {
|
||||
server.waitForReconcile();
|
||||
} catch (Exception e) {
|
||||
log.warn("error while waiting for reconcile", e);
|
||||
}
|
||||
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
if (server.hasHierarchicalDocumentSymbolSupport() && h instanceof HierarchicalDocumentSymbolHandler) {
|
||||
List<? extends DocumentSymbol> r = ((HierarchicalDocumentSymbolHandler)h).handleHierarchic(params);
|
||||
//handle it when symbolHandler is sloppy and returns null instead of empty list.
|
||||
@@ -418,33 +385,40 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
: r.stream().map(symbolInfo -> Either.<SymbolInformation, DocumentSymbol>forLeft(symbolInfo))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return ImmutableList.of();
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
return CompletableFuture.completedFuture(ImmutableList.of());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
|
||||
return async.invoke(() -> {
|
||||
// this doesn't happen async, because it accesses the internal documents structure
|
||||
// and therefore needs to be executed as part of the main LSP message queue
|
||||
|
||||
TrackedDocument doc = documents.get(params.getTextDocument().getUri());
|
||||
if (doc!=null) {
|
||||
|
||||
if (doc != null) {
|
||||
ImmutableList<Either<Command,CodeAction>> list = doc.getQuickfixes().stream()
|
||||
.filter((fix) -> fix.appliesTo(params.getRange(), params.getContext()))
|
||||
.map(Quickfix::getCodeAction)
|
||||
.map(command -> Either.<Command, CodeAction>forLeft(command))
|
||||
.collect(CollectorUtil.toImmutableList());
|
||||
return list;
|
||||
.filter((fix) -> fix.appliesTo(params.getRange(), params.getContext()))
|
||||
.map(Quickfix::getCodeAction)
|
||||
.map(command -> Either.<Command, CodeAction>forLeft(command))
|
||||
.collect(CollectorUtil.toImmutableList());
|
||||
return CompletableFuture.completedFuture(list);
|
||||
} else {
|
||||
return ImmutableList.of();
|
||||
return CompletableFuture.completedFuture(ImmutableList.of());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<? extends CodeLens>> codeLens(CodeLensParams params) {
|
||||
CodeLensHandler handler = this.codeLensHandler;
|
||||
|
||||
if (handler != null) {
|
||||
return async.invoke(() -> handler.handle(params));
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
return handler.handle(params);
|
||||
});
|
||||
}
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
@@ -453,8 +427,58 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
public CompletableFuture<CodeLens> resolveCodeLens(CodeLens unresolved) {
|
||||
CodeLensResolveHandler handler = this.codeLensResolveHandler;
|
||||
if (handler != null) {
|
||||
return async.invoke(() -> handler.handle(unresolved));
|
||||
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
return handler.handle(unresolved);
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didSave(DidSaveTextDocumentParams params) {
|
||||
// Workaround for PT 147263283, where error markers in STS are lost on document save.
|
||||
// STS 3.9.0 does not use the LSP4E editor for edit manifest.yml, which correctly retains error markers after save.
|
||||
// Instead, because the LSP4E editor is missing support for hovers and completions, STS 3.9.0 uses its own manifest editor
|
||||
// which extends the YEdit editor. This YEdit editor has a problem, where on save, all error markers are deleted.
|
||||
// When STS uses the LSP4E editor and no longer needs its own YEdit-based editor, the issue with error markers disappearing
|
||||
// on save should not be a problem anymore, and the workaround below will no longer be needed.
|
||||
if (documentSaveListeners != null) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
TextDocumentIdentifier docId = params.getTextDocument();
|
||||
String url = docId.getUri();
|
||||
log.debug("didSave: "+url);
|
||||
if (url != null) {
|
||||
TextDocument doc = getLatestSnapshot(url);
|
||||
if (doc != null) {
|
||||
for (Consumer<TextDocumentSaveChange> l : documentSaveListeners) {
|
||||
l.accept(new TextDocumentSaveChange(doc));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<? extends DocumentHighlight>> documentHighlight(DocumentHighlightParams highlightParams) {
|
||||
DocumentHighlightHandler handler = this.documentHighlightHandler;
|
||||
if (handler != null) {
|
||||
return CompletableFutures.computeAsync(cancelToken -> {
|
||||
return handler.handle(highlightParams);
|
||||
|
||||
});
|
||||
}
|
||||
else {
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<SignatureHelp> signatureHelp(SignatureHelpParams signatureHelpParams) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@@ -477,35 +501,14 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didSave(DidSaveTextDocumentParams params) {
|
||||
// Workaround for PT 147263283, where error markers in STS are lost on document save.
|
||||
// STS 3.9.0 does not use the LSP4E editor for edit manifest.yml, which correctly retains error markers after save.
|
||||
// Instead, because the LSP4E editor is missing support for hovers and completions, STS 3.9.0 uses its own manifest editor
|
||||
// which extends the YEdit editor. This YEdit editor has a problem, where on save, all error markers are deleted.
|
||||
// When STS uses the LSP4E editor and no longer needs its own YEdit-based editor, the issue with error markers disappearing
|
||||
// on save should not be a problem anymore, and the workaround below will no longer be needed.
|
||||
async.execute(() -> {
|
||||
if (documentSaveListeners != null) {
|
||||
TextDocumentIdentifier docId = params.getTextDocument();
|
||||
String url = docId.getUri();
|
||||
log.debug("didSave: "+url);
|
||||
if (url != null) {
|
||||
TextDocument doc = getDocument(url);
|
||||
if (doc != null) {
|
||||
for (Consumer<TextDocumentSaveChange> l : documentSaveListeners) {
|
||||
l.accept(new TextDocumentSaveChange(doc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
public void publishDiagnostics(TextDocumentIdentifier docId, Collection<Diagnostic> diagnostics) {
|
||||
LanguageClient client = server.getClient();
|
||||
if (client!=null && diagnostics!=null) {
|
||||
if (client != null && diagnostics != null) {
|
||||
PublishDiagnosticsParams params = new PublishDiagnosticsParams();
|
||||
params.setUri(docId.getUri());
|
||||
params.setDiagnostics(ImmutableList.copyOf(diagnostics));
|
||||
@@ -515,67 +518,82 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
|
||||
public void setQuickfixes(TextDocumentIdentifier docId, List<Quickfix<?>> quickfixes) {
|
||||
TrackedDocument td = documents.get(docId.getUri());
|
||||
if (td!=null) {
|
||||
if (td != null) {
|
||||
td.setQuickfixes(quickfixes);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized TextDocument get(TextDocumentPositionParams params) {
|
||||
return get(params.getTextDocument().getUri());
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
public synchronized void onHover(HoverHandler h) {
|
||||
Assert.isNull("A hover handler is already set, multiple handlers not supported yet", hoverHandler);
|
||||
this.hoverHandler = h;
|
||||
}
|
||||
|
||||
public synchronized TextDocument get(String uri) {
|
||||
TrackedDocument td = documents.get(uri);
|
||||
return td == null ? null : td.getDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<? extends DocumentHighlight>> documentHighlight(DocumentHighlightParams highlightParams) {
|
||||
return async.invoke(() -> {
|
||||
DocumentHighlightHandler handler = this.documentHighlightHandler;
|
||||
if (handler != null) {
|
||||
return handler.handle(highlightParams);
|
||||
}
|
||||
return NO_HIGHLIGHTS;
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasDefinitionHandler() {
|
||||
return definitionHandler!=null;
|
||||
}
|
||||
|
||||
public boolean hasReferencesHandler() {
|
||||
return this.referencesHandler!=null;
|
||||
}
|
||||
|
||||
public boolean hasDocumentSymbolHandler() {
|
||||
return this.documentSymbolHandler!=null;
|
||||
}
|
||||
|
||||
public boolean hasDocumentHighlightHandler() {
|
||||
return this.documentHighlightHandler!=null;
|
||||
public synchronized void onCodeLens(CodeLensHandler h) {
|
||||
Assert.isNull("A code lens handler is already set, multiple handlers not supported yet", codeLensHandler);
|
||||
this.codeLensHandler = h;
|
||||
}
|
||||
|
||||
public boolean hasCodeLensHandler() {
|
||||
return this.codeLensHandler != null;
|
||||
}
|
||||
|
||||
public synchronized void onCodeLensResolve(CodeLensResolveHandler h) {
|
||||
Assert.isNull("A code lens resolve handler is already set, multiple handlers not supported yet", codeLensResolveHandler);
|
||||
this.codeLensResolveHandler = h;
|
||||
}
|
||||
|
||||
public boolean hasCodeLensResolveProvider() {
|
||||
return this.codeLensResolveHandler != null;
|
||||
}
|
||||
|
||||
public TextDocument getDocumentSnapshot(TextDocumentIdentifier textDocumentIdentifier) {
|
||||
try {
|
||||
return async.invoke(() -> {
|
||||
TextDocument doc = get(textDocumentIdentifier.getUri());
|
||||
if (doc!=null) {
|
||||
return doc.copy();
|
||||
}
|
||||
return null;
|
||||
}).get();
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUtil.unchecked(e);
|
||||
}
|
||||
public synchronized void onDocumentSymbol(DocumentSymbolHandler h) {
|
||||
Assert.isNull("A DocumentSymbolHandler is already set, multiple handlers not supported yet", documentSymbolHandler);
|
||||
this.documentSymbolHandler = h;
|
||||
}
|
||||
|
||||
public boolean hasDocumentSymbolHandler() {
|
||||
return this.documentSymbolHandler != null;
|
||||
}
|
||||
|
||||
public synchronized void onDocumentHighlight(DocumentHighlightHandler h) {
|
||||
Assert.isNull("A DocumentHighlightHandler is already set, multiple handlers not supported yet", documentHighlightHandler);
|
||||
this.documentHighlightHandler = h;
|
||||
}
|
||||
|
||||
public boolean hasDocumentHighlightHandler() {
|
||||
return this.documentHighlightHandler != null;
|
||||
}
|
||||
|
||||
public synchronized void onCompletion(CompletionHandler h) {
|
||||
Assert.isNull("A completion handler is already set, multiple handlers not supported yet", completionHandler);
|
||||
this.completionHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onCompletionResolve(CompletionResolveHandler h) {
|
||||
Assert.isNull("A completionResolveHandler handler is already set, multiple handlers not supported yet", completionResolveHandler);
|
||||
this.completionResolveHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onDefinition(DefinitionHandler h) {
|
||||
Assert.isNull("A defintion handler is already set, multiple handlers not supported yet", definitionHandler);
|
||||
this.definitionHandler = h;
|
||||
}
|
||||
|
||||
public boolean hasDefinitionHandler() {
|
||||
return definitionHandler != null;
|
||||
}
|
||||
|
||||
public synchronized void onReferences(ReferencesHandler h) {
|
||||
Assert.isNull("A references handler is already set, multiple handlers not supported yet", referencesHandler);
|
||||
this.referencesHandler = h;
|
||||
}
|
||||
|
||||
public boolean hasReferencesHandler() {
|
||||
return this.referencesHandler != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -87,7 +87,7 @@ public class TextDocument implements IDocument {
|
||||
|
||||
public synchronized void apply(DidChangeTextDocumentParams params) throws BadLocationException {
|
||||
int newVersion = params.getTextDocument().getVersion();
|
||||
if (version<newVersion) {
|
||||
if (version < newVersion) {
|
||||
for (TextDocumentContentChangeEvent change : params.getContentChanges()) {
|
||||
apply(change);
|
||||
}
|
||||
@@ -290,7 +290,7 @@ public class TextDocument implements IDocument {
|
||||
}
|
||||
|
||||
public TextDocumentIdentifier getId() {
|
||||
if (uri!=null) {
|
||||
if (uri != null) {
|
||||
return new TextDocumentIdentifier(uri);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -56,7 +56,8 @@ public class YamlQuickfixes {
|
||||
MISSING_PROP_FIX = r.register("MISSING_PROP_FIX", (Object _params) -> {
|
||||
MissingPropertiesData params = gson.fromJson((JsonElement)_params, MissingPropertiesData.class);
|
||||
try {
|
||||
TextDocument _doc = textDocumentService.getDocument(params.getUri());
|
||||
TextDocument _doc = textDocumentService.getLatestSnapshot(params.getUri());
|
||||
|
||||
if (_doc != null) {
|
||||
YamlDocument doc = new YamlDocument(_doc, structureProvider);
|
||||
SNode root = doc.getStructure();
|
||||
@@ -95,7 +96,8 @@ public class YamlQuickfixes {
|
||||
SIMPLE_TEXT_EDIT = r.register("SIMPLE_TEXT_EDIT", (_params) -> {
|
||||
try {
|
||||
ReplaceStringData params = gson.fromJson((JsonElement)_params, ReplaceStringData.class);
|
||||
TextDocument _doc = textDocumentService.getDocument(params.getUri());
|
||||
TextDocument _doc = textDocumentService.getLatestSnapshot(params.getUri());
|
||||
|
||||
if (_doc != null) {
|
||||
return new QuickfixEdit(
|
||||
new WorkspaceEdit(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -64,7 +64,8 @@ public class TypeBasedYamlSymbolHandler implements DocumentSymbolHandler {
|
||||
@Override
|
||||
public List<? extends SymbolInformation> handle(DocumentSymbolParams params) {
|
||||
Builder<SymbolInformation> builder = ImmutableList.builder();
|
||||
TextDocument doc = documents.getDocument(params.getTextDocument().getUri());
|
||||
|
||||
TextDocument doc = documents.getLatestSnapshot(params.getTextDocument().getUri());
|
||||
if (doc != null) {
|
||||
for (Entry<Node, YType> entry : astTypeCache.getNodeTypes(params.getTextDocument().getUri()).getTypes().entrySet()) {
|
||||
if (definitionTypes.contains(entry.getValue())) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -86,9 +86,11 @@ public class LanguageServerAutoConf {
|
||||
handlers.put(l, h);
|
||||
}
|
||||
}
|
||||
|
||||
ImmutableMap<LanguageId, DefinitionHandler> immutableMap = ImmutableMap.copyOf(handlers);
|
||||
return () -> documents.onDefinition((position) -> {
|
||||
TextDocument doc = documents.get(position.getTextDocument().getUri());
|
||||
TextDocument doc = documents.getLatestSnapshot(position);
|
||||
|
||||
if (doc != null) {
|
||||
LanguageId language = doc.getLanguageId();
|
||||
DefinitionHandler handler = immutableMap.get(language);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -92,7 +92,7 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder {
|
||||
@Override
|
||||
public List<LocationLink> handle(DefinitionParams params) {
|
||||
try {
|
||||
TextDocument doc = server.getTextDocumentService().get(params);
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params);
|
||||
if (doc!=null) {
|
||||
YamlFileAST ast = asts.getSafeAst(doc, false);
|
||||
if (ast!=null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -142,8 +142,8 @@ public class ConcourseLanguageServerInitializer {
|
||||
// });
|
||||
|
||||
documents.onCompletion(params -> {
|
||||
TextDocument doc = documents.get(params);
|
||||
if (doc!=null) {
|
||||
TextDocument doc = documents.getLatestSnapshot(params);
|
||||
if (doc != null) {
|
||||
if (LanguageId.CONCOURSE_PIPELINE.equals(doc.getLanguageId())) {
|
||||
return forPipelines.completionEngine.getCompletions(params);
|
||||
} else if (LanguageId.CONCOURSE_TASK.equals(doc.getLanguageId())) {
|
||||
@@ -159,8 +159,8 @@ public class ConcourseLanguageServerInitializer {
|
||||
documents.onHover(params -> {
|
||||
log.debug("Concourse hover handler starting");
|
||||
try {
|
||||
TextDocument doc = documents.get(params);
|
||||
if (doc!=null) {
|
||||
TextDocument doc = documents.getLatestSnapshot(params);
|
||||
if (doc != null) {
|
||||
LanguageId languageId = doc.getLanguageId();
|
||||
if (LanguageId.CONCOURSE_PIPELINE.equals(doc.getLanguageId())) {
|
||||
return forPipelines.hoverEngine.handle(params);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -63,7 +63,7 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu
|
||||
@Override
|
||||
public List<LocationLink> handle(DefinitionParams definitionParams) {
|
||||
try {
|
||||
TextDocument doc = documents.get(definitionParams);
|
||||
TextDocument doc = documents.getLatestSnapshot(definitionParams);
|
||||
TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(sourceLinks, doc);
|
||||
FuzzyMap<PropertyInfo> index = params.indexProvider.getIndex(doc).getProperties();
|
||||
int offset;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2019, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -99,7 +99,7 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu
|
||||
|
||||
JavaTypeHyperlinkProvider javaTypeHyperlinkProvider = new JavaTypeHyperlinkProvider(projectFinder, locationProvider);
|
||||
PropertyNameHyperlinkProvider propertyNameHyperlinkProvider = new PropertyNameHyperlinkProvider(projectFinder, locationProvider);
|
||||
BeanRefHyperlinkProvider beanRefHyperlinkProvider = new BeanRefHyperlinkProvider(projectFinder, symbolIndex, documents);
|
||||
BeanRefHyperlinkProvider beanRefHyperlinkProvider = new BeanRefHyperlinkProvider(projectFinder, symbolIndex);
|
||||
|
||||
List<JavaTypeHyperlinkProvider> typeHandlersOnly = Arrays.asList(javaTypeHyperlinkProvider);
|
||||
List<PropertyNameHyperlinkProvider> propertyNameHandlers = Arrays.asList(propertyNameHyperlinkProvider);
|
||||
@@ -143,7 +143,7 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu
|
||||
public List<LocationLink> handle(DefinitionParams params) {
|
||||
try {
|
||||
if (config.isSpringXMLSupportEnabled() && config.areXmlHyperlinksEnabled()) {
|
||||
TextDocument doc = documents.get(params);
|
||||
TextDocument doc = documents.getLatestSnapshot(params);
|
||||
if (doc != null) {
|
||||
String content = doc.get();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -70,7 +70,7 @@ public class YamlPropertiesJavaDefinitionHandler implements DefinitionHandler, L
|
||||
@Override
|
||||
public List<LocationLink> handle(DefinitionParams definitionParams) {
|
||||
try {
|
||||
TextDocument doc = documents.get(definitionParams);
|
||||
TextDocument doc = documents.getLatestSnapshot(definitionParams);
|
||||
int offset = doc.toOffset(definitionParams.getPosition());
|
||||
YamlFileAST ast = getAst(doc);
|
||||
if (ast != null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2018 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -40,8 +40,8 @@ public class BootJavaCodeLensEngine implements CodeLensHandler {
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
String docURI = params.getTextDocument().getUri();
|
||||
|
||||
if (documents.get(docURI) != null) {
|
||||
TextDocument doc = documents.get(docURI).copy();
|
||||
TextDocument doc = documents.getLatestSnapshot(docURI);
|
||||
if (doc != null) {
|
||||
// Spring Boot LS get events from boot properties files as well, so filter them out
|
||||
if (server.getInterestingLanguages().contains(doc.getLanguageId())) {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -42,10 +42,9 @@ public class BootJavaDocumentHighlightEngine implements DocumentHighlightHandler
|
||||
@Override
|
||||
public List<DocumentHighlight> handle(DocumentHighlightParams params) {
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
String docURI = params.getTextDocument().getUri();
|
||||
|
||||
if (documents.get(docURI) != null) {
|
||||
TextDocument doc = documents.get(docURI).copy();
|
||||
TextDocument doc = documents.getLatestSnapshot(params);
|
||||
|
||||
if (doc != null) {
|
||||
// Spring Boot LS get events from boot properties files as well, so filter them out
|
||||
if (doc != null && server.getInterestingLanguages().contains(doc.getLanguageId())) {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -73,8 +73,9 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
@Override
|
||||
public Hover handle(HoverParams params) {
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
if (documents.get(params) != null) {
|
||||
TextDocument doc = documents.get(params).copy();
|
||||
TextDocument doc = documents.getLatestSnapshot(params);
|
||||
|
||||
if (doc != null) {
|
||||
// Spring Boot LS get events from boot properties files as well, so filter them out
|
||||
if (server.getInterestingLanguages().contains(doc.getLanguageId())) {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -53,8 +53,9 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
|
||||
|
||||
@Override
|
||||
public List<? extends Location> handle(ReferenceParams params) {
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
TextDocument doc = documents.get(params).copy();
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
TextDocument doc = documents.getLatestSnapshot(params);
|
||||
|
||||
if (doc != null) {
|
||||
// Spring Boot LS get events from boot properties files as well, so filter them out
|
||||
if (server.getInterestingLanguages().contains(doc.getLanguageId())) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -37,10 +37,10 @@ public class SpringProcessLiveHoverUpdater {
|
||||
|
||||
private final SimpleLanguageServer server;
|
||||
private final BootJavaHoverProvider hoverProvider;
|
||||
private final JavaProjectFinder projectFinder;
|
||||
|
||||
private boolean highlightsEnabled = true;
|
||||
private JavaProjectFinder projectFinder;
|
||||
private final Map<String, AtomicReference<IJavaProject>> watchedDocs;
|
||||
private boolean highlightsEnabled = true;
|
||||
|
||||
public SpringProcessLiveHoverUpdater(
|
||||
SimpleLanguageServer server,
|
||||
@@ -56,11 +56,7 @@ public class SpringProcessLiveHoverUpdater {
|
||||
server.getTextDocumentService().onDidChangeContent(params -> {
|
||||
TextDocument doc = params.getDocument();
|
||||
if (BootJavaLanguageServerComponents.LANGUAGES.contains(doc.getLanguageId())) {
|
||||
try {
|
||||
watchDocument(doc.getUri());
|
||||
} catch (Throwable t) {
|
||||
log.error("", t);
|
||||
}
|
||||
watchDocument(doc.getUri());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -81,7 +77,14 @@ public class SpringProcessLiveHoverUpdater {
|
||||
|
||||
public void watchDocument(String docURI) {
|
||||
this.watchedDocs.putIfAbsent(docURI, new AtomicReference<IJavaProject>());
|
||||
updateDoc(docURI);
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
updateDoc(docURI);
|
||||
} catch (Throwable t) {
|
||||
log.error("", t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void unwatchDocument(String docURI) {
|
||||
@@ -89,6 +92,7 @@ public class SpringProcessLiveHoverUpdater {
|
||||
cleanupLiveHints(docURI);
|
||||
}
|
||||
|
||||
// runs async
|
||||
private void updateDoc(String docURI) {
|
||||
try {
|
||||
IJavaProject project = getCachedProject(docURI);
|
||||
@@ -99,6 +103,7 @@ public class SpringProcessLiveHoverUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
// runs async
|
||||
private void update() {
|
||||
if (this.watchedDocs.size() > 0) {
|
||||
try {
|
||||
@@ -112,10 +117,11 @@ public class SpringProcessLiveHoverUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
// runs async
|
||||
private void update(String docURI, IJavaProject project) {
|
||||
if (highlightsEnabled) {
|
||||
try {
|
||||
TextDocument doc = this.server.getTextDocumentService().get(docURI);
|
||||
TextDocument doc = this.server.getTextDocumentService().getLatestSnapshot(docURI);
|
||||
if (doc != null) {
|
||||
CodeLens[] infos = this.hoverProvider.getLiveHoverHints(doc, project);
|
||||
publishLiveHints(docURI, infos);
|
||||
@@ -126,6 +132,7 @@ public class SpringProcessLiveHoverUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
// runs async
|
||||
private IJavaProject getCachedProject(String docURI) {
|
||||
AtomicReference<IJavaProject> reference = this.watchedDocs.get(docURI);
|
||||
if (reference != null) {
|
||||
@@ -141,8 +148,9 @@ public class SpringProcessLiveHoverUpdater {
|
||||
return null;
|
||||
}
|
||||
|
||||
// runs async
|
||||
private IJavaProject identifyProject(String docURI) {
|
||||
TextDocument doc = this.server.getTextDocumentService().get(docURI);
|
||||
TextDocument doc = this.server.getTextDocumentService().getLatestSnapshot(docURI);
|
||||
if (doc != null) {
|
||||
return projectFinder.find(doc.getId()).orElse(null);
|
||||
}
|
||||
@@ -151,8 +159,9 @@ public class SpringProcessLiveHoverUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
// runs sync or async
|
||||
private void publishLiveHints(String docURI, CodeLens[] codeLenses) {
|
||||
TextDocument doc = server.getTextDocumentService().get(docURI);
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docURI);
|
||||
if (doc != null) {
|
||||
int version = doc.getVersion();
|
||||
VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(docURI, version);
|
||||
@@ -160,8 +169,9 @@ public class SpringProcessLiveHoverUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
// runs sync or async
|
||||
private void cleanupLiveHints(String docURI) {
|
||||
publishLiveHints(docURI, new CodeLens[0]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -18,9 +18,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -45,13 +42,11 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.AsyncRunner;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
@@ -62,95 +57,94 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
private static final long CU_ACCESS_EXPIRATION = 1;
|
||||
private JavaProjectFinder projectFinder;
|
||||
private ProjectObserver projectObserver;
|
||||
private Cache<URI, CompilationUnit> uriToCu;
|
||||
private Cache<IJavaProject, Set<URI>> projectToDocs;
|
||||
private Cache<IJavaProject, Tuple2<List<Classpath>, INameEnvironmentWithProgress>> lookupEnvCache;
|
||||
private ProjectObserver.Listener projectListener;
|
||||
private SimpleTextDocumentService documents;
|
||||
private AsyncRunner async;
|
||||
|
||||
private final ProjectObserver.Listener projectListener;
|
||||
private final SimpleTextDocumentService documentService;
|
||||
// private AsyncRunner async;
|
||||
|
||||
private ReadLock readLock;
|
||||
private WriteLock writeLock;
|
||||
private final Cache<URI, CompilationUnit> uriToCu;
|
||||
private final Cache<IJavaProject, Set<URI>> projectToDocs;
|
||||
private final Cache<IJavaProject, Tuple2<List<Classpath>, INameEnvironmentWithProgress>> lookupEnvCache;
|
||||
|
||||
// private ReadLock readLock;
|
||||
// private WriteLock writeLock;
|
||||
|
||||
public CompilationUnitCache(JavaProjectFinder projectFinder, SimpleLanguageServer server, ProjectObserver projectObserver) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.projectObserver = projectObserver;
|
||||
this.lookupEnvCache = CacheBuilder.newBuilder().build();
|
||||
|
||||
// PT 154618835 - Avoid retaining the CU in the cache as it consumes memory if it hasn't been
|
||||
// accessed after some time
|
||||
uriToCu = CacheBuilder.newBuilder()
|
||||
this.uriToCu = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(CU_ACCESS_EXPIRATION, TimeUnit.MINUTES)
|
||||
.build();
|
||||
projectToDocs = CacheBuilder.newBuilder().build();
|
||||
this.projectToDocs = CacheBuilder.newBuilder().build();
|
||||
this.lookupEnvCache = CacheBuilder.newBuilder().build();
|
||||
|
||||
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
readLock = lock.readLock();
|
||||
writeLock = lock.writeLock();
|
||||
// ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
// this.readLock = lock.readLock();
|
||||
// this.writeLock = lock.writeLock();
|
||||
|
||||
this.documents = server == null ? null : server.getTextDocumentService();
|
||||
this.async = server == null ? new AsyncRunner(Schedulers.single()) : server.getAsync();
|
||||
this.documentService = server == null ? null : server.getTextDocumentService();
|
||||
// this.async = server == null ? new AsyncRunner(Schedulers.single()) : server.getAsync();
|
||||
|
||||
|
||||
if (documents != null) {
|
||||
documents.onDidChangeContent(doc -> invalidateCuForJavaFile(doc.getDocument().getId().getUri()));
|
||||
documents.onDidClose(doc -> invalidateCuForJavaFile(doc.getId().getUri()));
|
||||
// IMPORTANT ===> these notifications arrive within the lsp message loop, so reactions to them have to be fast
|
||||
// and not be blocked by waiting for anything
|
||||
if (documentService != null) {
|
||||
documentService.onDidChangeContent(doc -> invalidateCuForJavaFile(doc.getDocument().getId().getUri()));
|
||||
documentService.onDidClose(doc -> invalidateCuForJavaFile(doc.getId().getUri()));
|
||||
}
|
||||
|
||||
for (IJavaProject project : projectFinder.all()) {
|
||||
logger.info("CU Cache: initial lookup env creation for project <{}>", project.getElementName());
|
||||
loadLookupEnvTuple(project);
|
||||
}
|
||||
|
||||
async.execute(() -> {
|
||||
writeLock.lock();
|
||||
try {
|
||||
for (IJavaProject project : projectFinder.all()) {
|
||||
loadLookupEnvTuple(project);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
});
|
||||
|
||||
projectListener = new ProjectObserver.Listener() {
|
||||
|
||||
@Override
|
||||
public void deleted(IJavaProject project) {
|
||||
logger.info("CU Cache: deleted project {}", project.getElementName());
|
||||
async.execute(() -> {
|
||||
writeLock.lock();
|
||||
try {
|
||||
// async.execute(() -> {
|
||||
// writeLock.lock();
|
||||
// try {
|
||||
invalidateProject(project);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
});
|
||||
// } finally {
|
||||
// writeLock.unlock();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(IJavaProject project) {
|
||||
logger.info("CU Cache: created project {}", project.getElementName());
|
||||
async.execute(() -> {
|
||||
writeLock.lock();
|
||||
try {
|
||||
// async.execute(() -> {
|
||||
// writeLock.lock();
|
||||
// try {
|
||||
invalidateProject(project);
|
||||
// Load the new cache the value right away
|
||||
loadLookupEnvTuple(project);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
});
|
||||
// } finally {
|
||||
// writeLock.unlock();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changed(IJavaProject project) {
|
||||
logger.info("CU Cache: changed project {}", project.getElementName());
|
||||
async.execute(() -> {
|
||||
writeLock.lock();
|
||||
try {
|
||||
// async.execute(() -> {
|
||||
// writeLock.lock();
|
||||
// try {
|
||||
invalidateProject(project);
|
||||
// Load the new cache the value right away
|
||||
loadLookupEnvTuple(project);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
});
|
||||
// } finally {
|
||||
// writeLock.unlock();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -182,9 +176,10 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
}
|
||||
|
||||
public <T> T withCompilationUnit(IJavaProject project, URI uri, Function<CompilationUnit, T> requestor) {
|
||||
logger.info("CU Cache: work item for doc {}", uri.toString());
|
||||
|
||||
if (project != null) {
|
||||
|
||||
readLock.lock();
|
||||
CompilationUnit cu = null;
|
||||
|
||||
try {
|
||||
@@ -193,20 +188,23 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
String utiStr = uri.toString();
|
||||
String unitName = utiStr.substring(utiStr.lastIndexOf("/"));
|
||||
CompilationUnit cUnit = parse2(fetchContent(uri).toCharArray(), utiStr, unitName, lookupEnvTuple.getT1(), lookupEnvTuple.getT2());
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(uri);
|
||||
|
||||
logger.info("CU Cache: created new AST for {}", uri.toString());
|
||||
|
||||
return cUnit;
|
||||
});
|
||||
|
||||
if (cu != null) {
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(uri);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("", e);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
if (cu != null) {
|
||||
try {
|
||||
logger.info("CU Cache: sync start on AST for {}", uri.toString());
|
||||
synchronized (cu.getAST()) {
|
||||
return requestor.apply(cu);
|
||||
}
|
||||
@@ -214,6 +212,9 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
catch (Exception e) {
|
||||
logger.error("", e);
|
||||
}
|
||||
finally {
|
||||
logger.info("CU Cache: sync end on AST for {}", uri.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,51 +222,6 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
}
|
||||
|
||||
|
||||
private void invalidateCuForJavaFile(String uriStr) {
|
||||
URI uri = URI.create(uriStr);
|
||||
writeLock.lock();
|
||||
try {
|
||||
uriToCu.invalidate(uri);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception {
|
||||
// String[] classpathEntries = getClasspathEntries(project);
|
||||
// String docURI = document.getUri();
|
||||
// String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||
// char[] source = document.get(0, document.getLength()).toCharArray();
|
||||
// return parse(source, docURI, unitName, classpathEntries);
|
||||
// }
|
||||
//
|
||||
// public CompilationUnit parse(String uri, char[] source, IJavaProject project) throws Exception {
|
||||
// String[] classpathEntries = getClasspathEntries(project);
|
||||
// String unitName = uri.substring(uri.lastIndexOf("/"));
|
||||
// return parse(source, uri, unitName, classpathEntries);
|
||||
// }
|
||||
//
|
||||
// public static CompilationUnit parse(char[] source, String docURI, String unitName, String[] classpathEntries) throws Exception {
|
||||
// ASTParser parser = ASTParser.newParser(AST.JLS11);
|
||||
// Map<String, String> options = JavaCore.getOptions();
|
||||
// JavaCore.setComplianceOptions(JavaCore.VERSION_11, options);
|
||||
// parser.setCompilerOptions(options);
|
||||
// parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
// parser.setStatementsRecovery(true);
|
||||
// parser.setBindingsRecovery(true);
|
||||
// parser.setResolveBindings(true);
|
||||
//
|
||||
// String[] sourceEntries = new String[] {};
|
||||
// parser.setEnvironment(classpathEntries, sourceEntries, null, false);
|
||||
//
|
||||
// parser.setUnitName(unitName);
|
||||
// parser.setSource(source);
|
||||
//
|
||||
// CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
//
|
||||
// return cu;
|
||||
// }
|
||||
|
||||
public static CompilationUnit parse2(char[] source, String docURI, String unitName, IJavaProject project) throws Exception {
|
||||
List<Classpath> classpaths = createClasspath(getClasspathEntries(project));
|
||||
return parse2(source, docURI, unitName, classpaths, null);
|
||||
@@ -294,7 +250,7 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
needToResolveBindings = false;
|
||||
}
|
||||
|
||||
CompilationUnit cu = CUResolver.convert(unit, source, AST.JLS11, options, needToResolveBindings, DefaultWorkingCopyOwner.PRIMARY, flags);
|
||||
CompilationUnit cu = CUResolver.convert(unit, source, AST.JLS14, options, needToResolveBindings, DefaultWorkingCopyOwner.PRIMARY, flags);
|
||||
|
||||
return cu;
|
||||
}
|
||||
@@ -331,7 +287,16 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidateCuForJavaFile(String uriStr) {
|
||||
logger.info("CU Cache: invalidate AST for {}", uriStr);
|
||||
|
||||
URI uri = URI.create(uriStr);
|
||||
uriToCu.invalidate(uri);
|
||||
}
|
||||
|
||||
private void invalidateProject(IJavaProject project) {
|
||||
logger.info("CU Cache: invalidate project <{}>", project.getElementName());
|
||||
|
||||
Set<URI> docUris = projectToDocs.getIfPresent(project);
|
||||
if (docUris != null) {
|
||||
uriToCu.invalidateAll(docUris);
|
||||
@@ -342,13 +307,13 @@ public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
|
||||
@Override
|
||||
public String fetchContent(URI uri) throws Exception {
|
||||
if (documents != null) {
|
||||
TextDocument document = documents.get(uri.toString());
|
||||
if (documentService != null) {
|
||||
TextDocument document = documentService.getLatestSnapshot(uri.toString());
|
||||
if (document != null) {
|
||||
return document.get(0, document.getLength());
|
||||
return document.get();
|
||||
}
|
||||
}
|
||||
return IOUtils.toString(uri);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2019, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -24,7 +24,6 @@ import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformati
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
@@ -34,12 +33,10 @@ public class BeanRefHyperlinkProvider implements XMLHyperlinkProvider {
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final SpringSymbolIndex symbolIndex;
|
||||
private final SimpleTextDocumentService documents;
|
||||
|
||||
public BeanRefHyperlinkProvider(JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex, SimpleTextDocumentService documents) {
|
||||
public BeanRefHyperlinkProvider(JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.symbolIndex = symbolIndex;
|
||||
this.documents = documents;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,11 +44,26 @@ public class BeanRefHyperlinkProvider implements XMLHyperlinkProvider {
|
||||
Optional<IJavaProject> foundProject = this.projectFinder.find(doc.getId());
|
||||
if (foundProject.isPresent()) {
|
||||
final IJavaProject project = foundProject.get();
|
||||
String projectLocation = project.getLocationUri() != null ? project.getLocationUri().toString() : "";
|
||||
|
||||
// make sure the project and the symbol location share the same prefix "file:///"
|
||||
// looks like project locations are containing a "file:/" only
|
||||
if (!projectLocation.startsWith("file:///")) {
|
||||
projectLocation = "file:///" + projectLocation.substring("file:/".length());
|
||||
}
|
||||
|
||||
// make sure that only exact project locations are matched
|
||||
if (!projectLocation.endsWith("/")) {
|
||||
projectLocation = projectLocation + "/";
|
||||
}
|
||||
|
||||
List<SymbolInformation> symbols = symbolIndex.getSymbols(data -> symbolsFilter(data, attributeAt.getValue())).collect(Collectors.toList());
|
||||
if (!symbols.isEmpty()) {
|
||||
for (SymbolInformation symbol : symbols) {
|
||||
Location location = symbol.getLocation();
|
||||
if (project == documents.get(location.getUri())) {
|
||||
String uri = location.getUri();
|
||||
|
||||
if (uri != null && uri.startsWith(projectLocation)) {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +75,7 @@ public class BeanRefHyperlinkProvider implements XMLHyperlinkProvider {
|
||||
|
||||
private boolean symbolsFilter(EnhancedSymbolInformation data, String beanId) {
|
||||
SymbolAddOnInformation[] additionalInformation = data.getAdditionalInformation();
|
||||
if (additionalInformation != null) {
|
||||
if (beanId != null && additionalInformation != null) {
|
||||
for (SymbolAddOnInformation info : additionalInformation) {
|
||||
if (info instanceof BeansSymbolAddOnInformation) {
|
||||
return beanId.equals(((BeansSymbolAddOnInformation)info).getBeanID());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2019, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -63,7 +63,8 @@ public class AppYamlQuickfixes {
|
||||
DEPRECATED_PROPERTY = r.register("DEPRECATED_YAML_PROPERTY", (Object _params) -> {
|
||||
DeprecatedPropertyData params = gson.fromJson((JsonElement)_params, DeprecatedPropertyData.class);
|
||||
try {
|
||||
TextDocument _doc = textDocumentService.getDocument(params.getUri());
|
||||
TextDocument _doc = textDocumentService.getLatestSnapshot(params.getUri());
|
||||
|
||||
if (_doc != null) {
|
||||
YamlDocument doc = new YamlDocument(_doc, structureProvider);
|
||||
SNode root = doc.getStructure();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2020, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -316,7 +316,7 @@ public class ValueSpelExpressionValidationTest {
|
||||
server.getTextDocumentService().didOpen(openParams);
|
||||
server.getAsync().waitForAll();
|
||||
|
||||
TextDocument doc = server.getTextDocumentService().get(docUri);
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docUri);
|
||||
|
||||
int position = content.indexOf(selectedAnnotation);
|
||||
doc.replace(position, selectedAnnotation.length(), annotationStatementBeforeTest);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2020, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -141,7 +141,7 @@ public class XMLSpelExpressionValidationTest {
|
||||
server.getTextDocumentService().didOpen(openParams);
|
||||
server.getAsync().waitForAll();
|
||||
|
||||
TextDocument doc = server.getTextDocumentService().get(docUri);
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docUri);
|
||||
|
||||
int position = content.indexOf(selectedAnnotation);
|
||||
doc.replace(position, selectedAnnotation.length(), annotationStatementBeforeTest);
|
||||
|
||||
Reference in New Issue
Block a user