PT #164216122: JDT LS search performance improvement 2
This commit is contained in:
@@ -91,7 +91,7 @@ public class JavaLangugeClientTest {
|
||||
.javaSearchTypes(new JavaSearchParams(project.getLocationURI().toString(), "util.Map", true, true))
|
||||
.get(100, TimeUnit.SECONDS);
|
||||
assertNotNull(data);
|
||||
assertTrue(data.size() > 500);
|
||||
assertEquals(500, data.size());
|
||||
List<String> closeMatches = data.stream().filter(t -> t.contains("util.Map")).collect(Collectors.toList());
|
||||
assertEquals(2, closeMatches.size());
|
||||
assertNotNull(closeMatches.stream().filter(t -> "java.util.Map".equals(t)).findFirst().orElse(null));
|
||||
@@ -116,9 +116,9 @@ public class JavaLangugeClientTest {
|
||||
.javaSearchTypes(new JavaSearchParams(project.getLocationURI().toString(), "", true, false))
|
||||
.get(1000, TimeUnit.SECONDS);
|
||||
assertNotNull(data);
|
||||
assertTrue(data.size() > 10000);
|
||||
assertEquals(500, data.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void searchPackagesIncludingSysLibs() throws Exception {
|
||||
List<String> packages = client.javaSearchPackages(new JavaSearchParams(project.getLocationURI().toString(), "java.lang", true, true)).get(30, TimeUnit.SECONDS);
|
||||
@@ -136,7 +136,7 @@ public class JavaLangugeClientTest {
|
||||
@Test
|
||||
public void searchAllPackagesExcludingSysLibs() throws Exception {
|
||||
List<String> packages = client.javaSearchPackages(new JavaSearchParams(project.getLocationURI().toString(), "", true, false)).get(30, TimeUnit.SECONDS);
|
||||
assertTrue(packages.size() > 1000);
|
||||
assertEquals(500, packages.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -75,7 +75,7 @@ import org.springframework.ide.vscode.commons.protocol.java.TypeData;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
import org.springframework.tooling.jdt.ls.commons.classpath.ReusableClasspathListenerHandler;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaData;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaSearch;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaFluxSearch;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.TypeHierarchy;
|
||||
import org.springframework.tooling.jdt.ls.commons.javadoc.JavadocUtils;
|
||||
import org.springframework.tooling.jdt.ls.commons.resources.ResourceUtils;
|
||||
@@ -126,7 +126,7 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
|
||||
final private JavaData javaData = new JavaData(STS4LanguageClientImpl::label , Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance));
|
||||
|
||||
final private JavaSearch javaSearch = new JavaSearch(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance));
|
||||
final private JavaFluxSearch javaFluxSearch = new JavaFluxSearch(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance));
|
||||
|
||||
final private TypeHierarchy typeHierarchy = new TypeHierarchy(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), javaData);
|
||||
|
||||
@@ -443,11 +443,11 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
public CompletableFuture<List<String>> javaSearchTypes(JavaSearchParams params) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return javaSearch.fuzzySearchTypes(URI.create(params.getProjectUri()), params.getTerm(),
|
||||
params.isIncludeBinaries(), params.isIncludeSystemLibs()).collect(Collectors.toList());
|
||||
List<String> types = javaFluxSearch.fuzzySearchTypes(params);
|
||||
return types;
|
||||
} catch (Exception e) {
|
||||
LanguageServerCommonsActivator.logError(e,
|
||||
"Failed to search type with term '" + params.getTerm() + "' in project " + params.getProjectUri());
|
||||
LanguageServerCommonsActivator.logError(e, "Failed to search type with term '" + params.getTerm()
|
||||
+ "' in project " + params.getProjectUri());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
});
|
||||
@@ -457,10 +457,10 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
public CompletableFuture<List<String>> javaSearchPackages(JavaSearchParams params) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return javaSearch.fuzzySearchPackages(URI.create(params.getProjectUri()), params.getTerm(),
|
||||
params.isIncludeBinaries(), params.isIncludeSystemLibs()).collect(Collectors.toList());
|
||||
return javaFluxSearch.fuzzySearchPackages(params);
|
||||
} catch (Exception e) {
|
||||
LanguageServerCommonsActivator.logError(e, "Failed to search package with term '" + params.getTerm() +"' in project " + params.getProjectUri());
|
||||
LanguageServerCommonsActivator.logError(e, "Failed to search package with term '" + params.getTerm()
|
||||
+ "' in project " + params.getProjectUri());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,6 +43,8 @@ import reactor.util.function.Tuples;
|
||||
|
||||
public class JdtLsIndex implements ClasspathIndex {
|
||||
|
||||
private static final long SEARCH_TIMEOUT = 700;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JdtLsIndex.class);
|
||||
|
||||
private final STS4LanguageClient client;
|
||||
@@ -90,7 +92,7 @@ public class JdtLsIndex implements ClasspathIndex {
|
||||
|
||||
@Override
|
||||
public Flux<Tuple2<String, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs) {
|
||||
JavaSearchParams searchParams = new JavaSearchParams(projectUri.toString(), searchTerm, includeBinaries, includeSystemLibs);
|
||||
JavaSearchParams searchParams = new JavaSearchParams(projectUri.toString(), searchTerm, includeBinaries, includeSystemLibs, SEARCH_TIMEOUT);
|
||||
return Mono.fromFuture(client.javaSearchTypes(searchParams))
|
||||
.flatMapMany(results -> Flux.fromIterable(results).publishOn(Schedulers.parallel()))
|
||||
.filter(Objects::nonNull)
|
||||
@@ -100,7 +102,7 @@ public class JdtLsIndex implements ClasspathIndex {
|
||||
|
||||
@Override
|
||||
public Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm, boolean includeBinaries, boolean includeSystemLibs) {
|
||||
JavaSearchParams searchParams = new JavaSearchParams(projectUri.toString(), searchTerm, includeBinaries, includeSystemLibs);
|
||||
JavaSearchParams searchParams = new JavaSearchParams(projectUri.toString(), searchTerm, includeBinaries, includeSystemLibs, SEARCH_TIMEOUT);
|
||||
return Mono.fromFuture(client.javaSearchPackages(searchParams))
|
||||
.flatMapMany(results -> Flux.fromIterable(results).publishOn(Schedulers.parallel()))
|
||||
.filter(Objects::nonNull)
|
||||
|
||||
@@ -16,19 +16,25 @@ public class JavaSearchParams {
|
||||
private String term;
|
||||
private boolean includeBinaries;
|
||||
private boolean includeSystemLibs;
|
||||
private long timeLimit = -1;
|
||||
|
||||
public JavaSearchParams(String projectUri, String term) {
|
||||
this(projectUri, term, true, false);
|
||||
}
|
||||
|
||||
public JavaSearchParams(String projectUri, String term, boolean includeBinaries, boolean includeSystemLibs) {
|
||||
public JavaSearchParams(String projectUri, String term, boolean includeBinaries, boolean includeSystemLibs, long timeLimit) {
|
||||
super();
|
||||
this.projectUri = projectUri;
|
||||
this.term = term;
|
||||
this.includeBinaries = includeBinaries;
|
||||
this.includeSystemLibs = includeSystemLibs;
|
||||
this.setTimeLimit(timeLimit);
|
||||
}
|
||||
|
||||
public JavaSearchParams(String projectUri, String term, boolean includeBinaries, boolean includeSystemLibs) {
|
||||
this(projectUri, term, includeBinaries, includeSystemLibs, -1);
|
||||
}
|
||||
|
||||
public String getProjectUri() {
|
||||
return projectUri;
|
||||
}
|
||||
@@ -61,5 +67,12 @@ public class JavaSearchParams {
|
||||
this.includeSystemLibs = includeSystemLibs;
|
||||
}
|
||||
|
||||
|
||||
public long getTimeLimit() {
|
||||
return timeLimit;
|
||||
}
|
||||
|
||||
public void setTimeLimit(long timeLimit) {
|
||||
this.timeLimit = timeLimit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ Require-Bundle: org.eclipse.core.runtime,
|
||||
org.eclipse.m2e.jdt,
|
||||
org.eclipse.m2e.core,
|
||||
org.eclipse.lsp4j,
|
||||
org.eclipse.lsp4j.jsonrpc
|
||||
org.eclipse.lsp4j.jsonrpc,
|
||||
io.projectreactor.reactor-core,
|
||||
org.reactivestreams.reactive-streams
|
||||
Export-Package: org.springframework.ide.vscode.commons.protocol,
|
||||
org.springframework.ide.vscode.commons.protocol.java,
|
||||
org.springframework.tooling.jdt.ls.commons,
|
||||
|
||||
@@ -38,12 +38,25 @@
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<stripVersion>true</stripVersion>
|
||||
<outputDirectory>${project.build.directory}/dependencies</outputDirectory>
|
||||
<overWriteReleases>true</overWriteReleases>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>initialize</phase>
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
public abstract class CachingFluxJavaSearch<T> implements FluxSearch<T> {
|
||||
|
||||
private int MAX_RESULTS = 500;
|
||||
|
||||
final protected Logger logger;
|
||||
final protected boolean includeBinaries;
|
||||
final protected boolean includeSystemLibs;
|
||||
|
||||
private Cache<Tuple2<String,String>, CacheEntry> cache = createCache();
|
||||
|
||||
private class CacheEntry {
|
||||
boolean isComplete = false;
|
||||
int count = 0;
|
||||
Flux<T> values;
|
||||
|
||||
public CacheEntry(String query, Flux<T> producer) {
|
||||
values = producer
|
||||
.doOnNext(t -> count++)
|
||||
.doOnComplete(() -> isComplete = true)
|
||||
.take(MAX_RESULTS)
|
||||
.cache(MAX_RESULTS);
|
||||
values.subscribe(); // create infinite demand so that we actually force cache entries to be fetched upto the max.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CacheEntry [isComplete=" + isComplete + ", count=" + count + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public CachingFluxJavaSearch(Logger logger, boolean includeBinaries, boolean includeSystemLibs) {
|
||||
this.logger = logger;
|
||||
this.includeBinaries = includeBinaries;
|
||||
this.includeSystemLibs = includeSystemLibs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Flux<T> search(IJavaProject javaProject, String query) {
|
||||
Tuple2<String, String> key = key(javaProject, query);
|
||||
CacheEntry cached = null;
|
||||
try {
|
||||
cached = cache.get(key, () -> new CacheEntry(query, getValuesIncremental(javaProject, query)));
|
||||
} catch (ExecutionException e) {
|
||||
logger.log(e);
|
||||
}
|
||||
return cached.values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to use an already cached, complete result for a query that is a prefix of the current query to speed things up.
|
||||
* <p>
|
||||
* Falls back on doing a full-blown search if there's no usable 'prefix-query' in the cache.
|
||||
*/
|
||||
private Flux<T> getValuesIncremental(IJavaProject javaProject, String query) {
|
||||
// debug("trying to solve "+query+" incrementally");
|
||||
String subquery = query;
|
||||
while (subquery.length()>=1) {
|
||||
subquery = subquery.substring(0, subquery.length()-1);
|
||||
CacheEntry cached = null;
|
||||
try {
|
||||
cached = cache.get(key(javaProject, subquery), () -> null);
|
||||
} catch (ExecutionException | InvalidCacheLoadException e) {
|
||||
// Log.log(e);
|
||||
}
|
||||
if (cached!=null) {
|
||||
// debug("cached "+subquery+": "+cached);
|
||||
if (cached.isComplete) {
|
||||
return cached.values
|
||||
// .doOnNext((hint) -> debug("filter["+query+"]: "+hint.getValue()))
|
||||
.filter((result) -> 0!=FuzzyMatcher.matchScore(query, stringValue(result)));
|
||||
} else {
|
||||
// debug("subquery "+subquery+" cached but is incomplete");
|
||||
}
|
||||
}
|
||||
}
|
||||
// debug("full search for: "+query);
|
||||
return getValuesAsync(javaProject, query);
|
||||
}
|
||||
|
||||
protected abstract Flux<T> getValuesAsync(IJavaProject javaProject, String query);
|
||||
|
||||
protected abstract String stringValue(T t);
|
||||
|
||||
private Tuple2<String,String> key(IJavaProject javaProject, String query) {
|
||||
return Tuples.of(javaProject==null?null:javaProject.getElementName(), query);
|
||||
}
|
||||
|
||||
protected <K,V> Cache<K,V> createCache() {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).expireAfterAccess(1, TimeUnit.MINUTES).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,20 +12,21 @@ package org.springframework.tooling.jdt.ls.commons.java;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.jdt.core.IJavaElement;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
import org.eclipse.jdt.core.search.IJavaSearchConstants;
|
||||
import org.eclipse.jdt.core.search.IJavaSearchScope;
|
||||
import org.eclipse.jdt.core.search.SearchEngine;
|
||||
import org.eclipse.jdt.core.search.SearchMatch;
|
||||
@@ -34,6 +35,10 @@ import org.eclipse.jdt.core.search.SearchPattern;
|
||||
import org.eclipse.jdt.core.search.SearchRequestor;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.ReplayProcessor;
|
||||
import reactor.util.concurrent.Queues;
|
||||
|
||||
/**
|
||||
* Helper class to perform a search using Eclipse JDT search engine returning
|
||||
* the search results as a Flux.
|
||||
@@ -53,7 +58,7 @@ import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class StreamJdtSearch {
|
||||
public class FluxJdtSearch {
|
||||
|
||||
private static final boolean DEBUG = (""+Platform.getLocation()).contains("kdvolder");
|
||||
|
||||
@@ -67,23 +72,31 @@ public class StreamJdtSearch {
|
||||
private IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
|
||||
private SearchPattern pattern = null;
|
||||
private SearchParticipant[] participants = new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()};
|
||||
private int bufferSize = Queues.SMALL_BUFFER_SIZE;
|
||||
private boolean useSystemJob = false;
|
||||
private int jobPriority = Job.INTERACTIVE;
|
||||
private Logger logger;
|
||||
|
||||
public StreamJdtSearch(Logger logger) {
|
||||
|
||||
public FluxJdtSearch(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public StreamJdtSearch engine(SearchEngine engine) {
|
||||
public FluxJdtSearch engine(SearchEngine engine) {
|
||||
this.engine = engine;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamJdtSearch scope(IJavaSearchScope scope) {
|
||||
public FluxJdtSearch scope(IJavaSearchScope scope) {
|
||||
this.scope = scope;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamJdtSearch pattern(SearchPattern pattern) {
|
||||
public FluxJdtSearch bufferSize(int bufferSize) {
|
||||
this.bufferSize = bufferSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FluxJdtSearch pattern(SearchPattern pattern) {
|
||||
this.pattern = pattern;
|
||||
return this;
|
||||
}
|
||||
@@ -104,13 +117,20 @@ public class StreamJdtSearch {
|
||||
return SearchEngine.createJavaSearchScope(new IJavaElement[] {javaProject}, includeMask);
|
||||
}
|
||||
|
||||
class Requestor extends SearchRequestor {
|
||||
/**
|
||||
* Implementation of {@link SearchRequestor} that emits search results to an {@link ReplayProcessor}
|
||||
* with replay capability.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
class FluxSearchRequestor extends SearchRequestor {
|
||||
|
||||
private boolean isCanceled = false;
|
||||
private Stream.Builder<SearchMatch> results = Stream.builder();
|
||||
private ReplayProcessor<SearchMatch> emitter = ReplayProcessor.<SearchMatch>create(bufferSize);
|
||||
private Flux<SearchMatch> flux = emitter.doOnCancel(() -> isCanceled=true);
|
||||
|
||||
public Stream<SearchMatch> asStream() {
|
||||
return results.build();
|
||||
public Flux<SearchMatch> asFlux() {
|
||||
return flux;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,13 +140,16 @@ public class StreamJdtSearch {
|
||||
//Stop searching
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
results.add(match);
|
||||
emitter.onNext(match);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
isCanceled = true;
|
||||
}
|
||||
|
||||
public void done() {
|
||||
emitter.onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
protected SearchEngine searchEngine() {
|
||||
@@ -137,24 +160,34 @@ public class StreamJdtSearch {
|
||||
return new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()};
|
||||
}
|
||||
|
||||
public Stream<SearchMatch> search() {
|
||||
public Flux<SearchMatch> search() {
|
||||
validate();
|
||||
if (scope==null) {
|
||||
return Stream.of();
|
||||
return Flux.empty();
|
||||
}
|
||||
final Requestor requestor = new Requestor();
|
||||
long start = System.currentTimeMillis();
|
||||
debug("Starting search for '" + pattern + "'");
|
||||
try {
|
||||
searchEngine().search(pattern, participants, scope, requestor, new NullProgressMonitor());
|
||||
} catch (Exception e) {
|
||||
debug("Canceled search for: " + pattern);
|
||||
debug(" exception: " + e.getMessage());
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
debug(" duration: " + duration + " ms");
|
||||
requestor.cancel();
|
||||
}
|
||||
return requestor.asStream();
|
||||
final FluxSearchRequestor requestor = new FluxSearchRequestor();
|
||||
Job job = new Job("Search for "+pattern) {
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
long start = System.currentTimeMillis();
|
||||
debug("Starting search for '"+pattern+"'");
|
||||
try {
|
||||
searchEngine().search(pattern, participants, scope, requestor, monitor);
|
||||
requestor.done();
|
||||
} catch (Exception e) {
|
||||
debug("Canceled search for: "+pattern);
|
||||
debug(" exception: "+e.getMessage());
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
debug(" duration: "+duration+" ms");
|
||||
requestor.cancel();
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
job.setSystem(useSystemJob);
|
||||
job.setPriority(jobPriority);
|
||||
job.schedule();
|
||||
return requestor.asFlux();
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
@@ -164,6 +197,7 @@ public class StreamJdtSearch {
|
||||
// Assert.isNotNull(scope, "scope");
|
||||
Assert.isNotNull(pattern, "pattern");
|
||||
Assert.isNotNull(participants, "participants");
|
||||
Assert.isLegal(bufferSize > 0);
|
||||
}
|
||||
|
||||
public IJavaSearchScope workspaceScope(boolean includeBinaries) {
|
||||
@@ -186,44 +220,4 @@ public class StreamJdtSearch {
|
||||
}
|
||||
}
|
||||
|
||||
public static String toWildCardPattern(String query) {
|
||||
StringBuilder builder = new StringBuilder("*");
|
||||
for (char c : query.toCharArray()) {
|
||||
builder.append(c);
|
||||
builder.append('*');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static SearchPattern toPackagePattern(String wildCardedQuery) {
|
||||
int searchFor = IJavaSearchConstants.PACKAGE;
|
||||
int limitTo = IJavaSearchConstants.DECLARATIONS;
|
||||
int matchRule = SearchPattern.R_PATTERN_MATCH;
|
||||
return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule);
|
||||
}
|
||||
|
||||
public static SearchPattern toClassPattern(String wildCardedQuery) {
|
||||
int searchFor = IJavaSearchConstants.CLASS;
|
||||
int limitTo = IJavaSearchConstants.DECLARATIONS;
|
||||
int matchRule = SearchPattern.R_PATTERN_MATCH;
|
||||
return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule);
|
||||
}
|
||||
|
||||
public static SearchPattern toTypePattern(String wildCardedQuery) {
|
||||
int searchFor = IJavaSearchConstants.TYPE;
|
||||
int limitTo = IJavaSearchConstants.DECLARATIONS;
|
||||
int matchRule = SearchPattern.R_PATTERN_MATCH;
|
||||
return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule);
|
||||
}
|
||||
|
||||
public static String toProperTypeQuery(String query) {
|
||||
int idx = query.lastIndexOf('.');
|
||||
if (idx > 0 && idx < query.length() - 1 && Character.isLowerCase(query.charAt(idx + 1))) {
|
||||
return query + '.';
|
||||
} else {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public interface FluxSearch<T> {
|
||||
|
||||
Flux<T> search(IJavaProject project, String searchTerm);
|
||||
|
||||
default List<T> searchWithLimits(IJavaProject javaProject, String searchTerm, long timeLimit) {
|
||||
Flux<T> flux = this.search(javaProject, searchTerm);
|
||||
if (timeLimit > 0) {
|
||||
flux = flux.take(Duration.ofMillis(timeLimit));
|
||||
}
|
||||
return flux.collectList().block();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
class FuzzyMatcher {
|
||||
|
||||
/**
|
||||
* Match given pattern with a given data. The data is considered a 'match' for the
|
||||
* pattern if all characters in the pattern can be found in the data, in the
|
||||
* same order but with possible 'gaps' in between.
|
||||
* <p>
|
||||
* The function returns 0. when the pattern doesn't match the data and a non-zero
|
||||
* 'score' when it does. The higher the score, the better the match is considered to
|
||||
* be.
|
||||
*/
|
||||
public static double matchScore(CharSequence pattern, String data) {
|
||||
int ppos = 0; //pos of next char in pattern to look for
|
||||
int dpos = 0; //pos of next char in data not yet matched
|
||||
int gaps = 0; //number of 'gaps' in the match. A gap is any non-empty run of consecutive characters in the data that are not used by the match
|
||||
int skips = 0; //number of skipped characters. This is the sum of the length of all the gaps.
|
||||
int plen = pattern.length();
|
||||
int dlen = data.length();
|
||||
if (plen>dlen) {
|
||||
return 0.0;
|
||||
}
|
||||
while (ppos<plen) {
|
||||
if (dpos>=dlen) {
|
||||
//still chars left in pattern but no more data
|
||||
return 0.0;
|
||||
}
|
||||
char c = pattern.charAt(ppos++);
|
||||
int foundCharAt = data.indexOf(c, dpos);
|
||||
if (foundCharAt>=0) {
|
||||
if (foundCharAt>dpos) {
|
||||
gaps++;
|
||||
skips+=foundCharAt-dpos;
|
||||
}
|
||||
dpos = foundCharAt+1;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
//end of pattern reached. All matched.
|
||||
if (dpos<dlen) {
|
||||
//data left over
|
||||
//gaps++; don't count end skipped chars as a real 'gap'. Otherwise we
|
||||
//tend to favor matches at the end of the string over matches in the middle.
|
||||
skips+=dlen-dpos; //but do count the extra chars at end => more extra = worse score
|
||||
}
|
||||
return score(gaps, skips, pattern);
|
||||
}
|
||||
|
||||
private static double score(int gaps, int skips, CharSequence pattern) {
|
||||
if (gaps==0) {
|
||||
//gaps == 0 means a prefix match, ignore 'skips' at end of String and just sort
|
||||
// alphabetic (see STS-4049)
|
||||
return 0.5+pattern.length(); //all scored equally, assumes using a 'stable' sorter.
|
||||
} else {
|
||||
double badness = 1+gaps + skips/1000.0; // higher is worse
|
||||
return 1.0/badness + pattern.length(); //higher is better
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
import org.springframework.tooling.jdt.ls.commons.resources.ResourceUtils;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
public class JavaFluxSearch {
|
||||
|
||||
final private Logger logger;
|
||||
final private Cache<Tuple2<Boolean, Boolean>, PackageFluxSearch> packageSearchCache = CacheBuilder.newBuilder().build();
|
||||
final private Cache<Tuple2<Boolean, Boolean>, TypeFluxSearch> typeSearchCache = CacheBuilder.newBuilder().build();
|
||||
|
||||
public JavaFluxSearch(Logger logger) {
|
||||
super();
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public List<String> fuzzySearchPackages(JavaSearchParams params) throws Exception {
|
||||
URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri());
|
||||
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
|
||||
PackageFluxSearch fluxPackageSearch = packageSearchCache.get(
|
||||
Tuples.of(params.isIncludeBinaries(), params.isIncludeSystemLibs()), () -> new PackageFluxSearch(logger, params.isIncludeBinaries(), params.isIncludeSystemLibs())
|
||||
);
|
||||
return fluxPackageSearch.searchWithLimits(javaProject, params.getTerm(), params.getTimeLimit());
|
||||
}
|
||||
|
||||
public List<String> fuzzySearchTypes(JavaSearchParams params) throws Exception {
|
||||
URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri());
|
||||
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
|
||||
TypeFluxSearch fluxTypeSearch = typeSearchCache.get(
|
||||
Tuples.of(params.isIncludeBinaries(), params.isIncludeSystemLibs()), () -> new TypeFluxSearch(logger, params.isIncludeBinaries(), params.isIncludeSystemLibs())
|
||||
);
|
||||
return fluxTypeSearch.searchWithLimits(javaProject, params.getTerm(), params.getTimeLimit());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.IPackageFragment;
|
||||
import org.eclipse.jdt.core.IType;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
import org.springframework.tooling.jdt.ls.commons.resources.ResourceUtils;
|
||||
|
||||
public class JavaSearch {
|
||||
|
||||
private Logger logger;
|
||||
|
||||
public JavaSearch(Logger logger) {
|
||||
super();
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public Stream<String> fuzzySearchPackages(URI projectUri, String searchTerm, boolean includeBinaries, boolean includeSystemLibs) throws Exception {
|
||||
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
|
||||
return new StreamJdtSearch(logger)
|
||||
.scope(StreamJdtSearch.searchScope(javaProject, includeBinaries, includeSystemLibs))
|
||||
.pattern(StreamJdtSearch.toPackagePattern(StreamJdtSearch.toWildCardPattern(searchTerm)))
|
||||
.search()
|
||||
.parallel()
|
||||
.map(match -> match.getElement())
|
||||
.filter(o -> o instanceof IPackageFragment)
|
||||
.map(p -> ((IPackageFragment)p).getElementName());
|
||||
}
|
||||
|
||||
public Stream<String> fuzzySearchTypes(URI projectUri, String searchTerm, boolean includeBinaries, boolean includeSystemLibs) throws Exception {
|
||||
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
|
||||
return new StreamJdtSearch(logger)
|
||||
.scope(StreamJdtSearch.searchScope(javaProject, includeBinaries, includeSystemLibs))
|
||||
.pattern(StreamJdtSearch.toTypePattern(StreamJdtSearch.toWildCardPattern(StreamJdtSearch.toProperTypeQuery(searchTerm))))
|
||||
.search()
|
||||
.parallel()
|
||||
.map(match -> match.getElement())
|
||||
.filter(o -> o instanceof IType)
|
||||
.map(e -> ((IType) e).getFullyQualifiedName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.searchScope;
|
||||
import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.toPackagePattern;
|
||||
import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.toWildCardPattern;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.IPackageFragment;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public class PackageFluxSearch extends CachingFluxJavaSearch<String> {
|
||||
|
||||
public PackageFluxSearch(Logger logger, boolean includeBinaries, boolean includeSystemLibs) {
|
||||
super(logger, includeBinaries, includeSystemLibs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Flux<String> getValuesAsync(IJavaProject javaProject, String searchTerm) {
|
||||
try {
|
||||
return new FluxJdtSearch(logger)
|
||||
.scope(searchScope(javaProject, includeBinaries, includeSystemLibs))
|
||||
.pattern(toPackagePattern(toWildCardPattern(searchTerm)))
|
||||
.search()
|
||||
.map(match -> match.getElement())
|
||||
.filter(o -> o instanceof IPackageFragment)
|
||||
.map(p -> ((IPackageFragment)p).getElementName());
|
||||
} catch (JavaModelException e) {
|
||||
logger.log(e);
|
||||
return Flux.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String stringValue(String t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaElement;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
import org.eclipse.jdt.core.search.IJavaSearchConstants;
|
||||
import org.eclipse.jdt.core.search.IJavaSearchScope;
|
||||
import org.eclipse.jdt.core.search.SearchEngine;
|
||||
import org.eclipse.jdt.core.search.SearchPattern;
|
||||
|
||||
public class SearchUtils {
|
||||
|
||||
public static String toWildCardPattern(String query) {
|
||||
StringBuilder builder = new StringBuilder("*");
|
||||
for (char c : query.toCharArray()) {
|
||||
builder.append(c);
|
||||
builder.append('*');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static SearchPattern toPackagePattern(String wildCardedQuery) {
|
||||
int searchFor = IJavaSearchConstants.PACKAGE;
|
||||
int limitTo = IJavaSearchConstants.DECLARATIONS;
|
||||
int matchRule = SearchPattern.R_PATTERN_MATCH;
|
||||
return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule);
|
||||
}
|
||||
|
||||
public static SearchPattern toClassPattern(String wildCardedQuery) {
|
||||
int searchFor = IJavaSearchConstants.CLASS;
|
||||
int limitTo = IJavaSearchConstants.DECLARATIONS;
|
||||
int matchRule = SearchPattern.R_PATTERN_MATCH;
|
||||
return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule);
|
||||
}
|
||||
|
||||
public static SearchPattern toTypePattern(String wildCardedQuery) {
|
||||
int searchFor = IJavaSearchConstants.TYPE;
|
||||
int limitTo = IJavaSearchConstants.DECLARATIONS;
|
||||
int matchRule = SearchPattern.R_PATTERN_MATCH;
|
||||
return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule);
|
||||
}
|
||||
|
||||
public static String toProperTypeQuery(String query) {
|
||||
int idx = query.lastIndexOf('.');
|
||||
if (idx > 0 && idx < query.length() - 1 && Character.isLowerCase(query.charAt(idx + 1))) {
|
||||
return query + '.';
|
||||
} else {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a search scope that includes a given project and its dependencies.
|
||||
*/
|
||||
public static IJavaSearchScope searchScope(IJavaProject javaProject, boolean includeBinaries, boolean includeSystemLibs) throws JavaModelException {
|
||||
int includeMask =
|
||||
IJavaSearchScope.REFERENCED_PROJECTS |
|
||||
IJavaSearchScope.SOURCES;
|
||||
if (includeBinaries) {
|
||||
includeMask = includeMask | IJavaSearchScope.APPLICATION_LIBRARIES;
|
||||
}
|
||||
if (includeSystemLibs) {
|
||||
includeMask = includeMask | IJavaSearchScope.SYSTEM_LIBRARIES;
|
||||
}
|
||||
return SearchEngine.createJavaSearchScope(new IJavaElement[] {javaProject}, includeMask);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.tooling.jdt.ls.commons.java;
|
||||
|
||||
import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.searchScope;
|
||||
import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.toProperTypeQuery;
|
||||
import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.toTypePattern;
|
||||
import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.toWildCardPattern;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.IType;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public class TypeFluxSearch extends CachingFluxJavaSearch<String> {
|
||||
|
||||
public TypeFluxSearch(Logger logger, boolean includeBinaries, boolean includeSystemLibs) {
|
||||
super(logger, includeBinaries, includeSystemLibs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Flux<String> getValuesAsync(IJavaProject javaProject, String searchTerm) {
|
||||
try {
|
||||
return new FluxJdtSearch(logger)
|
||||
.scope(searchScope(javaProject, includeBinaries, includeSystemLibs))
|
||||
.pattern(toTypePattern(toWildCardPattern(toProperTypeQuery(searchTerm))))
|
||||
.search()
|
||||
.map(match -> match.getElement())
|
||||
.filter(o -> o instanceof IType)
|
||||
.map(e -> ((IType) e).getFullyQualifiedName());
|
||||
} catch (Exception e) {
|
||||
logger.log(e);
|
||||
return Flux.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String stringValue(String t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ package org.springframework.tooling.jdt.ls.extension;
|
||||
import org.eclipse.jdt.ls.core.internal.HoverInfoProvider;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaData;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaSearch;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaFluxSearch;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.TypeHierarchy;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
@@ -26,7 +26,7 @@ public class JavaHelpers {
|
||||
|
||||
final public static Supplier<JavaData> DATA = Suppliers.memoize(() -> new JavaData(element -> HoverInfoProvider.computeSignature(element).getValue(), logger));
|
||||
|
||||
final public static Supplier<JavaSearch> SEARCH = Suppliers.memoize(() -> new JavaSearch(logger));
|
||||
final public static Supplier<JavaFluxSearch> SEARCH = Suppliers.memoize(() -> new JavaFluxSearch(logger));
|
||||
|
||||
final public static Supplier<TypeHierarchy> HIERARCHY = Suppliers.memoize(() -> new TypeHierarchy(logger, DATA.get()));
|
||||
|
||||
|
||||
@@ -10,30 +10,27 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.jdt.ls.extension;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class SearchHandler implements IDelegateCommandHandler {
|
||||
|
||||
private Gson gson = new Gson();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object executeCommand(String commandId, List<Object> arguments, IProgressMonitor monitor) throws Exception {
|
||||
Map<String, Object> obj = (Map<String, Object>) arguments.get(0);
|
||||
String projectUri = (String) obj.get("projectUri");
|
||||
String term = (String) obj.get("term");
|
||||
Boolean includeBinaries = (Boolean) obj.get("includeBinaries");
|
||||
Boolean includeSystemLibs = (Boolean) obj.get("includeSystemLibs");
|
||||
JavaSearchParams params = gson.fromJson(gson.toJson(arguments.get(0)), JavaSearchParams.class);
|
||||
switch (commandId) {
|
||||
case "sts.java.search.types":
|
||||
return JavaHelpers.SEARCH.get().fuzzySearchTypes(URI.create(projectUri), term, includeBinaries, includeSystemLibs).collect(Collectors.toList());
|
||||
return JavaHelpers.SEARCH.get().fuzzySearchTypes(params);
|
||||
case "sts.java.search.packages":
|
||||
return JavaHelpers.SEARCH.get().fuzzySearchPackages(URI.create(projectUri), term, includeBinaries, includeSystemLibs).collect(Collectors.toList());
|
||||
return JavaHelpers.SEARCH.get().fuzzySearchPackages(params);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
<signing.skip>true</signing.skip>
|
||||
<signing.alias>pivotal</signing.alias>
|
||||
<signing.keystore>~/.keytool/pivotal.jks</signing.keystore>
|
||||
<misc.p2.repo.version>3.9.4.201901081830</misc.p2.repo.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
@@ -87,6 +88,11 @@
|
||||
<!--URL copied from jdt.ls target platform file, needed to satisfy some of its dependencies -->
|
||||
<url>https://download.jboss.org/jbosstools/updates/m2e-extensions/m2e-apt/1.5.0-2018-08-14_20-24-39-H12/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>p2-thirdparty-bundles</id>
|
||||
<layout>p2</layout>
|
||||
<url>http://dist.springsource.com/release/TOOLS/third-party/misc-p2-repo/${misc.p2.repo.version}</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2019 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
|
||||
@@ -14,11 +14,12 @@ import java.time.Duration;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||
import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
@@ -52,6 +53,8 @@ import reactor.util.function.Tuples;
|
||||
*/
|
||||
public abstract class CachingValueProvider implements ValueProviderStrategy {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CachingValueProvider.class);
|
||||
|
||||
private static final Duration DEFAULT_TIMEOUT = Duration.ofMillis(1000);
|
||||
|
||||
/**
|
||||
@@ -76,6 +79,8 @@ public abstract class CachingValueProvider implements ValueProviderStrategy {
|
||||
|
||||
public CacheEntry(String query, Flux<StsValueHint> producer) {
|
||||
values = producer
|
||||
.doOnNext(t -> count++)
|
||||
.doOnComplete(() -> isComplete = true)
|
||||
.take(MAX_RESULTS)
|
||||
.cache(MAX_RESULTS);
|
||||
values.subscribe(); // create infinite demand so that we actually force cache entries to be fetched upto the max.
|
||||
@@ -95,7 +100,7 @@ public abstract class CachingValueProvider implements ValueProviderStrategy {
|
||||
try {
|
||||
cached = cache.get(key, () -> new CacheEntry(query, getValuesIncremental(javaProject, query)));
|
||||
} catch (ExecutionException e) {
|
||||
Log.log(e);
|
||||
log.error("{}", e);
|
||||
}
|
||||
return cached.values;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import reactor.util.function.Tuples;
|
||||
* @author Kris De Volder
|
||||
* @author Alex Boyko
|
||||
*/
|
||||
public class LoggerNameProvider extends CachingValueProvider {
|
||||
public class LoggerNameProvider implements ValueProviderStrategy {
|
||||
|
||||
private static final String LOGGING_GROUPS_PREFIX = "logging.group.";
|
||||
private final ProjectBasedPropertyIndexProvider adhocProperties;
|
||||
@@ -56,6 +56,11 @@ public class LoggerNameProvider extends CachingValueProvider {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<StsValueHint> getValues(IJavaProject javaProject, String query) {
|
||||
return getValuesAsync(javaProject, query);
|
||||
}
|
||||
|
||||
Collection<String> loggerGroupNames(IJavaProject jp) {
|
||||
Builder<String> builder = ImmutableSet.builder();
|
||||
if (adhocProperties!=null && includeGroups) {
|
||||
@@ -75,8 +80,7 @@ public class LoggerNameProvider extends CachingValueProvider {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
|
||||
private Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
|
||||
return Flux.concat(
|
||||
Flux.fromIterable(loggerGroupNames(javaProject))
|
||||
.map(loggerName -> Tuples.of(StsValueHint.create(loggerName), FuzzyMatcher.matchScore(query, loggerName)))
|
||||
|
||||
@@ -105,7 +105,7 @@ public class LoggerNameProviderTest {
|
||||
public void incrementalResults() throws Exception {
|
||||
String fullQuery = "jboss";
|
||||
|
||||
CachingValueProvider p = create();
|
||||
LoggerNameProvider p = create();
|
||||
for (int i = 0; i <= fullQuery.length(); i++) {
|
||||
String query = fullQuery.substring(0, i);
|
||||
List<String> results = getResults(p, query);
|
||||
@@ -154,7 +154,7 @@ public class LoggerNameProviderTest {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private List<String> getResults(CachingValueProvider p, String query) {
|
||||
private List<String> getResults(LoggerNameProvider p, String query) {
|
||||
return p.getValues(project, query).toStream()
|
||||
.map((h) -> h.getValue().toString())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -19,5 +19,9 @@ cd ${workdir}/../../../headless-services/jdt-ls-extension
|
||||
cp org.springframework.tooling.jdt.ls.extension/target/*.jar ${workdir}/jars/jdt-ls-extension.jar
|
||||
cp org.springframework.tooling.jdt.ls.commons/target/*.jar ${workdir}/jars/jdt-ls-commons.jar
|
||||
|
||||
# Copy Reactor dependency bundles
|
||||
cp org.springframework.tooling.jdt.ls.commons/target/dependencies/io.projectreactor.reactor-core.jar ${workdir}/jars/
|
||||
cp org.springframework.tooling.jdt.ls.commons/target/dependencies/org.reactivestreams.reactive-streams.jar ${workdir}/jars/
|
||||
|
||||
cd ${workdir}/..
|
||||
yarn
|
||||
|
||||
@@ -16,8 +16,8 @@ export const JAVA_TYPE_REQUEST_TYPE = 'sts/javaType';
|
||||
export const JAVADOC_HOVER_LINK_REQUEST_TYPE = 'sts/javadocHoverLink';
|
||||
export const JAVA_LOCATION_REQUEST_TYPE = 'sts/javaLocation';
|
||||
export const JAVADOC_REQUEST_TYPE = 'sts/javadoc';
|
||||
export const SEARCH_TYPES_REQUEST_TYPE = 'sts/searchJavaTypes';
|
||||
export const SEACH_PACKAGES_REQUEST_TYPE = 'sts/searchJavaPackages';
|
||||
export const SEARCH_TYPES_REQUEST_TYPE = 'sts/javaSearchTypes';
|
||||
export const SEACH_PACKAGES_REQUEST_TYPE = 'sts/javaSearchPackages';
|
||||
export const SUBTYPES_REQUEST_TYPE = 'sts/javaSubTypes';
|
||||
export const SUPERTYPES_REQUEST_TYPE = 'sts/javaSuperTypes';
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ export class BootJavaExtension implements JavaExtensionContribution {
|
||||
getExtensionBundles() {
|
||||
const jarFolderPath = path.resolve(__dirname, '../../jars');
|
||||
return [
|
||||
path.resolve(jarFolderPath, 'io.projectreactor.reactor-core.jar'),
|
||||
path.resolve(jarFolderPath, 'org.reactivestreams.reactive-streams.jar'),
|
||||
path.resolve(jarFolderPath, 'jdt-ls-commons.jar'),
|
||||
path.resolve(jarFolderPath, 'jdt-ls-extension.jar')
|
||||
];
|
||||
|
||||
570
vscode-extensions/commons-vscode/package-lock.json
generated
570
vscode-extensions/commons-vscode/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
850
vscode-extensions/vscode-spring-boot/package-lock.json
generated
850
vscode-extensions/vscode-spring-boot/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,8 @@
|
||||
],
|
||||
"contributes": {
|
||||
"javaExtensions": [
|
||||
"./jars/io.projectreactor.reactor-core.jar",
|
||||
"./jars/org.reactivestreams.reactive-streams.jar",
|
||||
"./jars/jdt-ls-commons.jar",
|
||||
"./jars/jdt-ls-extension.jar"
|
||||
],
|
||||
|
||||
@@ -23,3 +23,7 @@ cp target/*.jar ${workdir}/jars
|
||||
cd ${workdir}/../../headless-services/jdt-ls-extension
|
||||
cp org.springframework.tooling.jdt.ls.extension/target/*.jar ${workdir}/jars/jdt-ls-extension.jar
|
||||
cp org.springframework.tooling.jdt.ls.commons/target/*.jar ${workdir}/jars/jdt-ls-commons.jar
|
||||
|
||||
# Copy Reactor dependency bundles
|
||||
cp org.springframework.tooling.jdt.ls.commons/target/dependencies/io.projectreactor.reactor-core.jar ${workdir}/jars/
|
||||
cp org.springframework.tooling.jdt.ls.commons/target/dependencies/org.reactivestreams.reactive-streams.jar ${workdir}/jars/
|
||||
|
||||
Reference in New Issue
Block a user