Merge branch 'master' of github.com:spring-projects/sts4
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -17,6 +18,8 @@ import java.util.concurrent.CompletableFuture;
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
import org.eclipse.lsp4j.InitializeParams;
|
||||
import org.eclipse.lsp4j.InitializeResult;
|
||||
import org.eclipse.lsp4j.Registration;
|
||||
import org.eclipse.lsp4j.RegistrationParams;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareFactoryManager;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider;
|
||||
@@ -56,6 +59,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.IComplet
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFoldersProposedService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LSFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
|
||||
@@ -174,13 +178,17 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
|
||||
public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
|
||||
CompletableFuture<InitializeResult> result = super.initialize(params);
|
||||
|
||||
this.indexer.initialize(this.getWorkspaceRoot());
|
||||
this.indexer.initialize(getWorkspaceRoots());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialized() {
|
||||
Registration registration = new Registration(WorkspaceFoldersProposedService.CAPABILITY_ID, WorkspaceFoldersProposedService.CAPABILITY_NAME, null);
|
||||
RegistrationParams registrationParams = new RegistrationParams(Collections.singletonList(registration));
|
||||
getClient().registerCapability(registrationParams);
|
||||
|
||||
// TODO: due to a missing message from lsp4e this "initialized" is not called in
|
||||
// the LSP4E case
|
||||
// if this gets fixed, the code should move here (from "initialize" above)
|
||||
@@ -360,4 +368,5 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
|
||||
public CompilationUnitCache getCompilationUnitCache() {
|
||||
return cuCache;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.BootProjectUtil;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringLiveHoverWatchdog;
|
||||
import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleCore;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleProjectCache;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.java.BootProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeProjectOvserver;
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver.Listener;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
@@ -105,12 +106,13 @@ public class SpringIndexer {
|
||||
this.symbols = Collections.synchronizedList(new ArrayList<>());
|
||||
this.symbolsByDoc = new ConcurrentHashMap<>();
|
||||
|
||||
server.getWorkspaceService().onDidChangeWorkspaceFolders(evt -> {
|
||||
System.err.println("Workspace roots have changed!");
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> initialize(final Path workspaceRoot) {
|
||||
if (workspaceRoot==null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
public CompletableFuture<Void> initialize(Collection<WorkspaceFolder> workspaceRoots) {
|
||||
synchronized(this) {
|
||||
if (this.initializeTask == null) {
|
||||
initializing.set(true);
|
||||
@@ -120,7 +122,9 @@ public class SpringIndexer {
|
||||
this.initializeTask = CompletableFuture.runAsync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scanFiles(workspaceRoot.toFile());
|
||||
for (WorkspaceFolder root : workspaceRoots) {
|
||||
scanFiles(root);
|
||||
}
|
||||
|
||||
SpringIndexer.this.updateQueue = new LinkedBlockingQueue<>();
|
||||
SpringIndexer.this.updateWorker = new Thread(new Runnable() {
|
||||
@@ -141,13 +145,12 @@ public class SpringIndexer {
|
||||
}
|
||||
}
|
||||
}, "Spring Annotation Index Update Worker");
|
||||
|
||||
updateWorker.start();
|
||||
initializing.set(false);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return this.initializeTask;
|
||||
}
|
||||
}
|
||||
@@ -163,7 +166,7 @@ public class SpringIndexer {
|
||||
symbols.clear();
|
||||
symbolsByDoc.clear();
|
||||
Log.info("Rebuilding SpringIndexer...");
|
||||
initialize(server.getWorkspaceRoot());
|
||||
initialize(server.getWorkspaceRoots());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,9 +255,9 @@ public class SpringIndexer {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void scanFiles(File directory) {
|
||||
private void scanFiles(WorkspaceFolder directory) {
|
||||
try {
|
||||
Map<Optional<IJavaProject>, List<String>> projects = Files.walk(directory.toPath())
|
||||
Map<Optional<IJavaProject>, List<String>> projects = Files.walk(Paths.get(new URI(directory.getUri())))
|
||||
.filter(path -> path.getFileName().toString().endsWith(".java"))
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
@@ -268,6 +271,7 @@ public class SpringIndexer {
|
||||
}
|
||||
|
||||
private void scanProject(IJavaProject project, String[] files) {
|
||||
System.err.println("scan project: "+project);
|
||||
try {
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS8);
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -94,7 +95,7 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
|
||||
if (range != null) {
|
||||
String propertyKey = value.substring(range.getStart(), range.getEnd());
|
||||
if (propertyKey != null && propertyKey.length() > 0) {
|
||||
return findReferencesFromPropertyFiles(languageServer.getWorkspaceRoot(), propertyKey);
|
||||
return findReferencesFromPropertyFiles(languageServer.getWorkspaceRoots(), propertyKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,21 +106,26 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
public CompletableFuture<List<? extends Location>> findReferencesFromPropertyFiles(Path workspaceRoot,
|
||||
String propertyKey) {
|
||||
public CompletableFuture<List<? extends Location>> findReferencesFromPropertyFiles(
|
||||
Collection<WorkspaceFolder> workspaceRoots,
|
||||
String propertyKey
|
||||
) {
|
||||
for (WorkspaceFolder workspaceFolder : workspaceRoots) {
|
||||
try {
|
||||
Path workspaceRoot = Paths.get(new URI(workspaceFolder.getUri()));
|
||||
try (Stream<Path> walk = Files.walk(workspaceRoot)) {
|
||||
List<Location> locations = walk
|
||||
.filter(path -> isPropertiesFile(path))
|
||||
.filter(path -> path.toFile().isFile())
|
||||
.map(path -> findReferences(path, propertyKey))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
try (Stream<Path> walk = Files.walk(workspaceRoot)) {
|
||||
List<Location> locations = walk
|
||||
.filter(path -> isPropertiesFile(path))
|
||||
.filter(path -> path.toFile().isFile())
|
||||
.map(path -> findReferences(path, propertyKey))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return CompletableFuture.completedFuture(locations);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return CompletableFuture.completedFuture(locations);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -30,9 +31,12 @@ import org.springframework.ide.vscode.boot.java.beans.test.SpringIndexerHarness.
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@@ -57,7 +61,7 @@ public class SpringIndexerBeansTest {
|
||||
public void testScanSimpleConfigurationClass() throws Exception {
|
||||
SpringIndexerHarness indexer = new SpringIndexerHarness(harness.getServer(), projectFinder, symbolProviders);
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-beans/").toURI());
|
||||
indexer.initialize(directory.toPath());
|
||||
indexer.initialize(indexer.wsFolder(directory));
|
||||
|
||||
String uriPrefix = "file://" + directory.getAbsolutePath();
|
||||
indexer.assertDocumentSymbols(uriPrefix + "/src/main/java/org/test/SimpleConfiguration.java",
|
||||
@@ -71,7 +75,7 @@ public class SpringIndexerBeansTest {
|
||||
@Test public void testScanSpecialConfigurationClass() throws Exception {
|
||||
SpringIndexerHarness indexer = new SpringIndexerHarness(harness.getServer(), projectFinder, symbolProviders);
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-beans/").toURI());
|
||||
indexer.initialize(directory.toPath());
|
||||
indexer.initialize(indexer.wsFolder(directory));
|
||||
|
||||
String uriPrefix = "file://" + directory.getAbsolutePath();
|
||||
String docUri = uriPrefix + "/src/main/java/org/test/SpecialConfiguration.java";
|
||||
@@ -103,7 +107,7 @@ public class SpringIndexerBeansTest {
|
||||
public void testScanSimpleFunctionBean() throws Exception {
|
||||
SpringIndexerHarness indexer = new SpringIndexerHarness(harness.getServer(), projectFinder, symbolProviders);
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-beans/").toURI());
|
||||
indexer.initialize(directory.toPath());
|
||||
indexer.initialize(indexer.wsFolder(directory));
|
||||
|
||||
String uriPrefix = "file://" + directory.getAbsolutePath();
|
||||
indexer.assertDocumentSymbols(uriPrefix + "/src/main/java/org/test/FunctionClass.java",
|
||||
@@ -119,7 +123,7 @@ public class SpringIndexerBeansTest {
|
||||
public void testScanSimpleComponentClass() throws Exception {
|
||||
SpringIndexerHarness indexer = new SpringIndexerHarness(harness.getServer(), projectFinder, symbolProviders);
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-beans/").toURI());
|
||||
indexer.initialize(directory.toPath());
|
||||
indexer.initialize(indexer.wsFolder(directory));
|
||||
|
||||
String uriPrefix = "file://" + directory.getAbsolutePath();
|
||||
indexer.assertDocumentSymbols(uriPrefix + "/src/main/java/org/test/SimpleComponent.java",
|
||||
@@ -134,7 +138,7 @@ public class SpringIndexerBeansTest {
|
||||
@Test public void testScanSimpleControllerClass() throws Exception {
|
||||
SpringIndexerHarness indexer = new SpringIndexerHarness(harness.getServer(), projectFinder, symbolProviders);
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-beans/").toURI());
|
||||
indexer.initialize(directory.toPath());
|
||||
indexer.initialize(indexer.wsFolder(directory));
|
||||
|
||||
String uriPrefix = "file://" + directory.getAbsolutePath();
|
||||
String docUri = uriPrefix + "/src/main/java/org/test/SimpleController.java";
|
||||
@@ -148,7 +152,7 @@ public class SpringIndexerBeansTest {
|
||||
@Test public void testScanRestControllerClass() throws Exception {
|
||||
SpringIndexerHarness indexer = new SpringIndexerHarness(harness.getServer(), projectFinder, symbolProviders);
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-beans/").toURI());
|
||||
indexer.initialize(directory.toPath());
|
||||
indexer.initialize(indexer.wsFolder(directory));
|
||||
|
||||
String uriPrefix = "file://" + directory.getAbsolutePath();
|
||||
String docUri = uriPrefix + "/src/main/java/org/test/SimpleRestController.java";
|
||||
|
||||
@@ -12,14 +12,14 @@ package org.springframework.ide.vscode.boot.java.beans.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
@@ -29,6 +29,7 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyA
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
@@ -139,7 +140,17 @@ public class SpringIndexerHarness {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
public void initialize(Path wsRoot) {
|
||||
indexer.initialize(wsRoot);
|
||||
public Collection<WorkspaceFolder> wsFolder(File directory) {
|
||||
if (directory!=null) {
|
||||
return ImmutableList.of(new WorkspaceFolder(
|
||||
directory.toURI().toString(),
|
||||
directory.getName()
|
||||
));
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
public void initialize(Collection<WorkspaceFolder> wsRoots) {
|
||||
indexer.initialize(wsRoots);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,22 @@ package org.springframework.ide.vscode.boot.java.references.test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValuePropertyReferencesProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@@ -34,7 +39,7 @@ public class PropertyReferenceFinderTest {
|
||||
ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null);
|
||||
|
||||
Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/simple-case/").toURI());
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(root, "test.property");
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(wsFolder(root), "test.property");
|
||||
|
||||
assertNotNull(resultFuture);
|
||||
List<? extends Location> locations = resultFuture.get();
|
||||
@@ -49,12 +54,22 @@ public class PropertyReferenceFinderTest {
|
||||
assertEquals(13, location.getRange().getEnd().getCharacter());
|
||||
}
|
||||
|
||||
private Collection<WorkspaceFolder> wsFolder(Path directory) {
|
||||
if (directory!=null) {
|
||||
return ImmutableList.of(new WorkspaceFolder(
|
||||
directory.toUri().toString(),
|
||||
directory.getFileName().toString()
|
||||
));
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindReferenceAtBeginningYMLFile() throws Exception {
|
||||
ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null);
|
||||
|
||||
Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/simple-yml/").toURI());
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(root, "test.property");
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(wsFolder(root), "test.property");
|
||||
|
||||
assertNotNull(resultFuture);
|
||||
List<? extends Location> locations = resultFuture.get();
|
||||
@@ -74,7 +89,7 @@ public class PropertyReferenceFinderTest {
|
||||
ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null);
|
||||
|
||||
Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/simple-case/").toURI());
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(root, "server.port");
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(wsFolder(root), "server.port");
|
||||
|
||||
assertNotNull(resultFuture);
|
||||
List<? extends Location> locations = resultFuture.get();
|
||||
@@ -94,7 +109,7 @@ public class PropertyReferenceFinderTest {
|
||||
ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null);
|
||||
|
||||
Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/multiple-files/").toURI());
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(root, "appl1.prop");
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(wsFolder(root), "appl1.prop");
|
||||
|
||||
assertNotNull(resultFuture);
|
||||
List<? extends Location> locations = resultFuture.get();
|
||||
@@ -121,14 +136,14 @@ public class PropertyReferenceFinderTest {
|
||||
assertEquals(1, location.getRange().getEnd().getLine());
|
||||
assertEquals(10, location.getRange().getEnd().getCharacter());
|
||||
}
|
||||
|
||||
|
||||
private Location getLocation(List<? extends Location> locations, URI docURI) {
|
||||
for (Location location : locations) {
|
||||
if (docURI.toString().equals(location.getUri())) {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -137,7 +152,7 @@ public class PropertyReferenceFinderTest {
|
||||
ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null);
|
||||
|
||||
Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/mixed-multiple-files/").toURI());
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(root, "appl1.prop");
|
||||
CompletableFuture<List<? extends Location>> resultFuture = provider.findReferencesFromPropertyFiles(wsFolder(root), "appl1.prop");
|
||||
|
||||
assertNotNull(resultFuture);
|
||||
List<? extends Location> locations = resultFuture.get();
|
||||
|
||||
@@ -48,7 +48,7 @@ public class SpringPropertyIndexTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanningAllAnnotationsSimpleProjectUpfront() throws Exception {
|
||||
public void testPropertiesIndexRefreshOnProjectChange() throws Exception {
|
||||
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-parent/test-annotation-indexing/").toURI()));
|
||||
propertyIndexProvider = (DefaultSpringPropertyIndexProvider) harness.getServer().getSpringPropertyIndexProvider();
|
||||
|
||||
|
||||
@@ -80,6 +80,13 @@
|
||||
<version>${dependencies.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>${mockito-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.ide.vscode.boot.common.PropertyCompletionFactory;
|
||||
import org.springframework.ide.vscode.boot.common.RelaxedNameConfig;
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
|
||||
@@ -23,24 +20,17 @@ import org.springframework.ide.vscode.boot.properties.hover.PropertiesHoverInfoP
|
||||
import org.springframework.ide.vscode.boot.properties.reconcile.SpringPropertiesReconcileEngine;
|
||||
import org.springframework.ide.vscode.boot.yaml.completions.ApplicationYamlAssistContext;
|
||||
import org.springframework.ide.vscode.boot.yaml.reconcile.ApplicationYamlReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleCore;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleProjectCache;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngineAdapter.HoverType;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeProjectOvserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LSFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenProjectCache;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -72,8 +62,8 @@ public class BootPropertiesLanguageServer extends SimpleLanguageServer {
|
||||
public boolean includeDeindentedProposals() { return false; };
|
||||
};
|
||||
// Shared:
|
||||
private final CompositeProjectOvserver projectObserver;
|
||||
private final CompositeJavaProjectFinder javaProjectFinder;
|
||||
private final ProjectObserver projectObserver;
|
||||
private final JavaProjectFinder javaProjectFinder;
|
||||
private final SpringPropertyIndexProvider indexProvider;
|
||||
private final TypeUtilProvider typeUtilProvider;
|
||||
private final VscodeCompletionEngineAdapter completionEngine;
|
||||
@@ -88,11 +78,16 @@ public class BootPropertiesLanguageServer extends SimpleLanguageServer {
|
||||
private final YamlStructureProvider yamlStructureProvider= YamlStructureProvider.DEFAULT;
|
||||
private YamlAssistContextProvider yamlAssistContextProvider;
|
||||
|
||||
public BootPropertiesLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, CompositeJavaProjectFinder javaProjectFinder) {
|
||||
public BootPropertiesLanguageServer(LSFactory<BootPropertiesLanguageServerParams> _params) {
|
||||
super("vscode-boot-properties");
|
||||
this.indexProvider = indexProvider;
|
||||
this.typeUtilProvider = typeUtilProvider;
|
||||
this.javaProjectFinder = javaProjectFinder;
|
||||
|
||||
BootPropertiesLanguageServerParams serverParams = _params.create(this);
|
||||
|
||||
this.indexProvider = serverParams.indexProvider;
|
||||
this.typeUtilProvider = serverParams.typeUtilProvider;
|
||||
this.javaProjectFinder = serverParams.projectFinder;
|
||||
this.projectObserver = serverParams.projectObserver;
|
||||
|
||||
this.completionFactory = new PropertyCompletionFactory(javaProjectFinder);
|
||||
this.yamlAssistContextProvider = new YamlAssistContextProvider() {
|
||||
@Override
|
||||
@@ -119,17 +114,7 @@ public class BootPropertiesLanguageServer extends SimpleLanguageServer {
|
||||
|
||||
HoverInfoProvider hoverInfoProvider = getHoverProvider();
|
||||
hoverEngine = new VscodeHoverEngineAdapter(this, hoverInfoProvider);
|
||||
documents.onHover(hoverEngine::getHover);
|
||||
|
||||
// Initialize project finders, project caches and project observers
|
||||
MavenProjectCache mavenProjectCache = new MavenProjectCache(getWorkspaceService().getFileObserver(), MavenCore.getDefault(), true, Paths.get(IJavaProject.PROJECT_CACHE_FOLDER));
|
||||
javaProjectFinder.addJavaProjectFinder(new MavenProjectFinder(mavenProjectCache));
|
||||
|
||||
GradleProjectCache gradleProjectCache = new GradleProjectCache(getWorkspaceService().getFileObserver(), GradleCore.getDefault(), true, Paths.get(IJavaProject.PROJECT_CACHE_FOLDER));
|
||||
javaProjectFinder.addJavaProjectFinder(new GradleProjectFinder(gradleProjectCache));
|
||||
|
||||
projectObserver = new CompositeProjectOvserver(Arrays.asList(mavenProjectCache, gradleProjectCache));
|
||||
|
||||
documents.onHover(hoverEngine::getHover);
|
||||
}
|
||||
|
||||
private ICompletionEngine getCompletionEngine() {
|
||||
@@ -197,4 +182,8 @@ public class BootPropertiesLanguageServer extends SimpleLanguageServer {
|
||||
public ProjectObserver getProjectObserver() {
|
||||
return projectObserver;
|
||||
}
|
||||
|
||||
public SpringPropertyIndexProvider getPropertiesIndexProvider() {
|
||||
return indexProvider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleCore;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleProjectCache;
|
||||
import org.springframework.ide.vscode.commons.gradle.GradleProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.java.BootProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeProjectOvserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LSFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenProjectCache;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
|
||||
/**
|
||||
* Parameters for creating Boot Properties language server
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class BootPropertiesLanguageServerParams {
|
||||
|
||||
public final JavaProjectFinder projectFinder;
|
||||
public final ProjectObserver projectObserver;
|
||||
public final SpringPropertyIndexProvider indexProvider;
|
||||
public final TypeUtilProvider typeUtilProvider;
|
||||
|
||||
public BootPropertiesLanguageServerParams(
|
||||
JavaProjectFinder projectFinder,
|
||||
ProjectObserver projectObserver,
|
||||
SpringPropertyIndexProvider indexProvider,
|
||||
TypeUtilProvider typeUtilProvider
|
||||
) {
|
||||
super();
|
||||
this.projectFinder = projectFinder;
|
||||
this.projectObserver = projectObserver;
|
||||
this.indexProvider = indexProvider;
|
||||
this.typeUtilProvider = typeUtilProvider;
|
||||
}
|
||||
|
||||
public static LSFactory<BootPropertiesLanguageServerParams> createDefault() {
|
||||
return (SimpleLanguageServer server) -> {
|
||||
// Initialize project finders, project caches and project observers
|
||||
FileObserver fileObserver = server.getWorkspaceService().getFileObserver();
|
||||
CompositeJavaProjectFinder javaProjectFinder = new CompositeJavaProjectFinder();
|
||||
MavenProjectCache mavenProjectCache = new MavenProjectCache(fileObserver, MavenCore.getDefault(), true, Paths.get(IJavaProject.PROJECT_CACHE_FOLDER));
|
||||
javaProjectFinder.addJavaProjectFinder(new MavenProjectFinder(mavenProjectCache));
|
||||
|
||||
GradleProjectCache gradleProjectCache = new GradleProjectCache(fileObserver, GradleCore.getDefault(), true, Paths.get(IJavaProject.PROJECT_CACHE_FOLDER));
|
||||
javaProjectFinder.addJavaProjectFinder(new GradleProjectFinder(gradleProjectCache));
|
||||
|
||||
CompositeProjectOvserver projectObserver = new CompositeProjectOvserver(Arrays.asList(mavenProjectCache, gradleProjectCache));
|
||||
|
||||
DefaultSpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder, projectObserver);
|
||||
indexProvider.setProgressService(server.getProgressService());
|
||||
|
||||
return new BootPropertiesLanguageServerParams(
|
||||
javaProjectFinder.filter(BootProjectUtil::isBootProject),
|
||||
projectObserver,
|
||||
indexProvider,
|
||||
(IDocument doc) -> new TypeUtil(javaProjectFinder.find(new TextDocumentIdentifier(doc.getUri())))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public static LSFactory<BootPropertiesLanguageServerParams> createTestDefault(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider) {
|
||||
return (SimpleLanguageServer server) -> {
|
||||
// Initialize project finders, project caches and project observers
|
||||
FileObserver fileObserver = server.getWorkspaceService().getFileObserver();
|
||||
CompositeJavaProjectFinder javaProjectFinder = new CompositeJavaProjectFinder();
|
||||
MavenProjectCache mavenProjectCache = new MavenProjectCache(fileObserver, MavenCore.getDefault(), false, null);
|
||||
mavenProjectCache.setAlwaysFireEventOnFileChanged(true);
|
||||
javaProjectFinder.addJavaProjectFinder(new MavenProjectFinder(mavenProjectCache));
|
||||
|
||||
GradleProjectCache gradleProjectCache = new GradleProjectCache(fileObserver, GradleCore.getDefault(), false, null);
|
||||
gradleProjectCache.setAlwaysFireEventOnFileChanged(true);
|
||||
javaProjectFinder.addJavaProjectFinder(new GradleProjectFinder(gradleProjectCache));
|
||||
|
||||
CompositeProjectOvserver projectObserver = new CompositeProjectOvserver(Arrays.asList(mavenProjectCache, gradleProjectCache));
|
||||
|
||||
return new BootPropertiesLanguageServerParams(
|
||||
javaProjectFinder.filter(BootProjectUtil::isBootProject),
|
||||
projectObserver,
|
||||
indexProvider,
|
||||
typeUtilProvider
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public static LSFactory<BootPropertiesLanguageServerParams> createTestDefault() {
|
||||
return (SimpleLanguageServer server) -> {
|
||||
// Initialize project finders, project caches and project observers
|
||||
FileObserver fileObserver = server.getWorkspaceService().getFileObserver();
|
||||
CompositeJavaProjectFinder javaProjectFinder = new CompositeJavaProjectFinder();
|
||||
MavenProjectCache mavenProjectCache = new MavenProjectCache(fileObserver, MavenCore.getDefault(), false, null);
|
||||
mavenProjectCache.setAlwaysFireEventOnFileChanged(true);
|
||||
javaProjectFinder.addJavaProjectFinder(new MavenProjectFinder(mavenProjectCache));
|
||||
|
||||
GradleProjectCache gradleProjectCache = new GradleProjectCache(fileObserver, GradleCore.getDefault(), false, null);
|
||||
gradleProjectCache.setAlwaysFireEventOnFileChanged(true);
|
||||
javaProjectFinder.addJavaProjectFinder(new GradleProjectFinder(gradleProjectCache));
|
||||
|
||||
CompositeProjectOvserver projectObserver = new CompositeProjectOvserver(Arrays.asList(mavenProjectCache, gradleProjectCache));
|
||||
|
||||
DefaultSpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder, projectObserver);
|
||||
indexProvider.setProgressService(server.getProgressService());
|
||||
|
||||
return new BootPropertiesLanguageServerParams(
|
||||
javaProjectFinder.filter(BootProjectUtil::isBootProject),
|
||||
projectObserver,
|
||||
indexProvider,
|
||||
(IDocument doc) -> new TypeUtil(javaProjectFinder.find(new TextDocumentIdentifier(doc.getUri())))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,14 +12,7 @@ package org.springframework.ide.vscode.boot;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
|
||||
/**
|
||||
* Starts up Language Server process
|
||||
@@ -31,14 +24,8 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
LaunguageServerApp.start("boot-properties", () -> {
|
||||
CompositeJavaProjectFinder javaProjectFinder = new CompositeJavaProjectFinder();
|
||||
DefaultSpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder);
|
||||
TypeUtilProvider typeUtilProvider = (IDocument doc) -> new TypeUtil(javaProjectFinder.find(new TextDocumentIdentifier(doc.getUri())));
|
||||
SimpleLanguageServer server = new BootPropertiesLanguageServer(indexProvider, typeUtilProvider, javaProjectFinder);
|
||||
indexProvider.setProgressService(server.getProgressService());
|
||||
return server;
|
||||
});
|
||||
LaunguageServerApp.start("boot-properties",
|
||||
() -> new BootPropertiesLanguageServer(BootPropertiesLanguageServerParams.createDefault()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.ProgressService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
|
||||
@@ -25,12 +26,13 @@ public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexPr
|
||||
private static final FuzzyMap<PropertyInfo> EMPTY_INDEX = new SpringPropertyIndex(null, null);
|
||||
|
||||
private JavaProjectFinder javaProjectFinder;
|
||||
private SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(ValueProviderRegistry.getDefault());
|
||||
private SpringPropertiesIndexManager indexManager;
|
||||
|
||||
private ProgressService progressService = (id, msg) -> { /*ignore*/ };
|
||||
|
||||
public DefaultSpringPropertyIndexProvider(JavaProjectFinder javaProjectFinder) {
|
||||
public DefaultSpringPropertyIndexProvider(JavaProjectFinder javaProjectFinder, ProjectObserver projectObserver) {
|
||||
this.javaProjectFinder = javaProjectFinder;
|
||||
this.indexManager = new SpringPropertiesIndexManager(ValueProviderRegistry.getDefault(), projectObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,16 +10,18 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.metadata;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.springframework.ide.vscode.boot.metadata.util.Listener;
|
||||
import org.springframework.ide.vscode.boot.metadata.util.ListenerManager;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.ProgressService;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
/**
|
||||
* Support for Reconciling, Content Assist and Hover Text in spring properties
|
||||
* file all make use of a per-project index of spring properties metadata extracted
|
||||
@@ -30,41 +32,68 @@ import org.springframework.ide.vscode.commons.util.Log;
|
||||
*/
|
||||
public class SpringPropertiesIndexManager extends ListenerManager<Listener<SpringPropertiesIndexManager>> {
|
||||
|
||||
private Map<IJavaProject, SpringPropertyIndex> indexes = null;
|
||||
private Cache<IJavaProject, SpringPropertyIndex> indexes;
|
||||
private final ValueProviderRegistry valueProviders;
|
||||
private static int progressIdCt = 0;
|
||||
|
||||
public SpringPropertiesIndexManager(ValueProviderRegistry valueProviders) {
|
||||
public SpringPropertiesIndexManager(ValueProviderRegistry valueProviders, ProjectObserver projectObserver) {
|
||||
this.valueProviders = valueProviders;
|
||||
this.indexes = CacheBuilder.newBuilder().build();
|
||||
if (projectObserver != null) {
|
||||
projectObserver.addListener(new ProjectObserver.Listener() {
|
||||
|
||||
@Override
|
||||
public void created(IJavaProject project) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changed(IJavaProject project) {
|
||||
indexes.invalidate(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleted(IJavaProject project) {
|
||||
indexes.invalidate(project);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public synchronized FuzzyMap<PropertyInfo> get(IJavaProject project, ProgressService progressService) {
|
||||
if (indexes==null) {
|
||||
indexes = new HashMap<>();
|
||||
public synchronized SpringPropertyIndex get(IJavaProject project, ProgressService progressService) {
|
||||
try {
|
||||
return indexes.get(project, () -> initIndex(project, progressService));
|
||||
} catch (ExecutionException e) {
|
||||
Log.log(e);
|
||||
return null;
|
||||
}
|
||||
SpringPropertyIndex index = indexes.get(project);
|
||||
if (index==null) {
|
||||
Log.info("Indexing Spring Boot Properties for "+project.getElementName());
|
||||
String progressId = getProgressId();
|
||||
if (progressService != null) {
|
||||
progressService.progressEvent(progressId, "Indexing Spring Boot Properties...");
|
||||
}
|
||||
|
||||
index = new SpringPropertyIndex(valueProviders, project.getClasspath());
|
||||
indexes.put(project, index);
|
||||
|
||||
if (progressService != null) {
|
||||
progressService.progressEvent(progressId, null);
|
||||
}
|
||||
Log.info("Indexing Spring Boot Properties for "+project.getElementName()+" DONE");
|
||||
Log.info("Indexed "+index.size()+" properties.");
|
||||
}
|
||||
|
||||
private SpringPropertyIndex initIndex(IJavaProject project, ProgressService progressService) {
|
||||
Log.info("Indexing Spring Boot Properties for "+project.getElementName());
|
||||
|
||||
String progressId = getProgressId();
|
||||
if (progressService != null) {
|
||||
progressService.progressEvent(progressId, "Indexing Spring Boot Properties...");
|
||||
}
|
||||
|
||||
SpringPropertyIndex index = new SpringPropertyIndex(valueProviders, project.getClasspath());
|
||||
|
||||
if (progressService != null) {
|
||||
progressService.progressEvent(progressId, null);
|
||||
}
|
||||
|
||||
Log.info("Indexing Spring Boot Properties for "+project.getElementName()+" DONE");
|
||||
Log.info("Indexed "+index.size()+" properties.");
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
if (indexes!=null) {
|
||||
indexes.clear();
|
||||
indexes.invalidateAll();
|
||||
for (Listener<SpringPropertiesIndexManager> l : getListeners()) {
|
||||
l.changed(this);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class PropertiesIndexTest {
|
||||
@Test
|
||||
public void springStandardPropertyPresent_Maven() throws Exception {
|
||||
SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(
|
||||
ValueProviderRegistry.getDefault());
|
||||
ValueProviderRegistry.getDefault(), null);
|
||||
IJavaProject mavenProject = projects.mavenProject(CUSTOM_PROPERTIES_PROJECT);
|
||||
FuzzyMap<PropertyInfo> index = indexManager.get(mavenProject, progressService);
|
||||
PropertyInfo propertyInfo = index.get("server.port");
|
||||
@@ -48,7 +48,7 @@ public class PropertiesIndexTest {
|
||||
@Test
|
||||
public void customPropertyPresent_Maven() throws Exception {
|
||||
SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(
|
||||
ValueProviderRegistry.getDefault());
|
||||
ValueProviderRegistry.getDefault(), null);
|
||||
IJavaProject mavenProject = projects.mavenProject(CUSTOM_PROPERTIES_PROJECT);
|
||||
FuzzyMap<PropertyInfo> index = indexManager.get(mavenProject, progressService);
|
||||
PropertyInfo propertyInfo = index.get("demo.settings.user");
|
||||
@@ -60,7 +60,7 @@ public class PropertiesIndexTest {
|
||||
@Test
|
||||
public void propertyNotPresent_Maven() throws Exception {
|
||||
SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(
|
||||
ValueProviderRegistry.getDefault());
|
||||
ValueProviderRegistry.getDefault(), null);
|
||||
IJavaProject mavenProject = projects.mavenProject(CUSTOM_PROPERTIES_PROJECT);
|
||||
FuzzyMap<PropertyInfo> index = indexManager.get(mavenProject, progressService);
|
||||
PropertyInfo propertyInfo = index.get("my.server.port");
|
||||
@@ -70,7 +70,7 @@ public class PropertiesIndexTest {
|
||||
@Test
|
||||
public void springStandardPropertyPresent_ClasspathFile() throws Exception {
|
||||
SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(
|
||||
ValueProviderRegistry.getDefault());
|
||||
ValueProviderRegistry.getDefault(), null);
|
||||
IJavaProject classpathFileProject = projects.javaProjectWithClasspathFile(CUSTOM_PROPERTIES_PROJECT);
|
||||
FuzzyMap<PropertyInfo> index = indexManager.get(classpathFileProject, progressService);
|
||||
PropertyInfo propertyInfo = index.get("server.port");
|
||||
@@ -82,7 +82,7 @@ public class PropertiesIndexTest {
|
||||
@Test
|
||||
public void customPropertyPresent_ClasspathFile() throws Exception {
|
||||
SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(
|
||||
ValueProviderRegistry.getDefault());
|
||||
ValueProviderRegistry.getDefault(), null);
|
||||
IJavaProject classpathFileProject = projects.javaProjectWithClasspathFile(CUSTOM_PROPERTIES_PROJECT);
|
||||
FuzzyMap<PropertyInfo> index = indexManager.get(classpathFileProject, progressService);
|
||||
PropertyInfo propertyInfo = index.get("demo.settings.user");
|
||||
@@ -94,7 +94,7 @@ public class PropertiesIndexTest {
|
||||
@Test
|
||||
public void propertyNotPresent_ClasspathFile() throws Exception {
|
||||
SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(
|
||||
ValueProviderRegistry.getDefault());
|
||||
ValueProviderRegistry.getDefault(), null);
|
||||
IJavaProject classpathFileProject = projects.javaProjectWithClasspathFile(CUSTOM_PROPERTIES_PROJECT);
|
||||
FuzzyMap<PropertyInfo> index = indexManager.get(classpathFileProject, progressService);
|
||||
PropertyInfo propertyInfo = index.get("my.server.port");
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServer;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServerParams;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.AbstractPropsEditorTest;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.StyledStringMatcher;
|
||||
import org.springframework.ide.vscode.boot.metadata.CachingValueProvider;
|
||||
@@ -1585,7 +1586,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
|
||||
@Override
|
||||
protected SimpleLanguageServer newLanguageServer() {
|
||||
BootPropertiesLanguageServer server = new BootPropertiesLanguageServer(md.getIndexProvider(), typeUtilProvider, javaProjectFinder);
|
||||
BootPropertiesLanguageServer server = new BootPropertiesLanguageServer(
|
||||
s -> new BootPropertiesLanguageServerParams(javaProjectFinder, null, md.getIndexProvider(),
|
||||
typeUtilProvider));
|
||||
server.setMaxCompletionsNumber(-1);
|
||||
return server;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServer;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServerParams;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.AbstractPropsEditorTest;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.StyledStringMatcher;
|
||||
import org.springframework.ide.vscode.boot.metadata.CachingValueProvider;
|
||||
@@ -3670,7 +3671,9 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
|
||||
@Override
|
||||
protected SimpleLanguageServer newLanguageServer() {
|
||||
BootPropertiesLanguageServer server = new BootPropertiesLanguageServer(md.getIndexProvider(), typeUtilProvider, javaProjectFinder);
|
||||
BootPropertiesLanguageServer server = new BootPropertiesLanguageServer(
|
||||
s -> new BootPropertiesLanguageServerParams(javaProjectFinder, null, md.getIndexProvider(),
|
||||
typeUtilProvider));
|
||||
server.setMaxCompletionsNumber(-1);
|
||||
return server;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.eclipse.lsp4j.InitializeResult;
|
||||
import org.eclipse.lsp4j.TextDocumentSyncKind;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectFinder;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServerParams;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class BootPropertiesLanguageServerTest {
|
||||
}
|
||||
|
||||
private LanguageServerHarness newHarness() throws Exception {
|
||||
Callable<? extends SimpleLanguageServer> f = () -> new BootPropertiesLanguageServer((d) -> null, (d) -> null, new CompositeJavaProjectFinder());
|
||||
Callable<? extends SimpleLanguageServer> f = () -> new BootPropertiesLanguageServer(BootPropertiesLanguageServerParams.createTestDefault());
|
||||
return new LanguageServerHarness(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.test;
|
||||
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServer;
|
||||
import org.springframework.ide.vscode.boot.BootPropertiesLanguageServerParams;
|
||||
import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.ProgressService;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
/**
|
||||
* Tests for Boot properties index
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class SpringPropertiesIndexTest {
|
||||
|
||||
private LanguageServerHarness<BootPropertiesLanguageServer> harness;
|
||||
|
||||
private DefaultSpringPropertyIndexProvider propertyIndexProvider;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
harness = new LanguageServerHarness<>(() -> new BootPropertiesLanguageServer(BootPropertiesLanguageServerParams.createTestDefault()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertiesIndexRefreshOnProjectChange() throws Exception {
|
||||
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/boot-1.2.0-properties-live-metadta/").toURI()));
|
||||
propertyIndexProvider = (DefaultSpringPropertyIndexProvider) harness.getServer().getPropertiesIndexProvider();
|
||||
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/boot-1.2.0-properties-live-metadta/").toURI());
|
||||
|
||||
File javaFile = new File(directory, "/src/main/java/demo/Application.java");
|
||||
|
||||
TextDocument doc = new TextDocument(javaFile.toURI().toString(), LanguageId.JAVA);
|
||||
|
||||
// Not cached yet, hence progress service invoked
|
||||
ProgressService progressService = mock(ProgressService.class);
|
||||
propertyIndexProvider.setProgressService(progressService);
|
||||
propertyIndexProvider.getIndex(doc);
|
||||
verify(progressService, atLeastOnce()).progressEvent(anyObject(), anyObject());
|
||||
|
||||
// Should be cached now, so progress service should not be touched
|
||||
progressService = mock(ProgressService.class);
|
||||
propertyIndexProvider.setProgressService(progressService);
|
||||
propertyIndexProvider.getIndex(doc);
|
||||
verify(progressService, never()).progressEvent(anyObject(), anyObject());
|
||||
|
||||
// Change POM file for the project
|
||||
harness.changeFile(new File(directory, MavenCore.POM_XML).toURI().toString());
|
||||
|
||||
// POM has changed, hence project needs to be reloaded, cached value is cleared
|
||||
progressService = mock(ProgressService.class);
|
||||
propertyIndexProvider.setProgressService(progressService);
|
||||
propertyIndexProvider.getIndex(doc);
|
||||
verify(progressService, atLeastOnce()).progressEvent(anyObject(), anyObject());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,12 +8,10 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
public class BootProjectUtil {
|
||||
@@ -177,7 +177,7 @@ public abstract class LaunguageServerApp {
|
||||
* @return
|
||||
*/
|
||||
protected ExecutorService createServerThreads() {
|
||||
return Executors.newSingleThreadExecutor();
|
||||
return Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
private <T> Launcher<T> createSocketLauncher(Object localService, Class<T> remoteInterface, SocketAddress socketAddress, ExecutorService executorService, Function<MessageConsumer, MessageConsumer> wrapper) throws IOException {
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEd
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public interface STS4LanguageClient extends LanguageClient {
|
||||
public interface STS4LanguageClient extends LanguageClient, WorkspaceFoldersProposedClient {
|
||||
|
||||
@JsonNotification("sts/highlight")
|
||||
void highlight(HighlightParams highlights);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Microsoft Corporation and others.
|
||||
* 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Microsoft Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
|
||||
public interface WorkspaceFoldersProposedClient {
|
||||
|
||||
/**
|
||||
* The workspace/workspaceFolders request is sent from the server to the client
|
||||
* to fetch the current open list of workspace folders.
|
||||
*
|
||||
* @return Returns the current open list of workspace folders. Returns null in
|
||||
* the response if only a single file is open in the tool. Returns an
|
||||
* empty array if a workspace is open but no folders are configured.
|
||||
*/
|
||||
@JsonRequest("workspace/workspaceFolders")
|
||||
CompletableFuture<WorkspaceFolder[]> getWorkspaceFolders();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Microsoft Corporation and others.
|
||||
* 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Microsoft Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.multiroot;
|
||||
|
||||
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
|
||||
|
||||
public class DidChangeWorkspaceFoldersParams {
|
||||
/**
|
||||
* The actual workspace folder change event.
|
||||
*/
|
||||
@NonNull
|
||||
private WorkspaceFoldersChangeEvent event;
|
||||
|
||||
public DidChangeWorkspaceFoldersParams() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event
|
||||
*/
|
||||
public DidChangeWorkspaceFoldersParams(@NonNull WorkspaceFoldersChangeEvent event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the event
|
||||
*/
|
||||
@NonNull
|
||||
public WorkspaceFoldersChangeEvent getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event
|
||||
* the event to set
|
||||
*/
|
||||
public void setEvent(@NonNull WorkspaceFoldersChangeEvent event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DidChangeWorkspaceFoldersParams [event=" + event + "]";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((event == null) ? 0 : event.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
DidChangeWorkspaceFoldersParams other = (DidChangeWorkspaceFoldersParams) obj;
|
||||
if (event == null) {
|
||||
if (other.event != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!event.equals(other.event)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Source code in this folder are copied from org.eclipse.jdt.ls.core.internal.lsp
|
||||
|
||||
They provide support for the proposed LSP protocol extension to deal with multi-root
|
||||
workspaces.
|
||||
@@ -0,0 +1,128 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Microsoft Corporation and others.
|
||||
* 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Microsoft Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.multiroot;
|
||||
|
||||
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
|
||||
|
||||
public class WorkspaceFolder {
|
||||
/**
|
||||
* The associated URI for this workspace folder.
|
||||
*/
|
||||
@NonNull
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* The name of the workspace folder. Defaults to the uri's basename.
|
||||
*/
|
||||
@NonNull
|
||||
private String name;
|
||||
|
||||
public WorkspaceFolder() {
|
||||
}
|
||||
|
||||
public WorkspaceFolder(@NonNull String uri, @NonNull String name) {
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the associated URI for this workspace folder.
|
||||
*
|
||||
* @return the uri
|
||||
*/
|
||||
@NonNull
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the associated URI for this workspace folder.
|
||||
*
|
||||
* @param uri
|
||||
* the uri to set
|
||||
*/
|
||||
public void setUri(@NonNull String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the workspace folder. Defaults to the uri's basename.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
@NonNull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the workspace folder. Defaults to the uri's basename.
|
||||
*
|
||||
* @param name
|
||||
* the name to set
|
||||
*/
|
||||
public void setName(@NonNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WorkspaceFolder [uri=" + uri + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((uri == null) ? 0 : uri.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
WorkspaceFolder other = (WorkspaceFolder) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
if (uri == null) {
|
||||
if (other.uri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!uri.equals(other.uri)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Microsoft Corporation and others.
|
||||
* 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Microsoft Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.multiroot;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
|
||||
|
||||
/**
|
||||
* The workspace folder change event.
|
||||
*/
|
||||
public class WorkspaceFoldersChangeEvent {
|
||||
/**
|
||||
* The array of added workspace folders
|
||||
*/
|
||||
@NonNull
|
||||
private WorkspaceFolder[] added;
|
||||
|
||||
/**
|
||||
* The array of the removed workspace folders
|
||||
*/
|
||||
@NonNull
|
||||
private WorkspaceFolder[] removed;
|
||||
|
||||
public WorkspaceFoldersChangeEvent() {
|
||||
}
|
||||
|
||||
public WorkspaceFoldersChangeEvent(@NonNull final WorkspaceFolder[] added, @NonNull final WorkspaceFolder[] removed) {
|
||||
this.added = added;
|
||||
this.removed = removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the added
|
||||
*/
|
||||
@NonNull
|
||||
public WorkspaceFolder[] getAdded() {
|
||||
return added;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param added
|
||||
* the added to set
|
||||
*/
|
||||
public void setAdded(@NonNull WorkspaceFolder[] added) {
|
||||
this.added = added;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the removed
|
||||
*/
|
||||
@NonNull
|
||||
public WorkspaceFolder[] getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param removed
|
||||
* the removed to set
|
||||
*/
|
||||
public void setRemoved(@NonNull WorkspaceFolder[] removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(added);
|
||||
result = prime * result + Arrays.hashCode(removed);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
WorkspaceFoldersChangeEvent other = (WorkspaceFoldersChangeEvent) obj;
|
||||
if (!Arrays.equals(added, other.added)) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(removed, other.removed)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WorkspaceFoldersChangeEvent [added=" + Arrays.toString(added) + ", removed=" + Arrays.toString(removed) + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Microsoft Corporation and others.
|
||||
* 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Microsoft Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.multiroot;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
|
||||
import org.eclipse.lsp4j.jsonrpc.services.JsonSegment;
|
||||
|
||||
/**
|
||||
* Server APIs for Workspace folders (prop
|
||||
* https://github.com/Microsoft/vscode-languageserver-node/blob/master/protocol/src/protocol.workspaceFolders.proposed.md
|
||||
*
|
||||
*/
|
||||
@JsonSegment("workspace")
|
||||
public interface WorkspaceFoldersProposedService {
|
||||
|
||||
public static final String CAPABILITY_NAME = "workspace/didChangeWorkspaceFolders";
|
||||
public static final String CAPABILITY_ID = UUID.randomUUID().toString();
|
||||
|
||||
/**
|
||||
* The workspace/didChangeWorkspaceFolders notification is sent from the client
|
||||
* to the server to inform the client about workspace folder configuration
|
||||
* changes.
|
||||
*
|
||||
* @param documentUri
|
||||
* the document from which the project configuration will be updated
|
||||
*/
|
||||
@JsonNotification
|
||||
void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ package org.springframework.ide.vscode.commons.languageserver.util;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -43,6 +45,9 @@ import org.springframework.ide.vscode.commons.languageserver.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter.LazyCompletionResolver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.DidChangeWorkspaceFoldersParams;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFoldersProposedService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix.QuickfixData;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEdit;
|
||||
@@ -70,7 +75,7 @@ import reactor.core.scheduler.Schedulers;
|
||||
* here so we can try to keep the subclass itself more 'clutter free' and focus on
|
||||
* what its really doing and not the 'wiring and plumbing'.
|
||||
*/
|
||||
public abstract class SimpleLanguageServer implements LanguageServer, LanguageClientAware, ServiceNotificationsClient {
|
||||
public abstract class SimpleLanguageServer implements LanguageServer, LanguageClientAware, ServiceNotificationsClient, WorkspaceFoldersProposedService {
|
||||
|
||||
private static final Scheduler RECONCILER_SCHEDULER = Schedulers.newSingle("Reconciler");
|
||||
|
||||
@@ -78,8 +83,6 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
private final String CODE_ACTION_COMMAND_ID;
|
||||
protected final LazyCompletionResolver completionResolver = createCompletionResolver();
|
||||
|
||||
private Path workspaceRoot;
|
||||
|
||||
private SimpleTextDocumentService tds;
|
||||
|
||||
private SimpleWorkspaceService workspace;
|
||||
@@ -169,16 +172,28 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
@Override
|
||||
public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
|
||||
Log.debug("Initializing: "+params);
|
||||
String rootPath = params.getRootPath();
|
||||
if (rootPath==null) {
|
||||
Log.debug("workspaceRoot NOT SET");
|
||||
} else {
|
||||
this.workspaceRoot= Paths.get(rootPath).toAbsolutePath().normalize();
|
||||
|
||||
// multi-root workspace handling
|
||||
List<WorkspaceFolder> workspaceFolders = getWorkspaceFolders(params);
|
||||
if (!workspaceFolders.isEmpty()) {
|
||||
this.getWorkspaceService().setWorkspaceFolders(workspaceFolders);
|
||||
}
|
||||
else {
|
||||
String rootPath = params.getRootPath();
|
||||
if (rootPath==null) {
|
||||
Log.debug("workspaceRoot NOT SET");
|
||||
} else {
|
||||
List<WorkspaceFolder> singleRootFolder = new ArrayList<>();
|
||||
Path path = Paths.get(rootPath);
|
||||
singleRootFolder.add(new WorkspaceFolder(path.toUri().toString(), path.getFileName().toString()));
|
||||
this.getWorkspaceService().setWorkspaceFolders(singleRootFolder);
|
||||
}
|
||||
}
|
||||
|
||||
this.hasCompletionSnippetSupport = safeGet(false, () -> params.getCapabilities().getTextDocument().getCompletion().getCompletionItem().getSnippetSupport());
|
||||
this.hasExecuteCommandSupport = safeGet(false, () -> params.getCapabilities().getWorkspace().getExecuteCommand()!=null);
|
||||
this.hasFileWatcherRegistrationSupport = safeGet(false, () -> params.getCapabilities().getWorkspace().getDidChangeWatchedFiles().getDynamicRegistration());
|
||||
Log.debug("workspaceRoot = "+workspaceRoot);
|
||||
Log.debug("workspaceRoots = "+getWorkspaceService().getWorkspaceRoots());
|
||||
Log.debug("hasCompletionSnippetSupport = "+hasCompletionSnippetSupport);
|
||||
Log.debug("hasExecuteCommandSupport = "+hasExecuteCommandSupport);
|
||||
|
||||
@@ -193,6 +208,31 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
return CompletableFuture.completedFuture(result);
|
||||
}
|
||||
|
||||
private List<WorkspaceFolder> getWorkspaceFolders(InitializeParams params) {
|
||||
List<WorkspaceFolder> initialFolders = new ArrayList<>();
|
||||
|
||||
Object initOptions = params.getInitializationOptions();
|
||||
if (initOptions != null && initOptions instanceof Map) {
|
||||
Map<?, ?> initializationOptions = (Map<?, ?>) initOptions;
|
||||
Object folders = initializationOptions.get("workspaceFolders");
|
||||
if (folders != null && folders instanceof List) {
|
||||
List<?> workspaceFolders = (List<?>) folders;
|
||||
for (Object object : workspaceFolders) {
|
||||
String folderPath = object.toString();
|
||||
String folderName = null;
|
||||
|
||||
int folderNameStart = folderPath.lastIndexOf("/");
|
||||
if (folderNameStart > 0) {
|
||||
folderName = folderPath.substring(folderPath.lastIndexOf("/") + 1);
|
||||
}
|
||||
initialFolders.add(new WorkspaceFolder(object.toString(), folderName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initialFolders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get some info safely. If there's any kind of exception, ignore it
|
||||
* and retutn default value instead.
|
||||
@@ -307,10 +347,29 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public Path getWorkspaceRoot() {
|
||||
return workspaceRoot;
|
||||
public Collection<WorkspaceFolder> getWorkspaceRoots() {
|
||||
return getWorkspaceService().getWorkspaceRoots();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Deprecated, shouldn't use and should be removed. Anyone calling this
|
||||
// * will have problems handling multi-root workspaces.
|
||||
// * <p>
|
||||
// * Use getWorkspaceRoots instead.
|
||||
// */
|
||||
// @Deprecated
|
||||
// public Path getWorkspaceRoot() {
|
||||
// try {
|
||||
// Optional<WorkspaceFolder> firstRoot = getWorkspaceRoots().stream().findFirst();
|
||||
// if (firstRoot.isPresent()) {
|
||||
// return new File(new URI(firstRoot.get().getUri())).toPath();
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// Log.log(e);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public synchronized SimpleTextDocumentService getTextDocumentService() {
|
||||
if (tds==null) {
|
||||
@@ -467,4 +526,10 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
public boolean canRegisterFileWatchersDynamically() {
|
||||
return hasFileWatcherRegistrationSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) {
|
||||
getWorkspaceService().didChangeWorkspaceFolders(params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -20,6 +23,10 @@ import org.eclipse.lsp4j.ExecuteCommandParams;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.WorkspaceSymbolParams;
|
||||
import org.eclipse.lsp4j.services.WorkspaceService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.DidChangeWorkspaceFoldersParams;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFoldersChangeEvent;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFoldersProposedService;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
@@ -28,15 +35,18 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class SimpleWorkspaceService implements WorkspaceService {
|
||||
public class SimpleWorkspaceService implements WorkspaceService, WorkspaceFoldersProposedService {
|
||||
|
||||
private SimpleLanguageServer server;
|
||||
private Set<WorkspaceFolder> workspaceRoots = new HashSet<>();
|
||||
|
||||
private ListenerList<Settings> configurationListeners = new ListenerList<>();
|
||||
private ExecuteCommandHandler executeCommandHandler;
|
||||
private WorkspaceSymbolHandler workspaceSymbolHandler;
|
||||
private SimpleServerFileObserver fileObserver;
|
||||
|
||||
private ListenerList<DidChangeWorkspaceFoldersParams> workspaceFolderListeners = new ListenerList<>();
|
||||
|
||||
public SimpleWorkspaceService(SimpleLanguageServer server) {
|
||||
this.server = server;
|
||||
this.fileObserver = new SimpleServerFileObserver(server);
|
||||
@@ -89,6 +99,27 @@ public class SimpleWorkspaceService implements WorkspaceService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) {
|
||||
WorkspaceFoldersChangeEvent evt = params.getEvent();
|
||||
boolean changed = false;
|
||||
for (WorkspaceFolder r : evt.getAdded()) {
|
||||
workspaceRoots.add(r);
|
||||
changed = true;
|
||||
}
|
||||
for (WorkspaceFolder r : evt.getRemoved()) {
|
||||
workspaceRoots.remove(r);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
workspaceFolderListeners.fire(params);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDidChangeWorkspaceFolders(Consumer<DidChangeWorkspaceFoldersParams> l) {
|
||||
workspaceFolderListeners.add(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
|
||||
if (this.executeCommandHandler!=null) {
|
||||
@@ -123,4 +154,14 @@ public class SimpleWorkspaceService implements WorkspaceService {
|
||||
fileObserver.dispose();
|
||||
}
|
||||
|
||||
public Collection<WorkspaceFolder> getWorkspaceRoots() {
|
||||
return ImmutableList.copyOf(workspaceRoots);
|
||||
}
|
||||
|
||||
public synchronized void setWorkspaceFolders(List<WorkspaceFolder> workspaceFolders) {
|
||||
workspaceRoots = new HashSet<>();
|
||||
workspaceRoots.addAll(workspaceFolders);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -48,4 +48,9 @@ public class MavenJavaProject extends AbstractJavaProject {
|
||||
return classpath.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MavenJavaProject("+classpath.getName()+")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ import org.springframework.ide.vscode.commons.languageserver.HighlightParams;
|
||||
import org.springframework.ide.vscode.commons.languageserver.ProgressParams;
|
||||
import org.springframework.ide.vscode.commons.languageserver.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEdit.CursorMovement;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LanguageServerTestListener;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.Settings;
|
||||
@@ -286,6 +287,16 @@ public class LanguageServerHarness<S extends SimpleLanguageServer> {
|
||||
}
|
||||
return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<WorkspaceFolder[]> getWorkspaceFolders() {
|
||||
if (workspaceRoot!=null) {
|
||||
return CompletableFuture.completedFuture(new WorkspaceFolder[]{
|
||||
new WorkspaceFolder(workspaceRoot.toURI().toString(), workspaceRoot.getName())
|
||||
});
|
||||
}
|
||||
return CompletableFuture.completedFuture(new WorkspaceFolder[]{});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
"typescript": "^2.3.0",
|
||||
"@types/node": "^6.0.68",
|
||||
"vscode": "^1.1.5",
|
||||
"vscode-languageclient": "^3.4.2"
|
||||
"vscode-languageclient": "^3.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Trace, NotificationType } from 'vscode-jsonrpc';
|
||||
import * as P2C from 'vscode-languageclient/lib/protocolConverter';
|
||||
import {WorkspaceEdit, Position} from 'vscode-languageserver-types';
|
||||
import {HighlightService, HighlightParams} from './highlight-service';
|
||||
import { log } from 'util';
|
||||
|
||||
let p2c = P2C.createConverter();
|
||||
|
||||
@@ -83,7 +84,8 @@ export function activate(options: ActivatorOptions, context: VSCode.ExtensionCon
|
||||
reader: socket,
|
||||
writer: socket
|
||||
});
|
||||
}).listen(port, () => {
|
||||
})
|
||||
.listen(port, () => {
|
||||
let processLaunchoptions = {
|
||||
cwd: VSCode.workspace.rootPath
|
||||
};
|
||||
@@ -151,6 +153,8 @@ function setupLanguageClient(context: VSCode.ExtensionContext, createServer: Ser
|
||||
let client = new LanguageClient(options.extensionId, options.extensionId,
|
||||
createServer, options.clientOptions
|
||||
);
|
||||
client.registerProposedFeatures();
|
||||
log("Proposed protocol extensions loaded!");
|
||||
if (options.TRACE) {
|
||||
client.trace = Trace.Verbose;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as FS from 'fs';
|
||||
import * as Net from 'net';
|
||||
import * as ChildProcess from 'child_process';
|
||||
import { LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo } from 'vscode-languageclient';
|
||||
import { TextDocument } from 'vscode';
|
||||
import { workspace, TextDocument } from 'vscode';
|
||||
import { Trace } from 'vscode-jsonrpc';
|
||||
|
||||
import * as commons from 'commons-vscode';
|
||||
@@ -38,7 +38,10 @@ export function activate(context: VSCode.ExtensionContext) {
|
||||
documentSelector: ['java'],
|
||||
synchronize: {
|
||||
configurationSection: 'boot-java'
|
||||
}
|
||||
},
|
||||
initializationOptions: {
|
||||
workspaceFolders: workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.toString()) : null
|
||||
},
|
||||
}
|
||||
};
|
||||
commons.activate(options, context);
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"vsce-package": "vsce package"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^3.4.2",
|
||||
"vscode-languageclient": "^3.4.5",
|
||||
"commons-vscode": "^0.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Reference in New Issue
Block a user